Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 156 additions & 24 deletions .github/workflows/version-bump.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ on:
- 'major'
- 'minor'
- 'patch'
enable_pr_reuse:
description: 'Enable PR reuse and branch renaming (experimental)'
required: true
default: false
type: boolean

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand Down Expand Up @@ -87,18 +92,72 @@ jobs:
echo "Backstage release version and current workspace version are the same, skipping version bump"
exit 1 # Non-zero exit code fails the step and job
fi
- name: 'Check for existing version bump PR'
id: check_existing_pr
if: ${{ inputs.enable_pr_reuse }}
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
with:
github-token: ${{secrets.GH_SERVICE_ACCOUNT_TOKEN}}
script: |
const workspace = '${{ matrix.workspace }}';

const { data: allOpenPRs } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
base: 'main'
});

const workspacePRs = allOpenPRs.filter(pr =>
pr.title.startsWith(`${workspace} - version:bump`) &&
pr.head.ref.startsWith(`${workspace}/`)
);

if (workspacePRs.length > 0) {
workspacePRs.sort((a, b) =>
new Date(b.created_at) - new Date(a.created_at)
);

const existingPR = workspacePRs[0];
console.log(`Found ${workspacePRs.length} existing PR(s) for ${workspace}`);
console.log(`Using most recently created PR #${existingPR.number}: ${existingPR.title}`);
console.log(`Will reuse branch: ${existingPR.head.ref}`);
core.setOutput('branch_name', existingPR.head.ref);
core.setOutput('pr_number', existingPR.number);
core.setOutput('has_existing_pr', 'true');
} else {
console.log('No existing version bump PR found, will create new branch');
const newBranch = `${workspace}/v${{ steps.set_release_name.outputs.release_version }}`;
core.setOutput('branch_name', newBranch);
core.setOutput('has_existing_pr', 'false');
}
- name: 'Configure git'
run: |
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
- name: 'Create workspace branch'
- name: 'Create or checkout workspace branch'
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
BRANCH=$(git branch --list ${{ matrix.workspace }}/v${{ steps.set_release_name.outputs.release_version }})

if [ "${{ inputs.enable_pr_reuse }}" == "true" ]; then
BRANCH_NAME="${{ steps.check_existing_pr.outputs.branch_name }}"
else
BRANCH_NAME="${{ matrix.workspace }}/v${{ steps.set_release_name.outputs.release_version }}"
fi

BRANCH=$(git branch --list "$BRANCH_NAME")
if [ ! -z "$BRANCH" ]; then
git branch -D ${{ matrix.workspace }}/v${{ steps.set_release_name.outputs.release_version }}
git branch -D "$BRANCH_NAME"
fi

if [ "${{ inputs.enable_pr_reuse }}" == "true" ] && git ls-remote --exit-code --heads origin "$BRANCH_NAME" > /dev/null 2>&1; then
echo "Remote branch exists, checking it out"
git fetch origin "$BRANCH_NAME"
git checkout -b "$BRANCH_NAME" "origin/$BRANCH_NAME"
else
echo "Creating new branch"
git checkout -b "$BRANCH_NAME"
fi
git checkout -b ${{ matrix.workspace }}/v${{ steps.set_release_name.outputs.release_version }}
- name: Run backstage-cli versions:bump --release ${{ inputs.release_line || 'main' }} command
working-directory: ./workspaces/${{ matrix.workspace }}
run: yarn backstage-cli versions:bump --release ${{ inputs.release_line || 'main' }}
Expand Down Expand Up @@ -131,28 +190,101 @@ jobs:
git status
git add -A -- :!.npmrc
git commit -m "v${{ steps.set_release_name.outputs.release_version }} version bump"
git push origin ${{ matrix.workspace }}/v${{ steps.set_release_name.outputs.release_version }}
- name: 'Create Pull Request'

if [ "${{ inputs.enable_pr_reuse }}" == "true" ]; then
BRANCH_NAME="${{ steps.check_existing_pr.outputs.branch_name }}"
else
BRANCH_NAME="${{ matrix.workspace }}/v${{ steps.set_release_name.outputs.release_version }}"
fi

