Skip to content

Release

Release #27

Workflow file for this run

name: Release
on:
pull_request:
types: [closed]
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to source release notes + comment from (recovery path when pull_request trigger misfired)'
required: false
type: string
default: ''
permissions:
contents: write
id-token: write
pull-requests: write
concurrency:
group: release
cancel-in-progress: false
jobs:
release:
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event.pull_request.merged && startsWith(github.head_ref, 'release'))
runs-on: ubuntu-latest
environment: Release
env:
COMPOSE_FILE: ./compose.yml
steps:
- name: Checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Start Database Services
run: docker compose up -d
- name: Enable Corepack (pre-setup-node)
# setup-node@v5 auto-probes `yarn cache dir` during setup; without corepack
# enabled first, the probe hits the runner's global yarn 1.22 and fails
# against our `packageManager: yarn@4.12.0` pin. Enable corepack on the
# runner's system Node BEFORE setup-node switches Node versions.
run: corepack enable
- name: Setup Node.js
# `registry-url` is intentionally omitted. When set, setup-node writes
# `~/.npmrc` with `//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}`.
# Under Trusted Publisher (no `NPM_TOKEN` secret), the substitution
# yields an empty `_authToken=` which npm treats as an unauthorized
# request and returns 404 — bypassing OIDC exchange. Leaving the
# registry URL as the built-in default lets npm CLI handle OIDC
# trusted-publisher auth natively.
uses: actions/setup-node@v5
with:
node-version: '24'
- name: Enable Corepack (post-setup-node)
run: corepack enable
- name: Pin Yarn version
# Pins Yarn to the version that matches yarn.lock (lockfile version 8).
# "yarn set version stable" upgrades to 4.14.x which introduced lockfile
# format version 9, breaking --immutable installs.
run: yarn set version 4.12.0
- name: Install
run: yarn install --immutable
- name: Build
run: yarn build
- name: Ensure Database Services
run: docker compose up -d
- name: Run Tests
run: yarn test:all
- name: Determine Version and Dist Tag
id: version
run: |
set -euo pipefail
STRATEGY=$(node -p "require('./lerna.json').version")
if [ "$STRATEGY" = "independent" ]; then
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
CURRENT_VERSION=$(echo "$LATEST_TAG" | sed 's/^v//')
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
CURRENT_VERSION="v${MAJOR}.$((MINOR + 1)).0"
DIST_TAG=$(node -p "require('./lerna.json').distTag || 'latest'")
else
CURRENT_VERSION=$(node -p "require('./lerna.json').version")
if echo "$CURRENT_VERSION" | grep -q '-'; then
DIST_TAG=$(echo "$CURRENT_VERSION" | cut -d '-' -f 2 | cut -d '.' -f 1)
else
DIST_TAG="latest"
fi
CURRENT_VERSION="v${CURRENT_VERSION}"
fi
echo "version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"
echo "dist_tag=$DIST_TAG" >> "$GITHUB_OUTPUT"
- name: Check if Tag Exists
id: check_tag
run: |
set -euo pipefail
if [ -n "$(git tag -l "${{ steps.version.outputs.version }}")" ]; then
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
fi
- name: Resolve Release Notes Source
id: notes
env:
GH_TOKEN: ${{ github.token }}
PR_BODY: ${{ github.event.pull_request.body }}
PR_NUMBER_INPUT: ${{ inputs.pr_number }}
run: |
set -euo pipefail
if [ -n "${PR_NUMBER_INPUT:-}" ]; then
BODY=$(gh pr view "$PR_NUMBER_INPUT" --json body --jq .body)
PR_NUM="$PR_NUMBER_INPUT"
else
BODY="$PR_BODY"
PR_NUM="${{ github.event.pull_request.number }}"
fi
{
echo "body<<EOF_RELEASE_BODY"
echo "$BODY"
echo "EOF_RELEASE_BODY"
} >> "$GITHUB_OUTPUT"
echo "pr_number=$PR_NUM" >> "$GITHUB_OUTPUT"
- name: Create Tag and Release
if: steps.check_tag.outputs.exists == 'false'
env:
GH_TOKEN: ${{ github.token }}
RELEASE_BODY: ${{ steps.notes.outputs.body }}
run: |
set -euo pipefail
git tag "${{ steps.version.outputs.version }}"
git push origin "${{ steps.version.outputs.version }}"
gh release create "${{ steps.version.outputs.version }}" \
--title "${{ steps.version.outputs.version }}" \
--notes "$RELEASE_BODY"
- name: Publish Packages to NPM Registry
if: steps.check_tag.outputs.exists == 'false'
env:
NPM_CONFIG_PROVENANCE: true
run: |
set -euo pipefail
# Per-package `npm publish` loop — bypasses lerna filtering because
# lerna v9 removed both `--ignore` (renamed to `--ignore-changes`
# with different semantics) and `--scope` for the publish command.
# npm CLI v9.5+ handles OIDC trusted-publisher exchange transparently
# when `id-token: write` permission + `environment: Release` are set
# at the job level (both are already configured above).
#
DIST_TAG="${{ steps.version.outputs.dist_tag }}"
PACKAGES=(core util request typeorm drizzle mikro-orm prisma)
for pkg in "${PACKAGES[@]}"; do
echo "::group::Publishing @nestjs-crud/$pkg@${{ steps.version.outputs.version }}"
(cd "packages/$pkg" && npm publish --access public --tag "$DIST_TAG")
echo "::endgroup::"
done
- name: Comment on Pull Request
if: steps.check_tag.outputs.exists == 'false' && steps.notes.outputs.pr_number != ''
env:
GH_TOKEN: ${{ github.token }}
run: |
gh pr comment ${{ steps.notes.outputs.pr_number }} \
--body "Packages with version [${{ steps.version.outputs.version }}](https://github.com/${{ github.repository }}/releases/tag/${{ steps.version.outputs.version }}) have been released"