129 lines
5 KiB
YAML
129 lines
5 KiB
YAML
name: Automatic Backport
|
||
|
||
on:
|
||
pull_request_target:
|
||
types: [closed, labeled] # fires when PR is closed (merged) or labeled
|
||
|
||
concurrency:
|
||
group: backport-${{ github.workflow }}-${{ github.event.pull_request.number }}
|
||
cancel-in-progress: true
|
||
|
||
permissions:
|
||
contents: write
|
||
pull-requests: write
|
||
|
||
jobs:
|
||
# Determine which backports are needed
|
||
prepare:
|
||
if: |
|
||
github.event.pull_request.merged == true &&
|
||
(
|
||
contains(github.event.pull_request.labels.*.name, 'backport') ||
|
||
contains(github.event.pull_request.labels.*.name, 'backport-previous') ||
|
||
(github.event.action == 'labeled' && (github.event.label.name == 'backport' || github.event.label.name == 'backport-previous'))
|
||
)
|
||
runs-on: [self-hosted]
|
||
outputs:
|
||
backport_current: ${{ steps.labels.outputs.backport }}
|
||
backport_previous: ${{ steps.labels.outputs.backport_previous }}
|
||
current_branch: ${{ steps.branches.outputs.current_branch }}
|
||
previous_branch: ${{ steps.branches.outputs.previous_branch }}
|
||
steps:
|
||
- name: Check which labels are present
|
||
id: labels
|
||
uses: actions/github-script@v7
|
||
with:
|
||
script: |
|
||
const pr = context.payload.pull_request;
|
||
const labels = pr.labels.map(l => l.name);
|
||
const isBackport = labels.includes('backport');
|
||
const isBackportPrevious = labels.includes('backport-previous');
|
||
|
||
core.setOutput('backport', isBackport ? 'true' : 'false');
|
||
core.setOutput('backport_previous', isBackportPrevious ? 'true' : 'false');
|
||
|
||
console.log(`backport label: ${isBackport}, backport-previous label: ${isBackportPrevious}`);
|
||
|
||
- name: Determine target branches
|
||
id: branches
|
||
uses: actions/github-script@v7
|
||
with:
|
||
script: |
|
||
// Get latest release
|
||
let latestRelease;
|
||
try {
|
||
latestRelease = await github.rest.repos.getLatestRelease({
|
||
owner: context.repo.owner,
|
||
repo: context.repo.repo
|
||
});
|
||
} catch (e) {
|
||
core.setFailed('No existing releases found; cannot determine backport target.');
|
||
return;
|
||
}
|
||
|
||
const [maj, min] = latestRelease.data.tag_name.replace(/^v/, '').split('.');
|
||
const currentBranch = `release-${maj}.${min}`;
|
||
const prevMin = parseInt(min) - 1;
|
||
const previousBranch = prevMin >= 0 ? `release-${maj}.${prevMin}` : '';
|
||
|
||
core.setOutput('current_branch', currentBranch);
|
||
core.setOutput('previous_branch', previousBranch);
|
||
|
||
console.log(`Current branch: ${currentBranch}, Previous branch: ${previousBranch || 'N/A'}`);
|
||
|
||
// Verify previous branch exists if we need it
|
||
if (previousBranch && '${{ steps.labels.outputs.backport_previous }}' === 'true') {
|
||
try {
|
||
await github.rest.repos.getBranch({
|
||
owner: context.repo.owner,
|
||
repo: context.repo.repo,
|
||
branch: previousBranch
|
||
});
|
||
console.log(`Previous branch ${previousBranch} exists`);
|
||
} catch (e) {
|
||
core.setFailed(`Previous branch ${previousBranch} does not exist.`);
|
||
return;
|
||
}
|
||
}
|
||
|
||
backport:
|
||
needs: prepare
|
||
if: |
|
||
github.event.pull_request.merged == true &&
|
||
(needs.prepare.outputs.backport_current == 'true' || needs.prepare.outputs.backport_previous == 'true')
|
||
runs-on: [self-hosted]
|
||
strategy:
|
||
matrix:
|
||
backport_type: [current, previous]
|
||
steps:
|
||
# 1. Determine target branch based on matrix
|
||
- name: Set target branch
|
||
id: target
|
||
if: |
|
||
(matrix.backport_type == 'current' && needs.prepare.outputs.backport_current == 'true') ||
|
||
(matrix.backport_type == 'previous' && needs.prepare.outputs.backport_previous == 'true')
|
||
run: |
|
||
if [ "${{ matrix.backport_type }}" == "current" ]; then
|
||
echo "branch=${{ needs.prepare.outputs.current_branch }}" >> $GITHUB_OUTPUT
|
||
echo "Target branch: ${{ needs.prepare.outputs.current_branch }}"
|
||
else
|
||
echo "branch=${{ needs.prepare.outputs.previous_branch }}" >> $GITHUB_OUTPUT
|
||
echo "Target branch: ${{ needs.prepare.outputs.previous_branch }}"
|
||
fi
|
||
|
||
# 2. Checkout (required by backport‑action)
|
||
- name: Checkout repository
|
||
if: steps.target.outcome == 'success'
|
||
uses: actions/checkout@v4
|
||
|
||
# 3. Create the back‑port pull request
|
||
- name: Create back‑port PR
|
||
id: backport
|
||
if: steps.target.outcome == 'success'
|
||
uses: korthout/backport-action@v3.2.1
|
||
with:
|
||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||
label_pattern: '' # don't read labels for targets
|
||
target_branches: ${{ steps.target.outputs.branch }}
|
||
merge_commits: skip
|
||
conflict_resolution: draft_commit_conflicts
|