Skip to content

Release

Release #5

Workflow file for this run

name: Release
# One job per stage, wired with `needs:`. That is the resume mechanism: because
# every stage first checks whether its work is already done, "Re-run failed jobs"
# picks up where the release stopped instead of redoing the 20-minute Maven
# Central publish.
#
# TEMPORARY: stages 2 and 4-8 also sit behind the `release-approval` environment,
# so the release advances one stage per human approval while the first few real
# releases are watched by hand. Drop those `environment:` lines once it is trusted.
# Two must not change with them: stage 3's gate is permanent (it triggers an
# irreversible publish), and stage 9 must never be gated (it reports failures, so
# needing approval to find out what broke defeats the point).
on:
workflow_dispatch:
inputs:
bump:
description: "Version component to increment. Patch unless this release carries a DB migration or breaks something."
type: choice
options: [patch, minor, major]
default: patch
dry_run:
description: "Read everything, write nothing. Prints what would change."
type: boolean
default: false
concurrency:
group: release
cancel-in-progress: false
permissions:
contents: read
env:
DRY_RUN: ${{ inputs.dry_run && '--dry-run' || '' }}
jobs:
plan:
name: 1 · plan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: ./.github/actions/setup
id: setup
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- run: uv run release plan --bump "${{ inputs.bump }}" --plan plan.json
env:
GITHUB_TOKEN: ${{ steps.setup.outputs.token }}
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: plan
path: plan.json
if-no-files-found: error
notes:
name: 2 · release notes
needs: [plan]
runs-on: ubuntu-latest
environment: release-approval
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: ./.github/actions/setup
id: setup
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: plan
- run: uv run release notes --plan plan.json
env:
GITHUB_TOKEN: ${{ steps.setup.outputs.token }}
frontend_release:
name: 3 · cut frontend release
needs: [notes]
runs-on: ubuntu-latest
# The Maven Central publish this sets off cannot be undone. This gate is
# permanent: it stays after the temporary per-stage gates above come off.
environment: release-approval
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: ./.github/actions/setup
id: setup
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: plan
- run: uv run release release-frontend --plan plan.json $DRY_RUN
env:
GITHUB_TOKEN: ${{ steps.setup.outputs.token }}
frontend_central:
name: 4 · frontend on Maven Central
needs: [frontend_release]
runs-on: ubuntu-latest
timeout-minutes: 45
environment: release-approval
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: ./.github/actions/setup
id: setup
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: plan
- run: uv run release await-frontend --plan plan.json $DRY_RUN
env:
GITHUB_TOKEN: ${{ steps.setup.outputs.token }}
backend_pom:
name: 5 · point backend at the new frontend
needs: [frontend_central]
runs-on: ubuntu-latest
environment: release-approval
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: ./.github/actions/setup
id: setup
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: plan
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
repository: cBioPortal/cbioportal
token: ${{ steps.setup.outputs.token }}
path: backend
fetch-depth: 0
- uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4
with:
java-version: "21"
distribution: temurin
- run: uv run release bump-pom --plan plan.json --workdir backend $DRY_RUN
env:
GITHUB_TOKEN: ${{ steps.setup.outputs.token }}
backend_release:
name: 6 · cut backend release
needs: [backend_pom]
runs-on: ubuntu-latest
environment: release-approval
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: ./.github/actions/setup
id: setup
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: plan
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
repository: cBioPortal/cbioportal
token: ${{ steps.setup.outputs.token }}
path: backend
- run: uv run release release-backend --plan plan.json --workdir backend $DRY_RUN
env:
GITHUB_TOKEN: ${{ steps.setup.outputs.token }}
backend_artifacts:
name: 7 · backend jar and image
needs: [backend_release]
runs-on: ubuntu-latest
timeout-minutes: 90
environment: release-approval
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: ./.github/actions/setup
id: setup
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: plan
- run: uv run release await-backend --plan plan.json $DRY_RUN
env:
GITHUB_TOKEN: ${{ steps.setup.outputs.token }}
snapshot_bump:
name: 8 · reopen master for development
needs: [backend_release]
runs-on: ubuntu-latest
environment: release-approval
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: ./.github/actions/setup
id: setup
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: plan
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
repository: cBioPortal/cbioportal
token: ${{ steps.setup.outputs.token }}
path: backend
fetch-depth: 0
- uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4
with:
java-version: "21"
distribution: temurin
- run: uv run release bump-snapshot --plan plan.json --workdir backend $DRY_RUN
env:
GITHUB_TOKEN: ${{ steps.setup.outputs.token }}
report:
name: 9 · hand off
needs:
- plan
- notes
- frontend_release
- frontend_central
- backend_pom
- backend_release
- backend_artifacts
- snapshot_bump
# Must run when an earlier stage failed or the run was cancelled. A release
# that dies quietly is the failure mode this repo exists to remove.
if: always()
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: ./.github/actions/setup
id: setup
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- name: No plan, nothing to report
if: needs.plan.result != 'success'
run: |
{
echo "## Release did not start"
echo
echo "Stage 1 did not complete, so no version was ever chosen and nothing"
echo "was written. See the \`plan\` job for the precondition that failed."
} >> "$GITHUB_STEP_SUMMARY"
exit 1
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
if: needs.plan.result == 'success'
with:
name: plan
- name: Summarise and file the release issue
if: needs.plan.result == 'success'
run: |
uv run release report --plan plan.json $DRY_RUN \
--run-url "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \
--result plan=${{ needs.plan.result }} \
--result notes=${{ needs.notes.result }} \
--result frontend-release=${{ needs.frontend_release.result }} \
--result frontend-central=${{ needs.frontend_central.result }} \
--result backend-pom=${{ needs.backend_pom.result }} \
--result backend-release=${{ needs.backend_release.result }} \
--result backend-artifacts=${{ needs.backend_artifacts.result }} \
--result snapshot-bump=${{ needs.snapshot_bump.result }}
env:
GITHUB_TOKEN: ${{ steps.setup.outputs.token }}
RELEASE_ASSIGNEE: ${{ vars.RELEASE_ASSIGNEE }}