Skip to content

Commit 11d6f49

Browse files
Adopt versioning Cadl-Ranch specs (microsoft#5273)
Fixes microsoft#3965 Filed Azure/cadl-ranch#779 as versioning is implemented in tsp compiler. --------- Co-authored-by: Jorge Rangel <102122018+jorgerangel-msft@users.noreply.github.com>
1 parent fc51b1f commit 11d6f49

File tree

157 files changed

+10076
-11
lines changed

Some content is hidden

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

157 files changed

+10076
-11
lines changed

packages/http-client-csharp/eng/scripts/Generate.ps1

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,6 @@ foreach ($directory in $directories) {
7979
continue
8080
}
8181

82-
if ($folders.Contains("versioning")) {
83-
continue # TODO: adopt versioning cadl ranch specs https://github.com/microsoft/typespec/issues/3965
84-
}
85-
8682
if ($failingSpecs.Contains($subPath)) {
8783
Write-Host "Skipping $subPath" -ForegroundColor Yellow
8884
continue
@@ -97,11 +93,19 @@ foreach ($directory in $directories) {
9793
if (-not (Test-Path $generationDir)) {
9894
New-Item -ItemType Directory -Path $generationDir | Out-Null
9995
}
96+
97+
if ($folders.Contains("versioning")) {
98+
Generate-Versioning $directory.FullName $generationDir -generateStub $stubbed
99+
$cadlRanchLaunchProjects.Add($($folders -join "-") + "-v1", $("TestProjects/CadlRanch/$($subPath.Replace([System.IO.Path]::DirectorySeparatorChar, '/'))") + "/v1")
100+
$cadlRanchLaunchProjects.Add($($folders -join "-") + "-v2", $("TestProjects/CadlRanch/$($subPath.Replace([System.IO.Path]::DirectorySeparatorChar, '/'))") + "/v2")
101+
continue
102+
}
100103

101104
$cadlRanchLaunchProjects.Add(($folders -join "-"), ("TestProjects/CadlRanch/$($subPath.Replace([System.IO.Path]::DirectorySeparatorChar, '/'))"))
102105
if ($LaunchOnly) {
103106
continue
104107
}
108+
105109
Write-Host "Generating $subPath" -ForegroundColor Cyan
106110
Invoke (Get-TspCommand $specFile $generationDir $stubbed)
107111

packages/http-client-csharp/eng/scripts/Generation.psm1

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ function Get-TspCommand {
2525
[string]$specFile,
2626
[string]$generationDir,
2727
[bool]$generateStub = $false,
28-
[string]$namespaceOverride = $null
28+
[string]$namespaceOverride = $null,
29+
[string]$apiVersion = $null
2930
)
3031
$command = "npx tsp compile $specFile"
3132
$command += " --trace @typespec/http-client-csharp"
@@ -43,6 +44,10 @@ function Get-TspCommand {
4344
if ($namespaceOverride) {
4445
$command += " --option @typespec/http-client-csharp.namespace=$namespaceOverride"
4546
}
47+
48+
if ($apiVersion) {
49+
$command += " --option @typespec/http-client-csharp.api-version=$apiVersion"
50+
}
4651

4752
return $command
4853
}
@@ -101,9 +106,52 @@ function Generate-Srv-Driven {
101106
}
102107
}
103108

109+
function Generate-Versioning {
110+
param (
111+
[string]$specFilePath,
112+
[string]$outputDir,
113+
[bool]$generateStub = $false,
114+
[bool]$createOutputDirIfNotExist = $true
115+
)
116+
117+
$v1Dir = $(Join-Path $outputDir "v1")
118+
if ($createOutputDirIfNotExist -and -not (Test-Path $v1Dir)) {
119+
New-Item -ItemType Directory -Path $v1Dir | Out-Null
120+
}
121+
122+
$v2Dir = $(Join-Path $outputDir "v2")
123+
if ($createOutputDirIfNotExist -and -not (Test-Path $v2Dir)) {
124+
New-Item -ItemType Directory -Path $v2Dir | Out-Null
125+
}
126+
$outputFolders = $outputDir.Split([System.IO.Path]::DirectorySeparatorChar)
127+
## get the last two directories of the output directory and add V1/V2 to disambiguate the namespaces
128+
$namespaceRoot = $(($outputFolders[-2..-1] | `
129+
ForEach-Object { $_.Substring(0,1).ToUpper() + $_.Substring(1) }) -join ".")
130+
$v1NamespaceOverride = $namespaceRoot + ".V1"
131+
$v2NamespaceOverride = $namespaceRoot + ".V2"
132+
133+
Invoke (Get-TspCommand $specFilePath $v1Dir -generateStub $generateStub -apiVersion "v1" -namespaceOverride $v1NamespaceOverride)
134+
Invoke (Get-TspCommand $specFilePath $v2Dir -generateStub $generateStub -apiVersion "v2" -namespaceOverride $v2NamespaceOverride)
135+
136+
if ($outputFolders.Contains("removed")) {
137+
$v2PreviewDir = $(Join-Path $outputDir "v2Preview")
138+
if ($createOutputDirIfNotExist -and -not (Test-Path $v2PreviewDir)) {
139+
New-Item -ItemType Directory -Path $v2PreviewDir | Out-Null
140+
}
141+
$v2PreviewNamespaceOverride = $namespaceRoot + ".V2Preview"
142+
Invoke (Get-TspCommand $specFilePath $v2PreviewDir -generateStub $generateStub -apiVersion "v2preview" -namespaceOverride $v2PreviewNamespaceOverride)
143+
}
144+
145+
# exit if the generation failed
146+
if ($LASTEXITCODE -ne 0) {
147+
exit $LASTEXITCODE
148+
}
149+
}
150+
104151

105152
Export-ModuleMember -Function "Invoke"
106153
Export-ModuleMember -Function "Get-TspCommand"
107154
Export-ModuleMember -Function "Refresh-Build"
108155
Export-ModuleMember -Function "Compare-Paths"
109156
Export-ModuleMember -Function "Generate-Srv-Driven"
157+
Export-ModuleMember -Function "Generate-Versioning"

packages/http-client-csharp/eng/scripts/Get-CadlRanch-Coverage.ps1

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ foreach ($directory in $directories) {
3737
if (-not (Test-Path $specFile)) {
3838
$specFile = Join-Path $specsDirectory $subPath "main.tsp"
3939
}
40+
41+
if ($subPath.Contains("versioning")) {
42+
if ($subPath.Contains("v1")) {
43+
# this will generate v1 and v2 so we only need to call it once for one of the versions
44+
Generate-Versioning ($(Join-Path $specsDirectory $subPath) | Split-Path) $($outputDir | Split-Path) -createOutputDirIfNotExist $false
45+
}
46+
continue
47+
}
4048

4149
$command = Get-TspCommand $specFile $outputDir
4250
Invoke $command

packages/http-client-csharp/eng/scripts/Test-CadlRanch.ps1

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,19 @@ foreach ($directory in $directories) {
5959
$specFile = Join-Path $specsDirectory $subPath "client.tsp"
6060
if (-not (Test-Path $specFile)) {
6161
$specFile = Join-Path $specsDirectory $subPath "main.tsp"
62+
}
63+
64+
if ($subPath.Contains("versioning")) {
65+
if ($subPath.Contains("v1")) {
66+
# this will generate v1 and v2 so we only need to call it once for one of the versions
67+
Generate-Versioning ($(Join-Path $specsDirectory $subPath) | Split-Path) $($outputDir | Split-Path) -createOutputDirIfNotExist $false
68+
}
6269
}
63-
64-
$command = Get-TspCommand $specFile $outputDir
65-
Invoke $command
70+
else {
71+
$command = Get-TspCommand $specFile $outputDir
72+
Invoke $command
73+
}
74+
6675
# exit if the generation failed
6776
if ($LASTEXITCODE -ne 0) {
6877
exit $LASTEXITCODE
@@ -73,7 +82,6 @@ foreach ($directory in $directories) {
7382
Generate-Srv-Driven $(Join-Path $specsDirectory $subPath) $outputDir -createOutputDirIfNotExist $false
7483
}
7584

76-
7785
Write-Host "Testing $subPath" -ForegroundColor Cyan
7886
$command = "dotnet test $cadlRanchCsproj --filter `"FullyQualifiedName~$testFilter`""
7987
Invoke $command

packages/http-client-csharp/generator/Microsoft.Generator.CSharp.Input/src/InputTypes/InputParameter.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ namespace Microsoft.Generator.CSharp.Input
77
{
88
public sealed class InputParameter
99
{
10+
private readonly bool _isApiVersion;
11+
1012
public InputParameter(
1113
string name,
1214
string nameInRequest,
@@ -33,7 +35,7 @@ public InputParameter(
3335
DefaultValue = defaultValue;
3436
Kind = kind;
3537
IsRequired = isRequired;
36-
IsApiVersion = isApiVersion;
38+
_isApiVersion = isApiVersion;
3739
IsResourceParameter = isResourceParameter;
3840
IsContentType = isContentType;
3941
IsEndpoint = isEndpoint;
@@ -51,7 +53,7 @@ public InputParameter(
5153
public InputConstant? DefaultValue { get; }
5254
public InputOperationParameterKind Kind { get; }
5355
public bool IsRequired { get; }
54-
public bool IsApiVersion { get; }
56+
public bool IsApiVersion => _isApiVersion || Type is InputEnumType enumType && enumType.Usage.HasFlag(InputModelTypeUsage.ApiVersionEnum);
5557
public bool IsResourceParameter { get; }
5658
public bool IsContentType { get; }
5759
public bool IsEndpoint { get; }

packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Properties/launchSettings.json

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,66 @@
260260
"commandName": "Executable",
261261
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
262262
},
263+
"http-versioning-added-v1": {
264+
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/added/v1 -p StubLibraryPlugin",
265+
"commandName": "Executable",
266+
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
267+
},
268+
"http-versioning-added-v2": {
269+
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/added/v2 -p StubLibraryPlugin",
270+
"commandName": "Executable",
271+
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
272+
},
273+
"http-versioning-madeOptional-v1": {
274+
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/madeOptional/v1 -p StubLibraryPlugin",
275+
"commandName": "Executable",
276+
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
277+
},
278+
"http-versioning-madeOptional-v2": {
279+
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/madeOptional/v2 -p StubLibraryPlugin",
280+
"commandName": "Executable",
281+
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
282+
},
283+
"http-versioning-removed-v1": {
284+
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/removed/v1 -p StubLibraryPlugin",
285+
"commandName": "Executable",
286+
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
287+
},
288+
"http-versioning-removed-v2": {
289+
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/removed/v2 -p StubLibraryPlugin",
290+
"commandName": "Executable",
291+
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
292+
},
293+
"http-versioning-renamedFrom-v1": {
294+
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/renamedFrom/v1 -p StubLibraryPlugin",
295+
"commandName": "Executable",
296+
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
297+
},
298+
"http-versioning-renamedFrom-v2": {
299+
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/renamedFrom/v2 -p StubLibraryPlugin",
300+
"commandName": "Executable",
301+
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
302+
},
303+
"http-versioning-returnTypeChangedFrom-v1": {
304+
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/returnTypeChangedFrom/v1 -p StubLibraryPlugin",
305+
"commandName": "Executable",
306+
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
307+
},
308+
"http-versioning-returnTypeChangedFrom-v2": {
309+
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/returnTypeChangedFrom/v2 -p StubLibraryPlugin",
310+
"commandName": "Executable",
311+
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
312+
},
313+
"http-versioning-typeChangedFrom-v1": {
314+
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/typeChangedFrom/v1 -p StubLibraryPlugin",
315+
"commandName": "Executable",
316+
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
317+
},
318+
"http-versioning-typeChangedFrom-v2": {
319+
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/typeChangedFrom/v2 -p StubLibraryPlugin",
320+
"commandName": "Executable",
321+
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
322+
},
263323
"Unbranded-TypeSpec": {
264324
"commandLineArgs": "$(SolutionDir)/TestProjects/Local/Unbranded-TypeSpec -p ClientModelPlugin",
265325
"commandName": "Executable",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using NUnit.Framework;
5+
using System;
6+
using System.Linq;
7+
using Versioning.Added.V1;
8+
using Versioning.Added.V1.Models;
9+
10+
namespace TestProjects.CadlRanch.Tests.Http.Versioning.Added.V1
11+
{
12+
public class VersioningAddedV1Tests : CadlRanchTestBase
13+
{
14+
[CadlRanchTest]
15+
public void TestAddedMembersV1Client()
16+
{
17+
/* verify ModelV1. */
18+
var properties = typeof(ModelV1).GetProperties();
19+
Assert.IsNotNull(properties);
20+
Assert.AreEqual(2, properties.Length);
21+
/* verify property UnionProp added in V2 is not present.*/
22+
Assert.IsNull(typeof(ModelV1).GetProperty("UnionProp"));
23+
24+
/* verify EnumV1. */
25+
Assert.True(typeof(EnumV1).IsEnum);
26+
var enumValues = typeof(EnumV1).GetEnumNames();
27+
Assert.IsNotNull(enumValues);
28+
Assert.AreEqual(1, enumValues.Length);
29+
/* verify added enum value EnumMemberV2. */
30+
Assert.IsFalse(enumValues.Contains("EnumMemberV2"));
31+
32+
/* check existence of the added model ModelV2. */
33+
Assert.IsNull(Type.GetType("Versioning.Added.V1.Models.ModelV2"));
34+
35+
/* check existence of the added enum EnumV2. */
36+
Assert.IsNull(Type.GetType("Versioning.Added.V1.Models.EnumV2"));
37+
38+
/* check the added parameter. */
39+
var methods = typeof(AddedClient).GetMethods().Where(m => m.Name == "V1" || m.Name == "V1Async");
40+
Assert.IsNotNull(methods);
41+
Assert.AreEqual(4, methods.Count());
42+
var methodsArray = methods.ToArray();
43+
foreach (var method in methodsArray)
44+
{
45+
Assert.IsFalse(method.GetParameters().Any(p => p.Name == "headerV2"));
46+
}
47+
48+
/* check the existence of added method in V2. */
49+
var addedMethods = typeof(AddedClient).GetMethods().Where(m => m.Name == "V2" || m.Name == "V2Async");
50+
Assert.IsEmpty(addedMethods);
51+
52+
/* check the existence of added interface in V2. */
53+
Assert.IsNull(Type.GetType("Versioning.Added.V1.InterfaceV2"));
54+
}
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Threading.Tasks;
5+
using NUnit.Framework;
6+
using System;
7+
using System.Linq;
8+
using Versioning.Added.V2;
9+
using Versioning.Added.V2.Models;
10+
11+
namespace TestProjects.CadlRanch.Tests.Http.Versioning.Added.V2
12+
{
13+
public class VersioningAddedV2Tests : CadlRanchTestBase
14+
{
15+
[CadlRanchTest]
16+
public void TestAddedMembersV2Client()
17+
{
18+
/* verify ModelV1. */
19+
var properties = typeof(ModelV1).GetProperties();
20+
Assert.IsNotNull(properties);
21+
Assert.AreEqual(3, properties.Length);
22+
/* verify added property UnionProp in V2.*/
23+
Assert.IsNotNull(typeof(ModelV1).GetProperty("UnionProp"));
24+
25+
/* verify EnumV1. */
26+
Assert.True(typeof(EnumV1).IsEnum);
27+
var enumValues = typeof(EnumV1).GetEnumNames();
28+
Assert.IsNotNull(enumValues);
29+
Assert.AreEqual(2, enumValues.Length);
30+
/* verify added enum value EnumMemberV2. */
31+
Assert.IsTrue(enumValues.Contains("EnumMemberV2"));
32+
33+
/* check existence of the added model ModelV2. */
34+
Assert.IsNotNull(Type.GetType("Versioning.Added.V2.Models.ModelV2"));
35+
36+
/* check existence of the added enum EnumV2. */
37+
Assert.IsNotNull(Type.GetType("Versioning.Added.V2.Models.EnumV2"));
38+
39+
/* check the added parameter. */
40+
var methods = typeof(AddedClient).GetMethods().Where(m => m.Name == "V1" || m.Name == "V1Async");
41+
Assert.IsNotNull(methods);
42+
Assert.AreEqual(4, methods.Count());
43+
var methodsArray = methods.ToArray();
44+
foreach (var method in methodsArray)
45+
{
46+
Assert.IsTrue(method.GetParameters().Any(p => p.Name == "headerV2"));
47+
}
48+
49+
/* check the existence of added method in V2. */
50+
var addedMethods = typeof(AddedClient).GetMethods().Where(m => m.Name == "V2" || m.Name == "V2Async");
51+
Assert.IsNotNull(addedMethods);
52+
Assert.AreEqual(4, addedMethods.Count());
53+
54+
/* check the existence of added interface in V2. */
55+
Assert.IsNotNull(Type.GetType("Versioning.Added.V2.InterfaceV2"));
56+
}
57+
58+
[CadlRanchTest]
59+
public Task Versioning_Added_v1() => Test(async (host) =>
60+
{
61+
ModelV1 modelV1 = new ModelV1("foo", EnumV1.EnumMemberV2, BinaryData.FromObjectAsJson(10));
62+
var response = await new AddedClient(host).V1Async("bar", modelV1);
63+
Assert.AreEqual(200, response.GetRawResponse().Status);
64+
Assert.AreEqual("foo", response.Value.Prop);
65+
Assert.AreEqual(EnumV1.EnumMemberV2, response.Value.EnumProp);
66+
Assert.AreEqual(10, response.Value.UnionProp.ToObjectFromJson<int>());
67+
});
68+
69+
[CadlRanchTest]
70+
public Task Versioning_Added_v2() => Test(async (host) =>
71+
{
72+
ModelV2 modelV2 = new ModelV2("foo", EnumV2.EnumMember, BinaryData.FromObjectAsJson("bar"));
73+
var response = await new AddedClient(host).V2Async(modelV2);
74+
Assert.AreEqual(200, response.GetRawResponse().Status);
75+
Assert.AreEqual("foo", response.Value.Prop);
76+
Assert.AreEqual(EnumV2.EnumMember, response.Value.EnumProp);
77+
Assert.AreEqual("bar", response.Value.UnionProp.ToObjectFromJson<string>());
78+
});
79+
80+
[CadlRanchTest]
81+
public Task Versioning_Added_InterfaceV2() => Test(async (host) =>
82+
{
83+
ModelV2 modelV2 = new ModelV2("foo", EnumV2.EnumMember, BinaryData.FromObjectAsJson("bar"));
84+
var response = await new AddedClient(host).GetInterfaceV2Client().V2InInterfaceAsync(modelV2);
85+
Assert.AreEqual(200, response.GetRawResponse().Status);
86+
Assert.AreEqual("foo", response.Value.Prop);
87+
Assert.AreEqual(EnumV2.EnumMember, response.Value.EnumProp);
88+
Assert.AreEqual("bar", response.Value.UnionProp.ToObjectFromJson<string>());
89+
});
90+
}
91+
}

0 commit comments

Comments
 (0)