Skip to content

Upstream-aware downstream CI (#4860)#4874

Open
msyyc wants to merge 21 commits into
Azure:mainfrom
msyyc:design/upstream-aware-emitter-ci
Open

Upstream-aware downstream CI (#4860)#4874
msyyc wants to merge 21 commits into
Azure:mainfrom
msyyc:design/upstream-aware-emitter-ci

Conversation

@msyyc

@msyyc msyyc commented Jul 13, 2026

Copy link
Copy Markdown
Member

Implements #4860.

What

Adds upstream-aware downstream CI: when a PR/merge-group changes an upstream dependency (compiler core/ submodule or in-repo libs like typespec-client-generator-core), the affected downstream emitter checks now run automatically. Closes the gap where an upstream-only change could merge with no emitter check.

How

  • Upstream package dependencies are derived from the real pnpm workspace graph (pnpm --filter "...<pkg>"), not a hand-maintained list — adding a new upstream lib needs zero config changes and cannot drift/under-trigger.
  • eng/scripts/detect-affected.ts (zero external deps, run directly via node; node --test unit/contract tests) — diffs the event's base..head (event-aware for pull_request vs merge_group), self-filters ignored files (**/test/**, **/tests/**, **/*.md), maps changes to workspace packages, expands to graph dependents, and emits one boolean output per target.
  • The small residual config the graph can't express is an inlined typed CONFIG in detect-affected.ts: per-target package name, CI-infra extra paths, and a coreSubmodule flag (for core/ submodule bumps).
  • .github/workflows/ci-downstream.yml — always-on entrypoint: detect-affected -> conditional per-target reusable-workflow jobs -> downstream-ci-gate.
  • ci-python/java/typescript.yml converted to on: workflow_call (invoked only by the entrypoint -> no double-runs).

Follow-up required before this gates merges (Strategy A migration)

A repo admin must add downstream / CI / Downstream CI Gate to required status checks (PR + merge queue) and remove any obsolete standalone emitter check names in the same window.

@azure-sdk-automation

Copy link
Copy Markdown
Contributor

No changes needing a change description found.

In workflow_call context github.workflow resolves to the caller
(downstream / CI), so ci-python and ci-java computed an identical
concurrency group and cancelled each other, leaving only TypeScript
to dispatch. Concurrency is already handled by the ci-downstream
entrypoint, so drop the redundant per-workflow blocks.

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

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

⚡ Benchmark Results

⚠️ 6 metric(s) regressed above the +5% threshold:

Metric Baseline Current Change
loader 🟡 304.5ms 🟡 320.1ms +5.1% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-header-explode 🔴 26.5ms 🔴 28.3ms +7.1% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-query-explode 🔴 27.6ms 🔴 29.5ms +6.8% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-child-resources 🔴 20.3ms 🔴 22.4ms +10.2% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/lro-location-header 🟡 19.5ms 🔴 20.8ms +6.7% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-response-body 🔴 29.5ms 🔴 31.2ms +5.6% 🔴
Full details – comparing f12f73c vs baseline rolling-baseline-3b1e01f-e161baf (rolling baseline (20 main runs))
Metric Baseline Current Change
total 🔴 1.00s 🔴 1.05s +4.4%
loader 🟡 304.5ms 🟡 320.1ms +5.1% 🔴
resolver 🟢 40.1ms 🟢 41.8ms +4.2%
checker 🟡 361.4ms 🟡 376.6ms +4.2%
validation 🟢 84.2ms 🟢 86.8ms +3.1%
 ↳ validation/@azure-tools/typespec-azure-core 🟡 12.5ms 🟡 13.3ms +6.2%
 ↳ validation/@typespec/http 🟡 15.4ms 🟡 16.1ms +4.6%
 ↳ validation/@typespec/rest 🟢 1.6ms 🟢 1.6ms +1.5%
 ↳ validation/@typespec/versioning 🔴 50.8ms 🔴 51.8ms +2.0%
 ↳ validation/compiler 🟢 3.8ms 🟢 3.9ms +2.4%
linter 🟡 213.4ms 🟡 222.7ms +4.4%
 ↳ linter/@azure-tools/typespec-azure-core/auth-required 🟢 0.1ms 🟢 0.1ms +3.8%
 ↳ linter/@azure-tools/typespec-azure-core/bad-record-type 🟢 0.6ms 🟢 0.6ms +1.0%
 ↳ linter/@azure-tools/typespec-azure-core/byos 🟢 8.3ms 🟢 8.5ms +2.5%
 ↳ linter/@azure-tools/typespec-azure-core/casing-style 🟢 1.4ms 🟢 1.5ms +2.0%
 ↳ linter/@azure-tools/typespec-azure-core/composition-over-inheritance 🟢 0.2ms 🟢 0.2ms +2.3%
 ↳ linter/@azure-tools/typespec-azure-core/documentation-required 🟢 1.9ms 🟢 2.0ms +3.0%
 ↳ linter/@azure-tools/typespec-azure-core/friendly-name 🟢 1.4ms 🟢 1.4ms +2.3%
 ↳ linter/@azure-tools/typespec-azure-core/key-visibility-required 🟢 0.4ms 🟢 0.4ms +2.9%
 ↳ linter/@azure-tools/typespec-azure-core/known-encoding 🟢 0.5ms 🟢 0.5ms +4.6%
 ↳ linter/@azure-tools/typespec-azure-core/long-running-polling-operation-required 🟢 0.8ms 🟢 0.8ms +1.5%
 ↳ linter/@azure-tools/typespec-azure-core/no-case-mismatch 🟢 0.7ms 🟢 0.7ms +6.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-closed-literal-union 🟢 1.0ms 🟢 1.0ms +0.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-enum 🟢 0.2ms 🟢 0.2ms +1.7%
 ↳ linter/@azure-tools/typespec-azure-core/no-error-status-codes 🟢 0.3ms 🟢 0.3ms +1.5%
 ↳ linter/@azure-tools/typespec-azure-core/no-explicit-routes-resource-ops 🟢 0.2ms 🟢 0.2ms +2.7%
 ↳ linter/@azure-tools/typespec-azure-core/no-format 🟢 0.8ms 🟢 0.8ms +3.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-generic-numeric 🟢 0.8ms 🟢 0.8ms +1.9%
 ↳ linter/@azure-tools/typespec-azure-core/no-header-explode 🔴 26.5ms 🔴 28.3ms +7.1% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-legacy-usage 🟢 2.1ms 🟢 2.1ms +2.8%
 ↳ linter/@azure-tools/typespec-azure-core/no-multiple-discriminator 🟢 0.2ms 🟢 0.3ms +7.8%
 ↳ linter/@azure-tools/typespec-azure-core/no-nullable 🟢 0.4ms 🟢 0.4ms +2.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-offsetdatetime 🟢 2.0ms 🟢 2.0ms +4.1%
 ↳ linter/@azure-tools/typespec-azure-core/no-openapi 🟢 2.3ms 🟢 2.3ms +0.9%
 ↳ linter/@azure-tools/typespec-azure-core/no-private-usage 🟢 3.2ms 🟢 3.2ms +1.9%
 ↳ linter/@azure-tools/typespec-azure-core/no-query-explode 🔴 27.6ms 🔴 29.5ms +6.8% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-response-body 🔴 33.2ms 🔴 34.6ms +4.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-rest-library-interfaces 🟢 0.1ms 🟢 0.1ms +1.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-route-parameter-name-mismatch 🟢 7.6ms 🟢 8.0ms +5.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-rpc-path-params 🟢 0.4ms 🟢 0.4ms +5.5%
 ↳ linter/@azure-tools/typespec-azure-core/no-string-discriminator 🟢 0.1ms 🟢 0.2ms +7.5%
 ↳ linter/@azure-tools/typespec-azure-core/no-unknown 🟢 0.3ms 🟢 0.4ms +4.8%
 ↳ linter/@azure-tools/typespec-azure-core/no-unnamed-union 🟢 0.8ms 🟢 0.8ms +1.4%
 ↳ linter/@azure-tools/typespec-azure-core/operation-missing-api-version 🟢 0.4ms 🟢 0.4ms -1.7%
 ↳ linter/@azure-tools/typespec-azure-core/request-body-problem 🟢 0.5ms 🟢 0.5ms +2.5%
 ↳ linter/@azure-tools/typespec-azure-core/require-versioned 🟢 0.1ms 🟢 0.1ms +4.3%
 ↳ linter/@azure-tools/typespec-azure-core/response-schema-problem 🔴 32.3ms 🔴 33.5ms +3.7%
 ↳ linter/@azure-tools/typespec-azure-core/rpc-operation-request-body 🟢 0.7ms 🟢 0.7ms +2.3%
 ↳ linter/@azure-tools/typespec-azure-core/spread-discriminated-model 🟢 0.4ms 🟢 0.5ms +3.9%
 ↳ linter/@azure-tools/typespec-azure-core/use-standard-names 🟢 7.5ms 🟢 7.9ms +5.6%
 ↳ linter/@azure-tools/typespec-azure-core/use-standard-operations 🟢 0.3ms 🟢 0.3ms +2.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-child-resources 🔴 20.3ms 🔴 22.4ms +10.2% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-lifecycle-operations 🟢 0.2ms 🟢 0.3ms +5.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-common-types-version 🟡 12.0ms 🟡 12.6ms +5.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-no-key 🟢 0.2ms 🟢 0.2ms +6.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-usage-discourage 🟢 0.1ms 🟢 0.1ms +6.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-delete-operation-response-codes 🟢 5.2ms 🟢 4.6ms -12.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-feature-file-usage-discourage 🟢 0.1ms 🟢 0.1ms +3.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-path-casing-conflicts 🟡 16.9ms 🟡 17.3ms +2.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-record 🟢 0.6ms 🟢 0.6ms +1.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-post-operation-response-codes 🟢 1.4ms 🟢 1.4ms +1.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-put-operation-response-codes 🟢 0.2ms 🟢 0.2ms -4.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-action-no-segment 🟢 0.4ms 🟢 0.5ms +1.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-duplicate-property 🟢 0.4ms 🟢 0.4ms +1.6%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-interface-requires-decorator 🟢 0.1ms 🟢 0.1ms +5.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-action-verb 🟢 0.2ms 🟢 0.2ms +1.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-envelope-property 🟢 0.3ms 🟢 0.3ms +3.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-version-format 🟢 0.2ms 🟢 0.2ms +3.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-key-invalid-chars 🟢 0.5ms 🟢 0.5ms +3.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-name-pattern 🟢 0.1ms 🟢 0.1ms +7.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation 🟢 0.5ms 🟢 0.6ms +2.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation-response 🟢 8.9ms 🟢 9.1ms +2.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-patch 🟢 0.8ms 🟢 0.8ms -1.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-path-segment-invalid-chars 🟢 0.4ms 🟢 0.4ms +3.3%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-provisioning-state 🟢 0.4ms 🟢 0.4ms +1.6%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/beyond-nesting-levels 🟢 0.2ms 🟢 0.2ms +1.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/empty-updateable-properties 🟢 0.4ms 🟢 0.4ms +3.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/improper-subscription-list-operation 🟢 0.1ms 🟢 0.1ms +7.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/lro-location-header 🟡 19.5ms 🔴 20.8ms +6.7% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-operations-endpoint 🟢 0.1ms 🟢 0.1ms +3.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-x-ms-identifiers 🟢 1.0ms 🟢 1.0ms +0.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-empty-model 🟢 0.3ms 🟢 0.3ms +1.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-override-props 🟢 0.3ms 🟢 0.3ms +0.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-reserved-resource-property 🟢 0.2ms 🟢 0.2ms +0.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-resource-delete-operation 🟢 0.5ms 🟢 0.5ms +6.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-response-body 🔴 29.5ms 🔴 31.2ms +5.6% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/patch-envelope 🟢 0.4ms 🟢 0.4ms +2.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/resource-name 🟢 0.4ms 🟢 0.4ms +0.3%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/secret-prop 🟢 5.3ms 🟢 5.4ms +1.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/unsupported-type 🟢 0.7ms 🟢 0.7ms +3.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/version-progression 🟢 0.3ms 🟢 0.3ms -2.5%
 ↳ linter/@azure-tools/typespec-client-generator-core/property-name-conflict 🟢 2.3ms 🟢 2.4ms +3.0%
 ↳ linter/@azure-tools/typespec-client-generator-core/require-client-suffix 🟢 1.7ms 🟢 1.7ms +0.6%
emit 🔴 5.98s 🔴 6.24s +4.4%
 ↳ emit/@Azure-Tools 🟢 0.0ms 🟢 0.0ms +0.0%
 ↳ emit/@azure-tools/typespec-autorest 🟢 124.1ms 🟢 127.8ms +3.0%
 ↳ emit/@azure-tools/typespec-python 🔴 2.23s 🔴 2.34s +4.9%
 ↳ emit/@typespec 🟢 0.0ms 🟢 0.0ms +0.0%
 ↳ emit/@typespec/http-client-js 🔴 566.1ms 🔴 582.9ms +3.0%
 ↳ emit/@typespec/openapi3 🟢 106.7ms 🟢 111.8ms +4.8%
 ↳ emit/@typespec/openapi3/compute 🟢 92.7ms 🟢 97.1ms +4.8%
 ↳ emit/@typespec/openapi3/write 🟢 13.7ms 🟢 14.4ms +5.1%

Averaged across 3 specs (azure-arm-resource-manager, azure-core-dataplane, azure-full).
Threshold: changes > ±5% are highlighted.
🟢 Fast · 🟡 Moderate (stages >200ms, rules >10ms) · 🔴 Slow (stages >400ms, rules >20ms)

- Remove docs/superpowers process artifacts from the PR (kept in session)
- Drop // @ts-check from detect-affected(.test).js: they import untyped
  js-yaml/minimatch that are not resolvable by root tsc during check:eng
  (matches existing lint-resourcemanager.js convention)
- Rename config key core-submodule -> coreSubmodule for valid JSDoc and
  clean property access
- prettier-format the scripts

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

Copy link
Copy Markdown
Contributor

You can try these changes here

🛝 Playground 🌐 Website

@markcowl
markcowl requested a review from iscai-msft July 13, 2026 18:20
Comment thread eng/scripts/detect-affected.js Outdated
Comment thread eng/scripts/detect-affected.js Outdated
Comment thread eng/ci/downstream-deps.yml Outdated
Replace the hand-maintained upstream dependency map with the real pnpm
workspace graph: changed files are self-filtered (test/**, *.md) in code,
mapped to their workspace packages, then expanded to graph dependents via
pnpm. This removes the drift-prone map (which under-triggered by omitting
autorest/rulesets) and covers all upstream deps automatically.

- Rewrite detect-affected as zero-dependency TypeScript run directly on
  Node (native type-stripping), no tsx and no js-yaml/minimatch.
- Inline the small residual config (per-target package name, CI-infra
  extra paths, coreSubmodule) that the graph cannot express as a typed const.
- Self-filter ignored files in code instead of pnpm --changed-files-ignore-pattern,
  which unreliably matches non-trailing-** globs.
- Enable allowImportingTsExtensions for eng tsconfig so the colocated test
  can import the .ts module under Node's native runner.

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

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

⚡ External Spec Benchmark Results

⚠️ 5 metric(s) regressed above the +5% threshold:

Metric Baseline Current Change
 ↳ validation/@azure-tools/typespec-client-generator-core 🔴 20.4ms 🔴 24.5ms +20.4% 🔴
 ↳ validation/@typespec/rest 🔴 23.4ms 🔴 26.3ms +12.3% 🔴
 ↳ validation/compiler 🔴 24.7ms 🔴 27.9ms +13.0% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-rest-library-interfaces 🟡 16.4ms 🟡 17.6ms +7.1% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-record 🟢 3.4ms 🟢 4.6ms +34.5% 🔴
Full details – comparing f12f73c vs baseline rolling-baseline-3497e82-e161baf (rolling baseline (2 main runs))
Metric Baseline Current Change
total 🔴 6.97s 🔴 6.60s -5.3% 🟢
loader 🔴 2.04s 🔴 1.85s -9.4% 🟢
resolver 🟢 152.3ms 🟢 157.4ms +3.4%
checker 🔴 1.55s 🔴 1.52s -1.6%
validation 🟡 382.7ms 🟡 390.3ms +2.0%
 ↳ validation/@azure-tools/typespec-azure-core 🟢 0.2ms 🟢 0.2ms +4.8%
 ↳ validation/@azure-tools/typespec-client-generator-core 🔴 20.4ms 🔴 24.5ms +20.4% 🔴
 ↳ validation/@typespec/http 🔴 158.3ms 🔴 153.3ms -3.2%
 ↳ validation/@typespec/rest 🔴 23.4ms 🔴 26.3ms +12.3% 🔴
 ↳ validation/@typespec/versioning 🔴 154.3ms 🔴 156.2ms +1.2%
 ↳ validation/compiler 🔴 24.7ms 🔴 27.9ms +13.0% 🔴
linter 🔴 2.83s 🔴 2.69s -5.0%
 ↳ linter/@azure-tools/typespec-azure-core/auth-required 🟢 0.1ms 🟢 0.1ms +4.7%
 ↳ linter/@azure-tools/typespec-azure-core/byos 🔴 131.4ms 🔴 127.3ms -3.1%
 ↳ linter/@azure-tools/typespec-azure-core/casing-style 🟢 9.6ms 🟢 9.8ms +2.1%
 ↳ linter/@azure-tools/typespec-azure-core/composition-over-inheritance 🟢 1.0ms 🟢 1.0ms +0.2%
 ↳ linter/@azure-tools/typespec-azure-core/documentation-required 🟡 14.1ms 🟡 14.4ms +2.5%
 ↳ linter/@azure-tools/typespec-azure-core/friendly-name 🟡 10.4ms 🟡 10.4ms -0.0%
 ↳ linter/@azure-tools/typespec-azure-core/key-visibility-required 🟢 3.2ms 🟢 3.3ms +3.0%
 ↳ linter/@azure-tools/typespec-azure-core/known-encoding 🟢 2.9ms 🟢 2.8ms -2.1%
 ↳ linter/@azure-tools/typespec-azure-core/long-running-polling-operation-required 🟢 5.5ms 🟢 5.4ms -2.7%
 ↳ linter/@azure-tools/typespec-azure-core/no-case-mismatch 🟢 3.3ms 🟢 3.3ms +2.0%
 ↳ linter/@azure-tools/typespec-azure-core/no-closed-literal-union 🟢 5.2ms 🟢 5.4ms +4.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-enum 🟢 0.4ms 🟢 0.4ms +2.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-error-status-codes 🟢 2.1ms 🟢 2.1ms +1.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-explicit-routes-resource-ops 🟢 1.5ms 🟢 1.5ms +0.5%
 ↳ linter/@azure-tools/typespec-azure-core/no-format 🟢 7.3ms 🟢 7.6ms +3.2%
 ↳ linter/@azure-tools/typespec-azure-core/no-generic-numeric 🟢 3.6ms 🟢 3.7ms +1.8%
 ↳ linter/@azure-tools/typespec-azure-core/no-header-explode 🔴 282.9ms 🔴 259.8ms -8.1% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/no-legacy-usage 🔴 22.5ms 🔴 22.0ms -2.1%
 ↳ linter/@azure-tools/typespec-azure-core/no-multiple-discriminator 🟢 0.8ms 🟢 0.8ms -0.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-nullable 🟢 2.9ms 🟢 2.9ms +1.4%
 ↳ linter/@azure-tools/typespec-azure-core/no-offsetdatetime 🟡 15.2ms 🟡 15.0ms -1.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-openapi 🔴 36.5ms 🔴 36.3ms -0.4%
 ↳ linter/@azure-tools/typespec-azure-core/no-private-usage 🔴 35.1ms 🔴 36.2ms +3.2%
 ↳ linter/@azure-tools/typespec-azure-core/no-query-explode 🔴 290.7ms 🔴 270.8ms -6.8% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/no-rest-library-interfaces 🟡 16.4ms 🟡 17.6ms +7.1% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-route-parameter-name-mismatch 🔴 128.6ms 🔴 116.7ms -9.3% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/no-rpc-path-params 🟢 1.9ms 🟢 2.0ms +4.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-string-discriminator 🟢 0.6ms 🟢 0.6ms -2.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-unknown 🟢 2.2ms 🟢 2.2ms +0.2%
 ↳ linter/@azure-tools/typespec-azure-core/no-unnamed-union 🟢 5.4ms 🟢 5.6ms +4.0%
 ↳ linter/@azure-tools/typespec-azure-core/operation-missing-api-version 🟢 3.3ms 🟢 3.4ms +2.8%
 ↳ linter/@azure-tools/typespec-azure-core/request-body-problem 🟢 5.1ms 🟢 5.5ms +6.8%
 ↳ linter/@azure-tools/typespec-azure-core/require-versioned 🟢 0.1ms 🟢 0.1ms -4.1%
 ↳ linter/@azure-tools/typespec-azure-core/response-schema-problem 🔴 324.9ms 🔴 307.7ms -5.3% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/rpc-operation-request-body 🟢 0.7ms 🟢 0.7ms -2.0%
 ↳ linter/@azure-tools/typespec-azure-core/spread-discriminated-model 🟢 3.4ms 🟢 3.6ms +3.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-child-resources 🔴 66.9ms 🔴 62.8ms -6.1% 🟢
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-lifecycle-operations 🟢 0.2ms 🟢 0.2ms -7.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-common-types-version 🔴 127.7ms 🔴 124.6ms -2.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-no-key 🟢 0.9ms 🟢 0.9ms -3.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-usage-discourage 🟢 0.6ms 🟢 0.6ms -1.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-delete-operation-response-codes 🟢 3.7ms 🟢 3.6ms -2.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-feature-file-usage-discourage 🟢 0.0ms 🟢 0.1ms +9.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-path-casing-conflicts 🔴 146.4ms 🔴 147.5ms +0.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-record 🟢 3.4ms 🟢 4.6ms +34.5% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-post-operation-response-codes 🟢 9.9ms 🟢 9.0ms -9.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-put-operation-response-codes 🟢 0.3ms 🟢 0.3ms +4.6%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-action-no-segment 🟢 4.4ms 🟢 4.3ms -2.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-duplicate-property 🟢 1.0ms 🟢 1.0ms -4.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-interface-requires-decorator 🟢 0.5ms 🟢 0.5ms +5.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-action-verb 🟢 1.5ms 🟢 1.5ms +2.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-envelope-property 🟢 0.8ms 🟢 0.8ms -0.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-version-format 🟢 0.3ms 🟢 0.3ms -0.6%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-key-invalid-chars 🟢 1.9ms 🟢 1.8ms -3.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-name-pattern 🟢 0.2ms 🟢 0.2ms +2.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation 🟢 3.3ms 🟢 3.4ms +4.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation-response 🔴 66.4ms 🔴 65.3ms -1.6%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-patch 🟢 4.1ms 🟢 4.0ms -4.3%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-path-segment-invalid-chars 🟢 1.4ms 🟢 1.4ms +0.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-provisioning-state 🟢 0.9ms 🟢 1.0ms +3.6%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/beyond-nesting-levels 🟢 0.8ms 🟢 0.8ms -1.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/empty-updateable-properties 🟢 1.5ms 🟢 1.5ms +2.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/improper-subscription-list-operation 🟢 0.1ms 🟢 0.1ms +8.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/lro-location-header 🔴 287.6ms 🔴 264.5ms -8.0% 🟢
 ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-operations-endpoint 🟢 0.2ms 🟢 0.2ms -3.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-x-ms-identifiers 🟢 4.4ms 🟢 4.5ms +1.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-empty-model 🟢 0.7ms 🟢 0.8ms +4.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-override-props 🟢 0.7ms 🟢 0.8ms +9.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-reserved-resource-property 🟢 0.7ms 🟢 0.7ms -0.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-resource-delete-operation 🟢 2.2ms 🟢 2.3ms +5.6%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-response-body 🔴 473.8ms 🔴 443.4ms -6.4% 🟢
 ↳ linter/@azure-tools/typespec-azure-resource-manager/patch-envelope 🟢 1.5ms 🟢 1.5ms +1.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/resource-name 🟢 1.6ms 🟢 1.7ms +5.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/secret-prop 🔴 82.4ms 🔴 80.0ms -2.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/unsupported-type 🟢 4.1ms 🟢 4.1ms +0.6%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/version-progression 🟢 0.3ms 🟢 0.3ms -1.6%
 ↳ linter/@azure-tools/typespec-client-generator-core/property-name-conflict 🔴 29.7ms 🔴 30.1ms +1.5%
 ↳ linter/@azure-tools/typespec-client-generator-core/require-client-suffix 🟢 6.6ms 🟢 6.8ms +2.2%
emit 🔴 11.50s 🔴 11.42s -0.7%
 ↳ emit/@Azure-Tools 🟢 0.0ms 🟢 0.0ms +0.0%
 ↳ emit/@azure-tools/typespec-client-generator-core 🔴 5.75s 🔴 5.71s -0.7%

Averaged across 3 specs (compute, network, web).
Threshold: changes > ±5% are highlighted.
🟢 Fast · 🟡 Moderate (stages >200ms, rules >10ms) · 🔴 Slow (stages >400ms, rules >20ms)

@msyyc
msyyc marked this pull request as ready for review July 14, 2026 07:06
@msyyc
msyyc requested review from bterlson and markcowl as code owners July 14, 2026 07:06
@msyyc
msyyc requested a review from Copilot July 14, 2026 07:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces an always-on “downstream / CI” entrypoint workflow that detects which downstream emitter CI jobs (Python/Java/TypeScript) are affected by upstream dependency changes, and then conditionally runs the corresponding reusable workflows to ensure emitter checks aren’t skipped when upstream-only changes land.

Changes:

  • Added downstream / CI workflow that runs an “affected targets” detector and gates results.
  • Added a new detect-affected script (and accompanying tests) to compute per-target boolean outputs.
  • Converted existing per-emitter CI workflows (python/java/typespec-ts) to workflow_call so they can be orchestrated by the entrypoint.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tsconfig.eng.json Enables TS extension imports for eng scripts/tests.
eng/scripts/package.json Adds a new dependency for eng scripts.
eng/scripts/detect-affected.ts Implements affected-target detection using git diff + pnpm workspace graph + extra path triggers.
eng/scripts/detect-affected.test.ts Adds node:test unit tests for the detection logic.
.github/workflows/ci-typescript.yml Converts TypeScript CI to a reusable workflow (workflow_call).
.github/workflows/ci-python.yml Converts Python CI to a reusable workflow (workflow_call).
.github/workflows/ci-java.yml Converts Java CI to a reusable workflow (workflow_call).
.github/workflows/ci-downstream.yml Adds the orchestrating “downstream / CI” workflow and a gate job.

Comment thread eng/scripts/detect-affected.ts Outdated
Comment thread eng/scripts/detect-affected.ts Outdated
Comment thread eng/scripts/detect-affected.ts Outdated
Comment thread .github/workflows/ci-downstream.yml
Comment thread eng/scripts/package.json
Comment thread eng/scripts/detect-affected.test.ts Outdated
msyyc and others added 2 commits July 14, 2026 15:19
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…ector tests

- Correct the 'add a target' comment to reference CONFIG.targets (was TARGETS).
- Add **/tests/** to the ignore globs so plural tests directories (e.g.
  typespec-python/tests) are treated as non-meaningful like **/test/**.
- Remove the now-unused minimatch dependency (replaced by the built-in
  glob matcher during the pnpm-graph refactor).
- Run the detector unit tests in CI via 'node --test' in the detect-affected
  job, and add a 'test:eng' root script for local parity.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@msyyc
msyyc requested a review from Copilot July 14, 2026 08:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

@msyyc
msyyc force-pushed the design/upstream-aware-emitter-ci branch from 167b847 to ecc30ad Compare July 14, 2026 09:04
@msyyc
msyyc requested a review from timotheeguerin July 14, 2026 09:07
@msyyc
msyyc force-pushed the design/upstream-aware-emitter-ci branch from ecc30ad to edc68e0 Compare July 14, 2026 09:10
Comment thread eng/scripts/detect-affected.ts Outdated
Comment thread eng/scripts/detect-affected.ts Outdated
@msyyc
msyyc force-pushed the design/upstream-aware-emitter-ci branch from edc68e0 to 7bf45b1 Compare July 15, 2026 05:10
Replace hand-rolled file->package mapping (getWorkspacePackages,
mapFilesToPackages), dependent expansion (getDependents), and glob
ignore (filterIgnored) with a single pnpm command that derives affected
packages from the workspace graph and applies test/markdown filtering
via --changed-files-ignore-pattern.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@msyyc
msyyc force-pushed the design/upstream-aware-emitter-ci branch from 7bf45b1 to 16248d5 Compare July 15, 2026 05:14
@msyyc
msyyc requested a review from timotheeguerin July 15, 2026 06:10
@msyyc

msyyc commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

@timotheeguerin updated with your review comment and pls help review again.

Comment thread .github/workflows/ci-java.yml
@msyyc
msyyc enabled auto-merge July 16, 2026 10:38
Comment thread .github/workflows/ci-downstream.yml Outdated
Comment thread .github/workflows/ci-downstream.yml Outdated
if: ${{ always() }}
runs-on: ubuntu-latest
steps:
- name: Validate downstream results

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.

  - name: Validate CI results
        run: |
          if [[ "${{ needs.core.result }}" == "failure" || "${{ needs.core.result }}" == "cancelled" ]]; then
            echo "Core CI failed or was cancelled"
            exit 1
          fi
          echo "All CI checks passed or were appropriately skipped"

this is the code I have in typespec core. might be more flexible if we add more stuff

@msyyc msyyc Jul 17, 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.

Made the gate generic: it validates results via toJSON(needs) + jq, so no job names are hardcoded here. Adding an emitter (e.g. go) then only needs a go entry in detect-affected.config.json, a ci-go.yml, and a go job block + go in this gate's needs:. The needs: entry and job block are unavoidable (GitHub requires a static uses: and explicit needs:), but the gate body never changes.

Comment thread eng/scripts/detect-affected.test.ts
Comment thread eng/scripts/detect-affected.test.ts Outdated
Comment thread eng/scripts/detect-affected.test.ts Outdated
msyyc and others added 5 commits July 17, 2026 09:47
Co-authored-by: Timothee Guerin <timothee.guerin@outlook.com>
Co-authored-by: Timothee Guerin <timothee.guerin@outlook.com>
Migrate eng/scripts/detect-affected.test.ts from node:test to the vitest
API and register eng/ as a vitest project so the detector unit test runs
as part of the normal `pnpm test` suite (ci.yml), mirroring the eng test
setup in typespec core.

- eng/vitest.config.ts: new project config merging defaultTypeSpecVitestConfig
- register eng/vitest.config.ts in vitest.config.fast.ts and vitest.config.ts
- test file now uses describe/it/expect and mocks console.log
- tsconfig.eng.json: exclude eng/vitest.config.ts (imports core, like core/eng)
- package.json test:eng: node --test -> vitest run
- ci-downstream.yml: drop redundant node --test step (covered by ci.yml)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 62793370-fd78-402e-b139-26588818aa1e
Make adding a new emitter (e.g. go) a config-only change: introduce
eng/scripts/detect-affected.config.json as the single source of truth for
the ignore globs, shared/extra CI-infra paths, submodule path, and the
target -> package map. The detector, its test, and the workflow gate are
now generic and no longer enumerate emitters by name.

- detect-affected.ts: load CONFIG from the JSON (readFileSync); use
  config.submodulePath; emit a single `affected=<json>` GITHUB_OUTPUT
- detect-affected.test.ts: add config-guard tests (submodulePath set,
  every target has a package)
- ci-downstream.yml:
  - detect-affected exposes one `affected` JSON output; emitter jobs gate
    on `fromJSON(needs.detect-affected.outputs.affected).<target>`
  - gate validates results generically via `toJSON(needs)` + jq, so a new
    emitter only needs a `needs:` entry, not a script edit

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 62793370-fd78-402e-b139-26588818aa1e
The JSDoc example omitted `--depth -1`, which the code actually passes.
Align the comment with the real command.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 62793370-fd78-402e-b139-26588818aa1e
@msyyc
msyyc requested a review from timotheeguerin July 17, 2026 03:29
@msyyc

msyyc commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

python ci failure is caused by #4909

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants