Skip to content

Commit

Permalink
Adopt versioning Cadl-Ranch specs (#5273)
Browse files Browse the repository at this point in the history
Fixes #3965

Filed Azure/cadl-ranch#779 as versioning is
implemented in tsp compiler.

---------

Co-authored-by: Jorge Rangel <[email protected]>
  • Loading branch information
JoshLove-msft and jorgerangel-msft authored Dec 5, 2024
1 parent fc51b1f commit 11d6f49
Show file tree
Hide file tree
Showing 157 changed files with 10,076 additions and 11 deletions.
12 changes: 8 additions & 4 deletions packages/http-client-csharp/eng/scripts/Generate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,6 @@ foreach ($directory in $directories) {
continue
}

if ($folders.Contains("versioning")) {
continue # TODO: adopt versioning cadl ranch specs https://github.com/microsoft/typespec/issues/3965
}

if ($failingSpecs.Contains($subPath)) {
Write-Host "Skipping $subPath" -ForegroundColor Yellow
continue
Expand All @@ -97,11 +93,19 @@ foreach ($directory in $directories) {
if (-not (Test-Path $generationDir)) {
New-Item -ItemType Directory -Path $generationDir | Out-Null
}

if ($folders.Contains("versioning")) {
Generate-Versioning $directory.FullName $generationDir -generateStub $stubbed
$cadlRanchLaunchProjects.Add($($folders -join "-") + "-v1", $("TestProjects/CadlRanch/$($subPath.Replace([System.IO.Path]::DirectorySeparatorChar, '/'))") + "/v1")
$cadlRanchLaunchProjects.Add($($folders -join "-") + "-v2", $("TestProjects/CadlRanch/$($subPath.Replace([System.IO.Path]::DirectorySeparatorChar, '/'))") + "/v2")
continue
}

$cadlRanchLaunchProjects.Add(($folders -join "-"), ("TestProjects/CadlRanch/$($subPath.Replace([System.IO.Path]::DirectorySeparatorChar, '/'))"))
if ($LaunchOnly) {
continue
}

Write-Host "Generating $subPath" -ForegroundColor Cyan
Invoke (Get-TspCommand $specFile $generationDir $stubbed)

Expand Down
50 changes: 49 additions & 1 deletion packages/http-client-csharp/eng/scripts/Generation.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ function Get-TspCommand {
[string]$specFile,
[string]$generationDir,
[bool]$generateStub = $false,
[string]$namespaceOverride = $null
[string]$namespaceOverride = $null,
[string]$apiVersion = $null
)
$command = "npx tsp compile $specFile"
$command += " --trace @typespec/http-client-csharp"
Expand All @@ -43,6 +44,10 @@ function Get-TspCommand {
if ($namespaceOverride) {
$command += " --option @typespec/http-client-csharp.namespace=$namespaceOverride"
}

if ($apiVersion) {
$command += " --option @typespec/http-client-csharp.api-version=$apiVersion"
}

return $command
}
Expand Down Expand Up @@ -101,9 +106,52 @@ function Generate-Srv-Driven {
}
}

function Generate-Versioning {
param (
[string]$specFilePath,
[string]$outputDir,
[bool]$generateStub = $false,
[bool]$createOutputDirIfNotExist = $true
)

$v1Dir = $(Join-Path $outputDir "v1")
if ($createOutputDirIfNotExist -and -not (Test-Path $v1Dir)) {
New-Item -ItemType Directory -Path $v1Dir | Out-Null
}

$v2Dir = $(Join-Path $outputDir "v2")
if ($createOutputDirIfNotExist -and -not (Test-Path $v2Dir)) {
New-Item -ItemType Directory -Path $v2Dir | Out-Null
}
$outputFolders = $outputDir.Split([System.IO.Path]::DirectorySeparatorChar)
## get the last two directories of the output directory and add V1/V2 to disambiguate the namespaces
$namespaceRoot = $(($outputFolders[-2..-1] | `
ForEach-Object { $_.Substring(0,1).ToUpper() + $_.Substring(1) }) -join ".")
$v1NamespaceOverride = $namespaceRoot + ".V1"
$v2NamespaceOverride = $namespaceRoot + ".V2"

Invoke (Get-TspCommand $specFilePath $v1Dir -generateStub $generateStub -apiVersion "v1" -namespaceOverride $v1NamespaceOverride)
Invoke (Get-TspCommand $specFilePath $v2Dir -generateStub $generateStub -apiVersion "v2" -namespaceOverride $v2NamespaceOverride)

if ($outputFolders.Contains("removed")) {
$v2PreviewDir = $(Join-Path $outputDir "v2Preview")
if ($createOutputDirIfNotExist -and -not (Test-Path $v2PreviewDir)) {
New-Item -ItemType Directory -Path $v2PreviewDir | Out-Null
}
$v2PreviewNamespaceOverride = $namespaceRoot + ".V2Preview"
Invoke (Get-TspCommand $specFilePath $v2PreviewDir -generateStub $generateStub -apiVersion "v2preview" -namespaceOverride $v2PreviewNamespaceOverride)
}

# exit if the generation failed
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
}


Export-ModuleMember -Function "Invoke"
Export-ModuleMember -Function "Get-TspCommand"
Export-ModuleMember -Function "Refresh-Build"
Export-ModuleMember -Function "Compare-Paths"
Export-ModuleMember -Function "Generate-Srv-Driven"
Export-ModuleMember -Function "Generate-Versioning"
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ foreach ($directory in $directories) {
if (-not (Test-Path $specFile)) {
$specFile = Join-Path $specsDirectory $subPath "main.tsp"
}

if ($subPath.Contains("versioning")) {
if ($subPath.Contains("v1")) {
# this will generate v1 and v2 so we only need to call it once for one of the versions
Generate-Versioning ($(Join-Path $specsDirectory $subPath) | Split-Path) $($outputDir | Split-Path) -createOutputDirIfNotExist $false
}
continue
}

$command = Get-TspCommand $specFile $outputDir
Invoke $command
Expand Down
16 changes: 12 additions & 4 deletions packages/http-client-csharp/eng/scripts/Test-CadlRanch.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,19 @@ foreach ($directory in $directories) {
$specFile = Join-Path $specsDirectory $subPath "client.tsp"
if (-not (Test-Path $specFile)) {
$specFile = Join-Path $specsDirectory $subPath "main.tsp"
}

if ($subPath.Contains("versioning")) {
if ($subPath.Contains("v1")) {
# this will generate v1 and v2 so we only need to call it once for one of the versions
Generate-Versioning ($(Join-Path $specsDirectory $subPath) | Split-Path) $($outputDir | Split-Path) -createOutputDirIfNotExist $false
}
}

$command = Get-TspCommand $specFile $outputDir
Invoke $command
else {
$command = Get-TspCommand $specFile $outputDir
Invoke $command
}

# exit if the generation failed
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
Expand All @@ -73,7 +82,6 @@ foreach ($directory in $directories) {
Generate-Srv-Driven $(Join-Path $specsDirectory $subPath) $outputDir -createOutputDirIfNotExist $false
}


Write-Host "Testing $subPath" -ForegroundColor Cyan
$command = "dotnet test $cadlRanchCsproj --filter `"FullyQualifiedName~$testFilter`""
Invoke $command
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ namespace Microsoft.Generator.CSharp.Input
{
public sealed class InputParameter
{
private readonly bool _isApiVersion;

public InputParameter(
string name,
string nameInRequest,
Expand All @@ -33,7 +35,7 @@ public InputParameter(
DefaultValue = defaultValue;
Kind = kind;
IsRequired = isRequired;
IsApiVersion = isApiVersion;
_isApiVersion = isApiVersion;
IsResourceParameter = isResourceParameter;
IsContentType = isContentType;
IsEndpoint = isEndpoint;
Expand All @@ -51,7 +53,7 @@ public InputParameter(
public InputConstant? DefaultValue { get; }
public InputOperationParameterKind Kind { get; }
public bool IsRequired { get; }
public bool IsApiVersion { get; }
public bool IsApiVersion => _isApiVersion || Type is InputEnumType enumType && enumType.Usage.HasFlag(InputModelTypeUsage.ApiVersionEnum);
public bool IsResourceParameter { get; }
public bool IsContentType { get; }
public bool IsEndpoint { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,66 @@
"commandName": "Executable",
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
},
"http-versioning-added-v1": {
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/added/v1 -p StubLibraryPlugin",
"commandName": "Executable",
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
},
"http-versioning-added-v2": {
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/added/v2 -p StubLibraryPlugin",
"commandName": "Executable",
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
},
"http-versioning-madeOptional-v1": {
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/madeOptional/v1 -p StubLibraryPlugin",
"commandName": "Executable",
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
},
"http-versioning-madeOptional-v2": {
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/madeOptional/v2 -p StubLibraryPlugin",
"commandName": "Executable",
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
},
"http-versioning-removed-v1": {
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/removed/v1 -p StubLibraryPlugin",
"commandName": "Executable",
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
},
"http-versioning-removed-v2": {
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/removed/v2 -p StubLibraryPlugin",
"commandName": "Executable",
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
},
"http-versioning-renamedFrom-v1": {
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/renamedFrom/v1 -p StubLibraryPlugin",
"commandName": "Executable",
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
},
"http-versioning-renamedFrom-v2": {
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/renamedFrom/v2 -p StubLibraryPlugin",
"commandName": "Executable",
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
},
"http-versioning-returnTypeChangedFrom-v1": {
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/returnTypeChangedFrom/v1 -p StubLibraryPlugin",
"commandName": "Executable",
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
},
"http-versioning-returnTypeChangedFrom-v2": {
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/returnTypeChangedFrom/v2 -p StubLibraryPlugin",
"commandName": "Executable",
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
},
"http-versioning-typeChangedFrom-v1": {
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/typeChangedFrom/v1 -p StubLibraryPlugin",
"commandName": "Executable",
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
},
"http-versioning-typeChangedFrom-v2": {
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/versioning/typeChangedFrom/v2 -p StubLibraryPlugin",
"commandName": "Executable",
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
},
"Unbranded-TypeSpec": {
"commandLineArgs": "$(SolutionDir)/TestProjects/Local/Unbranded-TypeSpec -p ClientModelPlugin",
"commandName": "Executable",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using NUnit.Framework;
using System;
using System.Linq;
using Versioning.Added.V1;
using Versioning.Added.V1.Models;

namespace TestProjects.CadlRanch.Tests.Http.Versioning.Added.V1
{
public class VersioningAddedV1Tests : CadlRanchTestBase
{
[CadlRanchTest]
public void TestAddedMembersV1Client()
{
/* verify ModelV1. */
var properties = typeof(ModelV1).GetProperties();
Assert.IsNotNull(properties);
Assert.AreEqual(2, properties.Length);
/* verify property UnionProp added in V2 is not present.*/
Assert.IsNull(typeof(ModelV1).GetProperty("UnionProp"));

/* verify EnumV1. */
Assert.True(typeof(EnumV1).IsEnum);
var enumValues = typeof(EnumV1).GetEnumNames();
Assert.IsNotNull(enumValues);
Assert.AreEqual(1, enumValues.Length);
/* verify added enum value EnumMemberV2. */
Assert.IsFalse(enumValues.Contains("EnumMemberV2"));

/* check existence of the added model ModelV2. */
Assert.IsNull(Type.GetType("Versioning.Added.V1.Models.ModelV2"));

/* check existence of the added enum EnumV2. */
Assert.IsNull(Type.GetType("Versioning.Added.V1.Models.EnumV2"));

/* check the added parameter. */
var methods = typeof(AddedClient).GetMethods().Where(m => m.Name == "V1" || m.Name == "V1Async");
Assert.IsNotNull(methods);
Assert.AreEqual(4, methods.Count());
var methodsArray = methods.ToArray();
foreach (var method in methodsArray)
{
Assert.IsFalse(method.GetParameters().Any(p => p.Name == "headerV2"));
}

/* check the existence of added method in V2. */
var addedMethods = typeof(AddedClient).GetMethods().Where(m => m.Name == "V2" || m.Name == "V2Async");
Assert.IsEmpty(addedMethods);

/* check the existence of added interface in V2. */
Assert.IsNull(Type.GetType("Versioning.Added.V1.InterfaceV2"));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Threading.Tasks;
using NUnit.Framework;
using System;
using System.Linq;
using Versioning.Added.V2;
using Versioning.Added.V2.Models;

namespace TestProjects.CadlRanch.Tests.Http.Versioning.Added.V2
{
public class VersioningAddedV2Tests : CadlRanchTestBase
{
[CadlRanchTest]
public void TestAddedMembersV2Client()
{
/* verify ModelV1. */
var properties = typeof(ModelV1).GetProperties();
Assert.IsNotNull(properties);
Assert.AreEqual(3, properties.Length);
/* verify added property UnionProp in V2.*/
Assert.IsNotNull(typeof(ModelV1).GetProperty("UnionProp"));

/* verify EnumV1. */
Assert.True(typeof(EnumV1).IsEnum);
var enumValues = typeof(EnumV1).GetEnumNames();
Assert.IsNotNull(enumValues);
Assert.AreEqual(2, enumValues.Length);
/* verify added enum value EnumMemberV2. */
Assert.IsTrue(enumValues.Contains("EnumMemberV2"));

/* check existence of the added model ModelV2. */
Assert.IsNotNull(Type.GetType("Versioning.Added.V2.Models.ModelV2"));

/* check existence of the added enum EnumV2. */
Assert.IsNotNull(Type.GetType("Versioning.Added.V2.Models.EnumV2"));

/* check the added parameter. */
var methods = typeof(AddedClient).GetMethods().Where(m => m.Name == "V1" || m.Name == "V1Async");
Assert.IsNotNull(methods);
Assert.AreEqual(4, methods.Count());
var methodsArray = methods.ToArray();
foreach (var method in methodsArray)
{
Assert.IsTrue(method.GetParameters().Any(p => p.Name == "headerV2"));
}

/* check the existence of added method in V2. */
var addedMethods = typeof(AddedClient).GetMethods().Where(m => m.Name == "V2" || m.Name == "V2Async");
Assert.IsNotNull(addedMethods);
Assert.AreEqual(4, addedMethods.Count());

/* check the existence of added interface in V2. */
Assert.IsNotNull(Type.GetType("Versioning.Added.V2.InterfaceV2"));
}

[CadlRanchTest]
public Task Versioning_Added_v1() => Test(async (host) =>
{
ModelV1 modelV1 = new ModelV1("foo", EnumV1.EnumMemberV2, BinaryData.FromObjectAsJson(10));
var response = await new AddedClient(host).V1Async("bar", modelV1);
Assert.AreEqual(200, response.GetRawResponse().Status);
Assert.AreEqual("foo", response.Value.Prop);
Assert.AreEqual(EnumV1.EnumMemberV2, response.Value.EnumProp);
Assert.AreEqual(10, response.Value.UnionProp.ToObjectFromJson<int>());
});

[CadlRanchTest]
public Task Versioning_Added_v2() => Test(async (host) =>
{
ModelV2 modelV2 = new ModelV2("foo", EnumV2.EnumMember, BinaryData.FromObjectAsJson("bar"));
var response = await new AddedClient(host).V2Async(modelV2);
Assert.AreEqual(200, response.GetRawResponse().Status);
Assert.AreEqual("foo", response.Value.Prop);
Assert.AreEqual(EnumV2.EnumMember, response.Value.EnumProp);
Assert.AreEqual("bar", response.Value.UnionProp.ToObjectFromJson<string>());
});

[CadlRanchTest]
public Task Versioning_Added_InterfaceV2() => Test(async (host) =>
{
ModelV2 modelV2 = new ModelV2("foo", EnumV2.EnumMember, BinaryData.FromObjectAsJson("bar"));
var response = await new AddedClient(host).GetInterfaceV2Client().V2InInterfaceAsync(modelV2);
Assert.AreEqual(200, response.GetRawResponse().Status);
Assert.AreEqual("foo", response.Value.Prop);
Assert.AreEqual(EnumV2.EnumMember, response.Value.EnumProp);
Assert.AreEqual("bar", response.Value.UnionProp.ToObjectFromJson<string>());
});
}
}
Loading

0 comments on commit 11d6f49

Please sign in to comment.