Skip to content

v1.0.0

v1.0.0 #8

Workflow file for this run

name: publish
on:
push:
tags: ['v*']
permissions:
id-token: write # npm Trusted Publishing OIDC
contents: write # GitHub Release creation
concurrency:
group: publish
cancel-in-progress: false
jobs:
publish:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22.14.0'
registry-url: https://registry.npmjs.org
- name: Use npm with Trusted Publishing support
run: npm install -g npm@^11.5.1
- name: Verify tag matches package.json version
run: |
set -eo pipefail
TAG_VERSION="${GITHUB_REF_NAME#v}"
PKG_VERSION="$(node -p 'require("./package.json").version')"
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
echo "::error::Tag v${TAG_VERSION} does not match package.json version ${PKG_VERSION}"
exit 1
fi
- name: Verify publishable file set
run: |
set -eo pipefail
PACK_JSON="$(npm pack --dry-run --json)"
PACK_JSON="${PACK_JSON}" node <<'NODE'
const data = JSON.parse(process.env.PACK_JSON)
const files = data[0].files.map((file) => file.path).sort()
const expected = [
'CHANGELOG.md',
'LICENSE',
'README.md',
'bin/appfigures',
'dist/af.js',
'package.json',
]
if (JSON.stringify(files) !== JSON.stringify(expected)) {
console.error(`Expected npm pack files ${JSON.stringify(expected)}, got ${JSON.stringify(files)}`)
process.exit(1)
}
NODE
- name: Extract release notes
run: |
set -eo pipefail
node - "${GITHUB_REF_NAME#v}" > release-notes.md <<'NODE'
const fs = require('fs')
const version = process.argv[2]
const content = fs.readFileSync('CHANGELOG.md', 'utf8')
const escaped = version.replace(/[.+*?^$(){}|[\]\\]/g, '\\$&')
const headerRe = new RegExp(`^## \\[${escaped}\\]`)
const nextHeaderRe = /^## \[/
const captured = []
let inSection = false
for (const line of content.split('\n')) {
if (inSection && nextHeaderRe.test(line)) break
if (headerRe.test(line)) {
inSection = true
continue
}
if (inSection) captured.push(line)
}
if (!inSection) {
console.error(`No CHANGELOG section found for version ${version}`)
process.exit(1)
}
process.stdout.write(captured.join('\n').trim() + '\n')
NODE
- name: Publish to npm
run: |
set -eo pipefail
NAME="$(node -p 'require("./package.json").name')"
VERSION="$(node -p 'require("./package.json").version')"
TAG="$(node -e 'const version = process.argv[1]; const match = version.match(/^\d+\.\d+\.\d+-([0-9A-Za-z]+)/); if (match) process.stdout.write(match[1]);' "${VERSION}")"
if npm view "${NAME}@${VERSION}" version >/dev/null 2>&1; then
echo "${NAME}@${VERSION} is already published; skipping npm publish"
exit 0
fi
if [ -n "$TAG" ]; then
npm publish --tag "$TAG"
else
npm publish
fi
- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
run: |
set -eo pipefail
if gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1; then
echo "Release ${GITHUB_REF_NAME} already exists; skipping"
exit 0
fi
VERSION="${GITHUB_REF_NAME#v}"
gh release create "${GITHUB_REF_NAME}" \
--title "@appfigures/cli v${VERSION}" \
--notes-file release-notes.md