Skip to content

Commit c7903bc

Browse files
authored
Merge branch 'main' into GenerateAPITextScript
2 parents 6c93b82 + b1c1c09 commit c7903bc

5,894 files changed

Lines changed: 1011176 additions & 860508 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/CODEOWNERS

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
# Core
1212
# PRLabel: %Core.Http
13-
/sdk/core/corehttp/ @lmazuel @annatisch @johanste @iscai-msft @kashifkhan
13+
/sdk/core/corehttp/ @lmazuel @johanste @iscai-msft @kashifkhan
1414

1515
# AzureSdkOwners: @kashifkhan
1616
# ServiceLabel: %Core.Http
@@ -19,12 +19,12 @@
1919
# ServiceLabel: %Azure.Core
2020

2121
# PRLabel: %Azure.Core
22-
/sdk/core/ @lmazuel @annatisch @johanste
23-
/sdk/core/azure-core/ @lmazuel @annatisch @johanste @iscai-msft @kashifkhan
22+
/sdk/core/ @lmazuel @johanste
23+
/sdk/core/azure-core/ @lmazuel @johanste @iscai-msft @kashifkhan
2424
/sdk/core/azure-mgmt-core/ @msyyc
2525

2626
# Smoke Tests
27-
/common/smoketest/ @lmazuel @chlowell @annatisch @mccoyp @shurd @southpolesteve
27+
/common/smoketest/ @lmazuel @chlowell @mccoyp @shurd @southpolesteve
2828

2929
####################
3030
# Client Libraries
@@ -112,10 +112,10 @@
112112
/sdk/textanalytics/ @quentinRobinson @wangyuantao
113113

114114
# PRLabel: %Cognitive - Translator
115-
/sdk/translation/ @jrjrguo @SG-MS
115+
/sdk/translation/ @jrjrguo @zhangeugenia
116116

117117
# ServiceLabel: %Cognitive - Translator
118-
# ServiceOwners: @jrjrguo @SG-MS
118+
# ServiceOwners: @jrjrguo @zhangeugenia
119119

120120
# ServiceLabel: %Communication
121121
# PRLabel: %Communication
@@ -249,10 +249,10 @@
249249
/sdk/eventgrid/ @rajeshka @shankarsama
250250

251251
# PRLabel: %Event Hubs
252-
/sdk/eventhub/ @axisc @hmlam @sjkwak
252+
/sdk/eventhub/ @axisc @hmlam @j7nw4r @SwayGom @sagar0207 @sjkwak
253253

254254
# ServiceLabel: %Event Hubs
255-
# ServiceOwners: @axisc @hmlam @sjkwak
255+
# ServiceOwners: @axisc @hmlam @j7nw4r @SwayGom @sagar0207 @sjkwak
256256

257257
# PRLabel: %Graph
258258
/sdk/graphrbac/ @lmazuel
@@ -753,7 +753,7 @@
753753
# ServiceOwners: @amber-yujueWang @rhurey @xitzhang @pankopon @emilyjiji
754754

755755
# PRLabel: %Storage
756-
/sdk/storage/ @annatisch @jalauzon-msft @vincenttran-msft @weirongw23-msft
756+
/sdk/storage/ @jalauzon-msft @vincenttran-msft @weirongw23-msft
757757

758758
# ServiceLabel: %Storage
759759
# ServiceOwners: @jalauzon-msft @vincenttran-msft
@@ -849,7 +849,7 @@
849849
/sdk/**/ci.yml @msyyc @lmazuel @scbedd @danieljurek
850850

