@@ -36,6 +36,15 @@ name: "npm Release"
3636#
3737# 3. Now this workflow can publish subsequent versions automatically
3838
39+ #
40+ # RELEASE FLOW:
41+ # 1. prepare-release: Creates a release branch, bumps VERSION/sqlite-vec.h/package.json
42+ # 2. build-*: All builds run from the release branch (with correct version baked in)
43+ # 3. publish-npm: Publishes to npm, then merges release branch to main on success
44+ #
45+ # If any step fails, main is untouched and the release branch can be deleted.
46+ #
47+
3948on :
4049 workflow_dispatch :
4150 inputs :
@@ -53,10 +62,70 @@ permissions:
5362 contents : read
5463
5564jobs :
65+ prepare-release :
66+ runs-on : ubuntu-24.04
67+ permissions :
68+ contents : write
69+ outputs :
70+ release_branch : ${{ steps.prepare.outputs.branch }}
71+ new_version : ${{ steps.prepare.outputs.version }}
72+ steps :
73+ - uses : actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
74+ with :
75+ fetch-depth : 0
76+
77+ - uses : actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
78+ with :
79+ node-version : " 20"
80+
81+ - uses : photostructure/git-ssh-signing-action@fdd4b062a9ba41473f013258cc9c7eea1640f826 # v1.2.0
82+ with :
83+ ssh-signing-key : ${{ secrets.SSH_SIGNING_KEY }}
84+ git-user-name : ${{ secrets.GIT_USER_NAME }}
85+ git-user-email : ${{ secrets.GIT_USER_EMAIL }}
86+
87+ - name : Prepare release branch
88+ id : prepare
89+ run : |
90+ # Get current version from VERSION file (source of truth)
91+ CURRENT=$(cat VERSION | tr -d '[:space:]')
92+ echo "Current version: $CURRENT"
93+
94+ # Calculate new version using npm's semver
95+ # Strip any prerelease suffix for the bump, then we'll keep it simple (no prerelease)
96+ BASE_VERSION=$(echo "$CURRENT" | sed 's/-.*//')
97+ NEW_VERSION=$(npx semver -i ${{ github.event.inputs.version }} "$BASE_VERSION")
98+ echo "New version: $NEW_VERSION"
99+
100+ # Create release branch
101+ BRANCH="release/v${NEW_VERSION}"
102+ git checkout -b "$BRANCH"
103+
104+ # Update VERSION file
105+ echo "$NEW_VERSION" > VERSION
106+
107+ # Regenerate sqlite-vec.h from template
108+ make sqlite-vec.h
109+
110+ # Update package.json (without creating git commit/tag)
111+ npm version "$NEW_VERSION" --no-git-tag-version
112+
113+ # Commit all version changes
114+ git add VERSION sqlite-vec.h package.json package-lock.json
115+ git commit -S -m "release: v${NEW_VERSION}"
116+ git push origin "$BRANCH"
117+
118+ # Output for subsequent jobs
119+ echo "branch=$BRANCH" >> $GITHUB_OUTPUT
120+ echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
121+
56122 build-linux-x64 :
123+ needs : [prepare-release]
57124 runs-on : ubuntu-24.04
58125 steps :
59126 - uses : actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
127+ with :
128+ ref : ${{ needs.prepare-release.outputs.release_branch }}
60129 - run : ./scripts/vendor.sh
61130 - run : make loadable
62131 - uses : actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
@@ -65,21 +134,26 @@ jobs:
65134 path : dist/vec0.so
66135
67136 build-linux-arm64 :
137+ needs : [prepare-release]
68138 runs-on : ubuntu-24.04-arm
69139 steps :
70140 - uses : actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
141+ with :
142+ ref : ${{ needs.prepare-release.outputs.release_branch }}
71143 - run : ./scripts/vendor.sh
72- - run : make sqlite-vec.h
73144 - run : make loadable
74145 - uses : actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
75146 with :
76147 name : linux-arm64
77148 path : dist/vec0.so
78149
79150 build-linux-x64-musl :
151+ needs : [prepare-release]
80152 runs-on : ubuntu-24.04
81153 steps :
82154 - uses : actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
155+ with :
156+ ref : ${{ needs.prepare-release.outputs.release_branch }}
83157 - run : |
84158 docker run --rm -v $(pwd):/tmp/project --entrypoint /bin/sh --platform linux/amd64 node:20-alpine -c "\
85159 apk add build-base bash curl unzip --update-cache && \
@@ -92,9 +166,12 @@ jobs:
92166 path : dist/vec0.so
93167
94168 build-linux-arm64-musl :
169+ needs : [prepare-release]
95170 runs-on : ubuntu-24.04-arm
96171 steps :
97172 - uses : actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
173+ with :
174+ ref : ${{ needs.prepare-release.outputs.release_branch }}
98175 - run : |
99176 docker run --rm -v $(pwd):/tmp/project --entrypoint /bin/sh --platform linux/arm64 node:20-alpine -c "\
100177 apk add build-base bash curl unzip --update-cache && \
@@ -107,9 +184,12 @@ jobs:
107184 path : dist/vec0.so
108185
109186 build-darwin-x64 :
187+ needs : [prepare-release]
110188 runs-on : macos-15-intel
111189 steps :
112190 - uses : actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
191+ with :
192+ ref : ${{ needs.prepare-release.outputs.release_branch }}
113193 - run : ./scripts/vendor.sh
114194 - run : make loadable
115195 - uses : actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
@@ -118,9 +198,12 @@ jobs:
118198 path : dist/vec0.dylib
119199
120200 build-darwin-arm64 :
201+ needs : [prepare-release]
121202 runs-on : macos-14
122203 steps :
123204 - uses : actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
205+ with :
206+ ref : ${{ needs.prepare-release.outputs.release_branch }}
124207 - run : ./scripts/vendor.sh
125208 - run : make loadable
126209 - uses : actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
@@ -129,13 +212,15 @@ jobs:
129212 path : dist/vec0.dylib
130213
131214 build-win32-x64 :
215+ needs : [prepare-release]
132216 runs-on : windows-latest
133217 steps :
134218 - uses : actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
219+ with :
220+ ref : ${{ needs.prepare-release.outputs.release_branch }}
135221 - uses : ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
136222 - run : ./scripts/vendor.sh
137223 shell : bash
138- - run : make sqlite-vec.h
139224 - run : mkdir dist
140225 - run : cl.exe /fPIC -shared /W4 /Ivendor/ /O2 /LD sqlite-vec.c -o dist/vec0.dll
141226 - uses : actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
@@ -144,15 +229,17 @@ jobs:
144229 path : dist/vec0.dll
145230
146231 build-win32-arm64 :
232+ needs : [prepare-release]
147233 runs-on : windows-11-arm
148234 steps :
149235 - uses : actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
236+ with :
237+ ref : ${{ needs.prepare-release.outputs.release_branch }}
150238 - uses : ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
151239 with :
152240 arch : arm64
153241 - run : ./scripts/vendor.sh
154242 shell : bash
155- - run : make sqlite-vec.h
156243 - run : mkdir dist
157244 - run : cl.exe /fPIC -shared /W4 /Ivendor/ /O2 /LD sqlite-vec.c -o dist/vec0.dll
158245 - uses : actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
@@ -164,6 +251,7 @@ jobs:
164251 runs-on : ubuntu-24.04
165252 needs :
166253 [
254+ prepare-release,
167255 build-linux-x64,
168256 build-linux-arm64,
169257 build-linux-x64-musl,
@@ -176,10 +264,14 @@ jobs:
176264 permissions :
177265 contents : write # Required to push version commits and tags
178266 id-token : write # Required for npm OIDC trusted publishing
267+ env :
268+ NEW_VERSION : ${{ needs.prepare-release.outputs.new_version }}
269+ RELEASE_BRANCH : ${{ needs.prepare-release.outputs.release_branch }}
179270 steps :
180271 - uses : actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
181272 with :
182- fetch-depth : 0 # Full history for version tags
273+ ref : ${{ needs.prepare-release.outputs.release_branch }}
274+ fetch-depth : 0 # Full history for merging
183275
184276 # Download all artifacts into platform-specific subdirectories
185277 - uses : actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
@@ -233,12 +325,7 @@ jobs:
233325 - name : Bump version and create signed tag
234326 run : |
235327 npm version ${{ github.event.inputs.version }} --sign-git-tag -m "release: %s"
236- NEW_VERSION=$(npm pkg get version | tr -d '"')
237- echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
238- # Keep VERSION file in sync with package.json
239- echo "$NEW_VERSION" > VERSION
240- git add VERSION
241- git commit --amend --no-edit
328+ echo "NEW_VERSION=$(npm pkg get version | tr -d '\"')" >> $GITHUB_ENV
242329
243330 - name : Push version commit and tag
244331 run : git push origin main --follow-tags
@@ -250,11 +337,31 @@ jobs:
250337
251338 - name : Publish to npm with OIDC
252339 run : |
253- VERSION="${{ env. NEW_VERSION } }"
340+ VERSION="${NEW_VERSION}"
254341 # Extract prerelease identifier if present (e.g., "beta" from "1.0.0-beta.1")
255342 if [[ "$VERSION" == *"-"* ]]; then
256343 TAG=$(echo "$VERSION" | sed 's/.*-\([a-zA-Z]*\).*/\1/')
257344 npm publish --provenance --access public --tag "$TAG"
258345 else
259346 npm publish --provenance --access public
260347 fi
348+
349+ # Only after successful npm publish: merge to main, tag, and create release
350+ - name : Merge release branch to main
351+ run : |
352+ git checkout main
353+ git merge --ff-only "$RELEASE_BRANCH"
354+
355+ - name : Create signed tag
356+ run : git tag -s "v${NEW_VERSION}" -m "v${NEW_VERSION}"
357+
358+ - name : Push to main with tag
359+ run : git push origin main --follow-tags
360+
361+ - name : Delete release branch
362+ run : git push origin --delete "$RELEASE_BRANCH"
363+
364+ - name : Create GitHub Release
365+ run : gh release create "v${NEW_VERSION}" --generate-notes
366+ env :
367+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
0 commit comments