Skip to content

v0.1.11

v0.1.11 #11

Workflow file for this run

# ─────────────────────────────────────────────────────────────────────────────
# Publish a release to npm: the engine packages, then @axiomcode/code-graph.
#
# @axiomcode/engine-<os>-<cpu> is one package per platform holding every
# language's engine. @axiomcode/code-graph lists them as optionalDependencies
# pinned to its own version, so `npm install` fetches exactly the one for the
# machine — no Soufflé, no compiler. The engines therefore go first: publishing
# the root before them would leave a window where the version it pins is not
# on the registry.
#
# Runs when:
# • a GitHub release is PUBLISHED (release.yml drafts one for each new version
# on main; publishing the draft is the release decision). Real publish.
# • manually (Actions → publish-npm → Run workflow) with dry_run, which packs
# every package and prints exactly what would be uploaded, uploading nothing.
#
# Needs the CLI_BINARY_PUBLISH secret (an npm token with publish rights on @axiomcode)
# for a real publish; a dry run needs nothing.
#
# Re-running is safe: a package whose version is already on the registry is
# skipped, so a run that failed half way can simply be run again.
# ─────────────────────────────────────────────────────────────────────────────
name: publish-npm
on:
release:
types: [published]
workflow_dispatch:
inputs:
dry_run:
description: pack and print, publish nothing
type: boolean
default: true
concurrency:
group: publish-npm-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: read
jobs:
# Fails in seconds, before any engine is compiled, when the tag and the tree
# disagree about the version.
check:
runs-on: ubuntu-24.04
outputs:
version: ${{ steps.v.outputs.version }}
dist_tag: ${{ steps.v.outputs.dist_tag }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- id: v
run: |
set -euo pipefail
if [ "${{ github.event_name }}" = release ]; then
node .github/scripts/version.mjs check "${{ github.event.release.tag_name }}"
else
node .github/scripts/version.mjs check
fi
version="$(node .github/scripts/version.mjs get)"
# A prerelease never becomes `latest`: 0.2.0-rc.1 goes out as `next`.
case "$version" in *-*) dist_tag=next;; *) dist_tag=latest;; esac
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "dist_tag=$dist_tag" >> "$GITHUB_OUTPUT"
echo "publishing $version as '$dist_tag'"
# Nothing is compiled here. The push that landed this version on main built every platform's
# engines, packed @axiomcode/code-graph and ran the five-platform e2e on exactly those files;
# release.yml drafted this release only after that run was green. Publishing ships that build,
# so what was tested is what users install, and a release costs one build, not three (#1350).
publish:
needs: [check]
runs-on: ubuntu-24.04
permissions:
contents: write # attach the tarballs to the release
actions: read # the release's CI run and its artifacts
env:
VERSION: ${{ needs.check.outputs.version }}
DIST_TAG: ${{ needs.check.outputs.dist_tag }}
DRY: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
- name: the green CI run that built and tested this commit
id: run
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
sha="$(git rev-parse HEAD)"
run="$(gh run list --workflow ci.yml --commit "$sha" --event push --branch main --status success \
--limit 1 --json databaseId --jq '.[0].databaseId // empty')"
if [ -z "$run" ]; then
echo "::error::no green CI run of a push to main for ${sha::8}: nothing built and tested this commit, so nothing is published"
exit 1
fi
echo "id=$run" >> "$GITHUB_OUTPUT"
echo "shipping the build of CI run $run ($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$run)"
- uses: actions/download-artifact@v4
with:
pattern: engines-*
path: artifacts
run-id: ${{ steps.run.outputs.id }}
github-token: ${{ github.token }}
- uses: actions/download-artifact@v4
with:
name: code-graph-tgz
path: artifacts/tgz
run-id: ${{ steps.run.outputs.id }}
github-token: ${{ github.token }}
# A real release ships every platform the root package pins. Missing one
# means some machine installs a version whose engine does not exist.
- name: every pinned platform was built
run: |
set -euo pipefail
missing=0
for name in $(node -p "Object.keys(require('./package.json').optionalDependencies||{}).join(' ')"); do
platform="${name#@axiomcode/engine-}"
if [ ! -d "artifacts/engines-$platform" ]; then
echo "::warning::no engines were built for $platform"
missing=1
fi
# and every query program the CLI runs, or impact/path need soufflé there (#1330)
for dl in plugins/axiomcode/skills/axiomcode/scripts/dl/*.dl; do
q="$(basename "$dl" .dl)"
if ! cmp -s <(python3 plugins/axiomcode/skills/axiomcode/scripts/dl_program.py --print-id "$dl") \
<(cat "artifacts/engines-$platform/queries/$q.id" 2>/dev/null; echo); then
echo "::warning::$platform has no query program for these $q.dl rules"
missing=1
fi
done
done
if [ "$missing" = 1 ] && [ "$DRY" != true ]; then
echo "::error::a real publish needs every platform package.json pins"; exit 1
fi
- name: assemble one engine package per platform
run: |
set -euo pipefail
for d in artifacts/engines-*; do
platform="${d#artifacts/engines-}"
bash packaging/assemble-engine-package.sh "$platform" "$VERSION" "$d" "packages/engine-$platform"
cat "packages/engine-$platform/package.json"
done
- name: the tested @axiomcode/code-graph tarball is this version
run: |
set -euo pipefail
tgz="$(ls artifacts/tgz/*.tgz)"
got="$(tar -xOzf "$tgz" package/package.json | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>console.log(JSON.parse(s).version))')"
[ "$got" = "$VERSION" ] || { echo "::error::the tested tarball is $got, this release is $VERSION"; exit 1; }
echo "TGZ=$tgz" >> "$GITHUB_ENV"
- name: publish (or dry-run)
env:
NODE_AUTH_TOKEN: ${{ secrets.CLI_BINARY_PUBLISH }}
run: |
set -euo pipefail
flag=""; [ "$DRY" = true ] && flag="--dry-run"
mkdir -p tarballs
publish() {
local dir="$1" name
name="$(node -p "require('./$dir/package.json').name")"
if [ -z "$flag" ] && npm view "$name@$VERSION" version >/dev/null 2>&1; then
echo "══ $name@$VERSION is already on the registry — skipped"
return
fi
echo "══ $name@$VERSION tag=$DIST_TAG $flag"
( cd "$dir" && npm pack --pack-destination "$GITHUB_WORKSPACE/tarballs" >/dev/null \
&& npm publish --access public --tag "$DIST_TAG" $flag )
}
for p in packages/engine-*; do publish "$p"; done
# the tarball the e2e installed, published as it is rather than packed again
if [ -z "$flag" ] && npm view "@axiomcode/code-graph@$VERSION" version >/dev/null 2>&1; then
echo "══ @axiomcode/code-graph@$VERSION is already on the registry — skipped"
else
echo "══ @axiomcode/code-graph@$VERSION tag=$DIST_TAG $flag"
cp "$TGZ" tarballs/
npm publish "$TGZ" --access public --tag "$DIST_TAG" $flag
fi
ls -la tarballs
if [ "$DRY" = true ]; then
echo "DRY RUN — nothing was uploaded."
else
echo "published $VERSION"
fi
- name: attach the tarballs to the release
if: github.event_name == 'release'
env:
GH_TOKEN: ${{ github.token }}
run: gh release upload "${{ github.event.release.tag_name }}" tarballs/*.tgz --clobber
- uses: actions/upload-artifact@v4
if: github.event_name == 'workflow_dispatch'
with: { name: npm-tarballs, path: tarballs, retention-days: 7 }