Skip to content

Commit 02a7cea

Browse files
l0lawrenceCopilot
andcommitted
Make emitter-diff check informational (pass unless real error)
The workflow no longer fails on a generated-output diff or gates on a label. It runs the tool without --fail-on-diff, so a diff exits 0 and only a real tool/build error fails the job. Diffs are reported via job summary, a sticky PR comment, and the HTML artifact. Drops the label trigger, the approval gate, and the emitter-diff-approved label requirement. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent dcd4ca9 commit 02a7cea

2 files changed

Lines changed: 22 additions & 62 deletions

File tree

.github/workflows/ci-emitter-diff-python.yml

Lines changed: 18 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ name: "python / emitter diff"
77
# how an emitter change affects generated SDKs. Powered by the language-agnostic
88
# eng/emitter-diff tool.
99
#
10-
# The check fails while generated output differs from the baseline UNTIL a
11-
# maintainer adds the `emitter-diff-approved` label to the PR. The label (not a
12-
# committed SHA) is the approval token, so it survives squash-merge / rebase /
13-
# force-push, and the check re-runs automatically when the label is added or
14-
# removed.
10+
# This check is informational: it always passes unless the tool hits a real
11+
# tool/build error. A generated-output diff does not fail the PR — it is only
12+
# reported (job summary + PR comment + HTML artifact) for reviewers to eyeball.
1513
#
1614
# Python's generator uses a native two-phase pipeline (TypeSpec emits YAML, then
1715
# a batched Python subprocess writes the .py files) with a venv co-located with
@@ -20,7 +18,6 @@ name: "python / emitter diff"
2018

