|
2 | 2 | # |
3 | 3 | # SPDX-License-Identifier: Apache-2.0 |
4 | 4 |
|
5 | | -name: "CI: Backport the merged PR" |
| 5 | +name: "CI: Backport a merged PR to a release branch" |
6 | 6 |
|
7 | 7 | on: |
8 | | - pull_request_target: |
9 | | - types: [closed, labeled] |
10 | | - branches: |
11 | | - - main |
12 | 8 | workflow_dispatch: |
13 | 9 | inputs: |
14 | 10 | backport-branch: |
15 | | - description: "Branch to backport commits onto" |
16 | | - required: false |
| 11 | + description: "Existing release branch to receive the fix" |
| 12 | + required: true |
17 | 13 | type: string |
18 | 14 | pull-request: |
19 | | - description: "PR to backport" |
| 15 | + description: "Merged PR to backport" |
20 | 16 | required: true |
21 | 17 | type: number |
22 | 18 |
|
23 | | - |
24 | 19 | permissions: |
25 | | - contents: write # so it can comment |
26 | | - pull-requests: write # so it can create pull requests |
| 20 | + contents: write |
| 21 | + pull-requests: write |
| 22 | + |
| 23 | +concurrency: |
| 24 | + group: backport-${{ inputs.pull-request }}-${{ inputs.backport-branch }} |
| 25 | + cancel-in-progress: false |
27 | 26 |
|
28 | 27 | jobs: |
29 | | - backport-from-pr: |
30 | | - name: Backport directly from a pull request |
31 | | - if: ${{ github.repository_owner == 'nvidia' && |
32 | | - github.event.pull_request.merged == true && |
33 | | - contains( github.event.pull_request.labels.*.name, 'to-be-backported') |
34 | | - }} |
| 28 | + backport: |
| 29 | + if: github.repository == 'NVIDIA/cuda-python' |
35 | 30 | runs-on: ubuntu-latest |
36 | 31 | steps: |
37 | | - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 |
| 32 | + - name: Checkout workflow source |
| 33 | + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 |
| 34 | + with: |
| 35 | + ref: ${{ github.sha }} |
38 | 36 |
|
39 | | - - name: Load branch name |
40 | | - id: get-branch |
| 37 | + - name: Validate source PR and target branch |
| 38 | + env: |
| 39 | + GH_TOKEN: ${{ github.token }} |
| 40 | + GH_REPO: ${{ github.repository }} |
| 41 | + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} |
| 42 | + BACKPORT_BRANCH: ${{ inputs.backport-branch }} |
| 43 | + PR_NUMBER: ${{ inputs.pull-request }} |
41 | 44 | run: | |
42 | | - OLD_BRANCH=$(yq '.backport_branch' ci/versions.yml) |
43 | | - echo "OLD_BRANCH=${OLD_BRANCH}" >> $GITHUB_ENV |
| 45 | + set -euo pipefail |
| 46 | + if [[ ! "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]]; then |
| 47 | + echo "::error::The source PR must be a positive integer." |
| 48 | + exit 1 |
| 49 | + fi |
| 50 | + if ! git check-ref-format "refs/heads/$BACKPORT_BRANCH"; then |
| 51 | + echo "::error::Provide one exact target branch name." |
| 52 | + exit 1 |
| 53 | + fi |
| 54 | + if [[ "$BACKPORT_BRANCH" == "$DEFAULT_BRANCH" ]]; then |
| 55 | + echo "::error::Choose a release branch, not the default branch." |
| 56 | + exit 1 |
| 57 | + fi |
| 58 | + if ! git ls-remote --exit-code --heads origin "refs/heads/$BACKPORT_BRANCH"; then |
| 59 | + echo "::error::The target branch must already exist in this repository." |
| 60 | + exit 1 |
| 61 | + fi |
| 62 | + if [[ "$(gh pr view "$PR_NUMBER" --repo "$GH_REPO" --json state --jq .state)" != MERGED ]]; then |
| 63 | + echo "::error::The source PR must already be merged in this repository." |
| 64 | + exit 1 |
| 65 | + fi |
44 | 66 |
|
45 | | - - name: Create backport pull requests |
| 67 | + # Workflow-file changes need a manual backport because GITHUB_TOKEN |
| 68 | + # cannot push them. Generated changes need target-specific regeneration. |
| 69 | + - name: Create backport pull request |
| 70 | + id: backport |
46 | 71 | uses: korthout/backport-action@8560fb503c275d433c56f05a2f64850093baa9f7 # v4.7.0 |
47 | 72 | with: |
| 73 | + source_pr_number: ${{ inputs.pull-request }} |
| 74 | + target_branches: ${{ inputs.backport-branch }} |
| 75 | + # The explicit target must not be combined with source PR labels. |
| 76 | + label_pattern: '' |
48 | 77 | copy_assignees: true |
49 | | - copy_labels_pattern: true |
| 78 | + copy_labels_pattern: '^(?!to-be-backported$|backport ).*' |
50 | 79 | copy_requested_reviewers: true |
51 | | - target_branches: ${{ env.OLD_BRANCH }} |
52 | | - backport-to-branch: |
53 | | - name: Backport a specific PR against a specific branch |
54 | | - if: github.repository_owner == 'nvidia' && github.event_name == 'workflow_dispatch' |
55 | | - runs-on: ubuntu-latest |
56 | | - steps: |
57 | | - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 |
58 | 80 |
|
59 | | - - name: Load branch from environment name |
60 | | - if: inputs.backport-branch == null |
| 81 | + - name: Require successful backport |
| 82 | + if: steps.backport.outputs.was_successful != 'true' |
61 | 83 | run: | |
62 | | - BACKPORT_BRANCH=$(yq '.backport_branch' ci/versions.yml) |
63 | | - echo "BACKPORT_BRANCH=${BRANCH}" >> $GITHUB_ENV |
64 | | -
|
65 | | - - name: Load branch name from input |
66 | | - if: inputs.backport-branch != null |
67 | | - run: echo "BACKPORT_BRANCH=${{ inputs.backport-branch }}" >> $GITHUB_ENV |
68 | | - |
69 | | - - name: Create backport pull requests |
70 | | - uses: korthout/backport-action@8560fb503c275d433c56f05a2f64850093baa9f7 # v4.7.0 |
71 | | - with: |
72 | | - copy_assignees: true |
73 | | - copy_labels_pattern: true |
74 | | - copy_requested_reviewers: true |
75 | | - target_branches: ${{ env.BACKPORT_BRANCH }} |
76 | | - source_pr_number: ${{ inputs.pull-request }} |
| 84 | + echo "::error::Backport failed; resolve the conflict or prepare the target-specific fix manually." |
| 85 | + exit 1 |
0 commit comments