git push origin "$BRANCH_NAME"
- name: 'Create or update Pull Request'
if: ${{ steps.check_for_changes.outputs.HAS_CHANGES == 1 }}
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
with:
github-token: ${{secrets.GH_SERVICE_ACCOUNT_TOKEN}}
script: |
await github.rest.pulls.create({
title: '${{ matrix.workspace }} - version:bump to v${{ steps.set_release_name.outputs.release_version }}',
owner: context.repo.owner,
repo: context.repo.repo,
head: '${{ matrix.workspace }}/v${{ steps.set_release_name.outputs.release_version }}',
base: 'main',
body: [
'Backstage release v${{ steps.set_release_name.outputs.release_version }} has been published, this Pull Request contains the changes to upgrade ${{ matrix.workspace }} to this new release',
' ',
'Please review the changelog before approving, there may be manual changes needed:',
' ',
'- Changelog: [v${{ steps.set_release_name.outputs.release_version }}](https://github.com/backstage/backstage/blob/master/docs/releases/v${{ steps.set_release_name.outputs.release_version }}-changelog.md)',
'- Upgrade Helper: [From ${{ steps.set_release_name.outputs.current_version }} to ${{ steps.set_release_name.outputs.release_version }}](https://backstage.github.io/upgrade-helper/?from=${{ steps.set_release_name.outputs.current_version }}&to=${{ steps.set_release_name.outputs.release_version }})',
' ',
'Created by [Version Bump ${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})',
' '
].join('\n')
});
const workspace = '${{ matrix.workspace }}';
const releaseVersion = '${{ steps.set_release_name.outputs.release_version }}';
const currentVersion = '${{ steps.set_release_name.outputs.current_version }}';
const enablePRReuse = ${{ inputs.enable_pr_reuse }};

let branchName, hasExistingPR;
if (enablePRReuse) {
branchName = '${{ steps.check_existing_pr.outputs.branch_name }}';
hasExistingPR = '${{ steps.check_existing_pr.outputs.has_existing_pr }}' === 'true';
} else {
branchName = `${workspace}/v${releaseVersion}`;
hasExistingPR = false;
}

const prBody = [
'Backstage release v' + releaseVersion + ' has been published, this Pull Request contains the changes to upgrade ' + workspace + ' to this new release',
' ',
'Please review the changelog before approving, there may be manual changes needed:',
' ',
'- Changelog: [v' + releaseVersion + '](https://github.com/backstage/backstage/blob/master/docs/releases/v' + releaseVersion + '-changelog.md)',
'- Upgrade Helper: [From ' + currentVersion + ' to ' + releaseVersion + '](https://backstage.github.io/upgrade-helper/?from=' + currentVersion + '&to=' + releaseVersion + ')',
' ',
'Created by [Version Bump ${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})',
' '
].join('\n');

if (hasExistingPR) {
const prNumber = parseInt('${{ steps.check_existing_pr.outputs.pr_number }}');
console.log(`Updating existing PR #${prNumber} to v${releaseVersion}`);

const { data: existingPRData } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});

const updatedTitle = workspace + ' - version:bump to v' + releaseVersion;
const updatedBody = prBody + '\n\n---\n\n<details>\n<summary>Previous version bump information</summary>\n\n' + existingPRData.body + '\n\n</details>';

const newBranchName = `${workspace}/v${releaseVersion}`;
const currentBranchName = existingPRData.head.ref;

if (currentBranchName !== newBranchName) {
console.log(`Renaming branch from ${currentBranchName} to ${newBranchName}`);
await github.rest.repos.renameBranch({
owner: context.repo.owner,
repo: context.repo.repo,
branch: currentBranchName,
new_name: newBranchName
});
console.log(`Successfully renamed branch to ${newBranchName}`);
}

await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
title: updatedTitle,
body: updatedBody
});

const previousVersionMatch = existingPRData.title.match(/version:bump to v([\d.]+)/);
const previousVersion = previousVersionMatch ? previousVersionMatch[1] : 'unknown';

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: `Updated version bump to v${releaseVersion} (previously v${previousVersion}).\n\nThe branch has been updated with the latest changes. Please review the updated changelog and upgrade helper links in the PR description.`
});

console.log(`Successfully updated PR #${prNumber} to v${releaseVersion}`);

} else {
const { data: newPR } = await github.rest.pulls.create({
title: workspace + ' - version:bump to v' + releaseVersion,
owner: context.repo.owner,
repo: context.repo.repo,
head: branchName,
base: 'main',
body: prBody
});
console.log(`Created new PR #${newPR.number}`);
}