Skip to content

ci: Python emitter regen-diff check (PoC) - #5

Draft
l0lawrence wants to merge 1 commit into
mainfrom
l0lawrence/emitter-regen-diff-ci
Draft

l0lawrence wants to merge 1 commit into
mainfrom
l0lawrence/emitter-regen-diff-ci

Conversation

@l0lawrence

Copy link
Copy Markdown
Owner

What

Proof-of-concept CI check that detects when a change to the Python emitter (packages/http-client-python) alters its generated test code.

On a PR touching packages/http-client-python/**, the workflow:

  1. Regenerates the emitter's generated test code twice — once with the emitter at the PR head, once with the emitter at a pinned baseline commit stored in packages/http-client-python/eng/regen-diff-baseline.txt.
  2. Diffs the two generated trees.
  3. Fails CI if there is any diff.
  4. Uploads a colorized HTML view of the diff as a workflow artifact (python-regen-diff-html).
  5. Posts/updates a PR comment (via the secure workflow_run pattern) linking to the artifact.

If a diff is expected, the author bumps the baseline SHA to accept the new output.

Files

  • packages/http-client-python/eng/regen-diff-baseline.txt — pinned baseline commit SHA.
  • packages/http-client-python/eng/scripts/ci/regen-diff-html.ts — dependency-free reporter (git diff --no-index → HTML + comment payload + result.json).
  • .github/workflows/python-emitter-regen-diff.ymlpull_request: generate (head/base matrix) → diff → fail-on-diff.
  • .github/workflows/python-emitter-regen-diff-comment.ymlworkflow_run: posts the PR comment (works for fork PRs).

Notes / caveats

  • Cost: regenerates twice per PR (full Python setup each time). A follow-up could cache the base regen keyed by the baseline SHA to halve the work.
  • Both regens fetch the same production baseline seed, so it cancels out in the diff; current-date values also cancel since both run in the same CI run (hence no cross-day caching).
  • Proof-of-concept — Python only. A sibling PR ports the same setup to Azure/typespec-azure. Intended to be extended to the csharp/java/js emitters next.

Regenerate the http-client-python generated test code with the emitter at the
PR head and at a pinned baseline commit, diff the two outputs, fail CI on any
diff, and post a PR comment linking to an HTML view of the diff (uploaded as a
workflow artifact).

Adds:
- packages/http-client-python/eng/regen-diff-baseline.txt (pinned baseline SHA)
- packages/http-client-python/eng/scripts/ci/regen-diff-html.ts (diff -> HTML/comment)
- .github/workflows/python-emitter-regen-diff.yml (regen x2 + diff + fail)
- .github/workflows/python-emitter-regen-diff-comment.yml (workflow_run comment)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

❌ There is undocummented changes. Run chronus add to add a changeset or click here.

The following packages have changes but are not documented.

  • @typespec/http-client-python
Show changes

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved workflow security, permissions, and reliability issues remain.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds a proof-of-concept CI check comparing Python emitter-generated tests with a pinned baseline, publishing diff artifacts and PR comments.

Changes:

  • Adds the baseline commit and diff-report generator.
  • Adds head/base regeneration and fail-on-diff workflows.
  • Adds artifact-based PR commenting.
File summaries
File Description
packages/http-client-python/eng/scripts/ci/regen-diff-html.ts Generates diff reports and comment payloads.
packages/http-client-python/eng/regen-diff-baseline.txt Defines the pinned baseline commit.
.github/workflows/python-emitter-regen-diff.yml Regenerates and compares generated code.
.github/workflows/python-emitter-regen-diff-comment.yml Publishes or updates PR comments from artifacts.
Review details

Suppressed comments (5)

.github/workflows/python-emitter-regen-diff-comment.yml:11

  • GitHub only triggers a workflow_run workflow when that workflow file exists on the default branch. Since this companion workflow is introduced by the same PR as the producer workflow, it will not post the promised comment for this PR's run; bootstrap this privileged workflow on the default branch (or use an already-installed commenter) before relying on this pattern.
  workflow_run:
    workflows: ["Python Emitter Regen Diff"]
    types: [completed]

.github/workflows/python-emitter-regen-diff-comment.yml:18

  • The producer workflow cancels older runs for the same PR, but this workflow_run workflow has no corresponding concurrency control. A canceled older run that already uploaded its payload can be processed after a newer run and overwrite the PR comment with a stale diff link; key this workflow by PR number and cancel the previous commenter run.
jobs:
  comment:
    if: github.event.workflow_run.event == 'pull_request'

.github/workflows/python-emitter-regen-diff.yml:60

  • For a pull request from a fork, this checkout still targets the base repository because no repository is supplied. The head SHA therefore is not present in the repository being checked out, so the head matrix job fails before regeneration; select the PR head repository for the head entry and the base repository for the baseline/manual entries.
        uses: actions/checkout@v6
        with:
          ref: ${{ matrix.which == 'base' && needs.read-baseline.outputs.sha || github.event.pull_request.head.sha || github.sha }}

.github/workflows/python-emitter-regen-diff.yml:79

  • Both matrix jobs run npm run regenerate, and that regeneration independently fetches the mutable typespec-python-generated-tests branch when preparing tests/generated. If the branch advances between the head and base jobs, the comparison includes upstream seed changes and can fail even when the emitter is unchanged. Resolve the seed branch to one commit once and reuse that commit for both regens (or share one prepared seed artifact).
      - name: Regenerate
        run: npm run regenerate

packages/http-client-python/eng/scripts/ci/regen-diff-html.ts:125

  • Header detection is not limited to pre-hunk metadata. An added line whose content starts with ++ is serialized as +++ , so this branch consumes real hunk content as a file header, overwrites newPath, and drops the line from the rendered diff. Only recognize file headers before entering a hunk (for example, by tracking whether @@ has been seen).
    if (line.startsWith("+++ ")) {
      const p = line.slice(4);
      if (p === "/dev/null") current.status = "removed";
      else current.newPath = p;
  • Files reviewed: 4/4 changed files
  • Comments generated: 5
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +35 to +38
const prNumber = parseInt(
fs.readFileSync('comment-payload/pr-number.txt', 'utf8').trim(),
10,
);
Comment on lines +13 to +14
permissions:
pull-requests: write
Comment on lines +21 to +31
- name: Download comment payload
uses: actions/download-artifact@v8
with:
name: python-regen-diff-comment
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
path: comment-payload

- name: Post or update PR comment
uses: actions/github-script@v7
with:
Comment on lines +43 to +44
SHA=$(grep -v '^[[:space:]]*#' "$FILE" | grep -v '^[[:space:]]*$' | head -n1 | tr -d '[:space:]')
if [ -z "$SHA" ]; then echo "No baseline SHA found in $FILE" >&2; exit 1; fi
Comment on lines +141 to +142
if (line.startsWith("+") && !line.startsWith("+++")) current.insertions++;
else if (line.startsWith("-") && !line.startsWith("---")) current.deletions++;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants