Skip to content

Commit 771cdb3

Browse files
authored
chore: refactor publish workflow (#34)
1 parent e42ea6b commit 771cdb3

File tree

3 files changed

+117
-159
lines changed

3 files changed

+117
-159
lines changed

.github/actions/npm-publish/action.yml

Lines changed: 0 additions & 127 deletions
This file was deleted.

.github/workflows/ci.yml

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -113,32 +113,3 @@ jobs:
113113

114114
- name: Build library
115115
run: bun run build
116-
117-
publish:
118-
name: publish to npm
119-
runs-on: ubuntu-latest
120-
# Only publish on main branch pushes after all checks pass
121-
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
122-
needs: [fmt, lint, typecheck, test, build]
123-
permissions:
124-
contents: read
125-
id-token: write # Required for OIDC trusted publishing
126-
steps:
127-
- name: Checkout code
128-
uses: actions/checkout@v4
129-
with:
130-
fetch-depth: 0 # Required for git describe to find tags
131-
132-
- uses: oven-sh/setup-bun@v1
133-
with:
134-
bun-version: latest
135-
136-
- name: Install dependencies
137-
run: bun install
138-
139-
- uses: ./.github/actions/setup-zig
140-
with:
141-
version: 0.15.2
142-
143-
- name: Publish to NPM
144-
uses: ./.github/actions/npm-publish

.github/workflows/publish.yml

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ on:
44
push:
55
tags:
66
- 'v*'
7+
workflow_run:
8+
workflows: ['ci']
9+
types:
10+
- completed
11+
branches:
12+
- main
713

814
permissions:
915
contents: read
@@ -13,8 +19,10 @@ jobs:
1319
publish:
1420
name: publish to npm
1521
runs-on: ubuntu-latest
22+
# Only run if CI workflow succeeded (for workflow_run trigger)
23+
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'push' }}
1624
steps:
17-
- name: Checkout tag
25+
- name: Checkout code
1826
uses: actions/checkout@v4
1927
with:
2028
ref: ${{ github.ref }}
@@ -52,5 +60,111 @@ jobs:
5260
- name: Build library
5361
run: bun run build
5462

55-
- name: Publish to NPM
56-
uses: ./.github/actions/npm-publish
63+
- name: Setup Node.js for npm
64+
uses: actions/setup-node@v4
65+
with:
66+
node-version: '20'
67+
registry-url: 'https://registry.npmjs.org'
68+
69+
# Ensure npm 11.5.1 or later for trusted publishing
70+
- run: npm install -g npm@latest
71+
72+
- name: Detect trigger type
73+
id: detect
74+
run: |
75+
if [[ $GITHUB_REF == refs/tags/* ]]; then
76+
echo "is_tag=true" >> $GITHUB_OUTPUT
77+
echo "trigger_type=tag" >> $GITHUB_OUTPUT
78+
echo "trigger_name=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
79+
echo "📦 Detected tag push: ${GITHUB_REF#refs/tags/}"
80+
else
81+
echo "is_tag=false" >> $GITHUB_OUTPUT
82+
echo "trigger_type=branch" >> $GITHUB_OUTPUT
83+
echo "trigger_name=${GITHUB_REF#refs/heads/}" >> $GITHUB_OUTPUT
84+
echo "🚧 Detected branch push: ${GITHUB_REF#refs/heads/}"
85+
fi
86+
87+
- name: Generate version
88+
id: version
89+
run: |
90+
# Get base version from package.json
91+
BASE_VERSION=$(jq -r .version package.json)
92+
93+
if [[ "${{ steps.detect.outputs.is_tag }}" == "true" ]]; then
94+
# For tags, use the base version as-is (stable release)
95+
NPM_VERSION="${BASE_VERSION}"
96+
NPM_TAG="latest"
97+
echo "📦 Publishing stable release: ${NPM_VERSION}"
98+
else
99+
# For main branch, create a pre-release version using git describe
100+
# Format: 0.3.0-next.5.g1a2b3c4 (base-next.commits.hash)
101+
GIT_COMMIT=$(git rev-parse --short HEAD)
102+
COMMITS_SINCE_TAG=$(git rev-list --count HEAD ^$(git describe --tags --abbrev=0 2>/dev/null || echo HEAD) 2>/dev/null || echo "0")
103+
NPM_VERSION="${BASE_VERSION}-next.${COMMITS_SINCE_TAG}.g${GIT_COMMIT}"
104+
NPM_TAG="next"
105+
echo "🚧 Publishing pre-release: ${NPM_VERSION}"
106+
fi
107+
108+
echo "version=${NPM_VERSION}" >> $GITHUB_OUTPUT
109+
echo "tag=${NPM_TAG}" >> $GITHUB_OUTPUT
110+
111+
# Update package.json with the new version
112+
node -e "const fs = require('fs'); const pkg = JSON.parse(fs.readFileSync('package.json')); pkg.version = '${NPM_VERSION}'; fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');"
113+
114+
echo "Updated package.json to version ${NPM_VERSION}"
115+
116+
- name: Validate tag matches package.json version
117+
if: steps.detect.outputs.is_tag == 'true'
118+
run: |
119+
# Extract version from package.json
120+
PKG_VERSION=$(jq -r .version package.json)
121+
122+
# Extract version from git tag (strip 'v' prefix)
123+
TAG_VERSION=${GITHUB_REF#refs/tags/v}
124+
125+
echo "Package version: $PKG_VERSION"
126+
echo "Tag version: $TAG_VERSION"
127+
128+
if [ "$PKG_VERSION" != "$TAG_VERSION" ]; then
129+
echo "❌ Error: Version mismatch!"
130+
echo " package.json version: $PKG_VERSION"
131+
echo " Git tag version: $TAG_VERSION"
132+
echo ""
133+
echo "Please ensure the git tag matches the version in package.json"
134+
exit 1
135+
fi
136+
137+
echo "✅ Version validation passed: $PKG_VERSION"
138+
139+
- name: Check if version exists
140+
id: check-exists
141+
run: |
142+
PACKAGE_NAME=$(node -p "require('./package.json').name")
143+
VERSION="${{ steps.version.outputs.version }}"
144+
145+
if npm view "${PACKAGE_NAME}@${VERSION}" version &>/dev/null; then
146+
echo "exists=true" >> $GITHUB_OUTPUT
147+
echo "Version ${VERSION} already exists on npm"
148+
else
149+
echo "exists=false" >> $GITHUB_OUTPUT
150+
echo "Version ${VERSION} does not exist, will publish"
151+
fi
152+
153+
- name: Publish to npm (with OIDC trusted publishing)
154+
if: steps.check-exists.outputs.exists == 'false'
155+
run: npm publish --tag ${{ steps.version.outputs.tag }} --provenance --access public
156+
157+
- name: Update dist-tag (version already exists)
158+
if: steps.check-exists.outputs.exists == 'true' && steps.detect.outputs.is_tag == 'true'
159+
run: |
160+
PACKAGE_NAME=$(node -p "require('./package.json').name")
161+
VERSION="${{ steps.version.outputs.version }}"
162+
TAG="${{ steps.version.outputs.tag }}"
163+
164+
echo "Version ${VERSION} already published, updating dist-tag to ${TAG}"
165+
npm dist-tag add "${PACKAGE_NAME}@${VERSION}" "${TAG}"
166+
167+
- name: Skip (pre-release already exists)
168+
if: steps.check-exists.outputs.exists == 'true' && steps.detect.outputs.is_tag != 'true'
169+
run: |
170+
echo "⏭️ Pre-release version already exists, skipping"

0 commit comments

Comments
 (0)