851851
# Add Johnathan Walker as code owner for Event Hubs SDK
852-
/sdk/eventhub/azure-eventhub/* @j7nw4r
852+
/sdk/eventhub/azure-eventhub/* @j7nw4r @SwayGom @sagar0207
853853

854854
# Add Johnathan Walker as code owner for Service Bus SDK
855-
/sdk/servicebus/azure-servicebus/* @j7nw4r
855+
/sdk/servicebus/azure-servicebus/* @j7nw4r @SwayGom @sagar0207

.github/skills/azsdk-common-generate-sdk-locally/SKILL.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ license: MIT
44
metadata:
55
version: "1.1.0"
66
distribution: shared
7-
description: "Generate, build, and test Azure SDKs locally from TypeSpec with automatic customization. WHEN: \"generate SDK locally\", \"build SDK\", \"run SDK tests\", \"update changelog\", \"fix SDK build errors\", \"fix breaking changes\", \"resolve SDK generation errors\", \"customize TypeSpec\", \"rename SDK client\", \"rename SDK model\", \"hide operation from SDK\", \"fix analyzer errors\", \"resolve customization drift\", \"create subclient\", \"update metadata\", \"update version\". DO NOT USE FOR: publishing to package registries, CI pipeline configuration, API design review. INVOKES: azsdk_verify_setup, azsdk_package_generate_code, azsdk_package_build_code, azsdk_package_run_check, azsdk_package_run_tests, azsdk_customized_code_update, azsdk_package_update_changelog_content, azsdk_package_update_metadata, azsdk_package_update_version."
7+
description: "Generate, build, and test Azure SDKs locally from TypeSpec with automatic customization. WHEN: \"generate SDK locally\", \"build SDK\", \"run SDK tests\", \"run CI checks\", \"validate package\", \"run checks\", \"update changelog\", \"fix SDK build errors\", \"fix breaking changes\", \"resolve SDK generation errors\", \"customize TypeSpec\", \"rename SDK client\", \"rename SDK model\", \"hide operation from SDK\", \"fix analyzer errors\", \"resolve customization drift\", \"create subclient\", \"update metadata\", \"update version\". DO NOT USE FOR: publishing to package registries, CI pipeline configuration, API design review. INVOKES: azsdk_verify_setup, azsdk_package_generate_code, azsdk_package_build_code, azsdk_package_run_check, azsdk_package_run_tests, azsdk_customized_code_update, azsdk_package_update_changelog_content, azsdk_package_update_metadata, azsdk_package_update_version."
88
compatibility: "azure-sdk-mcp server, local azure-sdk-for-{language} clone, language build tools"
99
---
1010

@@ -44,10 +44,17 @@ Prerequisites: azure-sdk-mcp server must be running. Without MCP, use `npx tsp-c
4444

4545
[SDK repos](references/sdk-repos.md) | [Customization workflow](references/customization-workflow.md) | [Detailed workflow](references/detailed-workflow.md)
4646

47+
## Guardrails
48+
49+
- **NEVER modify generated SDK code files directly for customizations.** Always use `azure-sdk-mcp:azsdk_customized_code_update`. It handles classification, TypeSpec decorators, code patches, regeneration, and build as a single atomic workflow.
50+
- If `azure-sdk-mcp:azsdk_customized_code_update` fails or times out, **report the error to the user** and suggest retrying. Do not attempt to replicate its behavior by editing files manually.
51+
- Only the customization tool understands the correct layering of TypeSpec decorators vs code patches and ensures regenerated code stays consistent.
52+
4753
## Examples
4854

4955
- "Generate the SDK locally for my TypeSpec service"
5056
- "Build and test the Python SDK package"
57+
- "Run CI checks for my SDK package"
5158
- "Fix the SDK build errors on this PR"
5259
- "The SDK generation has breaking changes, resolve them"
5360
- "Rename FooClient to BarClient for .NET"
@@ -65,4 +72,5 @@ Prerequisites: azure-sdk-mcp server must be running. Without MCP, use `npx tsp-c
6572
- Run `azure-sdk-mcp:azsdk_verify_setup` to confirm MCP and tools.
6673
- If build fails with type conflicts, breaking changes, analyzer errors, or customization drift, use `azure-sdk-mcp:azsdk_customized_code_update` to apply customizations.
6774
- The customization tool uses a two-phase approach: TypeSpec decorators first (Phase A), then code repairs if needed (Phase B).
75+
- If `azure-sdk-mcp:azsdk_customized_code_update` fails or times out, report the error and retry. Do not manually edit generated SDK code — manual edits will be overwritten on the next regeneration.
6876
- Without MCP, use `npx tsp-client` CLI.

.github/workflows/event-processor.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
--query value)
5050
5151
echo "::add-mask::$LABEL_SERVICE_API_KEY"
52-
echo "LABEL_SERVICE_API_KEY=$LABEL_SERVICE_API_KEY" >> $GITHUB_ENV
52+
echo "LABEL_SERVICE_API_KEY=$LABEL_SERVICE_API_KEY" >> "$GITHUB_ENV"
5353
5454
APP_CONFIG_ENDPOINT=$(az keyvault secret show \
5555
--vault-name issue-labeler \
@@ -58,7 +58,7 @@ jobs:
5858
--query value)
5959
6060
echo "::add-mask::$APP_CONFIG_ENDPOINT"
61-
echo "APP_CONFIG_ENDPOINT=$APP_CONFIG_ENDPOINT" >> $GITHUB_ENV
61+
echo "APP_CONFIG_ENDPOINT=$APP_CONFIG_ENDPOINT" >> "$GITHUB_ENV"
6262
6363
# To run github-event-processor built from source, for testing purposes, uncomment everything
6464
# in between the Start/End-Build From Source comments and comment everything in between the

.github/workflows/typespec-python-regenerate.yml

Lines changed: 201 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ on:
2020
permissions:
2121
contents: write
2222
issues: write
23+
pull-requests: write
2324

2425
# Note: with cancel-in-progress, a newer run can cancel an older one after it
2526
# has force-pushed the branch but before it finishes updating the tracking
@@ -157,45 +158,230 @@ jobs:
157158
! -path "$TARGET/template/*" \
158159
-print -exec cp -f "$TEMPLATE" {} \;
159160
160-
- name: Commit and push to dedicated branch
161+
- name: Create or update tracking issue with PR link
162+
env:
163+
GH_TOKEN: ${{ github.token }}
161164
run: |
162165
set -euo pipefail
163-
BRANCH="typespec-python-generated-tests"
166+
TARGET_BRANCH="typespec-python-generated-tests"
164167
git config user.name "github-actions[bot]"
165168
git config user.email "github-actions[bot]@users.noreply.github.com"
166169
170+
GENERATED_DIR="eng/tools/azure-sdk-tools/emitter/generated"
171+
167172
# Quick check: skip if regeneration produced no changes vs HEAD.
168-
if [ -z "$(git status --porcelain -- eng/tools/azure-sdk-tools/emitter/generated/)" ]; then
173+
if [ -z "$(git status --porcelain -- "$GENERATED_DIR")" ]; then
169174
echo "No changes to commit"
170175
exit 0
171176
fi
172177
173-
# Push regenerated files directly to the dedicated branch.
174-
# This branch is machine-managed and may be force-pushed.
175178
PR_NUMBER="${{ steps.typespec-info.outputs.typespec_pr_number }}"
179+
# Use a distinct source branch per origin so a main-based run and a
180+
# PR-based run never force-push over each other.
176181
if [ -n "$PR_NUMBER" ]; then
177182
SOURCE_LABEL="microsoft/typespec PR #${PR_NUMBER}"
183+
SOURCE_BRANCH="regen/typespec-python-pr-${PR_NUMBER}"
178184
else
179185
SOURCE_LABEL="microsoft/typespec@main"
186+
SOURCE_BRANCH="regen/typespec-python-main"
180187
fi
181188
182-
# Base on origin/main so the dedicated branch never inherits
183-
# unrelated content from whatever ref the workflow checked out.
189+
# Save regenerated files to a temp dir before switching branches,
190+
# since they are untracked and would be lost on checkout.
191+
TMPDIR=$(mktemp -d)
192+
cp -r "$GENERATED_DIR"/. "$TMPDIR"
193+
194+
# Ensure the target branch exists; create from origin/main if not.
184195
git fetch --no-tags --depth=1 origin main
185-
git checkout -B "$BRANCH" origin/main
196+
if ! git fetch --no-tags --depth=1 origin "$TARGET_BRANCH" 2>/dev/null; then
197+
git push origin "origin/main:refs/heads/$TARGET_BRANCH"
198+
git fetch --no-tags --depth=1 origin "$TARGET_BRANCH"
199+
fi
200+
201+
# Clean up untracked generated files so checkout doesn't conflict.
202+
rm -rf "$GENERATED_DIR"
203+
204+
# Create source branch based on the target branch.
205+
git checkout -B "$SOURCE_BRANCH" "origin/$TARGET_BRANCH"
186206
187-
# Re-apply just the regenerated tree on top of origin/main.
188-
git checkout HEAD@{1} -- eng/tools/azure-sdk-tools/emitter/generated
189-
git add -f eng/tools/azure-sdk-tools/emitter/generated/
207+
# Restore regenerated files from the temp dir.
208+
mkdir -p "$GENERATED_DIR"
209+
rm -rf "$GENERATED_DIR"/*
210+
cp -r "$TMPDIR"/. "$GENERATED_DIR"
211+
rm -rf "$TMPDIR"
212+
git add -f "$GENERATED_DIR"/
190213
191214
if git diff --cached --quiet; then
192-
echo "No changes vs origin/main"
215+
echo "No changes vs $TARGET_BRANCH"
193216
exit 0
194217
fi
195218
196-
git commit -m "[typespec-python] Regenerate tests from ${SOURCE_LABEL}"
197-
git push origin "$BRANCH" --force-with-lease
198-
echo "::notice::Pushed regenerated tests to $BRANCH"
219+
COMMIT_MSG="[typespec-python] Regenerate tests from ${SOURCE_LABEL}"
220+
git commit -m "$COMMIT_MSG"
221+
git push origin "$SOURCE_BRANCH" --force-with-lease
222+
223+
# GitHub Actions' default GITHUB_TOKEN is not permitted to create pull
224+
# requests in this repository, so instead of opening a PR directly we
225+
# create/update a tracking issue containing a pre-filled "compare" link
226+
# that a maintainer can click to open the PR manually.
227+
REPO="${{ github.repository }}"
228+
SERVER="${{ github.server_url }}"
229+
RUN_URL="${SERVER}/${REPO}/actions/runs/${{ github.run_id }}"
230+
TS_REF_URL="${{ steps.typespec-info.outputs.typespec_ref_url }}"
231+
232+
# Determine assignees. For manual (workflow_dispatch) triggers, assign
233+
# to the user who triggered the run. For automatic triggers (push,
234+
# schedule), fall back to the default maintainers.
235+
EVENT_NAME="${{ github.event_name }}"
236+
ACTOR="${{ github.actor }}"
237+
if [ "$EVENT_NAME" = "workflow_dispatch" ] && [ -n "$ACTOR" ]; then
238+
ASSIGNEES="$ACTOR"
239+
CC_LINE="cc @${ACTOR}"
240+
else
241+
ASSIGNEES="iscai-msft,msyyc"
242+
CC_LINE="cc @iscai-msft @msyyc"
243+
fi
244+
245+
TITLE="$COMMIT_MSG"
246+
247+
# Reuse an existing open tracking issue if one exists (matched by exact
248+
# title). We list by label and match the title with jq because GitHub's
249+
# search tokenizer strips characters like [ ] @ # and /, making a title
250+
# search ambiguous.
251+
ISSUES_JSON=$(gh issue list --state open --label typespec-python \
252+
--limit 100 --json number,title)
253+
EXISTING_ISSUE=$(jq -r --arg title "$TITLE" \
254+
'first(.[] | select(.title == $title) | .number) // ""' <<< "$ISSUES_JSON")
255+
256+
if [ -n "$EXISTING_ISSUE" ]; then
257+
ISSUE_NUMBER="$EXISTING_ISSUE"
258+
echo "Reusing existing tracking issue #$ISSUE_NUMBER"
259+
else
260+
echo "Creating new tracking issue"
261+
# `gh issue create` prints the new issue's URL to stdout; parse the
262+
# trailing number out of it. The body is filled in below once we have
263+
# the compare URL.
264+
# Assignees are applied best-effort in the final `gh issue edit`
265+
# below, so a non-assignable actor never fails issue creation.
266+
ISSUE_URL=$(gh issue create --title "$TITLE" \
267+
--body "Tracking issue for TypeSpec Python regeneration. Details will be filled in shortly." \
268+
--label "typespec-python")
269+
ISSUE_NUMBER="${ISSUE_URL##*/}"
270+
echo "Created issue #$ISSUE_NUMBER ($ISSUE_URL)"
271+
fi
272+
273+
# If an open PR already exists from the source branch to the target
274+
# branch, point the tracking issue at it instead of asking for a new one.
275+
EXISTING_PR_JSON=$(gh pr list --state open --head "$SOURCE_BRANCH" --base "$TARGET_BRANCH" \
276+
--json number,url --limit 1)
277+
EXISTING_PR_URL=$(echo "$EXISTING_PR_JSON" | jq -r '.[0].url // empty')
278+
EXISTING_PR_NUMBER=$(echo "$EXISTING_PR_JSON" | jq -r '.[0].number // empty')
279+
280+
if [ -n "$EXISTING_PR_URL" ]; then
281+
ISSUE_BODY="A pull request already exists for this regeneration.
282+
283+
👉 [View pull request #${EXISTING_PR_NUMBER}](${EXISTING_PR_URL})
284+
285+
The branch \`${SOURCE_BRANCH}\` was just updated with the latest regenerated tests; the existing PR will reflect those changes automatically.
286+
287+
Details:
288+
- Source: [${SOURCE_LABEL}](${TS_REF_URL})
289+
- Branch: [\`${SOURCE_BRANCH}\`](${SERVER}/${REPO}/tree/${SOURCE_BRANCH})
290+
- Latest workflow run: ${RUN_URL}
291+
292+
> Note: the PR targets the \`${TARGET_BRANCH}\` branch, so merging it will **not** auto-close this issue. Please close this issue manually after the PR is merged.
293+
294+
${CC_LINE}"
295+
else
296+
# Build a "compare" URL that opens the PR creation page pre-filled.
297+
# GitHub Actions cannot create PRs directly (org policy), so the
298+
# reviewer just needs to click the link to open the PR. The PR is
299+
# based on the dedicated target branch, not main.
300+
ISSUE_LINK="${SERVER}/${REPO}/issues/${ISSUE_NUMBER}"
301+
# For PR-sourced runs, mark the prefilled PR as do-not-merge: it only
302+
# exists to surface the code diff of the upstream typespec PR.
303+
PR_TITLE="$TITLE"
304+
NOTE_PREFIX=""
305+
DRAFT_PARAM=""
306+
if [ -n "$PR_NUMBER" ]; then
307+
PR_TITLE="$TITLE (DO NOT MERGE)"
308+
NOTE_PREFIX=$'NOTE: This PR exists only to display the code diff. Please do not merge it.\n\n'
309+
# PR-sourced regenerations open the prefilled PR as a draft
310+
# (draft=1 is undocumented but honored by the quick_pull form).
311+
DRAFT_PARAM="&draft=1"
312+
fi
313+
PR_TITLE_ENC=$(jq -rn --arg t "$PR_TITLE" '$t|@uri')
314+
PR_BODY_RAW="${NOTE_PREFIX}Fixes ${ISSUE_LINK}
315+
316+
Source: ${TS_REF_URL}
317+
318+
Automated regeneration of TypeSpec Python generated tests from ${SOURCE_LABEL}.
319+
320+
- Workflow run: ${RUN_URL}
321+
322+
This PR was auto-generated. Re-run the workflow to update it after new commits are pushed to the upstream TypeSpec PR"
323+
PR_BODY_ENC=$(jq -rn --arg b "$PR_BODY_RAW" '$b|@uri')
324+
COMPARE_URL="${SERVER}/${REPO}/compare/${TARGET_BRANCH}...${SOURCE_BRANCH}?quick_pull=1${DRAFT_PARAM}&title=${PR_TITLE_ENC}&body=${PR_BODY_ENC}"
325+
326+
ISSUE_BODY="GitHub Actions is not permitted to create pull requests in this repository, so this issue tracks the regeneration instead.
327+
328+
**Click the link below to open a pre-filled PR:**
329+
330+
👉 [Create pull request from \`${SOURCE_BRANCH}\`](${COMPARE_URL})
331+
332+
Details:
333+
- Source: [${SOURCE_LABEL}](${TS_REF_URL})
334+
- Branch: [\`${SOURCE_BRANCH}\`](${SERVER}/${REPO}/tree/${SOURCE_BRANCH})
335+
- Latest workflow run: ${RUN_URL}
336+
337+
> Note: the PR targets the \`${TARGET_BRANCH}\` branch, so merging it will **not** auto-close this issue. Please close this issue manually after the PR is merged.
338+
339+
${CC_LINE}"
340+
fi
341+
342+
# Write the final body onto the tracking issue (whether reused or just
343+
# created) and re-apply the expected label. Assignment is best-effort:
344+
# a non-assignable actor must not fail the workflow.
345+
gh issue edit "$ISSUE_NUMBER" --body "$ISSUE_BODY" --add-label "typespec-python"
346+
gh issue edit "$ISSUE_NUMBER" --add-assignee "$ASSIGNEES" \
347+
|| echo "::warning::Could not assign issue #${ISSUE_NUMBER} to ${ASSIGNEES}"
348+
echo "::notice::Tracking issue #${ISSUE_NUMBER} updated with PR compare link"
349+
350+
- name: Clean up stale regen branches
351+
if: always()
352+
env:
353+
GH_TOKEN: ${{ github.token }}
354+
run: |
355+
set -euo pipefail
356+
TARGET_BRANCH="typespec-python-generated-tests"
357+
PR_NUMBER="${{ steps.typespec-info.outputs.typespec_pr_number }}"
358+
if [ -n "$PR_NUMBER" ]; then
359+
CURRENT_BRANCH="regen/typespec-python-pr-${PR_NUMBER}"
360+
else
361+
CURRENT_BRANCH="regen/typespec-python-main"
362+
fi
363+
364+
# Prune any regen/typespec-python-* branch whose PR (to the target
365+
# branch) is no longer open but did exist at some point (merged or
366+
# closed). Branches that never had a PR opened are left alone, since a
367+
# maintainer may still click the pre-filled compare link to open one.
368+
BRANCHES=$(git ls-remote --heads origin \
369+
| sed 's#.*refs/heads/##' \
370+
| grep '^regen/typespec-python-' || true)
371+
for b in $BRANCHES; do
372+
if [ "$b" = "$CURRENT_BRANCH" ]; then
373+
continue
374+
fi
375+
OPEN_COUNT=$(gh pr list --state open --head "$b" --base "$TARGET_BRANCH" \
376+
--json number --jq 'length')
377+
ALL_COUNT=$(gh pr list --state all --head "$b" --base "$TARGET_BRANCH" \
378+
--json number --jq 'length')
379+
if [ "$OPEN_COUNT" = "0" ] && [ "$ALL_COUNT" != "0" ]; then
380+
echo "Deleting stale branch $b (PR merged/closed, none open)"
381+
git push origin --delete "$b" \
382+
|| echo "::warning::Failed to delete branch $b"
383+
fi
384+
done
199385
200386
notify-on-failure:
201387
name: "Notify on failure"

0 commit comments

Comments
 (0)