Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions .github/actions/release/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,21 @@ runs:
git config commit.gpgsign true
git config tag.gpgsign true
git config user.signingkey $(gpg --list-secret-keys --with-colons "${{ inputs.gh_email }}" | awk -F: '/^sec:/ {print $5; exit}')
- name: Fast-forward to latest main
shell: bash
# Checkout is pinned to github.sha. If a prior release pushed commits/tags while this job
# was queued, those tags won't be reachable from our stale HEAD. Both verify-versions.sh and
# nx release use --merged HEAD for tag resolution, so HEAD must be current. This rebase is
# always a fast-forward (no local commits yet).
run: |
git fetch origin main
git rebase origin/main
- name: Verify version alignment
shell: bash
run: ./.github/scripts/verify-versions.sh
- name: Release
shell: bash
# Skip publish to avoid orphaned npm versions if push fails.
env:
GH_TOKEN: ${{ inputs.gh_token }}
GITHUB_TOKEN: ${{ inputs.gh_token }}
Expand All @@ -47,16 +57,32 @@ runs:
# https://docs.npmjs.com/generating-provenance-statements#using-third-party-package-publishing-tools
# https://philna.sh/blog/2026/01/28/trusted-publishing-npm/
NPM_CONFIG_PROVENANCE: true
run: npx nx release --yes
run: npx nx release --skip-publish
- name: Push release commit and tags
shell: bash
# nx release (unified command) creates the git commit and tags locally but does not push them,
# regardless of the release.git.push setting in nx.json. It only pushes automatically when
# createRelease (GitHub/GitLab releases) is enabled. Since we use createReleaseInGitHub: false,
# we push manually here so that the version bumps in package.json reach the remote and
# nacho-bot can create PRs in consuming repos.
# Rebase before push: if a PR merged to main while nx release was running, the version
# commit needs to be on top of latest main to avoid non-fast-forward rejection. This rebase
# replays only the single version commit created by nx release (merge commit that triggered
# this workflow is always an ancestor of origin/main).
# HUSKY=0 disables pre-push hooks in CI — tests are run separately by the CI pipeline.
env:
HUSKY: '0'
run: git push --follow-tags
run: |
git fetch origin main
git rebase origin/main
git push --follow-tags
Comment thread
petrsimon marked this conversation as resolved.
- name: Publish to npm
shell: bash
# Publish only after push succeeds to prevent orphaned npm versions.
# If push failed, re-running this job is safe — no npm versions published yet.
# https://docs.npmjs.com/generating-provenance-statements#using-third-party-package-publishing-tools
# https://philna.sh/blog/2026/01/28/trusted-publishing-npm/
env:
NPM_CONFIG_PROVENANCE: true
run: npx nx release publish

29 changes: 27 additions & 2 deletions .github/scripts/verify-versions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"

mismatch=0
registry_error=0
npm_stderr_file="$(mktemp)"
trap 'rm -f "$npm_stderr_file"' EXIT # clean up temp file on exit
# Column widths for alignment
printf "%-60s %-12s %-12s %-15s %s\n" "PACKAGE" "DISK" "GIT TAG" "NPM" "STATUS"
printf '%.0s-' {1..110}
Expand Down Expand Up @@ -54,13 +57,25 @@ for dir in "$REPO_ROOT"/packages/*/; do
[[ -z "$tag_ver" ]] && tag_ver="NONE"

# --- npm registry version ---
npm_ver="$(npm view "$pkg" version --fetch-timeout=10000 2>/dev/null)" || true
[[ -z "$npm_ver" ]] && npm_ver="NOT_ON_NPM"
npm_ver="$(npm view "$pkg" version --fetch-timeout=10000 2>"$npm_stderr_file")" && npm_rc=0 || npm_rc=$?
if [[ $npm_rc -ne 0 ]]; then
if grep -q 'E404' "$npm_stderr_file"; then
npm_ver="NOT_ON_NPM"
else
npm_ver="REGISTRY_ERROR"
fi
fi

# --- Compare ---
if [[ "$disk_ver" == "$tag_ver" && "$disk_ver" == "$npm_ver" ]]; then
status="OK"
marker="✓"
elif [[ "$npm_ver" == "REGISTRY_ERROR" ]]; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering what happens if $npm_ver is "NOT_ON_NPM" here? Do we need another elif?

status="REGISTRY_ERROR"
marker="✗"
mismatch=1
registry_error=1
echo "::error::${pkg}: npm registry lookup failed (timeout, auth, or outage). Cannot verify npm version."
elif [[ "$tag_ver" == "NONE" && "$npm_ver" == "NOT_ON_NPM" ]]; then
# New package: no tag, not published. Flag as informational but still a mismatch.
status="NEW_PACKAGE"
Expand All @@ -80,6 +95,16 @@ done
echo ""
if [[ $mismatch -ne 0 ]]; then
echo "Version verification FAILED. Fix mismatches before releasing."
if [[ $registry_error -ne 0 ]]; then
echo ""
echo "npm registry lookup failed for one or more packages. Check registry status,"
echo "network connectivity, and npm authentication before re-running."
else
echo ""
echo "If disk and tag match but npm is behind, a prior npm publish likely failed."
echo "Pull latest main with tags, build, and run 'npx nx release publish' to recover."
echo "Subsequent releases will remain blocked until the missing version is published."
fi
exit 1
else
echo "All package versions are aligned across disk, git tags, and npm registry."
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ jobs:
# Only run on push to main branch (never on PRs, workflow_dispatch, etc.)
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
environment: npm-publish
# Serialize release jobs to prevent concurrent git pushes to master.
concurrency:
group: ${{ github.workflow }}-release
cancel-in-progress: false
Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/pr-title.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: PR title lint
permissions:
contents: read
on:
pull_request:
branches:
- main
types: [opened, edited, reopened]

jobs:
pr-title-lint:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
fetch-depth: 0
- uses: './.github/actions/setup-environment'
- name: Install
shell: bash
run: npm ci
- name: Validate PR title with commitlint
shell: bash
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: echo "$PR_TITLE" | npx commitlint --verbose
Loading