From 0a9fa5807b1b7a189ada175c7d21d997d8dc5665 Mon Sep 17 00:00:00 2001 From: Fuchsi* Huber Date: Thu, 20 Aug 2026 21:54:31 +0200 Subject: [PATCH 1/3] feat: support for yarn projects; improvement: rewrote bump script in python --- .github/workflows/bump.yaml | 46 +++- .github/workflows/tests.yml | 34 +++ .gitignore | 3 + bump-version/README.md | 130 ++++++++--- bump-version/action.yml | 208 +++++------------ bump-version/bump.py | 437 ++++++++++++++++++++++++++++++++++++ changelog/27.feature.md | 1 + changelog/27.fix.md | 1 + changelog/27.improvement.md | 1 + pyproject.toml | 10 +- tests/conftest.py | 24 ++ tests/test_bump.py | 194 ++++++++++++++++ uv.lock | 96 ++++++-- 13 files changed, 968 insertions(+), 217 deletions(-) create mode 100644 .github/workflows/tests.yml create mode 100755 bump-version/bump.py create mode 100644 changelog/27.feature.md create mode 100644 changelog/27.fix.md create mode 100644 changelog/27.improvement.md create mode 100644 tests/conftest.py create mode 100644 tests/test_bump.py diff --git a/.github/workflows/bump.yaml b/.github/workflows/bump.yaml index 165ba1c..732373b 100644 --- a/.github/workflows/bump.yaml +++ b/.github/workflows/bump.yaml @@ -23,14 +23,24 @@ name: Bump on: workflow_call: inputs: + project-type: + description: > + Kind of project to bump: 'uv' (Python) or 'yarn' (Node). See the bump-version + action for how bump-rule/pre-release-base/pre-release-bump differ per type. + required: false + type: string + default: "uv" bump-rule: - description: | - Whitespace-separated list of segments passed to uv version --bump. - Each segment becomes a separate --bump. - - Examples: "patch", "minor", "major", "stable", "minor alpha", "patch rc". - + description: | + For project-type 'uv': whitespace-separated list of segments passed to + uv version --bump. Each segment becomes a separate --bump. + + Examples: "patch", "minor", "major", "stable", "minor alpha", "patch rc". + From a stable version, prerelease segments (alpha, beta, rc, dev) must be combined with a release segment. + + For project-type 'yarn': passed through verbatim as arguments to + `npm version `, e.g. "patch" or "preminor --preid alpha". required: true type: string pre-release-base: @@ -60,7 +70,10 @@ on: type: boolean default: true workspace-packages: - description: "Newline-separated uv workspace packages to mirror the version onto." + description: > + Newline-separated workspace packages to mirror the version onto: uv package + names for project-type 'uv', or paths relative to the repo root for + project-type 'yarn'. required: false type: string default: "" @@ -75,7 +88,12 @@ on: type: string default: "" python-version: - description: "Python version to install via setup-uv." + description: "Python version to install via setup-uv. Also used to run towncrier (via uvx) for project-type 'yarn'." + required: false + type: string + default: "" + node-version: + description: "Node version to install via actions/setup-node. Only used for project-type 'yarn'." required: false type: string default: "" @@ -167,10 +185,22 @@ jobs: with: python-version: ${{ inputs.python-version }} + - name: Setup Node + if: inputs.project-type == 'yarn' + uses: actions/setup-node@v7.0.0 + with: + node-version: ${{ inputs.node-version }} + + - name: Enable corepack + if: inputs.project-type == 'yarn' + shell: bash + run: corepack enable + - name: Bump version id: bump uses: climate-resource/github-actions/bump-version@v1.4.3 with: + project-type: ${{ inputs.project-type }} bump-rule: ${{ inputs.bump-rule }} pre-release-bump: ${{ inputs.pre-release-bump }} pre-release-base: ${{ inputs.pre-release-base }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..753d80d --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,34 @@ +name: Tests + +on: + pull_request: + paths: + - "**/*.py" + - "pyproject.toml" + - "uv.lock" + - ".github/workflows/tests.yml" + push: + branches: + - main + paths: + - "**/*.py" + - "pyproject.toml" + - "uv.lock" + - ".github/workflows/tests.yml" + +permissions: + contents: read + +jobs: + pytest: + runs-on: gus-small + steps: + - name: Check out repository + uses: actions/checkout@v6.0.2 + + - name: Setup uv + uses: ./setup-uv + + - name: Run tests + shell: bash + run: uv run --group dev pytest diff --git a/.gitignore b/.gitignore index e43b0f9..007a5a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ .DS_Store +__pycache__/ +.pytest_cache/ +.venv/ diff --git a/bump-version/README.md b/bump-version/README.md index 854598d..eed2857 100644 --- a/bump-version/README.md +++ b/bump-version/README.md @@ -1,32 +1,47 @@ # bump-version -Composite action that bumps a Python project's version with `uv version --bump`, -updates the CHANGELOG via towncrier, commits, tags, pushes, and (by default) -lands a follow-up commit that moves `main` onto a pre-release version so future commits don't share the tagged version. +Composite action that bumps a project's version, updates the CHANGELOG via +towncrier, commits, tags, pushes, and (by default) lands a follow-up commit that +moves the branch onto a pre-release version so future commits don't share the +tagged version. -## Prerequisites +Two project types are supported, selected with `project-type`: + +| `project-type` | Version lives in | Bumped with | +| --- | --- | --- | +| `uv` (default) | `pyproject.toml` | `uv version --bump` | +| `yarn` | `package.json` | `npm version` | + +For `yarn`, `npm version` is used purely as a version-bumping CLI — yarn remains +the package manager and owns the lockfile. -The action assumes: +The logic lives in [`bump.py`](bump.py), which `action.yml` invokes with +`uv run --script`. Its unit tests are in [`../tests/test_bump.py`](../tests/test_bump.py). -- `uv` is on PATH (use [`setup-uv`](../setup-uv) before this action). +## Prerequisites + +- **`uv` is on PATH for both project types** (use [`setup-uv`](../setup-uv) + before this action). It runs the script itself, so it is required even for + `project-type: yarn`, where it also provides towncrier via `uvx`. +- For `project-type: yarn`, `node`, `npm` and `yarn` must be on PATH (use + `actions/setup-node` and `corepack enable`). - The checked-out repo has full history (`fetch-depth: 0`). - The default `GITHUB_TOKEN` is sufficient to push the bump commit and tag. + The default `GITHUB_TOKEN` is sufficient to push the bump commit and tag. Check out with a PAT only when branch protection blocks the `github-actions` bot, or when downstream workflows must fire from the tag push (a push made with `GITHUB_TOKEN` does not trigger other workflows). -- The project's `pyproject.toml` is managed by `uv` (i.e. `uv version --short` returns the current version). -- `towncrier` is available via `uv run` when `update-changelog: true` (the default). ## Inputs | Input | Default | Description | | --- | --- | --- | -| `bump-rule` | _required_ | Whitespace-separated list of segments passed to `uv version --bump`. Each segment becomes a separate `--bump`. Examples: `patch`, `minor`, `major`, `stable`, `minor alpha`, `patch rc`. From a stable version, prerelease segments (`alpha`, `beta`, `rc`, `dev`) must be combined with a release segment. | -| `pre-release-bump` | `dev` | Pre-release segment for the second commit (`dev`, `alpha`, `beta`, `rc`). Use `none` to skip the second commit. | -| `pre-release-base` | `patch` | Base bump applied before the pre-release segment in the second commit. Use `none` to add the pre-release marker without bumping the base. | -| `update-changelog` | `true` | Run `uv run towncrier build` for the new version. | +| `project-type` | `uv` | `uv` for a Python project, `yarn` for a Node project. | +| `bump-rule` | _required_ | Whitespace-separated arguments describing the bump. For `uv`, each segment becomes a separate `--bump`: `patch`, `minor`, `major`, `stable`, `minor alpha`, `patch rc`. From a stable version, prerelease segments (`alpha`, `beta`, `rc`, `dev`) must be combined with a release segment. For `yarn`, passed verbatim to `npm version`: `patch`, `preminor --preid alpha`, `prerelease --preid rc`. | +| `pre-release-bump` | `dev` | Pre-release segment for the second commit. For `uv`: `dev`, `alpha`, `beta`, `rc`. For `yarn`: verbatim `npm version` arguments, e.g. `--preid dev`. Use `none` to skip the second commit. | +| `pre-release-base` | `patch` | Base bump applied before the pre-release segment in the second commit. For `uv`: a bump rule (`patch`, `minor`, `major`, …). For `yarn`: an `npm version` strategy word, e.g. `prepatch`. Use `none` to add the pre-release marker without bumping the base. | +| `update-changelog` | `true` | Build the CHANGELOG with towncrier for the new version. | | `commit-email` | `ci-runner@climate-resource.invalid` | Author email for both commits. | -| `workspace-packages` | _empty_ | Newline-separated workspace package names to mirror the version onto. | -| `lock` | `true` | Run `uv lock` after each version change. | +| `workspace-packages` | _empty_ | Newline-separated workspace packages to mirror the version onto. For `uv`: package names. For `yarn`: directory paths relative to the repo root, e.g. `apps/analysis-portal`. | +| `lock` | `true` | Refresh the lockfile after each version change (`uv lock`, or `yarn install --mode=update-lockfile`). | | `pre-commit-command` | _empty_ | Shell command run after the changelog build and before each bump commit. Use it to regenerate version-derived files (e.g. an OpenAPI schema) so they stay in sync in the tagged commit. The command must succeed; a non-zero exit aborts the bump. | | `pre-commit-skip` | `false` | Pass `-n` to `git commit` to bypass pre-commit hooks. | | `push` | `true` | Push the bump commit, tag, and pre-release commit. | @@ -38,27 +53,40 @@ The action assumes: | `base-version` | Version before the bump. | | `new-version` | Tagged version (no `v` prefix). | | `tag` | New git tag, with `v` prefix. | -| `dev-version` | Pre-release version landed on `main` after tagging (when applicable). | -| `is-prerelease` | `'true'` when the tagged version matches `(a\|b\|rc\|dev)`. Use to gate downstream release steps. | +| `dev-version` | Pre-release version landed on the branch after tagging (when applicable). | +| `is-prerelease` | `'true'` when the tagged version is a pre-release. Use to gate downstream release steps. | + +`base-version`, `new-version`, `tag` and `is-prerelease` are written as soon as +the release is tagged, so they remain available to later steps even if the +pre-release commit fails. ## Behaviour -1. Reads the current version (`BASE_VERSION = uv version --short`). -2. `uv version --frozen --bump ` to obtain `NEW_VERSION`. -3. Mirrors `NEW_VERSION` to each `workspace-packages` entry. -4. If `update-changelog: true`, runs - `uv run towncrier build --yes --version v$NEW_VERSION`. -5. Optionally `uv lock`. -6. If `pre-commit-command` is set, runs it (so version-derived files are - regenerated before the commit). -7. `git commit -a -m "bump: version $BASE_VERSION -> $NEW_VERSION"`. -8. `git tag v$NEW_VERSION`. -9. Pushes the commit and tag. -10. If `pre-release-bump != none` and the tagged version is not already a - pre-release, applies `pre-release-base` (default `patch`) then - `pre-release-bump` (default `dev`), mirrors workspace packages, locks, runs - `pre-commit-command` again, and creates a `bump(): ...` - commit which is pushed. +**Phase 1 — tag the release** + +1. Read the current version (`base-version`). +2. Apply `bump-rule` to the root project to obtain `new-version`. +3. Mirror `new-version` onto each `workspace-packages` entry. +4. Refresh the lockfile, if `lock: true`. +5. Build the CHANGELOG with towncrier, if `update-changelog: true`. +6. Run `pre-commit-command`, if set. +7. `git commit -a -m "bump: version -> "`. +8. `git tag v`, then push the commit and tag if `push: true`. + +**Phase 2 — land the pre-release** + +Skipped entirely when `pre-release-bump: none`, or when the tagged version is +already a pre-release. Otherwise it applies `pre-release-base` then +`pre-release-bump`, repeats the mirror / lock / `pre-commit-command` steps, and +creates a `bump(