Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci(release_workspace_version): prototype prior version release, add documentation #2626

Merged
merged 11 commits into from
Feb 24, 2025
189 changes: 189 additions & 0 deletions .github/workflows/release_workspace_version.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
name: Prior Version Release Workspace

on:
# ADDED: Only trigger on PR closed event on workspace/** branch.
# The assumption is that branch protection rules and CODEOWNERS are configured.

pull_request:
types:
- closed
branches:
- 'workspace/**'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}

jobs:
# ADDED: Checks if PR is a Version Packages PR on workspace/** branch
# and validates PR title, author, branch and merged status.
check-merged-pr:
name: Check if PR is a Version Packages PR on workspace/** branch
runs-on: ubuntu-latest
outputs:
is_version_pr: ${{ steps.check_pr.outputs.is_version_pr }}
workspace_name: ${{ steps.extract_workspace.outputs.workspace_name }}
steps:
- name: Check PR title, author, branch and merged status
id: check_pr
run: |
if [[ "${{ github.event.pull_request.title }}" == Version*Packages* \
&& "${{ github.event.pull_request.user.login }}" == "backstage-service" ]] \
&& [[ "${{ github.event.pull_request.head.ref }}" == maintenance-changesets-release/* ]] \
&& [[ "${{ github.event.pull_request.merged }}" == "true" ]]; then
echo "is_version_pr=true" >> $GITHUB_ENV
else
echo "is_version_pr=false" >> $GITHUB_ENV
exit 1
fi
# ADDED: Extracts workspace name from branch, ensuring it is a workspace/** branch
- name: Extract Workspace name from branch
id: extract_workspace
run: |
WORKSPACE_NAME=$(echo "${{ github.ref }}" | cut -d'/' -f2)
echo "workspace_name=$WORKSPACE_NAME" >> $GITHUB_ENV

- name: Verify workspace match
run: |
PR_WORKSPACE=$(echo "${{ github.event.pull_request.head.ref }}" | cut -d'/' -f2)
if [[ "$PR_WORKSPACE" != "${{ env.workspace_name }}" ]]; then
echo "Workspace mismatch: PR workspace ($PR_WORKSPACE) does not match target branch workspace (${{ env.workspace_name }})"
exit 1
fi

changesets-pr:
name: Update Version Packages PR for ${{ needs.check-merged-pr.outputs.workspace_name }} on branch ${{ github.ref }}
runs-on: ubuntu-latest
needs: check-merged-pr
defaults:
run:
working-directory: ./workspaces/${{ needs.check-merged-pr.outputs.workspace_name }}
env:
CI: true
NODE_OPTIONS: --max-old-space-size=4096
outputs:
needs_release: ${{ steps.release_check.outputs.needs_release }}
steps:
- name: Checkout
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4
with:
ref: ${{ github.ref }}

- name: Verify maintenance-changesets-release branch does not exist
run: |
if git ls-remote --exit-code origin "refs/heads/maintenance-changesets-release/${{ needs.check-merged-pr.outputs.workspace_name }}"; then
echo "Error: maintenance-changesets-release/${{ needs.check-merged-pr.outputs.workspace_name }} branch already exists. Please clean up the branch before proceeding."
exit 1
fi

- name: Set up Node
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4
with:
node-version: 20
registry-url: https://registry.npmjs.org/ # Needed for auth

- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT

- uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles(format('workspaces/${0}/**/yarn.lock', needs.check-merged-pr.outputs.workspace_name)) }}
restore-keys: |
${{ runner.os }}-yarn-

- name: yarn install
run: yarn install --immutable

- name: Fetch previous commit for release check
run: git fetch origin '${{ github.event.before }}'

- name: Fetch the commit that triggered the workflow (used by backstage/changesets-action)
run: git fetch origin ${{ github.sha }}
continue-on-error: true

- name: Check if release
id: release_check
run: |
yarn install
node scripts/ci/check-if-release.js
working-directory: ./
env:
WORKSPACE_NAME: ${{ needs.check-merged-pr.outputs.workspace_name }}
COMMIT_SHA_BEFORE: '${{ github.event.before }}'

- name: Update Version Packages (${{ needs.check-merged-pr.outputs.workspace_name }}) PR
id: changesets-pr
if: steps.release_check.outputs.needs_release != 'true'
uses: backstage/changesets-action@291bfc1f76d1dcfbf967f5810dc0423592eae09a # v2.3.1
with:
title: Version Packages (${{ needs.check-merged-pr.outputs.workspace_name }})
cwd: workspaces/${{ needs.check-merged-pr.outputs.workspace_name }}
version: yarn changeset version
versionBranch: maintenance-changesets-release/${{ needs.check-merged-pr.outputs.workspace_name }}
skipRootChangelogUpdate: true
env:
GITHUB_TOKEN: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}

release:
name: Prior Version Release workspace ${{ needs.check-merged-pr.outputs.workspace_name }} on branch ${{ github.ref }}
runs-on: ubuntu-latest
needs: changesets-pr
if: needs.changesets-pr.outputs.needs_release == 'true'
defaults:
run:
working-directory: ./workspaces/${{ needs.check-merged-pr.outputs.workspace_name }}
env:
CI: true
NODE_OPTIONS: --max-old-space-size=4096

steps:
- name: Checkout
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4
with:
ref: ${{ github.ref }}
- name: Set up Node
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4
with:
node-version: 20
registry-url: https://registry.npmjs.org/ # Needed for auth

- name: Install root dependencies
run: yarn install --immutable
working-directory: ${{ github.workspace }}

- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT

- uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles(format('workspaces/${0}/**/yarn.lock', needs.check-merged-pr.outputs.workspace_name)) }}
restore-keys: |
${{ runner.os }}-yarn-
- name: yarn install
run: yarn install --immutable

- name: Compile TypeScript
run: yarn tsc:full

- name: Build all packages
run: yarn build:all

# CHANGED: Publish with tag "maintenance" to avoid overwriting the latest npm tag
- name: publish
run: |
yarn config set -H 'npmAuthToken' "${{secrets.NPM_TOKEN}}"
yarn workspaces foreach -v --no-private --include "${{ needs.check-merged-pr.outputs.workspace_name }}" npm publish --access public --tolerate-republish --tag "maintenance"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Create tag
working-directory: ${{ github.workspace }}/scripts/ci
run: node create-tag.js
env:
WORKSPACE_NAME: ${{ needs.check-merged-pr.outputs.workspace_name }}
GITHUB_TOKEN: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
54 changes: 54 additions & 0 deletions docs/plugin-maintainers-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Plugin Maintainer Guide

## Table of Contents

- [Plugin Maintainer Guide](#plugin-maintainer-guide)
- [Table of Contents](#table-of-contents)
- [Maintaining and patching an older release line](#maintaining-and-patching-an-older-release-line)
- [Patching an older release](#patching-an-older-release)

## Maintaining and patching an older release line

It may be necessary to patch a prior release line of a plugin when users depend on an older, but stable version and while a newer, incompatible, major version of the plugin exists. Typically for these older releases, only major bugs and security issues will need to be remediated. Not every plugin will need this workflow.

This guide will describe the steps needed to release on an older version.

### Patching an older release

When patching an older release, follow the steps below to ensure the correct workflow is applied:

1. Request a `workspace/${workspace}` branch by asking one of the [@backstage/community-plugins-maintainers](https://github.com/orgs/backstage/teams/community-plugins-maintainers).

- Ensure that a branch named `workspace/${workspace}` exists, with appropriate branch protections in place. This branch will be used for patch releases.
- The `${workspace}` should correspond to the specific plugin or component you are patching.

2. Reset the `workspace` branch:

- Reset the `workspace/${workspace}` branch to the version of the plugin you need to patch.
- You can use the autogenerated version tags from previous releases to pinpoint the prior release version to apply the patch.

3. Apply your commits:

- Apply the necessary patch fixes or security updates.
- Do not manually bump the version in `package.json`. The version bump must be handled via changesets.

4. Submit a PR following the required workflow:

- Open a pull request with your changes against the `workspace/${workspace}` branch.
- Ensure the PR:
- Contains only necessary fixes.
- Includes a changeset.

5. Merge the PR to trigger the release workflow:

- The PR must meet these conditions to be merged:
- The PR title starts with "Version Packages" (automatically generated by changesets).
- The PR originates from a `maintenance-changesets-release/${workspace}` branch.
- The PR is authored by `backstage-service`.
- The PR is merged, not just closed.
- Once merged, the release workflow will automatically trigger, building and publishing the new release.

6. Confirm the release:
- Once the workflow completes, a new version will be published.
- A new Git tag will be created, which can be used for future patches.
- The release will be tagged as "maintenance" in the package registry to avoid overwriting latest stable versions.