Skip to content

fix(sdk): Windows harness reliability — opencode prompts over stdin, … #163

fix(sdk): Windows harness reliability — opencode prompts over stdin, …

fix(sdk): Windows harness reliability — opencode prompts over stdin, … #163

name: Coverage Badge
# Updates the README coverage badge gist after a merge to main, without
# re-running the coverage pipeline. The coverage numbers that ship with main
# are the ones computed on the PR's merge commit (coverage.yml runs on every
# PR), so we just locate that PR's coverage-summary artifact and push it to
# the gist.
on:
push:
branches: [main]
workflow_dispatch:
inputs:
run_id:
description: "Coverage Summary run ID to pull artifact from (optional; defaults to latest success on main)"
required: false
type: string
permissions:
contents: read
actions: read
jobs:
update-badge:
runs-on: ubuntu-latest
# Skip release automation commits — they don't change coverage.
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
steps:
- name: Resolve Coverage Summary run ID for this merge
id: resolve
uses: actions/github-script@v7
env:
OVERRIDE_RUN_ID: ${{ github.event.inputs.run_id }}
with:
script: |
const override = process.env.OVERRIDE_RUN_ID;
if (override) {
core.info(`Using override run_id=${override}`);
core.setOutput('run_id', override);
return;
}
// Find the PR associated with the merge commit. Merge commits to
// main are produced by either squash/rebase (one PR) or a merge
// commit (one PR); the associated-PRs endpoint handles all three.
const { data: prs } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: context.sha,
});
// Prefer a PR whose base is main and that is closed/merged.
const pr = prs.find(p => p.base && p.base.ref === 'main') || prs[0];
if (!pr) {
core.warning(`No PR associated with ${context.sha}; skipping badge update.`);
core.setOutput('skip', 'true');
return;
}
core.info(`Associated PR #${pr.number} head_sha=${pr.head.sha}`);
// Find the most recent successful Coverage Summary run whose head
// SHA matches the PR's head. That run's artifact reflects coverage
// against main at merge time.
const { data: runs } = await github.rest.actions.listWorkflowRuns({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'coverage.yml',
head_sha: pr.head.sha,
status: 'success',
per_page: 10,
});
if (runs.workflow_runs.length === 0) {
core.warning(`No successful Coverage Summary run found for PR #${pr.number} (${pr.head.sha}); skipping badge update.`);
core.setOutput('skip', 'true');
return;
}
const run = runs.workflow_runs[0];
core.info(`Using Coverage Summary run ${run.id} (${run.html_url})`);
core.setOutput('run_id', run.id.toString());
core.setOutput('pr_number', pr.number.toString());
- name: Confirm artifact exists
if: steps.resolve.outputs.skip != 'true'
id: artifact
uses: actions/github-script@v7
env:
RUN_ID: ${{ steps.resolve.outputs.run_id }}
with:
script: |
const run_id = Number(process.env.RUN_ID);
const { data } = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id,
});
const artifact = data.artifacts.find(a => a.name === 'coverage-summary');
if (!artifact) {
core.warning(`Run ${run_id} has no coverage-summary artifact (likely a docs-only PR); skipping badge update.`);
core.setOutput('skip', 'true');
return;
}
if (artifact.expired) {
core.warning(`coverage-summary artifact on run ${run_id} has expired; skipping badge update.`);
core.setOutput('skip', 'true');
return;
}
- name: Download coverage-summary artifact
if: steps.resolve.outputs.skip != 'true' && steps.artifact.outputs.skip != 'true'
uses: actions/download-artifact@v4
with:
name: coverage-summary
run-id: ${{ steps.resolve.outputs.run_id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
path: coverage
- name: Update coverage badge gist
# GitHub Actions does not allow secrets.* inside if: expressions, so
# surface them through env and gate on that to keep this a no-op on
# forks / repos without the secrets configured.
if: steps.resolve.outputs.skip != 'true' && steps.artifact.outputs.skip != 'true' && env.COVERAGE_GIST_ID != '' && env.GIST_TOKEN != ''
uses: actions/github-script@v7
env:
COVERAGE_GIST_ID: ${{ secrets.COVERAGE_GIST_ID }}
GIST_TOKEN: ${{ secrets.GIST_TOKEN }}
with:
github-token: ${{ secrets.GIST_TOKEN }}
script: |
const fs = require('fs');
const badge = fs.readFileSync('coverage/badge.json', 'utf8');
const summary = fs.readFileSync('coverage/summary.json', 'utf8');
await github.rest.gists.update({
gist_id: process.env.COVERAGE_GIST_ID,
files: {
'badge.json': { content: badge },
'coverage-summary.json': { content: summary },
},
});
core.info('Coverage badge gist updated.');