feat(conform): multi-track video authoring — V2+ stacking render-veri… #207
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |