Skip to content

Commit 21bdc9e

Browse files
authored
Merge branch 'main' into savaity/add-find-package-skill
2 parents 4763978 + a8e02c1 commit 21bdc9e

8,113 files changed

Lines changed: 399775 additions & 218505 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/workflows/event-processor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ jobs:
6868
run: >
6969
dotnet tool install
7070
Azure.Sdk.Tools.GitHubEventProcessor
71-
--version 1.0.0-dev.20260129.1
71+
--version 1.0.0-dev.20260403.1
7272
--add-source https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json
7373
--global
7474
shell: bash

.github/workflows/post-apiview.yml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,32 @@ name: After APIView
33
on:
44
check_run:
55
types: [completed]
6-
6+
77
permissions:
88
pull-requests: write
99
contents: read
1010

1111
jobs:
1212
post-apiview:
1313
name: After APIView
14-
runs-on: ["self-hosted", "1ES.Pool=azsdk-pool-github-runners"]
14+
runs-on:
15+
[
16+
"self-hosted",
17+
"1ES.Pool=azsdk-pool-github-runners",
18+
"JobId=azsdk-${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }}",
19+
]
1520
if: |
1621
toJson(github.event.check_run.pull_requests) != '[]' &&
1722
github.event.check_run.check_suite.app.name == 'Azure Pipelines' && (
1823
contains(github.event.check_run.name, 'Build Build') ||
19-
contains(github.event.check_run.name, 'Build Analyze') )
24+
contains(github.event.check_run.name, 'Build Analyze') ||
25+
contains(github.event.check_run.name, 'SDK Validation') )
2026
steps:
2127
- name: Checkout
2228
uses: actions/checkout@v6
2329
with:
24-
sparse-checkout: 'eng/common'
25-
30+
sparse-checkout: "eng/common"
31+
2632
- name: Create APIView Comment on PR
2733
run: |
2834
. "eng/common/scripts/Helpers/ApiView-Helpers.ps1"

.github/workflows/scheduled-event-processor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
run: >
4040
dotnet tool install
4141
Azure.Sdk.Tools.GitHubEventProcessor
42-
--version 1.0.0-dev.20260129.1
42+
--version 1.0.0-dev.20260403.1
4343
--add-source https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json
4444
--global
4545
shell: bash

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,6 @@ stress-test-addons*
126126

127127
# Temp typespec files
128128
TempTypeSpecFiles/
129+
130+
# Azure Artifacts Credential Provider runtime
131+
.azure-artifacts/

