-
Notifications
You must be signed in to change notification settings - Fork 394
140 lines (128 loc) · 6.04 KB
/
Copy pathci-emitter-diff-python.yml
File metadata and controls
140 lines (128 loc) · 6.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
name: "python / emitter diff"
# Diffs generated code between this PR's emitter and the merge-base baseline.
# Informational only: reports a sticky PR comment + HTML artifact, and fails the
# job only on a tool/build error (never on a diff). See eng/emitter-diff.
#
# The tool runs `npm run regenerate` verbatim in each tree. It auto-prepares the
# baseline tree it fetches from GitHub (via the preset's --setup: install +
# build + venv), so this workflow only builds the head (PR) emitter itself.
on:
pull_request:
branches: [main, release/*]
paths:
- "packages/http-client-python/**"
- "eng/emitter-diff/**"
- ".github/workflows/ci-emitter-diff-python.yml"
workflow_dispatch:
inputs:
baseline:
description: "Baseline emitter ref (local path or github ref). Defaults to the PR merge-base. A gh:/github: ref is fetched and auto-prepared (install + build) by the tool; a local: path is used as-is."
required: false
default: ""
permissions:
contents: read
pull-requests: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
emitter-diff:
name: "Generate & Diff"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: ./.github/actions/setup
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install repo dependencies
run: pnpm install
- name: Determine baseline
id: baseline
# Dispatch input is untrusted: pass via env, reference only as "$VAR".
env:
BASELINE_INPUT: ${{ github.event.inputs.baseline || '' }}
BASE_REF: ${{ github.event.pull_request.base.ref || github.event.repository.default_branch }}
run: |
input="$BASELINE_INPUT"
if [ -n "$input" ]; then
echo "ref=$input" >> "$GITHUB_OUTPUT"
echo "Baseline (explicit): $input"
else
# merge-base = a real commit on the base branch; survives squash/rebase.
git fetch --no-tags origin "$BASE_REF"
base_sha="$(git merge-base FETCH_HEAD HEAD)"
[ -n "$base_sha" ] || { echo "::error::No merge-base with $BASE_REF."; exit 1; }
# gh:<sha> = this repo at the merge-base. The tool fetches that tree
# and auto-preps it (install + build + venv) via the preset's --setup.
echo "ref=gh:$base_sha" >> "$GITHUB_OUTPUT"
echo "Baseline (merge-base): gh:$base_sha"
fi
- name: Prepare head emitter (build + venv)
working-directory: packages/http-client-python
# http-client-python is excluded from the pnpm workspace (standalone,
# registry-versioned deps), so the repo-level `pnpm install` above does
# NOT provision its node_modules. Install them first (scripts skipped),
# then `npm run setup` (build + venv). Mirrors the baseline tree prep the
# tool does via the python preset's --setup.
run: |
npm install --ignore-scripts
npm run setup
- name: Run emitter diff
id: diff
working-directory: packages/http-client-python
env:
BASELINE_REF: ${{ steps.baseline.outputs.ref }}
RUNNER_TEMP: ${{ runner.temp }}
run: |
set +e
# No --fail-on-diff (informational); tool/build errors still exit non-zero
# (checked in "Fail on tool error").
npm run diff-spector-tests -- \
--ci \
--baseline "$BASELINE_REF" \
--html "$RUNNER_TEMP/emitter-diff.html" \
| tee "$RUNNER_TEMP/emitter-diff.log"
echo "status=${PIPESTATUS[0]}" >> "$GITHUB_OUTPUT"
# Reuse the tool's own summary line (strip ANSI) instead of re-parsing.
summary="$(sed -r 's/\x1b\[[0-9;]*m//g' "$RUNNER_TEMP/emitter-diff.log" \
| grep -oE 'Diff summary: [0-9]+ file\(s\), \+[0-9]+ / -[0-9]+' | head -1)"
echo "summary=${summary:-No changes to generated output.}" >> "$GITHUB_OUTPUT"
- name: Upload HTML diff
if: always()
uses: actions/upload-artifact@v7
with:
name: emitter-diff-html
path: ${{ runner.temp }}/emitter-diff.html
if-no-files-found: ignore
retention-days: 7
- name: Comment on PR
if: always() && github.event_name == 'pull_request'
continue-on-error: true
uses: actions/github-script@v7
env:
BASELINE: ${{ steps.baseline.outputs.sha || steps.baseline.outputs.ref }}
STATUS: ${{ steps.diff.outputs.status }}
SUMMARY: ${{ steps.diff.outputs.summary }}
with:
script: |
const marker = "<!-- emitter-diff-python -->";
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const { STATUS, SUMMARY, BASELINE } = process.env;
let body = `${marker}\n### Python emitter diff\nBaseline \`${BASELINE}\` vs this PR.\n\n`;
body += STATUS !== "0"
? `⚠️ **emitter-diff failed** (exit \`${STATUS}\`) — tool/build error, not a diff. See the [run](${runUrl}).\n`
: `${SUMMARY}\n\nFull rendered diff: **emitter-diff-html** artifact on the [run](${runUrl}).\n`;
body += `\n_Informational check (eng/emitter-diff); does not block the PR._`;
const { owner, repo } = context.repo, issue_number = context.issue.number;
const { data } = await github.rest.issues.listComments({ owner, repo, issue_number });
const hit = data.find((c) => c.body && c.body.includes(marker));
if (hit) await github.rest.issues.updateComment({ owner, repo, comment_id: hit.id, body });
else await github.rest.issues.createComment({ owner, repo, issue_number, body });
- name: Fail on tool error
if: always()
env:
STATUS: ${{ steps.diff.outputs.status }}
run: '[ "$STATUS" = "0" ] || { echo "::error::emitter-diff failed (exit $STATUS)."; exit 1; }'