Skip to content

Add language-agnostic emitter-diff tool + python adapter#11119

Closed
l0lawrence wants to merge 7 commits into
microsoft:mainfrom
l0lawrence:l0lawrence-emitter-diff
Closed

Add language-agnostic emitter-diff tool + python adapter#11119
l0lawrence wants to merge 7 commits into
microsoft:mainfrom
l0lawrence:l0lawrence-emitter-diff

Conversation

@l0lawrence

Copy link
Copy Markdown
Member

Draft / RFC. Porting the language-agnostic emitter-diff tool (built in Azure/typespec-azure) to microsoft/typespec to gather upstream feedback. End-to-end generation has not been run in CI yet — locally verified: typecheck clean + CLI loads. Opening as draft for discussion.

What

A language-agnostic tool, eng/emitter-diff (@typespec/emitter-diff), that diffs the generated code produced by two versions of a TypeSpec emitter and optionally runs the emitter's generated-code test suites. It resolves a baseline emitter from an npm version, a local folder, or a GitHub url/sha, generates with both baseline and head, and renders the diff as a clickable HTML report (default), a VS Code diff, or a terminal patch.

Ships the python adapter for @typespec/http-client-python, which drives the package's existing regenerate.ts two-phase native pipeline (TypeSpec → YAML, then a batched Python subprocess), building and creating a venv per emitter version.

Changes

  • eng/emitter-diff/ — the tool: CLI/orchestrator, ref resolver (npm/local/github), generic EmitterAdapter interface + registry, diff engine (HTML/VS Code/terminal), python adapter.
  • packages/http-client-python/eng/scripts/ci/regenerate.ts — adds --httpSpecsDir, --azureSpecsDir, --no-baseline so the tool can pin specs and skip the published-baseline clone. Defaults preserve current behavior.
  • pnpm-workspace.yaml — adds eng/emitter-diff as a workspace member and diff2html to the catalog (lockfile updated).
  • .github/workflows/ci-emitter-diff-python.yml — PR workflow with an approved-baseline gate.

Approved-baseline gate

The approved generated-output baseline is a commit SHA in eng/emitter-diff/baselines/python.sha. CI builds the emitter for both the PR checkout and a worktree of that commit, diffs them, uploads the HTML artifact, and posts a sticky PR comment. If the output differs, the run exits 2 and the job fails. To approve an intended change, update the SHA to a commit on your branch containing your emitter changes and push — once the baseline matches head, the diff is empty and the check passes.

Notes / open questions

  • Python's native pipeline needs a venv per emitter version, so the adapter builds + npm run installs each side. --use-pyodide from the azure variant is dropped (no pyodide path in core).
  • The tool is designed to host future c#/java/go/rust adapters with no core changes.
  • Companion PR in Azure/typespec-azure (Support generating Python SDK with Pyodide #4784).

l0lawrence and others added 2 commits June 30, 2026 13:22
Ports the eng/emitter-diff tool: diffs generated code between two emitter
versions (npm version, local folder, or github ref) and optionally runs the
emitter's generated-code test suites. Ships the python adapter for
@typespec/http-client-python, driving its native two-phase regenerate pipeline
with a venv per emitter version.

- eng/emitter-diff: @typespec/emitter-diff package (CLI, ref resolver, diff
  engine with HTML/VS Code/terminal output, adapter registry).
- regenerate.ts: add --httpSpecsDir, --azureSpecsDir, --no-baseline flags.
- pnpm-workspace.yaml: add eng/emitter-diff member + diff2html catalog entry.
- ci-emitter-diff-python.yml: PR workflow that diffs head vs the PR base commit,
  uploads the rendered HTML artifact, and posts a sticky PR comment.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CI now diffs the PR's emitter against the emitter at the commit recorded in
eng/emitter-diff/baselines/python.sha and fails when generated output differs.
To approve an intended change, update that SHA to a commit on the branch that
contains the emitter changes and push; once the baseline matches head the diff
is empty and the check passes.

- cli.ts: --fail-on-diff now exits 2 for "diff present" (vs 1 for hard errors)
  so CI can distinguish an unapproved diff from a failure.
- baselines/python.sha: the approved baseline commit.
- ci-emitter-diff-python.yml: read the SHA file as baseline, run with
  --fail-on-diff, enforce the gate, and explain approval in the summary/comment.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@microsoft-github-policy-service microsoft-github-policy-service Bot added emitter:client:python Issue for the Python client emitter: @typespec/http-client-python eng labels Jun 30, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jun 30, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-client-python@11119

commit: ce0ab95

@github-actions

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @typespec/http-client-python
Show changes

@typespec/http-client-python - internal ✏️

Add --httpSpecsDir, --azureSpecsDir, and --no-baseline flags to regenerate.ts so the language-agnostic eng/emitter-diff tool can drive code generation against pinned specs without cloning the published baseline.

l0lawrence and others added 2 commits June 30, 2026 13:29
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use a non-literal import specifier + local type so a typecheck that doesn't
install this package's deps (e.g. the parent repo's check:eng, which includes
core/eng) doesn't fail with TS2307; availability is validated at runtime.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@azure-sdk-automation

azure-sdk-automation Bot commented Jun 30, 2026

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

l0lawrence and others added 3 commits June 30, 2026 13:54
run_batch.py was always passed PLUGIN_DIR as --generated-dir, so when the
emitter-diff tool redirects output via --generatedFolder the batch phase looked
in the wrong tree, found no .tsp-codegen config files, and wrote zero .py files
(leaving the path-bearing config files behind as spurious diffs). Pass the
parent of GENERATED_FOLDER instead; it equals PLUGIN_DIR in the default case so
normal regeneration is unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The two sides write to isolated output dirs, use separate venvs, and emit
uniquely-named temp YAML, so they can regenerate concurrently. Run them with
Promise.all and tag each side's streamed output with a [baseline]/[head] prefix
so the interleaved logs stay attributable. Add --sequential to opt back into
one-at-a-time generation (quieter logs, lower peak CPU/memory).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Temporarily set the approved baseline to microsoft#10947 (timedelta duration encoding)
so the diff PR comment and approval gate can be exercised end-to-end. Revert to
the blessed HEAD SHA after the demo.

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

Copy link
Copy Markdown
Member Author

Superseded by #11122 — same branch, moved into a microsoft/typespec branch so the emitter-diff CI PR-comment and approved-baseline gate run with a read-write token (fork PRs get a read-only token and can't post comments). Continuing there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:client:python Issue for the Python client emitter: @typespec/http-client-python eng

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant