Skip to content

feat(conform): the conform emulator — interchange in, rendering .drt out #203

feat(conform): the conform emulator — interchange in, rendering .drt out

feat(conform): the conform emulator — interchange in, rendering .drt out #203

Workflow file for this run

name: Publish npm package
on:
push:
tags:
- "v*"
# Manual re-trigger. A tag push is single-shot: if Actions cannot allocate a
# runner (2026-08-06 outage — the v2.84.0 tag registered no run at all), there
# is nothing to re-run and the only other recovery is deleting and re-pushing
# a published tag. `gh run rerun` is not a substitute either: it re-presents
# the consumed single-use OIDC token and fails provenance with
# IDENTITY_TOKEN_READ_ERROR. A fresh dispatch mints a fresh token.
workflow_dispatch:
inputs:
ref:
description: "Tag or ref to publish (e.g. v2.84.0). Defaults to the selected branch."
required: false
type: string
permissions:
contents: read
id-token: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v5
with:
# Empty on a tag push, which checkout treats as "use the triggering ref".
ref: ${{ inputs.ref || '' }}
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Set up Node
uses: actions/setup-node@v5
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"
- name: Run Python smoke tests
run: python tests/test_import.py
- name: Run static guard tests
# Drift guards that gate every publish: no undefined names in src/,
# tool action lists in sync with dispatch, control-panel guide in
# sync with the panel's navigation and screenshots, the
# Blackmagic-facing api-limitations.md in sync with the api_truth ledger,
# the tool counts quoted across the docs in sync with reality, and the
# mcp[cli] cap that keeps a fresh install working (issue #103).
#
# tests.test_import is listed here as well as in the smoke step above:
# that step runs the module's run_all(), which only picks up bare
# test_-prefixed functions, so a TestCase in the same file would
# otherwise never run in CI.
run: |
pip install pyflakes
python -m unittest tests.test_static_undefined_names tests.test_action_list_drift tests.test_panel_docs_drift tests.test_api_limitations_doc tests.test_doc_tool_counts tests.test_import
- name: Run Node CLI smoke tests
run: |
node bin/davinci-resolve-mcp.mjs --help
node bin/davinci-resolve-mcp.mjs --version
- name: Run setup dry run
shell: bash
run: |
# The runner has no Resolve, so verification MUST fail here and setup
# MUST exit non-zero — that is the contract this step exists to pin
# (a zero over an install whose scripting API cannot load is how
# "Setup complete!" over a dead install shipped in the first place).
# What is checked is that the summary line and the exit status agree,
# in whichever direction the environment takes them, and that setup
# got far enough to print a summary at all rather than crashing.
export DAVINCI_RESOLVE_MCP_INSTALL_ROOT="$(mktemp -d)"
set +e
out="$(node bin/davinci-resolve-mcp.mjs setup --dry-run --no-venv --clients manual --update-policy never 2>&1)"
status=$?
set -e
echo "$out"
echo "--- setup exited with status $status ---"
if grep -qE 'Traceback \(most recent call last\)' <<<"$out"; then
echo "::error::setup crashed with a traceback"
exit 1
fi
incomplete=0
grep -qE 'Setup incomplete|Environment incomplete' <<<"$out" && incomplete=1
complete=0
grep -qE 'Setup complete!|Environment ready!' <<<"$out" && complete=1
if [ "$incomplete" -eq 0 ] && [ "$complete" -eq 0 ]; then
echo "::error::setup printed no summary line"
exit 1
fi
if [ "$incomplete" -eq 1 ] && [ "$complete" -eq 1 ]; then
echo "::error::setup printed both a success and a failure summary"
exit 1
fi
if [ "$incomplete" -eq 1 ] && [ "$status" -eq 0 ]; then
echo "::error::setup reported incomplete but exited 0 — the bug #154 fixed"
exit 1
fi
if [ "$complete" -eq 1 ] && [ "$status" -ne 0 ]; then
echo "::error::setup reported success but exited $status"
exit 1
fi
echo "summary line and exit status agree"
- name: Check npm package contents
run: npm pack --dry-run
- name: Check npm version availability
id: npm_version
shell: bash
run: |
package_name="$(node -p "require('./package.json').name")"
package_version="$(node -p "require('./package.json').version")"
if npm view "${package_name}@${package_version}" version >/dev/null 2>&1; then
echo "publish=false" >> "$GITHUB_OUTPUT"
echo "${package_name}@${package_version} is already published; skipping npm publish."
else
echo "publish=true" >> "$GITHUB_OUTPUT"
echo "${package_name}@${package_version} is not published yet."
fi
- name: Compute expected tarball checksum
id: pack_meta
if: steps.npm_version.outputs.publish == 'true'
shell: bash
run: |
shasum="$(npm pack --dry-run --json | node -p "JSON.parse(require('fs').readFileSync(0, 'utf8'))[0].shasum")"
echo "shasum=${shasum}" >> "$GITHUB_OUTPUT"
echo "Expected tarball shasum: ${shasum}"
- name: Publish to npm
id: npm_publish
if: steps.npm_version.outputs.publish == 'true'
continue-on-error: true
run: npm publish --provenance --access public
- name: Verify publish landed
if: steps.npm_version.outputs.publish == 'true' && steps.npm_publish.outcome == 'failure'
shell: bash
run: |
# npm publish can exit nonzero after the registry has already accepted
# the PUT: a retried request re-presents the consumed single-use OIDC
# exchange token and gets 401 "token is invalid" (observed on the
# v2.37.0 run). Only fail the job if the exact tarball is not live.
package_name="$(node -p "require('./package.json').name")"
package_version="$(node -p "require('./package.json').version")"
expected="${{ steps.pack_meta.outputs.shasum }}"
for attempt in 1 2 3 4 5 6; do
published="$(npm view "${package_name}@${package_version}" dist.shasum 2>/dev/null || true)"
if [ -n "${published}" ]; then
if [ "${published}" = "${expected}" ]; then
echo "npm publish reported failure, but ${package_name}@${package_version} is live with the expected shasum ${expected}. Treating as success."
exit 0
fi
echo "::error::${package_name}@${package_version} exists on the registry with shasum ${published}, expected ${expected}. Refusing to mask the publish failure."
exit 1
fi
echo "Attempt ${attempt}: ${package_name}@${package_version} not visible on the registry yet; retrying in 10s."
sleep 10
done
echo "::error::npm publish failed and ${package_name}@${package_version} never appeared on the registry."
exit 1