Skip to content

chore(release): 0.81.0 — eval-campaign scaffold prep primitives (#225) #85

chore(release): 0.81.0 — eval-campaign scaffold prep primitives (#225)

chore(release): 0.81.0 — eval-campaign scaffold prep primitives (#225) #85

Workflow file for this run

name: Publish
on:
push:
tags:
- 'v*'
workflow_dispatch:
jobs:
# Verify both packages build and pass tests, in lockstep.
# If either fails, neither publishes.
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
registry-url: https://registry.npmjs.org
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install JS deps
run: pnpm install --frozen-lockfile
- name: Typecheck JS
run: pnpm typecheck
- name: Test JS
run: pnpm test
- name: Build JS and emit OpenAPI spec
run: pnpm build
- name: Verify packed package exports
run: pnpm run verify:package
- name: Verify version lock between npm and PyPI packages
run: |
NPM_VERSION=$(node -p "require('./package.json').version")
PY_VERSION=$(grep -E '^version' clients/python/pyproject.toml | head -1 | sed -E 's/.*"([^"]+)".*/\1/')
PY_RUNTIME_VERSION=$(python -c "import pathlib,re; text=pathlib.Path('clients/python/src/agent_eval_rpc/__init__.py').read_text(); match=re.search(r'__version__ = \"([^\"]+)\"', text); print(match.group(1) if match else '')")
if [ "$NPM_VERSION" != "$PY_VERSION" ]; then
echo "::error::Version mismatch: npm=$NPM_VERSION pypi=$PY_VERSION. Bump them together."
exit 1
fi
if [ -n "$PY_RUNTIME_VERSION" ] && [ "$NPM_VERSION" != "$PY_RUNTIME_VERSION" ]; then
echo "::error::Version mismatch: npm=$NPM_VERSION python_runtime=$PY_RUNTIME_VERSION. Bump them together."
exit 1
fi
if [[ "${GITHUB_REF:-}" == refs/tags/v* ]]; then
TAG_VERSION="${GITHUB_REF#refs/tags/v}"
if [ "$TAG_VERSION" != "$NPM_VERSION" ]; then
echo "::error::Tag/version mismatch: tag=$TAG_VERSION package=$NPM_VERSION."
exit 1
fi
fi
echo "Versions locked: $NPM_VERSION"
- name: Install Python client
working-directory: clients/python
run: pip install -e ".[dev]"
- name: Test Python client (incl. real subprocess integration)
working-directory: clients/python
run: pytest -v
- name: Upload OpenAPI artifact
uses: actions/upload-artifact@v4
with:
name: openapi
path: dist/openapi.json
- name: Upload Python build context
uses: actions/upload-artifact@v4
with:
name: python-source
path: clients/python
publish-npm:
needs: verify
# Publish on a v* tag OR a manual dispatch — always via OIDC trusted
# publishing (tokenless). The Trusted Publisher on npmjs (package Settings →
# Trusted Publisher → GitHub Actions: org tangle-network, repo agent-eval,
# workflow publish.yml) mints a short-lived credential from the id-token —
# no NPM_TOKEN, nothing to rotate, plus provenance attestation.
if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
# Both publish steps are idempotent: re-running a version already on the
# registry (e.g. after a manual publish) skips rather than fails, so the
# downstream PyPI step still runs.
# Tokenless OIDC trusted publishing. The id-token→publish-credential
# exchange is an npm-CLI feature (>= 11.5.1) and Node 22 bundles npm 10, so
# upgrade npm and publish with it (pnpm only signs provenance — the PUT
# then 404s on auth). agent-eval has no `workspace:` deps, so `npm publish`
# is safe here. Idempotent: a version already on the registry is skipped so
# the downstream PyPI step still runs.
- name: Publish to npm (OIDC trusted publishing)
run: |
npm install -g npm@latest
NAME=$(node -p "require('./package.json').name")
VERSION=$(node -p "require('./package.json').version")
if npm view "$NAME@$VERSION" version --registry=https://registry.npmjs.org >/dev/null 2>&1; then
echo "$NAME@$VERSION already on registry; skipping publish"
else
npm publish --provenance --access public --registry=https://registry.npmjs.org
fi
publish-pypi:
# PyPI must not publish a version npm failed to publish. The npm job is
# idempotent and succeeds when the version is already on the registry, so
# reruns can still repair a missing PyPI artifact without creating skew.
needs: [verify, publish-npm]
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install build tools
run: pip install build twine
- name: Build wheel + sdist
working-directory: clients/python
run: python -m build
- name: Check whether this version is already on PyPI
id: pypi-check
run: |
VERSION=$(grep -E '^version' clients/python/pyproject.toml | head -1 | sed -E 's/.*"([^"]+)".*/\1/')
if curl -sf "https://pypi.org/pypi/agent-eval-rpc/$VERSION/json" >/dev/null; then
echo "agent-eval-rpc==$VERSION already on PyPI; skipping publish"
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Publish to PyPI (trusted publishing)
if: steps.pypi-check.outputs.skip != 'true'
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: clients/python/dist