CONTRIBUTING.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@ For detailed instructions, refer to the [Maven Credential Provider documentation
125125

126126
> **Note:** For Maven Azure DevOps pipeline authentication, use the [MavenAuthenticate@0](https://learn.microsoft.com/azure/devops/pipelines/tasks/reference/maven-authenticate-v0) pipeline task.
127127
128+
##### Matching CI behavior locally
129+
130+
All Maven dependency and artifact resolution already uses the Azure Artifacts feed by default via `<repositories>` declarations in the project POMs. However, Maven plugins and extensions do not honor POM-level repositories. To route plugin traffic through the Azure Artifacts feed as well (matching CI behavior), copy the mirror settings:
131+
132+
```bash
133+
cp eng/settings.xml ~/.m2/settings.xml
134+
```
135+
128136
##### Troubleshooting 401 Unauthorized errors
129137

130138
If you encounter a `401 Unauthorized` error when running Maven commands:

NuGet.Config

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<configuration>
3+
<packageSources>
4+
<clear />
5+
<!-- Do not add any additional feeds. If new packages are needed they need to
6+
come from the azure-sdk-for-net DevOps feed which has an upstream set to nuget.org -->
7+
<add key="azure-sdk-for-net" value="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json" />
8+
</packageSources>
9+
<disabledPackageSources>
10+
<clear />
11+
</disabledPackageSources>
12+
</configuration>

eng/automation/generate.py

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -277,17 +277,68 @@ def sdk_automation_typespec(config: dict) -> List[dict]:
277277
return packages
278278

279279

280-
def verify_self_serve_parameters(api_version, sdk_release_type):
281-
if sdk_release_type and sdk_release_type not in ["stable", "beta"]:
282-
raise ValueError(f"Invalid SDK release type [{sdk_release_type}], only support 'stable' or 'beta'.")
283-
if api_version and sdk_release_type:
284-
if api_version.endswith("-preview") and sdk_release_type == "stable":
285-
raise ValueError(f"SDK release type is [stable], but API version [{api_version}] is preview.")
286-
logging.info(f"[SelfServe] Generate with apiVersion: {api_version} and sdkReleaseType: {sdk_release_type}")
287-
elif api_version or sdk_release_type:
288-
raise ValueError(
289-
"Both [API version] and [SDK release type] parameters are required for self-serve SDK generation."
290-
)
280+
def infer_sdk_release_type(sdk_root: str, sdk_folder: str, module: str) -> str:
281+
"""Infer SDK release type from the generated metadata JSON.
282+
283+
Reads {sdk_root}/{sdk_folder}/src/main/resources/META-INF/{module}_metadata.json
284+
and inspects the apiVersions values:
285+
- All GA (no 'preview' substring) -> 'stable'
286+
- Any preview or mixed -> 'beta'
287+
- Fallback on error -> 'beta' (safe default)
288+
"""
289+
metadata_path = os.path.join(sdk_root, sdk_folder, "src", "main", "resources", "META-INF", f"{module}_metadata.json")
290+
try:
291+
with open(metadata_path, "r") as f:
292+
metadata = json.load(f)
293+
api_versions = metadata.get("apiVersions", {})
294+
if not api_versions:
295+
logging.warning(f"[SelfServe] No apiVersions found in {metadata_path}, defaulting to beta.")
296+
return "beta"
297+
298+
has_preview = any("preview" in v.lower() for v in api_versions.values())
299+
inferred = "beta" if has_preview else "stable"
300+
logging.info(f"[SelfServe] Inferred sdkReleaseType={inferred} from apiVersions: {api_versions}")
301+
return inferred
302+
except FileNotFoundError:
303+
logging.warning(f"[SelfServe] Metadata file not found: {metadata_path}, defaulting to beta.")
304+
return "beta"
305+
except Exception as e:
306+
logging.warning(f"[SelfServe] Failed to read metadata file {metadata_path}: {e}, defaulting to beta.")
307+
return "beta"
308+
309+
310+
def update_revapi_skip(pom_path: str, beta: bool):
311+
"""Update revapi.skip property in pom.xml based on release type.
312+
313+
beta=True: ensure <revapi.skip>true</revapi.skip> (add if missing, flip if false)
314+
beta=False: flip <revapi.skip>true</revapi.skip> to false if present (skip if absent, as false is default)
315+
"""
316+
try:
317+
with open(pom_path, "r") as f:
318+
content = f.read()
319+
if beta:
320+
if "<revapi.skip>true</revapi.skip>" in content:
321+
return
322+
if "<revapi.skip>false</revapi.skip>" in content:
323+
new_content = content.replace("<revapi.skip>false</revapi.skip>", "<revapi.skip>true</revapi.skip>")
324+
logging.info(f"[SelfServe] Changed revapi.skip to true in {pom_path}")
325+
else:
326+
new_content = re.sub(
327+
r'([ \t]*)</properties>',
328+
r'\1 <revapi.skip>true</revapi.skip>\n\1</properties>',
329+
content,
330+
count=1,
331+
)
332+
logging.info(f"[SelfServe] Added revapi.skip=true to {pom_path}")
333+
else:
334+
if "<revapi.skip>true</revapi.skip>" not in content:
335+
return
336+
new_content = content.replace("<revapi.skip>true</revapi.skip>", "<revapi.skip>false</revapi.skip>")
337+
logging.info(f"[SelfServe] Changed revapi.skip to false in {pom_path}")
338+
with open(pom_path, "w") as f:
339+
f.write(new_content)
340+
except Exception as e:
341+
logging.warning(f"[SelfServe] Failed to update revapi.skip in {pom_path}: {e}")
291342

292343

293344
def sdk_automation_typespec_project(tsp_project: str, config: dict) -> dict:
@@ -299,14 +350,11 @@ def sdk_automation_typespec_project(tsp_project: str, config: dict) -> dict:
299350
repo_url: str = config["repoHttpsUrl"]
300351
sdk_release_type: str = config["sdkReleaseType"] if "sdkReleaseType" in config else None
301352
api_version = config["apiVersion"] if "apiVersion" in config else None
353+
# Generate with beta by default; will be corrected after inference if needed
302354
release_beta_sdk: bool = not sdk_release_type or sdk_release_type == "beta"
303355
breaking: bool = False
304356
changelog = ""
305357
breaking_change_items = []
306-
run_mode: str = config["runMode"] if "runMode" in config else None
307-
308-
if run_mode == "release" or run_mode == "local":
309-
verify_self_serve_parameters(api_version, sdk_release_type)
310358

311359
succeeded, require_sdk_integration, sdk_folder, service, module = generate_typespec_project(
312360
tsp_project,
@@ -317,10 +365,14 @@ def sdk_automation_typespec_project(tsp_project: str, config: dict) -> dict:
317365
remove_before_regen=True,
318366
group_id=GROUP_ID,
319367
api_version=api_version,
320-
generate_beta_sdk=release_beta_sdk,
321368
)
322369

323370
if succeeded:
371+
# Infer sdk release type from generated metadata when not explicitly provided
372+
if not sdk_release_type and sdk_folder and module:
373+
inferred_type = infer_sdk_release_type(sdk_root, sdk_folder, module)
374+
release_beta_sdk = inferred_type == "beta"
375+
324376
# TODO (weidxu): move to typespec-java
325377
if require_sdk_integration:
326378
update_service_files_for_new_lib(sdk_root, service, GROUP_ID, module)
@@ -332,6 +384,9 @@ def sdk_automation_typespec_project(tsp_project: str, config: dict) -> dict:
332384
output_folder = sdk_folder
333385
update_version(sdk_root, output_folder)
334386

387+
# Update revapi.skip based on release type
388+
update_revapi_skip(os.path.join(sdk_root, output_folder, "pom.xml"), beta=release_beta_sdk)
389+
335390
# compile
336391
succeeded = compile_arm_package(sdk_root, module)
337392
if succeeded:

eng/automation/generate_utils.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,6 @@ def generate_typespec_project(
532532
remove_before_regen: bool = False,
533533
group_id: str = None,
534534
api_version: str = None,
535-
generate_beta_sdk: bool = True,
536535
version: str = None, # SDK version
537536
disable_customization: bool = False,
538537
**kwargs,
@@ -610,10 +609,6 @@ def generate_typespec_project(
610609

611610
if remove_before_regen and group_id:
612611
remove_generated_source_code(os.path.join(sdk_root, sdk_folder), f"{group_id}.{service}")
613-
_, current_version = set_or_increase_version(
614-
sdk_root, group_id, module, version=version, preview=generate_beta_sdk
615-
)
616-
emitter_options.append(f"package-version={current_version}")
617612
if api_version:
618613
emitter_options.append(f"api-version={api_version}")
619614

eng/automation/test_generate.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import os
2+
import tempfile
3+
import unittest
4+
5+
from generate import update_revapi_skip
6+
7+
POM_WITH_REVAPI_TRUE = """\
8+
<project>
9+
<properties>
10+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
11+
<jacoco.min.linecoverage>0</jacoco.min.linecoverage>
12+
<revapi.skip>true</revapi.skip>
13+
</properties>
14+
</project>
15+
"""
16+
17+
POM_WITH_REVAPI_FALSE = """\
18+
<project>
19+
<properties>
20+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
21+
<jacoco.min.linecoverage>0</jacoco.min.linecoverage>
22+
<revapi.skip>false</revapi.skip>
23+
</properties>
24+
</project>
25+
"""
26+
27+
POM_WITHOUT_REVAPI = """\
28+
<project>
29+
<properties>
30+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
31+
<jacoco.min.linecoverage>0</jacoco.min.linecoverage>
32+
</properties>
33+
</project>
34+
"""
35+
36+
37+
class TestUpdateRevapiSkip(unittest.TestCase):
38+
39+
def _write_and_update(self, content: str, beta: bool) -> str:
40+
fd, path = tempfile.mkstemp(suffix=".xml")
41+
try:
42+
with os.fdopen(fd, "w") as f:
43+
f.write(content)
44+
update_revapi_skip(path, beta)
45+
with open(path, "r") as f:
46+
return f.read()
47+
finally:
48+
os.unlink(path)
49+
50+
# --- beta=True cases ---
51+
52+
def test_beta_already_true_no_change(self):
53+
result = self._write_and_update(POM_WITH_REVAPI_TRUE, beta=True)
54+
self.assertEqual(result, POM_WITH_REVAPI_TRUE)
55+
56+
def test_beta_false_flipped_to_true(self):
57+
result = self._write_and_update(POM_WITH_REVAPI_FALSE, beta=True)
58+
self.assertIn("<revapi.skip>true</revapi.skip>", result)
59+
self.assertNotIn("<revapi.skip>false</revapi.skip>", result)
60+
61+
def test_beta_missing_added_true(self):
62+
result = self._write_and_update(POM_WITHOUT_REVAPI, beta=True)
63+
self.assertIn("<revapi.skip>true</revapi.skip>", result)
64+
self.assertIn("</properties>", result)
65+
66+
# --- beta=False (stable) cases ---
67+
68+
def test_stable_true_flipped_to_false(self):
69+
result = self._write_and_update(POM_WITH_REVAPI_TRUE, beta=False)
70+
self.assertIn("<revapi.skip>false</revapi.skip>", result)
71+
self.assertNotIn("<revapi.skip>true</revapi.skip>", result)
72+
73+
def test_stable_already_false_no_change(self):
74+
result = self._write_and_update(POM_WITH_REVAPI_FALSE, beta=False)
75+
self.assertEqual(result, POM_WITH_REVAPI_FALSE)
76+
77+
def test_stable_missing_not_added(self):
78+
result = self._write_and_update(POM_WITHOUT_REVAPI, beta=False)
79+
self.assertNotIn("revapi.skip", result)
80+
self.assertEqual(result, POM_WITHOUT_REVAPI)
81+
82+
83+
if __name__ == "__main__":
84+
unittest.main()

eng/common/mcp/azure-sdk-mcp.ps1

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,23 +105,28 @@ $guid = [System.Guid]::NewGuid()
105105
$tempInstallDirectory = Join-Path $tmp "azsdk-install-$($guid)"
106106

107107
# If already installed, use first class version mechanism
108-
$azsdkCmd = Get-Command -ErrorAction SilentlyContinue $packageName
108+
$azsdkCmd = Get-Command -ErrorAction Ignore $packageName
109109
if ($azsdkCmd -and !$InstallDirectory) {
110110
$ErrorActionPreference = "Stop"
111111
$upgrade = & $packageName upgrade --check --output json | out-string
112112
if (!$LASTEXITCODE) {
113113
$ErrorActionPreference = 'Ignore'
114114
$localVersion = $upgrade | ConvertFrom-Json -AsHashtable
115115
$ErrorActionPreference = 'Stop'
116-
if ($localVersion.old_version -and $localVersion.old_version -eq ($Version ? $Version : $localVersion.new_version)) {
116+
if ($localVersion -and $localVersion.old_version -and $localVersion.old_version -eq ($Version ? $Version : $localVersion.new_version)) {
117117
log "Version up to date at $($localVersion.old_version)"
118118
if ($Run) {
119119
$proc = Start-Process -PassThru -WorkingDirectory $RunDirectory -FilePath $azsdkCmd.Path -ArgumentList 'mcp' -NoNewWindow -Wait
120120
exit $proc.ExitCode
121121
}
122122
exit 0
123123
}
124-
log "Version not up to date at " + $localVersion.old_version
124+
if ($localVersion) {
125+
log "Version not up to date at " + $localVersion.old_version
126+
} else {
127+
log "Failed to parse version:"
128+
log $upgrade
129+
}
125130
}
126131
}
127132

0 commit comments

Comments
 (0)