mirror of
https://github.com/infiniteCable2/openpilot.git
synced 2026-09-15 03:53:41 +08:00
fd0d4a5aab
pull_request_target is needed for security, but at the same time it makes life a little harder because the ref is different so we need to do some work to make sure we get what we are supposed to get
322 lines
14 KiB
YAML
322 lines
14 KiB
YAML
name: sunnypilot prebuilt action
|
||
|
||
env:
|
||
BUILD_DIR: "/data/openpilot"
|
||
OUTPUT_DIR: ${{ github.workspace }}/output
|
||
CI_DIR: ${{ github.workspace }}/release/ci
|
||
SCONS_CACHE_DIR: ${{ github.workspace }}/release/ci/scons_cache
|
||
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
|
||
|
||
# Branch configurations
|
||
MASTER_BRANCH: "master"
|
||
MASTER_NEW_BRANCH: "master-new"
|
||
DEV_C3_SOURCE_BRANCH: "master-dev-c3-new"
|
||
|
||
# Target branch configurations
|
||
STAGING_TARGET_BRANCH: "staging-c3-new"
|
||
DEV_TARGET_BRANCH: "dev-c3-new"
|
||
RELEASE_TARGET_BRANCH: "release-c3-new"
|
||
|
||
on:
|
||
push:
|
||
branches: [ master, master-new, master-dev-c3-new ]
|
||
tags: [ '*' ]
|
||
pull_request_target:
|
||
types: [ labeled ]
|
||
workflow_dispatch:
|
||
inputs:
|
||
wait_for_tests:
|
||
description: 'Wait for selfdrive_tests to finish'
|
||
required: false
|
||
type: boolean
|
||
default: false
|
||
|
||
jobs:
|
||
validate_tests:
|
||
runs-on: ubuntu-24.04
|
||
if: ((github.event_name == 'workflow_dispatch' && inputs.wait_for_tests) || contains(github.event_name, 'pull_request') && (github.event.action == 'labeled' && github.event.label.name == 'prebuilt'))
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
- name: Wait for Tests
|
||
uses: ./.github/workflows/wait-for-action # Path to where you place the action
|
||
with:
|
||
workflow: selfdrive_tests.yaml # The workflow file to monitor
|
||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
build:
|
||
needs: [ validate_tests ]
|
||
concurrency:
|
||
group: build-${{ github.head_ref || github.ref_name }}
|
||
cancel-in-progress: false
|
||
runs-on: self-hosted
|
||
outputs:
|
||
new_branch: ${{ steps.set-env.outputs.new_branch }}
|
||
version: ${{ steps.set-env.outputs.version }}
|
||
extra_version_identifier: ${{ steps.set-env.outputs.extra_version_identifier }}
|
||
commit_sha: ${{ steps.set-env.outputs.commit_sha }}
|
||
if: ${{ (always() && !failure() && !cancelled()) && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
with:
|
||
submodules: recursive
|
||
ref: ${{ github.head_ref || github.ref_name }}
|
||
repository: ${{ github.event.pull_request.head.repo.fork && github.event.pull_request.head.repo.full_name || github.repository }}
|
||
- run: git lfs pull
|
||
|
||
- name: Cache SCons
|
||
uses: actions/cache@v4
|
||
with:
|
||
path: ${{env.SCONS_CACHE_DIR}}
|
||
key: scons-${{ runner.os }}-${{ runner.arch }}-${{ github.head_ref || github.ref_name }}-${{ github.sha }}
|
||
# Note: GitHub Actions enforces cache isolation between different build sources (PR builds, workflow dispatches, etc.)
|
||
# for security. Only caches from the default branch are shared across all builds. This is by design and cannot be overridden.
|
||
restore-keys: |
|
||
scons-${{ runner.os }}-${{ runner.arch }}-${{ github.head_ref || github.ref_name }}
|
||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_NEW_BRANCH }}
|
||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_BRANCH }}
|
||
scons-${{ runner.os }}-${{ runner.arch }}
|
||
|
||
- name: Set Configuration
|
||
if: (!github.event.pull_request.head.repo.fork)
|
||
run: |
|
||
if [[ "${{ github.head_ref || github.ref_name }}" == "${{ env.DEV_C3_SOURCE_BRANCH }}" ]]; then
|
||
# Dev configuration
|
||
echo "BRANCH_TYPE=dev" >> $GITHUB_ENV
|
||
echo "NEW_BRANCH=${{ env.DEV_TARGET_BRANCH }}" >> $GITHUB_ENV
|
||
echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV
|
||
echo "EXTRA_VERSION_IDENTIFIER=${{ github.run_number }}" >> $GITHUB_ENV
|
||
|
||
elif [[ "${{ github.head_ref || github.ref_name }}" == "${{ env.MASTER_BRANCH }}" || "${{ github.ref_name }}" == "${{ env.MASTER_NEW_BRANCH }}" ]]; then
|
||
# Master configuration
|
||
echo "BRANCH_TYPE=master" >> $GITHUB_ENV
|
||
echo "NEW_BRANCH=${{ env.STAGING_TARGET_BRANCH }}" >> $GITHUB_ENV
|
||
echo "EXTRA_VERSION_IDENTIFIER=staging" >> $GITHUB_ENV
|
||
echo "VERSION=$(cat common/version.h | grep COMMA_VERSION | sed -e 's/[^0-9|.]//g')-staging" >> $GITHUB_ENV
|
||
|
||
elif [[ "${{ github.ref }}" == refs/tags/* ]]; then
|
||
# Tag configuration
|
||
echo "BRANCH_TYPE=tag" >> $GITHUB_ENV
|
||
echo "NEW_BRANCH=${{ env.RELEASE_TARGET_BRANCH }}" >> $GITHUB_ENV
|
||
echo "EXTRA_VERSION_IDENTIFIER=release" >> $GITHUB_ENV
|
||
echo "VERSION=$(cat common/version.h | grep COMMA_VERSION | sed -e 's/[^0-9|.]//g')-release" >> $GITHUB_ENV
|
||
|
||
else
|
||
# Feature branch configuration
|
||
echo "BRANCH_TYPE=dispatch" >> $GITHUB_ENV
|
||
echo "NEW_BRANCH=${{ github.head_ref || github.ref_name }}-prebuilt" >> $GITHUB_ENV
|
||
echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV
|
||
fi
|
||
|
||
- name: Set Configuration (only forks)
|
||
if: (github.event.pull_request.head.repo.fork)
|
||
run: |
|
||
echo "BRANCH_TYPE=dispatch" >> $GITHUB_ENV
|
||
echo "NEW_BRANCH=${{ github.head_ref || github.ref_name }}-fork-prebuilt" >> $GITHUB_ENV
|
||
echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV
|
||
|
||
- name: Set environment variables
|
||
id: set-env
|
||
run: |
|
||
# Write to GITHUB_OUTPUT from environment variables
|
||
echo "new_branch=$NEW_BRANCH" >> $GITHUB_OUTPUT
|
||
[[ ! -z "$EXTRA_VERSION_IDENTIFIER" ]] && echo "extra_version_identifier=$EXTRA_VERSION_IDENTIFIER" >> $GITHUB_OUTPUT
|
||
[[ ! -z "$VERSION" ]] && echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||
echo "commit_sha=${{ github.sha }}" >> $GITHUB_OUTPUT
|
||
|
||
# Set up common environment
|
||
source /etc/profile;
|
||
export UV_PROJECT_ENVIRONMENT=${HOME}/venv
|
||
export VIRTUAL_ENV=$UV_PROJECT_ENVIRONMENT
|
||
printenv >> $GITHUB_ENV
|
||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
||
cat $GITHUB_OUTPUT
|
||
fi
|
||
|
||
- name: Setup build environment
|
||
run: |
|
||
mkdir -p "${BUILD_DIR}/"
|
||
sudo find $BUILD_DIR/ -mindepth 1 -delete
|
||
echo "Starting build stage..."
|
||
echo "BUILD_DIR: ${BUILD_DIR}"
|
||
echo "CI_DIR: ${CI_DIR}"
|
||
echo "VERSION: ${{ steps.set-env.outputs.version }}"
|
||
echo "UV_PROJECT_ENVIRONMENT: ${UV_PROJECT_ENVIRONMENT}"
|
||
echo "VIRTUAL_ENV: ${VIRTUAL_ENV}"
|
||
echo "-------"
|
||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
||
printenv
|
||
fi
|
||
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --disable
|
||
|
||
- name: Build Main Project
|
||
run: |
|
||
export PYTHONPATH="$BUILD_DIR"
|
||
./release/release_files.py | sort | uniq | rsync -rRl${RUNNER_DEBUG:+v} --files-from=- . $BUILD_DIR/
|
||
cd $BUILD_DIR
|
||
sed -i '/from .board.jungle import PandaJungle, PandaJungleDFU/s/^/#/' panda/__init__.py
|
||
scons -j$(nproc) cache_dir=${{env.SCONS_CACHE_DIR}} --minimal
|
||
touch ${BUILD_DIR}/prebuilt
|
||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
||
ls -la ${BUILD_DIR}
|
||
fi
|
||
|
||
- name: Prepare Output
|
||
run: |
|
||
sudo rm -rf ${OUTPUT_DIR}
|
||
mkdir -p ${OUTPUT_DIR}
|
||
rsync -am${RUNNER_DEBUG:+v} \
|
||
--include='**/panda/board/' \
|
||
--include='**/panda/board/obj' \
|
||
--include='**/panda/board/obj/panda.bin.signed' \
|
||
--include='**/panda/board/obj/panda_h7.bin.signed' \
|
||
--include='**/panda/board/obj/bootstub.panda.bin' \
|
||
--include='**/panda/board/obj/bootstub.panda_h7.bin' \
|
||
--exclude='.sconsign.dblite' \
|
||
--exclude='*.a' \
|
||
--exclude='*.o' \
|
||
--exclude='*.os' \
|
||
--exclude='*.pyc' \
|
||
--exclude='moc_*' \
|
||
--exclude='*.cc' \
|
||
--exclude='Jenkinsfile' \
|
||
--exclude='supercombo.onnx' \
|
||
--exclude='**/panda/board/*' \
|
||
--exclude='**/panda/board/obj/**' \
|
||
--exclude='**/panda/certs/' \
|
||
--exclude='**/panda/crypto/' \
|
||
--exclude='**/release/' \
|
||
--exclude='**/.github/' \
|
||
--exclude='**/selfdrive/ui/replay/' \
|
||
--exclude='**/__pycache__/' \
|
||
--exclude='**/selfdrive/ui/*.h' \
|
||
--exclude='**/selfdrive/ui/**/*.h' \
|
||
--exclude='**/selfdrive/ui/qt/offroad/sunnypilot/' \
|
||
--exclude='${{env.SCONS_CACHE_DIR}}' \
|
||
--exclude='**/.git/' \
|
||
--exclude='**/SConstruct' \
|
||
--exclude='**/SConscript' \
|
||
--exclude='**/.venv/' \
|
||
--delete-excluded \
|
||
--chown=comma:comma \
|
||
${BUILD_DIR}/ ${OUTPUT_DIR}/
|
||
|
||
- name: 'Tar.gz files'
|
||
run: |
|
||
tar czf prebuilt.tar.gz -C ${{ env.OUTPUT_DIR }} .
|
||
ls -la prebuilt.tar.gz
|
||
|
||
- name: 'Upload Artifact'
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: prebuilt
|
||
path: prebuilt.tar.gz
|
||
|
||
- name: Re-enable powersave
|
||
if: always()
|
||
run: |
|
||
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --enable
|
||
|
||
|
||
publish:
|
||
concurrency:
|
||
group: publish-${{ github.head_ref || github.ref_name }}
|
||
cancel-in-progress: true
|
||
if: ${{ (always() && !failure() && !cancelled()) && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
|
||
needs: [ build ]
|
||
runs-on: ubuntu-24.04
|
||
environment: ${{ (contains(fromJSON(vars.AUTO_DEPLOY_PREBUILT_BRANCHES), github.head_ref || github.ref_name) || contains(github.event.pull_request.labels.*.name, 'prebuilt')) && 'auto-deploy' || 'feature-branch' }}
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Download build artifacts
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
name: prebuilt
|
||
|
||
- name: Untar prebuilt
|
||
run: |
|
||
mkdir -p ${{ env.OUTPUT_DIR }}
|
||
tar xzf prebuilt.tar.gz -C ${{ env.OUTPUT_DIR }}
|
||
|
||
- name: Configure Git
|
||
run: |
|
||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||
git config --global user.name "github-actions[bot]"
|
||
|
||
- name: Publish to Public Repository
|
||
env:
|
||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
run: |
|
||
echo '${{ toJSON(needs.build.outputs) }}'
|
||
ls -la ${{ env.OUTPUT_DIR }}
|
||
|
||
${{ env.CI_DIR }}/publish.sh \
|
||
"${{ github.workspace }}" \
|
||
"${{ env.OUTPUT_DIR }}" \
|
||
"${{ needs.build.outputs.new_branch }}" \
|
||
"${{ needs.build.outputs.version }}" \
|
||
"https://x-access-token:${{github.token}}@github.com/sunnypilot/sunnypilot.git" \
|
||
"-${{ needs.build.outputs.extra_version_identifier }}"
|
||
|
||
echo ""
|
||
echo "---- ℹ️ To update the list of branches that auto deploy prebuilts -----"
|
||
echo ""
|
||
echo "1. Go to: ${{ github.server_url }}/${{ github.repository }}/settings/variables/actions/AUTO_DEPLOY_PREBUILT_BRANCHES"
|
||
echo "2. Current value: ${{ vars.AUTO_DEPLOY_PREBUILT_BRANCHES }}"
|
||
echo "3. Update as needed (JSON array with no spaces)"
|
||
|
||
notify:
|
||
needs: [ build, publish ]
|
||
runs-on: ubuntu-24.04
|
||
if: ${{ (always() && !failure() && !cancelled()) && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
- name: Setup Alpine Linux environment
|
||
uses: jirutka/setup-alpine@v1.2.0
|
||
with:
|
||
packages: 'jq gettext curl'
|
||
|
||
- name: Send Discord Notification
|
||
env:
|
||
DISCORD_WEBHOOK: ${{ contains(fromJSON(vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES), github.head_ref || github.ref_name) && secrets.DISCORD_DEV_FEEDBACK_CHANNEL_WEBHOOK || secrets.DISCORD_DEV_PRIVATE_CHANNEL_WEBHOOK }}
|
||
run: |
|
||
TEMPLATE='${{ vars.DISCORD_GENERAL_UPDATE_NOTICE }}'
|
||
export EXTRA_VERSION_IDENTIFIER="${{ needs.build.outputs.extra_version_identifier }}"
|
||
export VERSION="${{ needs.build.outputs.version }}"
|
||
export branch_name=${{ github.head_ref || github.ref_name }}
|
||
export new_branch=${{ needs.build.outputs.new_branch }}
|
||
export extra_version_identifier=${{ needs.build.outputs.extra_version_identifier || github.run_number}}
|
||
echo ${TEMPLATE} | envsubst | jq -c '.' | tee payload.json
|
||
curl -X POST -H "Content-Type: application/json" -d @payload.json $DISCORD_WEBHOOK
|
||
|
||
echo ""
|
||
echo "---- ℹ️ To update the list of branches that notify to dev-feedback -----"
|
||
echo ""
|
||
echo "1. Go to: ${{ github.server_url }}/${{ github.repository }}/settings/variables/actions/DEV_FEEDBACK_NOTIFICATION_BRANCHES"
|
||
echo "2. Current value: ${{ vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES }}"
|
||
echo "3. Update as needed (JSON array with no spaces)"
|
||
shell: alpine.sh {0}
|
||
|
||
manage-pr-labels:
|
||
name: Remove prebuilt label
|
||
runs-on: ubuntu-latest
|
||
if: (always() && contains(github.event_name, 'pull_request') && (github.event.action == 'labeled' && github.event.label.name == 'prebuilt'))
|
||
env:
|
||
LABEL: prebuilt
|
||
steps:
|
||
- name: Remove trust-fork-pr label if present
|
||
uses: actions/github-script@v7
|
||
with:
|
||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||
script: |
|
||
const prNumber = context.payload.pull_request.number;
|
||
|
||
await github.rest.issues.removeLabel({
|
||
owner: context.repo.owner,
|
||
repo: context.repo.repo,
|
||
issue_number: prNumber,
|
||
name: process.env.LABEL
|
||
});
|
||
|
||
console.log(`Removed '${process.env.LABEL}' label from PR #${prNumber}`);
|