From 48982559a2ef10f9e4129a832780b11cf7bb5668 Mon Sep 17 00:00:00 2001 From: Eliot Lim Date: Sun, 31 May 2026 22:52:47 +0800 Subject: [PATCH 1/4] ci: add CI release workflow Replaces the laptop release script (scripts/release_prep.sh) with a workflow_dispatch job gated by the `release` GitHub Environment. It bumps the app package.json files via .internal.versionrc.js, regenerates CHANGELOG.md, commits to develop, pushes the vX.Y.Z tag, and updates the GitHub Releases page. A GitHub App token is used rather than GITHUB_TOKEN: the default token can neither bypass develop's branch protection nor trigger the downstream tag-driven build and deploy workflows. Part of the Improved Release Process RFC. Co-Authored-By: Claude Opus 4.7 --- .github/workflows/release.yml | 98 +++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..c1adfce7b9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,98 @@ +name: Release + +# Cuts a monorepo app release from `develop`, replacing the old laptop flow +# (scripts/release_prep.sh). Does exactly what that script did by hand: +# bumps the app package.json files via .internal.versionrc.js, regenerates +# CHANGELOG.md, commits both back to develop, pushes the vX.Y.Z tag, and +# updates the GitHub Releases page. +# +# The tag push fans out to the build (build-release-image.yml), staging deploy +# (deploy-ecs-stg.yml) and production deploy (deploy-ecs-prod.yml) workflows. +# +# The SDK release flow is separate: see .github/workflows/publish-sdk.yml. + +on: + workflow_dispatch: + +# Only one release may be in flight at a time, so two dispatches can't race to +# bump the version off the same base commit. +concurrency: + group: release + cancel-in-progress: false + +permissions: + contents: read + +env: + NODE_VERSION: '22.22' + PNPM_VERSION: '10.30.3' + CTV_VERSION: '12.6.1' # commit-and-tag-version, pinned to package.json + +jobs: + release: + name: Cut release + runs-on: ubuntu-latest + # `release` GitHub Environment gates who can cut a tag (required reviewers + # configured in repo settings). + environment: release + steps: + # A GitHub App token (not GITHUB_TOKEN) is required for two reasons: + # 1. it can be granted bypass of develop's branch protection to push the + # version-bump commit; and + # 2. pushes made with GITHUB_TOKEN do not trigger other workflows, so the + # tag push would not start the build/deploy workflows. + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.RELEASE_BOT_APP_ID }} + private-key: ${{ secrets.RELEASE_BOT_PRIVATE_KEY }} + + - name: Checkout develop + uses: actions/checkout@v4.3.1 + with: + ref: develop + fetch-depth: 0 + token: ${{ steps.app-token.outputs.token }} + + - name: Configure git identity + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + APP_SLUG: ${{ steps.app-token.outputs.app-slug }} + run: | + bot_user_id="$(gh api "/users/${APP_SLUG}[bot]" --jq .id)" + git config user.name "${APP_SLUG}[bot]" + git config user.email "${bot_user_id}+${APP_SLUG}[bot]@users.noreply.github.com" + + - name: Install pnpm + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0 + with: + version: ${{ env.PNPM_VERSION }} + + - name: Use Node.js + uses: actions/setup-node@v4.4.0 + with: + node-version: ${{ env.NODE_VERSION }} + + # Bumps the eight app package.json files, regenerates CHANGELOG.md, and + # creates the `chore: bump version to vX.Y.Z` commit + matching vX.Y.Z tag + # locally. Same config the laptop flow used. + - name: Bump version, regenerate changelog and tag + run: pnpm dlx commit-and-tag-version@${{ env.CTV_VERSION }} --config .internal.versionrc.js + + - name: Resolve release version + id: version + run: echo "tag=v$(jq -r .version package.json)" >> "$GITHUB_OUTPUT" + + - name: Push commit and tag + run: | + git push origin HEAD:develop + git push origin "refs/tags/${{ steps.version.outputs.tag }}" + + - name: Update GitHub Releases page + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + gh release create "${{ steps.version.outputs.tag }}" \ + --verify-tag \ + --generate-notes From 902179fa841cb8065694c150881687969c7197db Mon Sep 17 00:00:00 2001 From: Eliot Lim Date: Mon, 1 Jun 2026 09:48:41 +0800 Subject: [PATCH 2/4] ci: deploy from version tags instead of release-al2/stg branches Point staging and production deploys (app, pdf-gen lambda, virus-scanner guardduty) at `v*` tag pushes rather than the release-al2 and stg mirror branches, and gate production behind the `production` GitHub Environment. Sidecar workflows check out the tag via github.ref_name. This retires the long-lived release branches: deploys now target immutable tags cut by the release workflow, and the prod approval is an explicit environment gate rather than a branch-merge convention. Part of the Improved Release Process RFC. Co-Authored-By: Claude Opus 4.7 --- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/deploy-ecs-prod.yml | 6 +++--- .github/workflows/deploy-ecs-stg.yml | 4 ++-- .github/workflows/deploy-pdf-gen-prod.yml | 8 ++++---- .github/workflows/deploy-pdf-gen-stg.yml | 8 ++++---- .github/workflows/deploy-virus-scanner-guardduty-prod.yml | 8 ++++---- .github/workflows/deploy-virus-scanner-guardduty-stg.yml | 6 +++--- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 21bf1995cb..2c8cbf06f4 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -7,7 +7,7 @@ name: 'CodeQL' on: push: - branches: [develop, release-al2] + branches: [develop] pull_request: # The branches below must be a subset of the branches above branches: [develop] diff --git a/.github/workflows/deploy-ecs-prod.yml b/.github/workflows/deploy-ecs-prod.yml index 9769120c38..fb09ac92a5 100644 --- a/.github/workflows/deploy-ecs-prod.yml +++ b/.github/workflows/deploy-ecs-prod.yml @@ -6,15 +6,15 @@ concurrency: on: push: - branches: - - release-al2 + tags: + - 'v*' jobs: deploy: name: Deploy uses: ./.github/workflows/deploy-ecs.yml with: - gha-environment: 'release-al2' + gha-environment: 'production' # Environment configuration environment: 'production' environment-site-name: 'prod' diff --git a/.github/workflows/deploy-ecs-stg.yml b/.github/workflows/deploy-ecs-stg.yml index 995ee212f3..946a0d7f4f 100644 --- a/.github/workflows/deploy-ecs-stg.yml +++ b/.github/workflows/deploy-ecs-stg.yml @@ -6,8 +6,8 @@ concurrency: on: push: - branches: - - stg + tags: + - 'v*' jobs: deploy: diff --git a/.github/workflows/deploy-pdf-gen-prod.yml b/.github/workflows/deploy-pdf-gen-prod.yml index 9143d6ba8a..ad03a2bccd 100644 --- a/.github/workflows/deploy-pdf-gen-prod.yml +++ b/.github/workflows/deploy-pdf-gen-prod.yml @@ -10,16 +10,16 @@ permissions: on: push: - branches: - - release-al2 + tags: + - 'v*' jobs: deploy-pdf-gen-lambda: name: Deploy PDF Generator Lambda uses: ./.github/workflows/deploy-pdf-gen-lambda.yml with: - gha-environment: 'release-al2' - checkoutBranch: 'release-al2' + gha-environment: 'production' + checkoutBranch: ${{ github.ref_name }} environment: 'production' secrets: cicd-role: ${{ secrets.IAC_AWS_CI_ROLE_TO_ASSUME }} diff --git a/.github/workflows/deploy-pdf-gen-stg.yml b/.github/workflows/deploy-pdf-gen-stg.yml index 98112741f2..37eadc2d9f 100644 --- a/.github/workflows/deploy-pdf-gen-stg.yml +++ b/.github/workflows/deploy-pdf-gen-stg.yml @@ -10,16 +10,16 @@ permissions: on: push: - branches: - - stg + tags: + - 'v*' jobs: - deploy-pdf-gen-lambda: + deploy-pdf-gen-lambda: name: Deploy PDF Generator Lambda uses: ./.github/workflows/deploy-pdf-gen-lambda.yml with: gha-environment: 'stg' - checkoutBranch: 'stg' + checkoutBranch: ${{ github.ref_name }} environment: 'stg' secrets: cicd-role: ${{ secrets.IAC_AWS_CI_ROLE_TO_ASSUME }} diff --git a/.github/workflows/deploy-virus-scanner-guardduty-prod.yml b/.github/workflows/deploy-virus-scanner-guardduty-prod.yml index 96c8229295..61a5afb1c9 100644 --- a/.github/workflows/deploy-virus-scanner-guardduty-prod.yml +++ b/.github/workflows/deploy-virus-scanner-guardduty-prod.yml @@ -10,16 +10,16 @@ permissions: on: push: - branches: - - release-al2 + tags: + - 'v*' jobs: deploy-scanner-guardduty: name: Deploy Scanner Guardduty uses: ./.github/workflows/aws-deploy-scanner-guardduty-iac.yml with: - checkoutBranch: 'release-al2' - gha-environment: 'release-al2' + checkoutBranch: ${{ github.ref_name }} + gha-environment: 'production' environment: 'production' provisionedConcurrency: 10 secrets: diff --git a/.github/workflows/deploy-virus-scanner-guardduty-stg.yml b/.github/workflows/deploy-virus-scanner-guardduty-stg.yml index 7cdf4c7979..ecaad189d2 100644 --- a/.github/workflows/deploy-virus-scanner-guardduty-stg.yml +++ b/.github/workflows/deploy-virus-scanner-guardduty-stg.yml @@ -10,15 +10,15 @@ permissions: on: push: - branches: - - stg + tags: + - 'v*' jobs: deploy-scanner-guardduty: name: Deploy Scanner GuardDuty uses: ./.github/workflows/aws-deploy-scanner-guardduty-iac.yml with: - checkoutBranch: 'stg' + checkoutBranch: ${{ github.ref_name }} gha-environment: 'stg' environment: 'stg' provisionedConcurrency: 1 From 666220052f547025cb4246e8eae24c7d53ae6744 Mon Sep 17 00:00:00 2001 From: Eliot Lim Date: Mon, 1 Jun 2026 09:49:25 +0800 Subject: [PATCH 3/4] ci: publish SDK from sdk-v* tags release-al2 is being decommissioned, so trigger the npm publish on sdk-v* tag pushes instead of release-al2 branch pushes. The sdk-v* tag is cut separately from the app release (documented in the workflow header); the SDK release flow is otherwise unchanged. Part of the Improved Release Process RFC. Co-Authored-By: Claude Opus 4.7 --- .github/workflows/publish-sdk.yml | 33 ++++++++++++------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/.github/workflows/publish-sdk.yml b/.github/workflows/publish-sdk.yml index 8d10f7f3a2..e0d4a698ca 100644 --- a/.github/workflows/publish-sdk.yml +++ b/.github/workflows/publish-sdk.yml @@ -2,23 +2,19 @@ name: Publish SDK # Release job for @opengovsg/formsg-sdk, published from packages/sdk. # -# Modeled after the old non-monorepo publish.yml -# (github.com/opengovsg/formsg-javascript-sdk), which used npm's OIDC -# "trusted publisher" flow (no NPM_TOKEN secret) and triggered on push -# to a dedicated `release` branch. In the monorepo, `release-al2` plays -# the same role: it is the branch that deploys to prod when a release -# PR (created by scripts/release_prep.sh) is merged into it. +# Uses npm's OIDC "trusted publisher" flow (no NPM_TOKEN secret). Triggered +# by pushing a `sdk-v` tag, which is cut separately from the app +# release: bump packages/sdk/package.json via .external.versionrc.js, then +# push the matching tag, e.g. # -# release_prep.sh bumps packages/sdk/package.json via -# .external.versionrc.js and pushes a `sdk-v` tag before -# opening the release PR, so by the time this workflow runs there is -# already a matching tag on the remote — all that is left to do is -# build, publish to npm via OIDC, and create the GitHub release. +# pnpm exec commit-and-tag-version --config .external.versionrc.js +# git push origin HEAD:develop && git push origin sdk-v # -# The version check in the `Resolve SDK version` step makes this job a -# no-op for monorepo releases that did not also bump the SDK — npm will -# already have the current version and the subsequent steps are -# skipped. +# By the time this workflow runs the tag already exists, so all that is left +# is to build, publish to npm via OIDC, and create the GitHub release. +# +# The version check in the `Resolve SDK version` step makes this job a no-op +# if the version is already on npm — the subsequent steps are skipped. env: NODE_VERSION: '22.22' @@ -27,11 +23,8 @@ env: on: push: - branches: - - release-al2 - paths: - - 'packages/sdk/**' - - '.github/workflows/publish-sdk.yml' + tags: + - 'sdk-v*' jobs: release: From c452e7ef83a963bbf24e47b0989f4d7b521fc2df Mon Sep 17 00:00:00 2001 From: Eliot Lim Date: Mon, 1 Jun 2026 09:53:52 +0800 Subject: [PATCH 4/4] chore: remove laptop release scripts The CI release workflow (.github/workflows/release.yml) replaces the manual release_prep.sh / release_hotfix.sh flow and their generate_pr_body.sh helper. Hotfixes now go through the same release workflow. Part of the Improved Release Process RFC. Co-Authored-By: Claude Opus 4.7 --- scripts/generate_pr_body.sh | 92 -------------------------- scripts/release_hotfix.sh | 127 ------------------------------------ scripts/release_prep.sh | 110 ------------------------------- 3 files changed, 329 deletions(-) delete mode 100755 scripts/generate_pr_body.sh delete mode 100644 scripts/release_hotfix.sh delete mode 100755 scripts/release_prep.sh diff --git a/scripts/generate_pr_body.sh b/scripts/generate_pr_body.sh deleted file mode 100755 index 39f726dc79..0000000000 --- a/scripts/generate_pr_body.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/bash -# Usage: generate_pr_body.sh [changelog_file] -# version_num - bare tag version number, e.g. 6.314.0 (no "v" prefix) -# changelog_file - path to changelog (default: CHANGELOG.md) -# -# Outputs the PR body to stdout. Use redirection to save to a file: -# ./scripts/generate_pr_body.sh 6.314.0 > .pr_body_release -# ./scripts/generate_pr_body.sh 6.314.0 path/to/CHANGELOG.md > .pr_body_release - -set -euo pipefail - -if [[ $# -lt 1 ]]; then - echo "Usage: $0 [changelog_file]" >&2 - echo " e.g. $0 6.314.0" >&2 - echo " e.g. $0 6.314.0 path/to/CHANGELOG.md" >&2 - exit 1 -fi - -release_version="$1" -changelog_file="${2:-CHANGELOG.md}" - -if [[ ! -f "${changelog_file}" ]]; then - echo "Error: changelog file not found: ${changelog_file}" >&2 - exit 1 -fi - -pr_body_working=".pr_body_working_${release_version}" -pr_body_for_tests=".pr_body_tests_${release_version}" - -cleanup() { - rm -f "${pr_body_working}" "${pr_body_for_tests}" -} -trap cleanup EXIT - -# Extract the changelog section for this version into a temp file -awk " - /^## \[${release_version}\]/ { flag=1; next } - /^## \[/ { flag=0 } - /^### Changelog$/ { flag=0 } - flag -" "${changelog_file}" > "${pr_body_working}" - -# Build a filtered view that EXCLUDES the Dependencies / Dev-Dependencies / Build System -# sections. This ensures we only derive tests from feature/fix PRs, not dependency bumps. -awk ' - # When we hit the skipped headings, start skipping lines - /^### Dependencies$/ { skip=1; next } - /^### Dev-Dependencies$/ { skip=1; next } - /^### Builds$/ { skip=1; next } - # When we hit the next top-level "###
" heading after that, stop skipping - /^### [A-Z]/ && skip==1 { skip=0 } - # Emit lines only when we are not skipping - !skip -' "${pr_body_working}" > "${pr_body_for_tests}" - -# Output the full changelog section first -cat "${pr_body_working}" - -# Append an overall "Tests" heading, under which we will aggregate the per-PR test plans -echo "" -echo "### Tests" -echo "" - -# For each non-deps bullet line that references a PR, fetch that PR's Tests -# section and append it under a heading derived from the changelog line. -grep '^[*] ' "${pr_body_for_tests}" | \ -grep '\[#\([0-9]\+\)\](' | \ -while read -r line_item; do - # Extract first PR number on the line, e.g. "#9183" or "[#9183](...)" - pr_id=$(echo "${line_item}" | grep -o -E '#[0-9]+' | head -n1 | tr -d '#') - [[ -z "${pr_id}" ]] && continue - - # Fetch the PR body and slice out only its "Tests" section (from the Tests heading - # until the next top-level heading), then normalize checkboxes and bump heading - # levels so nested headings render nicely inside the release PR body. - tests=$(gh pr view "${pr_id}" | \ - awk ' - /^##+ Tests?/ { f=1; next } - /^##+ [A-Z]/ && f { f=0 } - f - ' | \ - sed -E "s/\[[Xx]\]/[ ]/" | \ - sed -E "s/^(##+) /\1## /") - - if [[ ${tests} =~ [^[:space:]] ]]; then - # Use the changelog bullet as a subheading for this PR's tests - echo "${line_item}" | sed "s/^\* /### /" - # Then append the normalized Tests section from the PR body - echo "${tests}" - echo "" - fi -done diff --git a/scripts/release_hotfix.sh b/scripts/release_hotfix.sh deleted file mode 100644 index bf5081d490..0000000000 --- a/scripts/release_hotfix.sh +++ /dev/null @@ -1,127 +0,0 @@ -#!/bin/bash -set +x - -# To hotfix: -# 1. Make a new hotfix branch from release-al2 and the necessary fixes. -# 2. Run this script from this hotfix branch. It will deploy the changes to stg and create a PR for release-al2. -# 3. Verify the changes on stg. -# 4. Merge the PR into release-al2. This deploys the changes to production. -# 5. Make a PR and merge release-al2 back to develop to sync the changes with develop. - -# CLI flags: -# --recut If you have made changes after cutting, you can add this flag to use the newest changes for hotfix release. -# --nosquash The script squashes the changes in the hotfix branch into a single commit by default. This flag prevents the squashing if you want to keep the all the commits in the hotfix branch. - -# pre-requisites: install github CLI -# - github documentation: https://github.com/cli/cli#installation -# - github is remote 'origin' -# - PRs use test section LAST with heading "## Tests" -# - ALL build and release PRs start with "build: " - -hotfix_branch=$(git branch --show-current) - -if ! command -v gh >/dev/null 2>&1; then - echo -e "\033[31mInstall gh first\033[0m" - exit 1 -fi - -if ! gh auth status >/dev/null 2>&1; then - echo -e "\033[31mYou need to login: gh auth login\033[0m" - exit 1 -fi - -has_local_changes=$(git status --porcelain --untracked-files=no --ignored=no) -if [[ ${has_local_changes} ]]; then - set +x - echo -e "\033[31m==========\033[0m" - echo -e "\033[31mABORT: You have local modifications. Please stash or commit changes and run again.\033[0m" - echo -e "\033[31m==========\033[0m" - exit 1 -fi - -# Sync the remote hotfix/ branch -echo -e "\033[34mFetching latest tags and pulling latest changes\033[0m" -git fetch --all --tags -git pull - -echo -e "\033[34mResetting to the latest commit on the remote hotfix branch\033[0m" -git reset --hard ${hotfix_branch} - -# Create a temporary branch to squash commits and do version bumps -echo -e "\033[34mCreate a temporary branch to commit version bump changes\033[0m" -short_hash=$(git rev-parse --short HEAD) -temp_release_branch=temp_${short_hash} -# All subsequent actions are done on the temporary branch to prevent the hotfix branch from being polluted/modified. -git checkout -b ${temp_release_branch} - -# Squash the commit history into single commit titled the branch name, unless --nosquash is provided -if [[ " $* " != *" --nosquash "* ]]; then - echo -e "\033[34mSquashing commit history into single commit titled the branch name\033[0m" - git reset --soft release-al2 - git commit -a -n -m "fix: changes from ${hotfix_branch}" -fi - -may_force_push= -tag_force= - -if [[ " $* " == *" --recut "* ]]; then - tag_force=--tag-force - may_force_push=-f -fi - -pnpm exec commit-and-tag-version --config .internal.versionrc.js ${tag_force} -release_version_num=$(jq -r .version < package.json) -release_version="v${release_version_num}" -release_branch=release_${release_version} - -echo -e "\033[34mNext patch version: ${release_version}\033[0m" - - -if [[ " $* " == *" --recut "* ]]; then - echo -e "\033[34mRecutting: Deleting local and remote tag and release branch\033[0m" - # Delete the local and remote tag for this release version if it exists. - git push --delete origin ${release_version} - # Delete the local release branch for this release version if it exists. - git branch -D ${release_branch} -fi - -echo -e "\033[34mCreating release branch to merge into release-al2\033[0m" -git checkout -b ${release_branch} - -echo -e "\033[34mDeleting temporary branch\033[0m" -git branch -D ${temp_release_branch} - -echo -e "\033[34mPushing the updated release branch and tag to remote\033[0m" -git push origin ${may_force_push} HEAD:${release_branch} -git push origin ${release_version} - -echo -e "\033[34mPushing to stg for verification\033[0m" -git push -f origin HEAD:stg - -echo -e "\033[34mCreating PR for release ${release_version} into release-al2\033[0m" -pr_body_actual=".pr_body_actual_${release_version}" -scripts/generate_pr_body.sh "${release_version_num}" CHANGELOG.md > "${pr_body_actual}" - -# Creating PR to merge into release-al2: edit if it already exists, else create -existing_pr=$(gh pr list --state open --head "${release_branch}" --base "release-al2" --json number --jq '.[0].number' 2>/dev/null) -if [[ -n "${existing_pr}" ]]; then -echo -e "\033[34mEditing existing PR ${existing_pr}" - gh pr edit "${existing_pr}" \ - -t "build: release ${release_version}" \ - -F "${pr_body_actual}" -else - echo -e "\033[34mCreating new PR for release ${release_version}" - gh pr create \ - -H "${release_branch}" \ - -B "release-al2" \ - -t "build: release ${release_version}" \ - -F "${pr_body_actual}" -fi - -# Perform cleanup of temporary files and local release branch -echo -e "\033[34mCleaning up temporary files and local release branch\033[0m" -rm "${pr_body_actual}" -git checkout ${hotfix_branch} -git branch -D ${release_branch} - -echo -e "\033[34mHotfix preparation complete\033[0m" \ No newline at end of file diff --git a/scripts/release_prep.sh b/scripts/release_prep.sh deleted file mode 100755 index 8d27341c3d..0000000000 --- a/scripts/release_prep.sh +++ /dev/null @@ -1,110 +0,0 @@ -#!/bin/bash -set +x - -# pre-requisites: install github CLI -# - github documentation: https://github.com/cli/cli#installation -# - github is remote 'origin' -# - PRs use test section LAST with heading "## Tests" -# - ALL build and release PRs start with "build: " - -if ! command -v gh >/dev/null 2>&1; then - echo "Install gh first" - exit 1 -fi -if ! gh auth status >/dev/null 2>&1; then - echo "You need to login: gh auth login" - exit 1 -fi - -has_local_changes=$(git status --porcelain --untracked-files=no --ignored=no) -if [[ ${has_local_changes} ]]; then - set +x - echo ========== - echo "ABORT: You have local modifications. Please stash or commit changes and run again." - echo ========== - exit 1 -fi - -# Force sync with origin/develop -git fetch --all --tags -git reset --hard -git pull -git checkout develop -git reset --hard develop - -# Create temp branch for version bump and changelog generation -short_hash=$(git rev-parse --short HEAD) -temp_release_branch=temp_${short_hash} -git checkout -b ${temp_release_branch} - -may_force_push= -tag_force= -if [[ " $* " == *" --recut "* ]]; then - tag_force=--tag-force - may_force_push=-f -fi - -# Perform the version bumps, generate changelog and create local tags. -# 1. Monorepo release (.internal.versionrc.js) — bumps apps/*/package.json, -# packages/shared/package.json, etc. and creates a `v` tag. -pnpm exec commit-and-tag-version --config .internal.versionrc.js ${tag_force} -release_version_num=$(jq -r .version < package.json) -release_version="v${release_version_num}" -release_branch=release_${release_version} - -# 2. SDK release (.external.versionrc.js) — bumps packages/sdk/package.json, -# updates packages/sdk/CHANGELOG.md and creates a `sdk-v` tag. -# Only runs if there are new commits touching packages/sdk since the last -# sdk-v* tag. commit-and-tag-version does not exit non-zero when zero -# commits match the path filter, so we guard explicitly. -sdk_release_version= -last_sdk_tag=$(git tag --sort=-version:refname -l 'sdk-v*' | head -1) -if [[ -n "${last_sdk_tag}" ]] && [[ -z "$(git log "${last_sdk_tag}..HEAD" --oneline -- packages/sdk)" ]]; then - echo "No new SDK commits since ${last_sdk_tag}; skipping external (SDK) version bump." -elif pnpm exec commit-and-tag-version --config .external.versionrc.js ${tag_force}; then - sdk_release_version_num=$(jq -r .version < packages/sdk/package.json) - sdk_release_version="sdk-v${sdk_release_version_num}" -fi - -if [[ " $* " == *" --recut "* ]]; then - git push --delete origin ${release_version} || true - if [[ -n "${sdk_release_version}" ]]; then - git push --delete origin ${sdk_release_version} || true - fi - git branch -D ${release_branch} -fi - -git checkout -b ${release_branch} -git branch -D ${temp_release_branch} - -# Push the code and tags to origin -git push origin ${may_force_push} HEAD:${release_branch} -git push origin ${release_version} -if [[ -n "${sdk_release_version}" ]]; then - git push origin ${sdk_release_version} -fi - -# Deploy to staging for verification testing -git push -f origin HEAD:stg - -pr_body_actual=".pr_body_actual_${release_version}" -scripts/generate_pr_body.sh "${release_version_num}" CHANGELOG.md > "${pr_body_actual}" - -# Creating PR to merge into release-al2: edit if it already exists, else create -existing_pr=$(gh pr list --state open --head "${release_branch}" --base "release-al2" --json number --jq '.[0].number' 2>/dev/null) -if [[ -n "${existing_pr}" ]]; then - gh pr edit "${existing_pr}" \ - -t "build: release ${release_version}" \ - -F "${pr_body_actual}" -else - gh pr create \ - -H "${release_branch}" \ - -B "release-al2" \ - -t "build: release ${release_version}" \ - -F "${pr_body_actual}" -fi - -# cleanup -rm "${pr_body_actual}" -git checkout develop -git branch -D ${release_branch}