Skip to content

Commit a6896aa

Browse files
committed
Publish npm from release workflow
1 parent 8975a05 commit a6896aa

3 files changed

Lines changed: 90 additions & 5 deletions

File tree

.github/workflows/build-tui.yml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,80 @@ jobs:
187187
fi
188188
189189
gh release edit "$RELEASE_TAG" --draft=false --latest
190+
191+
publish-npm:
192+
needs:
193+
- prepare
194+
- release
195+
if: github.repository == 'VRSEN/OpenSwarm'
196+
runs-on: ubuntu-latest
197+
permissions:
198+
contents: read
199+
env:
200+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
201+
NPM_CONFIG_PROVENANCE: false
202+
steps:
203+
- name: Checkout release tag
204+
uses: actions/checkout@v4
205+
with:
206+
ref: ${{ needs.prepare.outputs.release_tag }}
207+
208+
- uses: actions/setup-node@v4
209+
with:
210+
node-version: 20
211+
registry-url: "https://registry.npmjs.org"
212+
213+
- name: Validate release metadata
214+
shell: bash
215+
env:
216+
GH_TOKEN: ${{ github.token }}
217+
RELEASE_TAG: ${{ needs.prepare.outputs.release_tag }}
218+
RELEASE_VERSION: ${{ needs.prepare.outputs.release_version }}
219+
run: |
220+
set -euo pipefail
221+
222+
if [[ -z "${NODE_AUTH_TOKEN}" ]]; then
223+
echo "NPM_TOKEN is required to publish to npm." >&2
224+
exit 1
225+
fi
226+
227+
if [[ "$RELEASE_TAG" != "v$RELEASE_VERSION" ]]; then
228+
echo "Release tag ($RELEASE_TAG) must match release version ($RELEASE_VERSION)." >&2
229+
exit 1
230+
fi
231+
232+
package_version="$(node -p "require('./package.json').version")"
233+
lock_version="$(node -p "require('./package-lock.json').packages[''].version")"
234+
python_version="$(python3 - <<'PY'
235+
import tomllib
236+
with open("pyproject.toml", "rb") as handle:
237+
print(tomllib.load(handle)["project"]["version"])
238+
PY
239+
)"
240+
241+
if [[ "$package_version" != "$RELEASE_VERSION" || "$lock_version" != "$RELEASE_VERSION" || "$python_version" != "$RELEASE_VERSION" ]]; then
242+
echo "Release tag, package.json, package-lock.json, and pyproject.toml versions must match." >&2
243+
echo "tag=$RELEASE_VERSION package=$package_version lock=$lock_version pyproject=$python_version" >&2
244+
exit 1
245+
fi
246+
247+
mapfile -t assets < <(gh release view "$RELEASE_TAG" --json assets --jq '.assets[].name' | sort)
248+
required_assets=(
249+
agentswarm-darwin-arm64
250+
agentswarm-darwin-x64
251+
agentswarm-linux-x64
252+
agentswarm-windows-x64.exe
253+
)
254+
255+
for required in "${required_assets[@]}"; do
256+
if ! printf '%s\n' "${assets[@]}" | grep -Fxq "$required"; then
257+
echo "Release $RELEASE_TAG is missing required asset: $required" >&2
258+
exit 1
259+
fi
260+
done
261+
262+
- name: Install dependencies
263+
run: npm ci
264+
265+
- name: Publish npm package
266+
run: npm publish --access public

.github/workflows/publish-npm-on-release.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Publish npm on Release
1+
name: Fallback Publish npm on Release
22

33
on:
44
release:
@@ -34,6 +34,11 @@ jobs:
3434
run: |
3535
set -euo pipefail
3636
37+
if [[ -z "${NODE_AUTH_TOKEN}" ]]; then
38+
echo "NPM_TOKEN is required to publish to npm." >&2
39+
exit 1
40+
fi
41+
3742
release_version="${RELEASE_TAG#v}"
3843
package_version="$(node -p "require('./package.json').version")"
3944
lock_version="$(node -p "require('./package-lock.json').packages[''].version")"

RELEASE.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Release Workflow
22

3-
OpenSwarm releases are GitHub Release driven. The release tag, npm package version, lockfile version, and Python project metadata must use the same version.
3+
OpenSwarm releases use one normal path: `Build TUI Binaries` builds the required assets, publishes the GitHub Release, then publishes `@vrsen/openswarm` to npm in the same workflow run. The release tag, npm package version, lockfile version, and Python project metadata must use the same version.
44

55
## Release Inputs
66

@@ -19,12 +19,15 @@ OpenSwarm releases are GitHub Release driven. The release tag, npm package versi
1919
2. Merge the version bump to `main`.
2020
3. Run the `Build TUI Binaries` workflow from the `main` branch in GitHub Actions. Leave `version` blank to use `package.json`, or pass the exact version without the `v` prefix.
2121
4. Confirm the workflow creates `vX.Y.Z` with all required binary assets.
22-
5. Let `Publish npm on Release` publish `@vrsen/openswarm` from the release tag.
22+
5. Let the downstream npm publish job in the same workflow publish `@vrsen/openswarm` from the release tag.
2323

24-
Pushing a matching `vX.Y.Z` tag also runs the binary release workflow, but the manual workflow is the preferred path because it builds assets and publishes the GitHub Release in one run.
24+
Pushing a matching `vX.Y.Z` tag also runs the binary release workflow. The manual workflow is the preferred path because it builds assets, publishes the GitHub Release, and publishes npm in one run.
25+
26+
GitHub releases created with `${{ github.token }}` do not start separate `on: release` workflows. `Fallback Publish npm on Release` exists only for releases that are published manually, externally, or through an API token that can trigger release workflows. It is not the normal release path.
2527

2628
## Release Gates
2729

2830
- The binary release workflow fails if the tag/input version does not match `package.json`, `package-lock.json`, and `pyproject.toml`.
29-
- The npm publish workflow fails if the GitHub Release is missing any required TUI binary asset.
31+
- The npm publish job fails if `NPM_TOKEN` is missing, versions do not match, or the GitHub Release is missing any required TUI binary asset.
32+
- The fallback npm publish workflow runs the same key checks for manually or externally published releases.
3033
- The npm package uses `publishConfig.access=public` so scoped publishes do not depend on CLI flags alone.

0 commit comments

Comments
 (0)