2119
on:
2220
pull_request:
23-
types: [opened, synchronize, reopened, labeled, unlabeled]
2421
branches:
2522
- main
2623
- release/*
@@ -112,42 +109,29 @@ jobs:
112109
# propagates. `pnpm --filter <pkg> exec` collapses any non-zero child exit
113110
# into pnpm's own generic exit 1 (ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL),
114111
# which would mask the "diff present" code (2) as a hard error (1).
112+
# No `--fail-on-diff`: this check is informational and never fails on a
113+
# diff. A real tool/build error still surfaces via a non-zero exit code
114+
# (checked in the "Fail on tool error" step below).
115115
pnpm exec tsx src/cli.ts \
116116
--emitter python \
117117
--baseline "$BASELINE_REF" \
118118
--work-dir "$RUNNER_TEMP/emitter-diff" \
119119
--html "$RUNNER_TEMP/emitter-diff.html" \
120120
--patch "$RUNNER_TEMP/emitter-diff.patch" \
121-
--fail-on-diff \
122121
| tee "$RUNNER_TEMP/emitter-diff.log"
123122
echo "status=${PIPESTATUS[0]}" >> "$GITHUB_OUTPUT"
124123
125124
- name: Write job summary
126125
if: always()
127126
env:
128127
BASELINE_SHA: ${{ steps.baseline.outputs.sha }}
129-
STATUS: ${{ steps.diff.outputs.status }}
130-
APPROVED: ${{ contains(github.event.pull_request.labels.*.name, 'emitter-diff-approved') }}
131128
RUNNER_TEMP: ${{ runner.temp }}
132129
run: |
133130
{
134131
echo "## Emitter diff"
135132
echo ""
136133
echo "Baseline (merge-base): \`$BASELINE_SHA\` vs current checkout."
137134
echo ""
138-
if [ "$STATUS" = "2" ]; then
139-
if [ "$APPROVED" = "true" ]; then
140-
echo "**Generated output changed** — approved via the \`emitter-diff-approved\` label."
141-
else
142-
echo "**Generated output changed vs the baseline.**"
143-
echo ""
144-
echo "If this change is intended, add the \`emitter-diff-approved\` label to this PR"
145-
echo "to accept it."
146-
fi
147-
elif [ "$STATUS" = "0" ]; then
148-
echo "Generated output matches the baseline."
149-
fi
150-
echo ""
151135
echo '```'
152136
grep -E "Diff summary:" "$RUNNER_TEMP/emitter-diff.log" || echo "No summary captured."
153137
echo '```'
@@ -171,7 +155,6 @@ jobs:
171155
env:
172156
BASELINE: ${{ steps.baseline.outputs.sha }}
173157
STATUS: ${{ steps.diff.outputs.status }}
174-
APPROVED: ${{ contains(github.event.pull_request.labels.*.name, 'emitter-diff-approved') }}
175158
PATCH_FILE: ${{ runner.temp }}/emitter-diff.patch
176159
HTML_FILE: ${{ runner.temp }}/emitter-diff.html
177160
with:
@@ -180,7 +163,6 @@ jobs:
180163
const marker = "<!-- emitter-diff-python -->";
181164
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
182165
const status = process.env.STATUS;
183-
const approved = process.env.APPROVED === "true";
184166
185167
// Parse the unified patch directly so the numbers match the tool exactly.
186168
let patch = "";
@@ -194,32 +176,27 @@ jobs:
194176
else if (line.startsWith("+") && !line.startsWith("+++")) insertions++;
195177
else if (line.startsWith("-") && !line.startsWith("---")) deletions++;
196178
}
179+
const hasChanges = patch.trim().length > 0;
197180
const htmlExists = fs.existsSync(process.env.HTML_FILE);
198181
199182
let body = `${marker}\n## Python emitter diff\n\n` +
200183
`Baseline \`${process.env.BASELINE}\` (merge-base) vs this PR's checkout.\n\n`;
201-
if (status !== "0" && status !== "2") {
184+
if (status !== "0") {
202185
// Hard error (build/venv/generate threw) — not a diff. Don't claim "no changes".
203186
body += `**emitter-diff failed to run** (exit \`${status}\`). This is a tool/build ` +
204187
`error, not a generated-output diff. See the ` +
205188
`[workflow run](${runUrl}) logs` +
206189
(htmlExists ? ` and the **emitter-diff-html** artifact` : "") + `.\n`;
207-
} else if (status === "0") {
190+
} else if (!hasChanges) {
208191
body += `**No changes** — generated output matches the baseline.\n`;
209192
} else {
210193
body += `**${files.length} file(s) changed** · +${insertions} / -${deletions}\n\n`;
211194
if (htmlExists) {
212195
body += `Download the **emitter-diff-html** artifact from the ` +
213-
`[workflow run](${runUrl}) for the full side-by-side rendered diff.\n\n`;
214-
}
215-
if (approved) {
216-
body += `This change is **approved** via the \`emitter-diff-approved\` label.\n`;
217-
} else {
218-
body += `**This check fails until the change is approved.** If the new output is ` +
219-
`intended, add the \`emitter-diff-approved\` label to this PR to accept it.\n`;
196+
`[workflow run](${runUrl}) for the full side-by-side rendered diff.\n`;
220197
}
221198
}
222-
body += `\n_Generated by \`eng/emitter-diff\`._`;
199+
body += `\n_Generated by \`eng/emitter-diff\`. This check is informational and does not block the PR._`;
223200
224201
const { owner, repo } = context.repo;
225202
const issue_number = context.issue.number;
@@ -231,32 +208,16 @@ jobs:
231208
await github.rest.issues.createComment({ owner, repo, issue_number, body });
232209
}
233210
234-
- name: Enforce approval
211+
- name: Fail on tool error
235212
if: always()
236213
env:
237214
STATUS: ${{ steps.diff.outputs.status }}
238-
APPROVED: ${{ contains(github.event.pull_request.labels.*.name, 'emitter-diff-approved') }}
239-
BASELINE_SHA: ${{ steps.baseline.outputs.sha }}
240215
run: |
241-
# Hard tool/build failure (not a diff) always fails.
242-
if [ "$STATUS" != "0" ] && [ "$STATUS" != "2" ]; then
243-
echo "::error::emitter-diff failed (exit $STATUS). See the log and artifact."
244-
exit 1
245-
fi
246-
# Only PRs carry the approval label; manual/dispatch runs are informational.
247-
if [ "$GITHUB_EVENT_NAME" != "pull_request" ]; then
248-
echo "Not a pull_request event; skipping the approval gate."
249-
exit 0
250-
fi
251-
if [ "$STATUS" = "2" ]; then
252-
if [ "$APPROVED" = "true" ]; then
253-
echo "Generated output differs from the baseline ($BASELINE_SHA), but the PR carries"
254-
echo "the 'emitter-diff-approved' label. Passing."
255-
exit 0
256-
fi
257-
echo "::error::Generated output differs from the baseline ($BASELINE_SHA)."
258-
echo "Review the emitter-diff-html artifact. If the change is intended, add the"
259-
echo "'emitter-diff-approved' label to this PR to accept it."
216+
# Informational check: a generated-output diff does NOT fail the PR
217+
# (the tool is run without --fail-on-diff, so a diff still exits 0).
218+
# Only a real tool/build error (non-zero exit) fails the job.
219+
if [ "$STATUS" != "0" ]; then
220+
echo "::error::emitter-diff failed (exit $STATUS). See the log and the emitter-diff-html artifact."
260221
exit 1
261222
fi
262-
echo "Generated output matches the baseline."
223+
echo "emitter-diff ran successfully (informational; diffs are reported, not enforced)."

eng/emitter-diff/README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,10 @@ of that merge-base commit, diffs the two, and then:
103103
- posts a **sticky PR comment** (updated in place on each push) with the changed-file and `+`/`-`
104104
counts and a link to download the artifact.
105105

106-
**Approval gate:** if the generated output differs from the baseline, the `--fail-on-diff` run
107-
exits with code `2` and the job **fails until the change is approved**. To approve an intended
108-
change, add the **`emitter-diff-approved`** label to the PR. The label — not a committed SHA — is
109-
the approval token, so it is unaffected by history rewrites; the workflow also triggers on
110-
`labeled`/`unlabeled`, so adding or removing the label re-runs the check automatically.
106+
**Informational:** the check **always passes unless the tool hits a real tool/build error** — a
107+
generated-output diff does not fail the PR. CI runs the tool without `--fail-on-diff`, so a diff
108+
still exits `0`; only a non-zero exit (a build/venv/generate failure) fails the job. Reviewers use
109+
the PR comment and the HTML artifact to eyeball the diff.
111110

112111
The comment step needs `pull-requests: write`. PRs **from forks** get a read-only token, so the
113112
comment is best-effort there (`continue-on-error`) — the artifact and job-summary still work.

0 commit comments

Comments
 (0)