Skip to content

Commit 2126f24

Browse files
authored
Bump tsp for Azure plugin (Azure#49110)
1 parent 8719038 commit 2126f24

File tree

110 files changed

+13348
-16500
lines changed

Some content is hidden

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

110 files changed

+13348
-16500
lines changed

eng/Packages.Data.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@
206206
</ItemGroup>
207207

208208
<ItemGroup Condition="'$(IsGeneratorLibrary)' == 'true'">
209-
<PackageReference Update="Microsoft.TypeSpec.Generator.ClientModel" Version="1.0.0-alpha.20250320.1" />
209+
<PackageReference Update="Microsoft.TypeSpec.Generator.ClientModel" Version="1.0.0-alpha.20250407.1" />
210210
<PackageReference Update="System.ClientModel" Version="1.3.0" />
211211
</ItemGroup>
212212

eng/packages/http-client-csharp-mgmt/emitter/src/emitter.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { DecoratorInfo } from "@azure-tools/typespec-client-generator-core";
77
import {
88
CodeModel,
99
CSharpEmitterOptions,
10+
InputClient,
1011
InputModelType,
1112
setSDKContextOptions
1213
} from "@typespec/http-client-csharp";
@@ -33,10 +34,14 @@ export async function $onEmit(context: EmitContext<CSharpEmitterOptions>) {
3334

3435
function updateCodeModel(codeModel: CodeModel): CodeModel {
3536
for (const client of codeModel.clients) {
37+
updateClient(client);
38+
}
39+
40+
function updateClient(client: InputClient) {
3641
// TODO: we can implement this decorator in TCGC until we meet the corner case
3742
// if the client has resourceMetadata decorator, it is a resource client and we don't need to add it again
3843
if (client.decorators?.some((d) => d.name == resourceMetadata)) {
39-
continue;
44+
return;
4045
}
4146

4247
// TODO: Once we have the ability to get resource hierarchy from TCGC directly, we can remove this implementation
@@ -89,6 +94,12 @@ function updateCodeModel(codeModel: CodeModel): CodeModel {
8994
resourceMetadataDecorator.arguments["resourceType"] = resourceType;
9095
client.decorators.push(resourceMetadataDecorator);
9196
}
97+
98+
if (client.children) {
99+
for (const child of client.children) {
100+
updateClient(child as InputClient);
101+
}
102+
}
92103
}
93104
return codeModel;
94105
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#Requires -Version 7.0
2+
param(
3+
$filter,
4+
[bool]$Stubbed = $true,
5+
[bool]$LaunchOnly = $false,
6+
[switch]$ForceNewProject = $false
7+
)
8+
9+
Import-Module "$PSScriptRoot\Generation.psm1" -DisableNameChecking -Force;
10+
11+
$mgmtPackageRoot = Resolve-Path (Join-Path $PSScriptRoot '..' '..')
12+
Write-Host "Mgmt Package root: $packageRoot" -ForegroundColor Cyan
13+
$mgmtSolutionDir = Join-Path $mgmtPackageRoot 'generator'
14+
15+
if (-not $LaunchOnly) {
16+
Refresh-Mgmt-Build
17+
18+
if ($null -eq $filter -or $filter -eq "Mgmt-TypeSpec") {
19+
Write-Host "Generating MgmtTypeSpec" -ForegroundColor Cyan
20+
$testProjectsLocalDir = Join-Path $mgmtPackageRoot 'generator' 'TestProjects' 'Local'
21+
22+
$mgmtTypespecTestProject = Join-Path $testProjectsLocalDir "Mgmt-TypeSpec"
23+
24+
Invoke (Get-Mgmt-TspCommand "$mgmtTypespecTestProject/main.tsp" $mgmtTypespecTestProject -forceNewProject $ForceNewProject)
25+
26+
# exit if the generation failed
27+
if ($LASTEXITCODE -ne 0) {
28+
exit $LASTEXITCODE
29+
}
30+
31+
Write-Host "Building MgmtTypeSpec" -ForegroundColor Cyan
32+
Invoke "dotnet build $mgmtPackageRoot/generator/TestProjects/Local/Mgmt-TypeSpec/src/MgmtTypeSpec.csproj"
33+
34+
# exit if the generation failed
35+
if ($LASTEXITCODE -ne 0) {
36+
exit $LASTEXITCODE
37+
}
38+
}
39+
}
40+
41+
# only write new launch settings if no filter was passed in
42+
if ($null -eq $filter) {
43+
$mgmtSpec = "TestProjects/Local/Mgmt-TypeSpec"
44+
45+
# Write the launch settings for Mgmt
46+
$mgmtLaunchSettings = @{}
47+
$mgmtLaunchSettings.Add("profiles", @{})
48+
$mgmtLaunchSettings["profiles"].Add("Mgmt-TypeSpec", @{})
49+
$mgmtLaunchSettings["profiles"]["Mgmt-TypeSpec"].Add("commandLineArgs", "`$(SolutionDir)/../dist/generator/Microsoft.TypeSpec.Generator.dll `$(SolutionDir)/$mgmtSpec -g MgmtClientGenerator")
50+
$mgmtLaunchSettings["profiles"]["Mgmt-TypeSpec"].Add("commandName", "Executable")
51+
$mgmtLaunchSettings["profiles"]["Mgmt-TypeSpec"].Add("executablePath", "dotnet")
52+
53+
$mgmtSortedLaunchSettings = @{}
54+
$mgmtSortedLaunchSettings.Add("profiles", [ordered]@{})
55+
$mgmtLaunchSettings["profiles"].Keys | Sort-Object | ForEach-Object {
56+
$profileKey = $_
57+
$originalProfile = $mgmtLaunchSettings["profiles"][$profileKey]
58+
59+
# Sort the keys inside each profile
60+
# This is needed due to non deterministic ordering of json elements in powershell
61+
$sortedProfile = [ordered]@{}
62+
$originalProfile.GetEnumerator() | Sort-Object Key | ForEach-Object {
63+
$sortedProfile[$_.Key] = $_.Value
64+
}
65+
66+
$mgmtSortedLaunchSettings["profiles"][$profileKey] = $sortedProfile
67+
}
68+
69+
# Write the launch settings to the launchSettings.json file
70+
$mgmtLaunchSettingsPath = Join-Path $mgmtSolutionDir "Azure.Generator.Mgmt" "src" "Properties" "launchSettings.json"
71+
# Write the settings to JSON and normalize line endings to Unix style (LF)
72+
$mgmtSortedLaunchSettings | ConvertTo-Json | ForEach-Object { ($_ -replace "`r`n", "`n") + "`n" } | Set-Content -NoNewline $mgmtLaunchSettingsPath
73+
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot '..')
2+
3+
function Invoke($command, $executePath=$repoRoot)
4+
{
5+
Write-Host "> $command"
6+
Push-Location $executePath
7+
if ($IsLinux -or $IsMacOs)
8+
{
9+
sh -c "$command 2>&1"
10+
}
11+
else
12+
{
13+
cmd /c "$command 2>&1"
14+
}
15+
Pop-Location
16+
17+
if($LastExitCode -ne 0)
18+
{
19+
Write-Error "Command failed to execute: $command"
20+
}
21+
}
22+
23+
function Get-Mgmt-TspCommand {
24+
param (
25+
[string]$specFile,
26+
[string]$generationDir,
27+
[bool]$generateStub = $false,
28+
[string]$apiVersion = $null,
29+
[bool]$forceNewProject = $false
30+
)
31+
$command = "npx tsp compile $specFile"
32+
$command += " --trace @azure-typespec/http-client-csharp-mgmt"
33+
$command += " --emit $repoRoot/../../http-client-csharp-mgmt"
34+
35+
$configFile = Join-Path $generationDir "tspconfig.yaml"
36+
if (Test-Path $configFile) {
37+
$command += " --config=$configFile"
38+
}
39+
$command += " --option @azure-typespec/http-client-csharp-mgmt.emitter-output-dir=$generationDir"
40+
$command += " --option @azure-typespec/http-client-csharp-mgmt.save-inputs=true"
41+
if ($generateStub) {
42+
$command += " --option @azure-typespec/http-client-csharp-mgmt.plugin-name=AzureStubPlugin"
43+
}
44+
45+
if ($apiVersion) {
46+
$command += " --option @azure-typespec/http-client-csharp-mgmt.api-version=$apiVersion"
47+
}
48+
49+
if ($forceNewProject) {
50+
$command += " --option @azure-typespec/http-client-csharp-mgmt.new-project=true"
51+
}
52+
53+
return $command
54+
}
55+
56+
function Refresh-Mgmt-Build {
57+
Write-Host "Building emitter and generator" -ForegroundColor Cyan
58+
Invoke "npm run build:emitter" "$repoRoot/../../http-client-csharp-mgmt"
59+
# exit if the generation failed
60+
if ($LASTEXITCODE -ne 0) {
61+
exit $LASTEXITCODE
62+
}
63+
64+
# we don't want to build the entire solution because the test projects might not build until after regeneration
65+
Invoke "dotnet build $repoRoot/../../http-client-csharp-mgmt/generator/Azure.Generator.Mgmt/src"
66+
# exit if the generation failed
67+
if ($LASTEXITCODE -ne 0) {
68+
exit $LASTEXITCODE
69+
}
70+
}
71+
72+
function Compare-Paths {
73+
param (
74+
[string]$path1,
75+
[string]$path2
76+
)
77+
78+
# Normalize the directory separators
79+
$normalizedPath1 = $path1 -replace '/', '\'
80+
$normalizedPath2 = $path2 -replace '/', '\'
81+
82+
# Strip off http from the beginning of path2 if it exists
83+
if ($normalizedPath2.StartsWith("http\")) {
84+
$normalizedPath2 = $normalizedPath2.Substring(5)
85+
}
86+
87+
# Compare the normalized paths
88+
return $normalizedPath1.Contains($normalizedPath2)
89+
}
90+
91+
function Generate-Srv-Driven {
92+
param (
93+
[string]$specFilePath,
94+
[string]$outputDir,
95+
[bool]$generateStub = $false,
96+
[bool]$createOutputDirIfNotExist = $true
97+
)
98+
99+
$v1Dir = $(Join-Path $outputDir "v1")
100+
if ($createOutputDirIfNotExist -and -not (Test-Path $v1Dir)) {
101+
New-Item -ItemType Directory -Path $v1Dir | Out-Null
102+
}
103+
104+
$v2Dir = $(Join-Path $outputDir "v2")
105+
if ($createOutputDirIfNotExist -and -not (Test-Path $v2Dir)) {
106+
New-Item -ItemType Directory -Path $v2Dir | Out-Null
107+
}
108+
109+
## get the last two directories of the output directory and add V1/V2 to disambiguate the namespaces
110+
$namespaceRoot = $(($outputDir.Split([System.IO.Path]::DirectorySeparatorChar)[-2..-1] | `
111+
ForEach-Object { $_.Substring(0,1).ToUpper() + $_.Substring(1) }) -replace '-(\p{L})', { $_.Groups[1].Value.ToUpper() } -replace '\W', '' -join ".")
112+
$v1SpecFilePath = $(Join-Path $specFilePath "old.tsp")
113+
$v2SpecFilePath = $(Join-Path $specFilePath "main.tsp")
114+
115+
Invoke (Get-TspCommand $v1SpecFilePath $v1Dir -generateStub $generateStub)
116+
Invoke (Get-TspCommand $v2SpecFilePath $v2Dir -generateStub $generateStub)
117+
118+
# exit if the generation failed
119+
if ($LASTEXITCODE -ne 0) {
120+
exit $LASTEXITCODE
121+
}
122+
}
123+
124+
function Generate-Versioning {
125+
param (
126+
[string]$specFilePath,
127+
[string]$outputDir,
128+
[bool]$generateStub = $false,
129+
[bool]$createOutputDirIfNotExist = $true
130+
)
131+
132+
$v1Dir = $(Join-Path $outputDir "v1")
133+
if ($createOutputDirIfNotExist -and -not (Test-Path $v1Dir)) {
134+
New-Item -ItemType Directory -Path $v1Dir | Out-Null
135+
}
136+
137+
$v2Dir = $(Join-Path $outputDir "v2")
138+
if ($createOutputDirIfNotExist -and -not (Test-Path $v2Dir)) {
139+
New-Item -ItemType Directory -Path $v2Dir | Out-Null
140+
}
141+
$outputFolders = $outputDir.Split([System.IO.Path]::DirectorySeparatorChar)
142+
## get the last two directories of the output directory and add V1/V2 to disambiguate the namespaces
143+
$namespaceRoot = $(($outputFolders[-2..-1] | `
144+
ForEach-Object { $_.Substring(0,1).ToUpper() + $_.Substring(1) }) -join ".")
145+
146+
Invoke (Get-TspCommand $specFilePath $v1Dir -generateStub $generateStub -apiVersion "v1")
147+
Invoke (Get-TspCommand $specFilePath $v2Dir -generateStub $generateStub -apiVersion "v2")
148+
149+
if ($outputFolders.Contains("removed")) {
150+
$v2PreviewDir = $(Join-Path $outputDir "v2Preview")
151+
if ($createOutputDirIfNotExist -and -not (Test-Path $v2PreviewDir)) {
152+
New-Item -ItemType Directory -Path $v2PreviewDir | Out-Null
153+
}
154+
Invoke (Get-TspCommand $specFilePath $v2PreviewDir -generateStub $generateStub -apiVersion "v2preview")
155+
}
156+
157+
# exit if the generation failed
158+
if ($LASTEXITCODE -ne 0) {
159+
exit $LASTEXITCODE
160+
}
161+
}
162+
163+
164+
Export-ModuleMember -Function "Invoke"
165+
Export-ModuleMember -Function "Get-Mgmt-TspCommand"
166+
Export-ModuleMember -Function "Refresh-Mgmt-Build"
167+
Export-ModuleMember -Function "Compare-Paths"
168+
Export-ModuleMember -Function "Generate-Srv-Driven"
169+
Export-ModuleMember -Function "Generate-Versioning"

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Mgmt/src/InputTransformation/InputClientTransformer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ internal static class InputClientTransformer
2626
// There is no need to check sub-clients or custom code since it is specific to handle the above removing
2727
if (operationsToKeep.Count == 0) return null;
2828

29-
return new InputClient(client.Name, client.Namespace, client.CrossLanguageDefinitionId, client.Summary, client.Doc, operationsToKeep, client.Parameters, client.Parent);
29+
return new InputClient(client.Name, client.Namespace, client.CrossLanguageDefinitionId, client.Summary, client.Doc, operationsToKeep, client.Parameters, client.Parent, client.Children);
3030
}
3131

3232
private static IReadOnlyList<InputParameter> TransformInputOperationParameters(InputOperation operation)

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Mgmt/src/ManagementClientGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public ManagementClientGenerator(GeneratorContext context) : base(context)
4444
/// <summary>
4545
/// Customize the generation output for Azure client SDK.
4646
/// </summary>
47-
public override void Configure()
47+
protected override void Configure()
4848
{
4949
base.Configure();
5050
// Include Azure.ResourceManager

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Mgmt/src/ManagementOutputLibrary.cs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,35 @@ private IReadOnlyList<ResourceClientProvider> BuildResources()
2323
var result = new List<ResourceClientProvider>();
2424
foreach (var client in ManagementClientGenerator.Instance.InputLibrary.InputNamespace.Clients)
2525
{
26-
// A resource client should contain the decorator "Azure.ResourceManager.@resourceMetadata"
27-
var resourceMetadata = client.Decorators.FirstOrDefault(d => d.Name.Equals(KnownDecorators.ResourceMetadata));
28-
if (resourceMetadata is null)
29-
{
30-
continue;
31-
}
26+
BuildResourceCore(result, client);
27+
}
28+
return result;
29+
}
30+
31+
private static void BuildResourceCore(List<ResourceClientProvider> result, Microsoft.TypeSpec.Generator.Input.InputClient client)
32+
{
33+
// A resource client should contain the decorator "Azure.ResourceManager.@resourceMetadata"
34+
var resourceMetadata = client.Decorators.FirstOrDefault(d => d.Name.Equals(KnownDecorators.ResourceMetadata));
35+
if (resourceMetadata is not null)
36+
{
3237
var resource = new ResourceClientProvider(client);
3338
ManagementClientGenerator.Instance.AddTypeToKeep(resource.Name);
3439
result.Add(resource);
3540
}
36-
return result;
41+
42+
foreach (var child in client.Children)
43+
{
44+
BuildResourceCore(result, child);
45+
}
3746
}
3847

3948
/// <inheritdoc/>
4049
// TODO: generate collections
4150
protected override TypeProvider[] BuildTypeProviders()
4251
{
4352
var resources = BuildResources();
44-
return [.. base.BuildTypeProviders(), ArmOperation, GenericArmOperation, .. resources, .. resources.Select(r => r.Source)];
53+
var test = base.BuildTypeProviders();
54+
return [.. test, ArmOperation, GenericArmOperation, .. resources, .. resources.Select(r => r.Source)];
4555
}
4656
}
4757
}

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Mgmt/src/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"profiles": {
33
"Mgmt-TypeSpec": {
4-
"commandLineArgs": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.dll $(SolutionDir)/TestProjects/Local/Mgmt-TypeSpec -g MgmtClientGenerator",
4+
"commandLineArgs": "$(SolutionDir)/../dist/generator/Microsoft.TypeSpec.Generator.dll $(SolutionDir)/TestProjects/Local/Mgmt-TypeSpec -g MgmtClientGenerator",
55
"commandName": "Executable",
66
"executablePath": "dotnet"
77
}

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Mgmt/test/Azure.Generator.Mgmt.Tests/Azure.Generator.Mgmt.Tests.csproj

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,14 @@
5454
</ItemGroup>
5555

5656
<ItemGroup>
57-
<ProjectReference Include="..\..\..\..\..\http-client-csharp\generator\Azure.Generator\test\Azure.Generator.Tests.csproj" />
5857
<ProjectReference Include="..\..\..\..\..\http-client-csharp\generator\Azure.Generator\test\common\Azure.Generator.Tests.Common.csproj" />
5958
<ProjectReference Include="..\..\src\Azure.Generator.Mgmt.csproj" />
6059
</ItemGroup>
6160

61+
<ItemGroup>
62+
<None Update="TestHelpers\Configuration.json">
63+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
64+
</None>
65+
</ItemGroup>
66+
6267
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"output-folder": "./outputFolder",
3+
"project-folder": "./projectFolder",
4+
"unknown-bool-property": false,
5+
"package-name": "sample-library",
6+
"unknown-string-property": "unknownPropertyValue",
7+
"license": {
8+
"name": "MIT License",
9+
"company": "Microsoft Corporation",
10+
"link": "https://mit-license.org",
11+
"header": "Copyright (c) Microsoft Corporation. All rights reserved.\n\nLicensed under the MIT License.",
12+
"description": "Copyright (c) Microsoft Corporation\n\n\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\n\nof this software and associated documentation files (the “Software”), to deal\n\nin the Software without restriction, including without limitation the rights\n\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n\ncopies of the Software, and to permit persons to whom the Software is\n\nfurnished to do so, subject to the following conditions:\n\n\n\nThe above copyright notice and this permission notice shall be included in\n\nall copies or substantial portions of the Software.\n\n\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n\nTHE SOFTWARE.\n"
13+
}
14+
}

0 commit comments

Comments
 (0)