diff --git a/.github/workflows/sunnypilot-master-dev-c3-prep.yaml b/.github/workflows/sunnypilot-master-dev-c3-prep.yaml index f6b749742..b252f42d7 100644 --- a/.github/workflows/sunnypilot-master-dev-c3-prep.yaml +++ b/.github/workflows/sunnypilot-master-dev-c3-prep.yaml @@ -1,13 +1,23 @@ -name: Nightly Branch Reset and PR Squash +name: Build dev-c3-new env: DEFAULT_SOURCE_BRANCH: "master-new" - DEFAULT_TARGET_BRANCH: "nightly" + DEFAULT_TARGET_BRANCH: "master-dev-c3-new" PR_LABEL: "dev-c3" + TRUST_FORK_PR_LABEL: "trust-fork-pr" LFS_URL: 'https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs' LFS_PUSH_URL: 'ssh://git@gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git' on: + push: + branches: + - master + - master-new + pull_request_target: + types: [ synchronize, opened, labeled ] + branches: + - 'master' + - 'master-new' workflow_dispatch: inputs: source_branch: @@ -20,18 +30,83 @@ on: required: true default: 'master-dev-c3-new' type: string -# schedule: -# - cron: '0 0 * * *' # Run at midnight UTC for nightly jobs: + manage-pr-labels: + name: Remove trust-fork-pr label if present + runs-on: ubuntu-latest + if: (github.event.pull_request.head.repo.fork && (github.event_name == 'pull_request_target' && github.event.action == 'synchronize')) + steps: + - name: Check if PR has dev-c3 label + id: check-labels + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const prNumber = context.payload.pull_request.number; + const { data: labels } = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber + }); + + const hasDevC3Label = labels.some(label => label.name === process.env.PR_LABEL); + const hasTrustLabel = labels.some(label => label.name === process.env.TRUST_FORK_PR_LABEL); + + console.log(`PR #${prNumber} has ${process.env.PR_LABEL} label: ${hasDevC3Label}`); + console.log(`PR #${prNumber} has ${process.env.TRUST_FORK_PR_LABEL} label: ${hasTrustLabel}`); + + core.setOutput('has-dev-c3', hasDevC3Label ? 'true' : 'false'); + core.setOutput('has-trust', hasTrustLabel ? 'true' : 'false'); + + - name: Remove trust-fork-pr label if present + if: steps.check-labels.outputs.has-dev-c3 == 'true' && steps.check-labels.outputs.has-trust == 'true' + 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.TRUST_FORK_PR_LABEL + }); + + console.log(`Removed '${process.env.TRUST_FORK_PR_LABEL}' label from PR #${prNumber} as it received new commits`); + + // Add a comment to the PR + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: `The \`${process.env.TRUST_FORK_PR_LABEL}\` label has been automatically removed because new commits were pushed to this PR. This PR will need to be re-reviewed before the label can be applied again.` + }); + reset-and-squash: runs-on: ubuntu-latest + if: ( + (github.event_name == 'workflow_dispatch') + || (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)) + || (github.event_name == 'pull_request_target' && ((github.event.action == 'labeled' && (github.event.label.name == 'dev-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3')))) + ) steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # Fetch all history for all branches token: ${{ secrets.GITHUB_TOKEN }} + - name: Wait for Tests + uses: ./.github/workflows/wait-for-action # Path to where you place the action + if: ( + (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)) + || (github.event_name == 'pull_request_target' && ((github.event.action == 'labeled' && (github.event.label.name == 'dev-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3')))) + ) + with: + workflow: selfdrive_tests.yaml # The workflow file to monitor + github-token: ${{ secrets.GITHUB_TOKEN }} + - name: Configure Git run: | git config --global user.name 'github-actions[bot]' diff --git a/.github/workflows/wait-for-action/action.yaml b/.github/workflows/wait-for-action/action.yaml new file mode 100644 index 000000000..574ef1518 --- /dev/null +++ b/.github/workflows/wait-for-action/action.yaml @@ -0,0 +1,44 @@ +name: 'Wait for Tests' +description: 'Action to wait for workflow tests to start and complete' +inputs: + workflow: + description: 'The workflow file name to monitor' + required: true + default: 'selfdrive_tests.yaml' + branch: + description: 'The branch to monitor (defaults to current branch)' + required: false + default: '' + github-token: + description: 'GitHub token for API access' + required: true + wait-time: + description: 'Initial sleep time in seconds before monitoring starts' + required: false + default: '30' + should-wait-for-start: + description: 'Whether to wait for tests to start' + required: false + default: false + +runs: + using: 'composite' + steps: + - name: Wait for tests to start + if: inputs.should-wait-for-start == 'true' + shell: bash + run: | + echo "Sleeping for ${{ inputs.wait-time }} seconds to give some time for the action to start and then we'll wait" + sleep ${{ inputs.wait-time }} + + - name: Wait for tests to finish + shell: bash + run: | + BRANCH="${{ inputs.branch || github.head_ref || github.ref_name }}" + + echo "Looking for workflow runs of ${{ inputs.workflow }} on branch $BRANCH" + RUN_ID=$(gh run list --workflow=${{ inputs.workflow }} --branch="$BRANCH" --limit=1 --json databaseId --jq '.[0].databaseId') + echo "Watching run ID: $RUN_ID" + gh run watch "$RUN_ID" + env: + GITHUB_TOKEN: ${{ inputs.github-token }} diff --git a/release/ci/squash_and_merge_prs.py b/release/ci/squash_and_merge_prs.py index 6d8f70f34..64fa32551 100755 --- a/release/ci/squash_and_merge_prs.py +++ b/release/ci/squash_and_merge_prs.py @@ -118,19 +118,9 @@ def process_pr(pr_data, source_branch, target_branch, squash_script_path): origin = "origin" if not head_repository.get('isFork', False) else head_repository.get('nameWithOwner', 'origin') if is_fork and trust_fork: - print(f"Removing label `{TRUST_FORK_LABEL}` from PR #{pr_number} as it is being processed") - subprocess.run(['gh', 'pr', 'edit', str(pr_number), '--remove-label', TRUST_FORK_LABEL], check=True) - pr_comments.append(f"ℹ️️ This PR is from a fork. The `{TRUST_FORK_LABEL}` label was removed as it is being processed right now.") print(f"Adding remote {origin} for PR #{pr_number}") subprocess.run(['git', 'remote', 'add', origin, head_repository.get('url')], check=False) - if is_fork and not trust_fork: - pr_comments.append( - f"⚠️ This PR is from a fork. Please add the `{TRUST_FORK_LABEL}` label to include it in the squash." + - "\n**Note**: The label is removed after the squash is done and must be added again for the next execution for security reasons." - ) - continue - if not is_valid: print(f"Warning: {skip_reason} for PR #{pr_number}, skipping") pr_comments.append(f"⚠️ This PR was skipped in the automated `{target_branch}` squash because **{skip_reason}**.")