From e2bf33b7879a34f5e581a3000d2be79d90afbfff Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Wed, 1 Jul 2026 15:07:05 +0900 Subject: [PATCH 1/4] ci: add package.json bumper workflow --- .github/workflows/version-bump.yml | 110 +++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 .github/workflows/version-bump.yml diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml new file mode 100644 index 000000000..a026fdba1 --- /dev/null +++ b/.github/workflows/version-bump.yml @@ -0,0 +1,110 @@ +name: Bump package versions + +# Can be triggered by closing a milestone or manually +on: + milestone: + types: [closed] + workflow_dispatch: + inputs: + version: + description: 'Version to bump to, e.g. 2.2.0' + required: true + +permissions: + contents: write + pull-requests: write + +concurrency: + group: version-bump-${{ github.event.milestone.number || github.run_id }} + cancel-in-progress: false + +jobs: + bump-version: + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + with: + egress-policy: audit + + - name: Checkout main + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + ref: main + + - name: Setup Node + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + with: + node-version: '24' + + - name: Resolve version + id: version + env: + MILESTONE_TITLE: ${{ github.event.milestone.title }} + MANUAL_VERSION: ${{ inputs.version }} + run: | + RAW="${MANUAL_VERSION:-$MILESTONE_TITLE}" + RAW="$(printf '%s' "$RAW" | tr -d '[:space:]')" + + if [[ ! "$RAW" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then + echo "::error::'$RAW' isn't a plain semver version (for example '2.2.0'). Not bumping." + exit 1 + fi + + VERSION="${RAW#v}" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "Resolved version: $VERSION" + + - name: Sanity check against current version + env: + VERSION: ${{ steps.version.outputs.version }} + run: | + CURRENT=$(node -p "require('./package.json').version") + NEWEST=$(printf '%s\n%s\n' "$CURRENT" "$VERSION" | sort -V | tail -n1) + if [ "$VERSION" = "$CURRENT" ] || [ "$NEWEST" != "$VERSION" ]; then + echo "::error::$VERSION is not newer than the current package.json version ($CURRENT)." + exit 1 + fi + + - name: Bump root package + env: + VERSION: ${{ steps.version.outputs.version }} + run: npm version "$VERSION" --no-git-tag-version --allow-same-version + + - name: Bump git-proxy-cli package + working-directory: packages/git-proxy-cli + env: + VERSION: ${{ steps.version.outputs.version }} + run: npm version "$VERSION" --no-git-tag-version --allow-same-version + + - name: Open version bump PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ steps.version.outputs.version }} + MILESTONE_TITLE: ${{ github.event.milestone.title }} + MILESTONE_URL: ${{ github.event.milestone.html_url }} + run: | + BRANCH="chore/bump-version-$VERSION" + RELEASE_BRANCH="release/${VERSION%.*}" + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + git checkout -b "$BRANCH" + git add package.json package-lock.json packages/git-proxy-cli/package.json + git commit -m "chore: bump version to $VERSION" + git push -u origin "$BRANCH" --force + + if [ -n "$MILESTONE_URL" ]; then + SOURCE_LINE="Triggered by closing milestone **$MILESTONE_TITLE** ($MILESTONE_URL)." + else + SOURCE_LINE="Triggered manually for version $VERSION." + fi + + BODY=$(printf '%s\n\nBumps:\n- `package.json`, `package-lock.json`\n- `packages/git-proxy-cli/package.json`\n\nOnce merged, cut `%s` from `main` per our [release process](https://git-proxy.finos.org/docs/development/releases) in order to generate a GitHub draft release.\n' "$SOURCE_LINE" "$RELEASE_BRANCH") + + if gh pr view "$BRANCH" >/dev/null 2>&1; then + echo "PR for $BRANCH already exists. Branch updated, no new PR opened." + else + gh pr create --base main --head "$BRANCH" --title "chore: bump version to $VERSION" --body "$BODY" + fi From 74edf282fc1cff3acd74a08b8d3751d790c4ba78 Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Wed, 1 Jul 2026 17:53:03 +0900 Subject: [PATCH 2/4] ci: add release branch bumper workflow --- .github/workflows/release-branch-bump.yml | 131 ++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 .github/workflows/release-branch-bump.yml diff --git a/.github/workflows/release-branch-bump.yml b/.github/workflows/release-branch-bump.yml new file mode 100644 index 000000000..832665308 --- /dev/null +++ b/.github/workflows/release-branch-bump.yml @@ -0,0 +1,131 @@ +name: Bump Patch Version on Release Branch + +# Manually bumps package.json + package-lock.json (root and +# packages/git-proxy-cli) to the next patch version on existing release +# branch, and opens a PR against that branch + +# This is needed since patch releases don't have an easy way to trigger the bump +# and people may forget to bump the versions manually in the patch PR +on: + workflow_dispatch: + inputs: + line: + description: 'Release branch to patch in X.Y format, e.g. 2.0 (targets release/2.0)' + required: true + +permissions: + contents: write + pull-requests: write + +concurrency: + group: patch-bump-${{ inputs.line }} + cancel-in-progress: false + +jobs: + bump-patch: + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + with: + egress-policy: audit + + - name: Validate release line + id: line + env: + LINE: ${{ inputs.line }} + run: | + if [[ ! "$LINE" =~ ^[0-9]+\.[0-9]+$ ]]; then + echo "::error::'$LINE' isn't a release line in X.Y form (expected e.g. '2.0')." + exit 1 + fi + echo "line=$LINE" >> "$GITHUB_OUTPUT" + echo "branch=release/$LINE" >> "$GITHUB_OUTPUT" + + - name: Checkout release branch + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + ref: ${{ steps.line.outputs.branch }} + + - name: Setup Node + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + with: + node-version: '24' + + - name: Confirm both packages exist on this branch + run: | + if [ ! -f packages/git-proxy-cli/package.json ]; then + echo "::error::packages/git-proxy-cli/package.json doesn't exist on this branch. It probably predates the CLI package split, bump this one by hand." + exit 1 + fi + + - name: Compute next patch version + id: version + env: + LINE: ${{ steps.line.outputs.line }} + run: | + CURRENT=$(node -p "require('./package.json').version") + + if [[ ! "$CURRENT" =~ ^([0-9]+\.[0-9]+)\.([0-9]+)$ ]]; then + echo "::error::root package.json version '$CURRENT' isn't a plain X.Y.Z, can't compute a patch bump automatically." + exit 1 + fi + + CURRENT_LINE="${BASH_REMATCH[1]}" + PATCH="${BASH_REMATCH[2]}" + + if [ "$CURRENT_LINE" != "$LINE" ]; then + echo "::error::release/$LINE's package.json is on $CURRENT, which isn't on the $LINE line. Refusing to guess, sort this out by hand first." + exit 1 + fi + + VERSION="$CURRENT_LINE.$((PATCH + 1))" + echo "current=$CURRENT" >> "$GITHUB_OUTPUT" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "Current: $CURRENT -> Next patch: $VERSION" + + - name: Check packages are in sync + env: + ROOT_VERSION: ${{ steps.version.outputs.current }} + run: | + CLI_VERSION=$(node -p "require('./packages/git-proxy-cli/package.json').version") + if [ "$CLI_VERSION" != "$ROOT_VERSION" ]; then + echo "::error::packages/git-proxy-cli is on $CLI_VERSION but root is on $ROOT_VERSION. Versions have already drifted, resolve by hand before bumping." + exit 1 + fi + + - name: Bump root package + env: + VERSION: ${{ steps.version.outputs.version }} + run: npm version "$VERSION" --no-git-tag-version --allow-same-version + + - name: Bump git-proxy-cli package + working-directory: packages/git-proxy-cli + env: + VERSION: ${{ steps.version.outputs.version }} + run: npm version "$VERSION" --no-git-tag-version --allow-same-version + + - name: Open patch bump PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ steps.version.outputs.version }} + CURRENT: ${{ steps.version.outputs.current }} + BASE_BRANCH: ${{ steps.line.outputs.branch }} + run: | + BRANCH="chore/patch-bump-$VERSION" + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + git checkout -b "$BRANCH" + git add package.json package-lock.json packages/git-proxy-cli/package.json packages/git-proxy-cli/package-lock.json + git commit -m "chore: bump version to $VERSION" + git push -u origin "$BRANCH" --force + + BODY=$(printf 'Automated patch bump on `%s`: `%s` -> `%s`.\n\nBumps:\n- `package.json` / `package-lock.json`\n- `packages/git-proxy-cli/package.json`\n\nOnce merged, this drafts a release on `%s`. Please publish it immedietaly, otherwise the draft release will get overwritten. Then, cascade-merge it forward into the next supported release branch (bumping that line too) if one exists.\nFor more details see our guide on [How to Publish a Patch Release](https://git-proxy.finos.org/docs/development/releases/#publishing-a-patch-release).\n' "$BASE_BRANCH" "$CURRENT" "$VERSION" "$BASE_BRANCH") + + if gh pr view "$BRANCH" >/dev/null 2>&1; then + echo "PR for $BRANCH already exists. Branch updated, no new PR opened." + else + gh pr create --base "$BASE_BRANCH" --head "$BRANCH" --title "chore: bump version to $VERSION" --body "$BODY" + fi From bf007efbcc937fced33fa701d120e8769eb45c5b Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Wed, 1 Jul 2026 17:57:39 +0900 Subject: [PATCH 3/4] docs: improve releases.md, add TLDR and link to workflows --- .github/workflows/version-bump.yml | 6 +++--- website/docs/development/releases.md | 29 +++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml index a026fdba1..622c9095d 100644 --- a/.github/workflows/version-bump.yml +++ b/.github/workflows/version-bump.yml @@ -1,4 +1,4 @@ -name: Bump package versions +name: Bump Package Version # Can be triggered by closing a milestone or manually on: @@ -19,7 +19,7 @@ concurrency: cancel-in-progress: false jobs: - bump-version: + bump-version-${{ inputs.branch }}: runs-on: ubuntu-latest steps: - name: Harden Runner @@ -92,7 +92,7 @@ jobs: git checkout -b "$BRANCH" git add package.json package-lock.json packages/git-proxy-cli/package.json - git commit -m "chore: bump version to $VERSION" + git commit -m "chore: bump git-proxy and git-proxy-cli to $VERSION" git push -u origin "$BRANCH" --force if [ -n "$MILESTONE_URL" ]; then diff --git a/website/docs/development/releases.md b/website/docs/development/releases.md index 23f12ab11..c2f81a1da 100644 --- a/website/docs/development/releases.md +++ b/website/docs/development/releases.md @@ -2,6 +2,14 @@ GitProxy has a standardized release process to ensure they are done in a timely manner, and to prevent extensive merge conflicts. We encourage contributors to read this before opening a PR. +## TL;DR on how to release + +1. When all issues in a milestone are completed, close it. This will generate a PR that bumps the project version +2. Review and merge the `package.json` bump +3. Make a branch from `main` called `release/X.Y`. This will generate a draft release, visible on [our Releases page](https://github.com/finos/git-proxy/releases). +4. Check the release notes, then click Publish. This will automatically [publish to NPM](https://www.npmjs.com/package/@finos/git-proxy). +5. Verify that NPM release was published correctly. + ## Branching Strategy GitProxy follows a [GitLabFlow branching strategy](https://about.gitlab.com/topics/version-control/what-is-gitlab-flow/) with **cascade-based merging** for bugfixes as opposed to cherry-picking. [This blogpost](https://blog.joshuins.com/implementing-cascading-merges-in-github-actions-part-1-99a907e566f3) explains in more detail how cascade-based merging works. See this [StackExchange discussion](https://softwareengineering.stackexchange.com/questions/460758/is-cascade-merging-forward-porting-riskier-than-backporting) for pros and cons of cascade-based merging. @@ -51,6 +59,14 @@ Keep in mind that maintainers may adjust the labels manually if appropriate. ## Release Process +The release process varies depending on whether you're cutting a new release or patching an existing one. See the section below on [How to Patch an Existing Release](#publishing-a-patch-release). + +### New release + +For new releases, you must first close the [related milestone](https://github.com/finos/git-proxy/milestones). This will generate a PR bumping `package.json`, `package-lock.json` and `packages/git-proxy-cli/package.json`. Once that PR is merged into `main`, make a new branch from `main` called `release/X.Y`, where `X` is the major version and `Y` is the minor version to which you want to bump. + +This will generate a draft release in our [Releases](https://github.com/finos/git-proxy/releases) page. Edit the release notes if necessary, and then click Publish. This will also automatically publish to NPM. + The actual release process is largely automated via two GitHub Actions workflows: [`release-drafter.yml`](https://github.com/finos/git-proxy/blob/main/.github/workflows/release-drafter.yml) and [`npm.yml`](https://github.com/finos/git-proxy/blob/main/.github/workflows/npm.yml). ### Release Drafter @@ -88,7 +104,10 @@ As detailed in [`npm.yml`](https://github.com/finos/git-proxy/blob/main/.github/ For patch releases, the same process applies. The only difference is that first we must perform the cascade-based merge flow from above: -First, we make a PR against the earliest supported version where the bug can be reproduced. Deprecated versions need not inherit the fix. Then, we open a PR against that version's release branch, ex. `release/2.2`. Once the bugfix has been merged, this automatically generates a draft release with a patch bump (ex. `2.2.0` -> `2.2.1`). We **must publish the release** (to prevent the draft from getting overwritten). Finally, we merge (_cascade_) the `release/2.2` branch into the next supported version, ex. `release/3.0`, and repeat the publishing process. +1. Make a PR against the release branch for the **earliest supported version** where the bug can be reproduced. The PR must include the bugfix, and also bump `package.json`, `package-lock.json` and `packages/git-proxy-cli/package.json` to the next patch version. Note that deprecated versions need not inherit the fix. +2. Merge the PR. If you forgot to bump `package.json`, you can generate a patch bump PR by using [this release branch bumper workflow](https://github.com/finos/git-proxy/actions/workflows/release-branch-bump.yml). Just set the branch version you want to target, such as `2.2`. +3. Once the bugfix and the version bump is merged, a draft release will be generated in our [Releases page](https://github.com/finos/git-proxy/releases). **Publish this release** before merging additional PRs to the release branch, or performing the cascade merges. **Don't forget to uncheck the "Set as latest release" default option** when publishing the release. +4. Once a patch has been published, you can cascade-merge the release branch into the next supported version. For example, if the currently supported versions are `2.2` and `3.0`, we will first publish a patch on `2.2` and then merge (AKA cascade) `release/2.2` into `release/3.0`. Then, we repeat the version bumping and publishing process. ### Cheatsheet and Troubleshooting @@ -97,7 +116,7 @@ The flows are roughly as follows: #### Releases 1. You merge new PRs to `main` -2. When a milestone is completed, make a PR to bump the GitProxy version on all of the relevant `package.json` files. This is necessary for publishing to NPM. +2. When a milestone is closed, a PR is autogenerated to bump the GitProxy version on all of the relevant `package.json` files. This is necessary for correctly publishing to NPM. 3. Make a `release/X.Y` branch to freeze feature development. New features and improvements go into `main`, not into the `release/X.Y` branch 4. Upon creating the branch, a draft release is automatically generated. 5. Review the draft release notes, and click Publish if appropriate. This will automatically build and publish to NPM @@ -106,10 +125,10 @@ The flows are roughly as follows: 1. Figure out which is the earliest _supported_ version where the bug can be reproduced. Suppose the latest two major versions are supported (`1.20.x` and `2.2.x`), then we only care about reproducing the bug on `release/1.20` and `release/2.2`. 2. Fix the bug and make a PR against the relevant version -3. In this PR, you **must** also bump the GitProxy version on all relevant `package.json` files for publishing to NPM (ex: `1.20.0` -> `1.20.1`) +3. In this PR, you **must** also bump the GitProxy version on all relevant `package.json` files for publishing to NPM (ex: `1.20.0` -> `1.20.1`). If you forgot to bump, you can easily generate a PR for it by using [release-branch-bump.yml](https://github.com/finos/git-proxy/actions/workflows/release-branch-bump.yml) 4. Once the PR is merged, a draft release will be generated to bump the patch version 5. Review the draft release notes and publish if appropriate. This will automatically **update** the NPM `release-1.20` line with the patched package. **Tip: Don't forget to uncheck the "Set as latest release" default option** -6. Then, make a PR to merge the `release/1.20` branch into `release/2.2`. **Don't forget to bump the GitProxy version for the new line** (ex: `2.2.0` -> `2.2.1`) +6. Then, make a PR to merge the `release/1.20` branch into `release/2.2`. **Don't forget to bump the GitProxy version for the new line too** (ex: `2.2.0` -> `2.2.1`) 7. Repeat steps 4-6 until all the supported versions have been published to both GitHub and NPM #### Troubleshooting @@ -122,7 +141,7 @@ Just re-run the `release-drafter.yml` workflow from the related release branch. ##### I published the draft release and forgot to bump the `package.json`s! -Usually, this will fail to publish to NPM at all. Just delete the bad release from the [GitHub releases page](https://github.com/finos/git-proxy/releases), delete the old related tag, then make a PR to the relevant `release/X.Y` branch bumping the `package.json` versions. When the PR is merged, publish the draft release making sure that a new tag is being created. This should trigger the NPM publish workflow and publish the updated package or override the existing one. +Usually, this will fail to publish to NPM at all, though it still generates a bad GitHub release. Just delete the bad release from the [GitHub releases page](https://github.com/finos/git-proxy/releases), delete the old related tag, then use the [release branch bumper workflow](https://github.com/finos/git-proxy/actions/workflows/release-branch-bump.yml) to make a PR against the relevant `release/X.Y` branch bumping the `package.json` versions. Once that PR is merged, publish the draft release making sure that a new tag is being created. This should trigger the NPM publish workflow and publish the updated package or override the existing one. ## Questions From 9be0981b5750ced34d0dd10a031f324f5b25a601 Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Wed, 1 Jul 2026 18:08:06 +0900 Subject: [PATCH 4/4] docs: update NPM publish section and remove autobump disclaimer --- website/docs/development/releases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/development/releases.md b/website/docs/development/releases.md index c2f81a1da..9c1a3883c 100644 --- a/website/docs/development/releases.md +++ b/website/docs/development/releases.md @@ -88,7 +88,7 @@ Publishing creates a git tag, and triggers the `npm.yml` workflow described belo ### Publish to NPM -This workflow runs whenever you publish a GitHub release. As of writing, we don't have any [automation for bumping the versions](https://github.com/finos/git-proxy/issues/1533) in `/package.json` and `/packages/git-proxy-cli/package.json`. You'll have to manually set these according to the appropriate semantic version generated by the release drafter. +This workflow runs whenever you publish a GitHub release. A PR bumping the `package.json` versions will be automatically generated via the [Bumper Workflow](https://github.com/finos/git-proxy/blob/main/.github/workflows/version-bump.yml) when closing the milestone. If for any reason the workflow failed, or got the version wrong, you can make your own PR bumping `./package.json`, `./package-lock.json` and `./packages/git-proxy-cli/package.json`, or [trigger the workflow manually](https://github.com/finos/git-proxy/actions/workflows/version-bump.yml) with your desired version. As detailed in [`npm.yml`](https://github.com/finos/git-proxy/blob/main/.github/workflows/npm.yml), it: