Skip to content

Migrate @azure-tools/typespec-go from autorest.go into this repo#4628

Open
tadelesh wants to merge 59 commits into
mainfrom
go-migration
Open

Migrate @azure-tools/typespec-go from autorest.go into this repo#4628
tadelesh wants to merge 59 commits into
mainfrom
go-migration

Conversation

@tadelesh

@tadelesh tadelesh commented Jun 15, 2026

Copy link
Copy Markdown
Member

Migrates @azure-tools/typespec-go from Azure/autorest.go into this monorepo. See Azure/autorest.go#1982 for full background and plan.

What's in this PR

Source code (Phase 3 of the migration plan)

  • New packages/typespec-go/ containing the emitter and its three previously-private workspace dependencies inlined:
    • codegen.gosrc/codegen/
    • codemodel.gosrc/codemodel/
    • naming.gosrc/naming/
  • Static assets: README.md, LICENSE, CHANGELOG.md, vitest.config.ts, tsconfig.json (mirrors typespec-python).
  • .chronus change entry.

Tests

The emitter is tested with three tiers, in order of preference (documented in docs/development.md):

  1. Emitter unit tests (scenarios) — the default. Markdown snapshot tests under test/unittest/scenarios/*.md: each .md compiles a small TypeSpec in memory and snapshots the generated Go, with no Go toolchain or mock server. ~29 focused scenarios cover naming, models/serialization, client & options shapes, polymorphism, client customizations (@@alternateType / @@clientName), containing-module, sample generation (example JSON input → *_example_test.go), and the former Regressions code-gen cases.
    • scenario-runner.ts — in-memory compile + snapshot harness (SCENARIOS_UPDATE=true regenerates expected blocks; ARM specs auto-routed to an ARM tester).
    • gen-scenario-suites.mjs — generates one vitest suite per .md; scenario-suites.guard.test.ts fails if they drift.
  2. External service specs — all Azure RM / data-plane service specs (17 modules) are sourced from Azure/azure-rest-api-specs at a pinned commit via a sparse, blobless, shallow clone:
    • .scripts/azure-rest-api-specs.json — pinned commit + sparse paths
    • .scripts/sync-azure-rest-api-specs.js — idempotent sync (skipped when cache marker matches)
    • .scripts/tspconfig.yaml — stub config that suppresses upstream tspconfig bleed (the per-language @azure-tools/typespec-go options that target azure-sdk-for-go)
  3. Local spec tests — kept only where the behavior can only be verified by executing generated Go at runtime. Just two remain:
    • gogenerate (test/tsp/GoGeneratetest/local/gogenerate) — the post-generation go generate hook.
    • fakeserver (test/tsp/FakeServertest/local/fakeserver) — fake-server runtime behavior (context cancellation, dispatch races, path/query decoding); a minimal 2-operation spec.

Removed local specs (migrated into scenarios): ClientOption, Internal.Pager, ModelsOnlyWithBaseTypes, NoOptionalBody, PageableLROs, Random.Management, RawJson, and the Test.Management ARM provider. The old Regressions grab-bag was split into scenarios plus the slimmed fakeserver runtime test. The local ExactName test was dropped (duplicated by an azure-http-specs scenario).

Build / regenerate

  • .scripts/tspcompile.js — Always invoked with --config=.scripts/tspconfig.yaml so upstream tspconfigs don't bleed.
  • .scripts/semaphore.js — 8-way parallel compile primitive.
  • .scripts/spector.js — reused start/stop wrapper around npx tsp-spector.

CI

  • .github/workflows/ci-go.yml — jobs: build, test (Go matrix 1.26.1/1.25.8 with regenerate + lint:go + spector-backed test:go:e2e), unit (vitest), docs (regen-docs).
  • .github/actions/setup-go/action.yml — composite wrapping actions/setup-go@v5.
  • eng/config/labels.ts — adds emitter:go area label + path mapping.
  • eng/pipelines/jobs/build-for-publish.yml — adds Go regen + e2e + upload-spector-coverage.yml template call (GeneratorName=@azure-tools/typespec-go) after the Python block.
  • tsconfig.ws.json includes the new package.
  • Root mise.toml pins go = "1.26.1" for local development; in CI Go is installed via actions/setup-go (GH Actions) and GoTool@0 (ADO release pipeline).
  • .gitignore ignores generated zz_*.go / go.mod / go.sum / LICENSE.txt / testdata under packages/typespec-go/test/.

Skipped per discussion

  • No nightly pipeline — all TypeSpec deps live in this repo now.
  • test/local/ stays in this repo — not relocated to azure-sdk-for-go.

Validation (local)

  • pnpm build
  • pnpm test (vitest unit) ✅ 47/47 (29 scenario suites + guard + emitter tests)
  • pnpm regenerate ✅ all tsp compiles
  • pnpm format:check ✅ clean for all packages/typespec-go/** files
  • pnpm lint:go0 issues (golangci-lint v2.11.4 + shadow, every generated module)
  • pnpm test:go:e2e ✅ spector start → hand-written test modules (azblob / azkeys / gogenerate / fakeserver) PASS → spector stop

Follow-ups (out of scope; tracked in autorest.go#1982)

  • Migrate remaining swagger-based data-plane SDKs to the latest autorest.go (Phase 1, in flight).
  • Stop maintaining codegen.go / codemodel.go / naming.go in autorest.go once Phase 4 lands.
  • Announce deprecation of autorest.go (after Phase 4).

Comment thread packages/typespec-go/src/codegen/fake/servers.ts Dismissed
@azure-sdk

azure-sdk commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

All changed packages have been documented.

  • @azure-tools/typespec-go
Show changes

@azure-tools/typespec-go - internal ✏️

Move @azure-tools/typespec-go from Azure/autorest.go into Azure/typespec-azure. The previously-private workspace packages @azure-tools/codegen.go, @azure-tools/codemodel.go, and @azure-tools/naming.go are now inlined into src/codegen, src/codemodel, and src/naming respectively. No behavior changes for emitter consumers.

@pkg-pr-new

pkg-pr-new Bot commented Jun 15, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@azure-tools/typespec-go@4628

commit: 825c2a6

@azure-sdk

azure-sdk commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

You can try these changes here

🛝 Playground 🌐 Website

tadelesh and others added 5 commits June 15, 2026 15:45
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix 13 spelling typos carried over from upstream source (acceptible,
  credendial, defef, deferenced, depracated, Disciminator, encounted,
  enveloipe, furture, hepler, Iterface, specifiy, uhandled).
- Rename formatValue's defef parameter to deref (callers pass positionally).
- Rename trackDisciminator function to trackDiscriminator.
- Add cspell ignorePaths for packages/typespec-go/{test,temp,.scripts}/**.
- Add legitimate Go SDK identifiers (azfake, azidentity, GOPATH, Errorf,
  Fatalf, polymorphics, Retriable, Unmarshaller, etc.) and Go stdlib
  package names (cmplx, fcgi, flate, gofmt, pkix, etc.) to dictionary.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ran pnpm sync-labels to regenerate triage policy files and CONTRIBUTING.md
labels reference with the new emitter:go area label.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
tadelesh and others added 4 commits June 15, 2026 16:27
The filtered install (--filter @azure-tools/typespec-go...) doesn't pull in
core's workspace-root devDependencies (prettier-plugin-organize-imports),
which @typespec/xml's gen-extern-signature -> tspd -> prettier requires
at build time. Match the build/test jobs and install everything.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- nooptionalbody/testdata/generate/transforms.go: hand-authored helper invoked by after_generate.go's //go:generate directive. Without it, the emit's post-step go generate fails, cleanGeneratedFiles wipes all zz_*.go except zz_version.go, and the orphan triggers a downstream golangci-lint 'unused const' error.

- rawjson/go.mod and go.sum: rawjson uses containing-module=rawjson/v2 and emits into subpkg/. The module root (one level up) must exist for the emit's post-step go mod tidy to find go.mod.

Also: surface emit failures in tspcompile.js by setting process.exitCode = 1. Previously a failed emit only logged 'exec error' and let the script exit 0, hiding the failure until a downstream lint job complained.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
tadelesh and others added 2 commits June 15, 2026 17:16
verify-labels CI runs pnpm sync-labels --github --check which requires the banner emitted by core/eng/common/scripts/labels/definitions.ts:295 to match exactly. PR #4563 had hand-patched the banner to a different path that the script never reproduces, so any PR touching CONTRIBUTING.md or eng/config/labels.ts fails the check. Re-running pnpm sync-labels produces this content; committing verbatim.

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

After pnpm regenerate finishes, the locally regenerated test artifacts under packages/typespec-go/test/{local,http-specs,azure-http-specs}/ are automatically mirrored into a sparse checkout of Azure/azure-sdk-assets@typespec-go in packages/typespec-go/temp/baseline/. Developers can then inspect codegen deltas with a plain git -C temp/baseline status / git diff — no separate command needed.

- New .scripts/sync-baseline.js: idempotent shallow+blobless sparse clone (test/local, test/http-specs, test/azure-http-specs); mirror copies the local tree into the checkout after regen.

- tspcompile.js: kicks off the sync at startup and runs the mirror in beforeExit so it fires after every emit's async callback has drained. Skipped on regen failure (process.exitCode != 0) so partial output doesn't pollute the baseline.

- ci-go.yml: TYPESPEC_GO_SKIP_BASELINE=1 on the Regenerate step so CI doesn't need network access to azure-sdk-assets.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread .chronus/changes/typespec-go-move-into-typespec-azure-2026-06-11-14-30-00.md Outdated
Comment thread .github/actions/setup-go/action.yml
Comment thread packages/typespec-go/package.json Outdated
Comment thread packages/typespec-go/package.json Outdated
Comment thread .github/workflows/ci-go.yml
Comment thread packages/typespec-go/.scripts/azure-rest-api-specs.json
@jhendrixMSFT

Copy link
Copy Markdown
Member

Are there plans to get more granular WRT what runs in CI? At present it looks like quite a few things ran that's not germane to this emitter.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
tadelesh and others added 12 commits July 8, 2026 13:38
…shot unit tests

Replace most hand-written local spec integration tests with fast, in-memory
markdown-driven snapshot unit tests under test/unittest/scenarios. Each scenario
compiles TypeSpec in-process and snapshots the generated Go source, run via vitest.

- Add the scenario harness (scenario-runner.ts), per-file suite generator
  (gen-scenario-suites.mjs), and a drift guard (scenario-suites.guard.test.ts).
- Migrate ClientOption, Internal.Pager, ModelsOnlyWithBaseTypes, NoOptionalBody,
  PageableLROs, Random.Management, RawJson and Test.Management (ARM) specs into
  focused scenarios, including sample-generation and example-input support.
- Migrate the Regressions code-gen cases into scenarios; slim the remaining
  integration test to fake-server runtime behavior and rename it to fakeserver.
- Keep gogenerate as a post-generation go-generate integration test.
- Document the testing strategy (scenarios first; local specs only for runtime
  Go behavior) in docs/development.md.

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

Adds a `test:update` script that runs vitest with SCENARIOS_UPDATE=true to
rewrite the expected output blocks in test/unittest/scenarios/*.md in place.
Uses a small .scripts/test-update.js wrapper (matching the existing script
wrappers) to set the env var cross-platform without a new dependency. Update
the development doc to reference the command.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
tspcompile.js now only sources two service specs from azure-rest-api-specs
(keyvault Keys → azkeys, storage BlobStorage → azblob); the other 15 RM/data-plane
spec paths are no longer referenced. Drop them from the sparse-checkout list so the
sync fetches only what the tests need.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Collapse wrapped prose paragraphs to single lines and correct the lint:go
description to note it covers test/local, test/http-specs and test/azure-http-specs
(not just test/local).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The old intro claimed everything under test/ is generated from specs. Describe the
actual mix (in-memory unit tests, local spec tests, external Spector specs) and note
that regenerate only writes the Go fixtures under test/local, test/http-specs and
test/azure-http-specs, while test/unittest is updated via pnpm test:update.

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

The old Step 3 (Regenerate) and Step 4 (Test) were both loosely "about tests" and
awkwardly ordered, while the closely-related Step 5 (Review the generated-code diff)
sat after them. Restructure so the steps follow the actual workflow:

- Step 3 "Regenerate and validate the generated code" now groups everything about
  the generated artifacts: regenerate, review the baseline diff (merged from the old
  Step 5), run the Go tests, lint the generated Go, and debug.
- Step 4 "Add or update tests" is now purely about authoring tests: choosing the
  right tier and writing an emitter unit-test scenario.
- Renumber the remaining steps and fix all cross-references and the TOC.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Regenerating fixtures, running the Go tests and linting are all part of the same
testing story as the unit-test scenarios (they exercise tiers 2 and 3 of the test
taxonomy), so splitting them across two top-level steps was artificial. Merge them
into one "Step 3: Test your changes" ordered from cheapest to heaviest: choose the
tier, write an in-memory scenario, then (for the generated-Go tiers) regenerate,
review the diff, run the Go tests, and lint. Renumber docs/PR to Steps 4/5 and fix
the TOC and cross-references.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ports Azure/autorest.go#2022 into the migrated emitter: emit
`fmt.Errorf("unmarshalling type %T: %s", recv, err.Error())` instead of the
`%v` + err form in the three JSON-unmarshaller code paths. This makes the intent
to propagate the error message explicit and avoids tripping errorlint in the
generated code.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bump the package version to 0.14.3 and add the 0.14.3 changelog section to match
the upstream Azure/autorest.go release (adapting Access.internal polymorphic
returns; JSON unmarshalling errors now use %s + err.Error()).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tadelesh tadelesh closed this Jul 10, 2026
@tadelesh tadelesh reopened this Jul 10, 2026
Resolve conflict in eng/pipelines/jobs/build-for-publish.yml: main (#4824)
decoupled emitter e2e + spector-coverage from the publish critical path by moving
those steps into eng/pipelines/jobs/spector-coverage.yml. Take main's version of
build-for-publish.yml and add the Go e2e steps as a new `spector_go` job in
spector-coverage.yml, matching the Python/Java/TS jobs (turbo-cache restore +
GoTool + regenerate + test:go:e2e + upload-spector-coverage).
Comment thread packages/typespec-go/docs/development.md Outdated
Comment thread packages/typespec-go/package.json Outdated
Comment thread packages/typespec-go/docs/development.md Outdated
To (re)generate the expected output blocks from the current emitter, run the update command and review the produced snapshots as part of your change:

```terminal
pnpm test:update

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not able to get this to work. I added a new testing.md file with a tsp block (simple operation that returns a model). After executing pnpm test:update the tests run/pass but I don't see any Go code in the .md file.

@tadelesh tadelesh Jul 16, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Did you add empty block with which generated Go file you want to check? I added a warning for empty Go block case.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It could be the case that I misspelled the file. I have it working now (erroring on no blocks is a nice addition and makes it clear the author did something wrong). But this makes me think that maybe we need some tweaks here.

  • if no Go blocks are specified, it would be great if the failure output could list the possible block names
  • it would also be good to have a simple way to say "all blocks". maybe something like go all, or even just an unnamed Go block

@Azure Azure deleted a comment from github-actions Bot Jul 16, 2026
tadelesh and others added 3 commits July 16, 2026 11:21
… fix scenario UX

- Rename the npm script `regenerate` back to `tspcompile` (matches the original
  name and the `.scripts/tspcompile.js` file); update ci-go.yml and the Go
  spector-coverage job to call `pnpm run tspcompile`.
- Remove the azure-sdk-assets baseline diff scheme entirely: delete
  .scripts/sync-baseline.js, drop the sync/mirror calls from tspcompile.js, the
  `TYPESPEC_GO_SKIP_BASELINE` env, and the "Review the generated-code diff" doc
  section (decided not to use this approach).
- Scenario usability: `test:update` now regenerates the per-scenario suites
  first so a newly added `.md` is picked up automatically; the harness now fails
  explicitly when a scenario has a `tsp` block but no `go <name>` output block
  (previously it silently passed producing no Go); make gen-scenario-suites emit
  prettier-stable output so regenerating never drifts; document the output-block
  requirement.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Wrap the verbose `turbo run build --filter=@azure-tools/typespec-go...` (build
the emitter plus its workspace deps) in a `build:deps` package script. Update
the development guide's Step 2 to `pnpm build:deps` and the four ci-go.yml build
steps to `pnpm --filter "@azure-tools/typespec-go" run build:deps`, giving a
single source of truth for how to build the emitter. Addresses the PR review
comment asking for a package.json script.

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

// DiscriminatedBaseNoSubTypes - A discriminated base type with no subtypes.
type DiscriminatedBaseNoSubTypes struct {
// REQUIRED; Some property.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: indentation is missing

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

Labels

eng meta:website TypeSpec.io updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants