From 6a049fd8a7d5d567ff9f66d4546e0ac070f57353 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Nov 2026 18:27:40 +0000 Subject: [PATCH] Release automatically when the version in package.json changes Add a release job to the Lint and Test workflow. On a push to the default branch, after lint and test pass, it reads the version from package.json and, when the tag v does not exist yet, creates it together with the GitHub release. Tags created with the workflow token do not start other workflows, so the Release workflow is now also callable and is run from the same workflow run with the new tag; its tag trigger is kept so a tag pushed by hand still publishes. Document the procedure in the README. Co-Authored-By: Claude Fable 5.1 --- .github/workflows/default.yml | 58 +++++++++++++++++++++++++++++++++++ .github/workflows/release.yml | 12 ++++++++ README.md | 5 +++ 3 files changed, 75 insertions(+) diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml index ee222f3..503de5b 100644 --- a/.github/workflows/default.yml +++ b/.github/workflows/default.yml @@ -37,3 +37,61 @@ jobs: run: npm ci - name: Test run: npm test + + release: + needs: [lint, test] + if: github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) + runs-on: ubuntu-latest + permissions: + contents: write + concurrency: + group: release + cancel-in-progress: false + outputs: + tag: ${{ steps.version.outputs.tag }} + created: ${{ steps.release.outputs.created }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Read version + id: version + run: | + version=$(sed -nE 's/^ *"version": *"([^"]+)".*/\1/p' package.json | head -1) + if [ -z "$version" ]; then + echo "No version found in package.json" >&2 + exit 1 + fi + echo "tag=v$version" >> "$GITHUB_OUTPUT" + - name: Create tag and release + id: release + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ steps.version.outputs.tag }} + run: | + status=0 + git ls-remote --exit-code --tags origin "refs/tags/$TAG" > /dev/null || status=$? + case "$status" in + 0) + echo "Tag $TAG already exists; nothing to release." + echo "created=false" >> "$GITHUB_OUTPUT" + ;; + 2) + gh release create "$TAG" --target "$GITHUB_SHA" --title "$TAG" --generate-notes + echo "created=true" >> "$GITHUB_OUTPUT" + ;; + *) + echo "Could not check whether tag $TAG exists (git ls-remote exited with $status)" >&2 + exit "$status" + ;; + esac + + publish: + needs: release + if: needs.release.outputs.created == 'true' + permissions: + contents: read + id-token: write + uses: ./.github/workflows/release.yml + with: + tag: ${{ needs.release.outputs.tag }} + secrets: inherit diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f890738..9dd731d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,12 @@ on: push: tags: - '**' + workflow_call: + inputs: + tag: + description: Tag to publish, for example v3.1.0 + required: true + type: string jobs: lint: @@ -11,6 +17,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + ref: ${{ inputs.tag || github.ref }} - name: Install node uses: actions/setup-node@v4 with: @@ -25,6 +33,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + ref: ${{ inputs.tag || github.ref }} - name: Install node uses: actions/setup-node@v4 with: @@ -43,6 +53,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + ref: ${{ inputs.tag || github.ref }} - name: Install node uses: actions/setup-node@v4 with: diff --git a/README.md b/README.md index 551be0a..f231721 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Requires **Node.js 20.18.1** or later. HTTP requests go through [undici](https:/ - [Connection reuse and HTTP/2](#connection-reuse-and-http2) - [Response Fields](#response-fields) - [TypeScript](#typescript) +- [Releasing](#releasing) ## Install @@ -236,3 +237,7 @@ The library is written in TypeScript and exports the following types: ```ts import IPData, { EU_BASE_URL, CacheConfig, HttpConfig, LookupParams, LookupResponse } from 'ipdata'; ``` + +## Releasing + +Releases are cut by CI. Bump `version` in `package.json` in a pull request (`npm version x.y.z --no-git-tag-version` also updates `package-lock.json`) and merge it. On the merge to `main`, CI tags the commit `vx.y.z`, creates the GitHub release with generated notes and publishes the package to [npm](https://www.npmjs.com/package/ipdata). A merge whose version is already tagged publishes nothing. Pushing a `vx.y.z` tag by hand still publishes that tag.