From 87e2e0c50f3809627d22ae26f463e8629e5f595b Mon Sep 17 00:00:00 2001 From: Chenjie Shi Date: Thu, 9 May 2024 11:19:28 +0800 Subject: [PATCH] [tcgc] `getDefaultApiVersion` and service version enum hornor api version config (#801) resolve: https://github.com/Azure/typespec-azure/issues/746 --------- Co-authored-by: iscai-msft Co-authored-by: iscai-msft <43154838+iscai-msft@users.noreply.github.com> --- .../tcgc_fix_api_version-2024-4-8-16-21-13.md | 7 ++ .../src/public-utils.ts | 13 ++- .../src/types.ts | 10 +++ .../test/decorators.test.ts | 4 +- .../test/public-utils.test.ts | 76 ++++++++++++++++ .../test/types.test.ts | 88 +++++++++++++++++++ 6 files changed, 195 insertions(+), 3 deletions(-) create mode 100644 .chronus/changes/tcgc_fix_api_version-2024-4-8-16-21-13.md diff --git a/.chronus/changes/tcgc_fix_api_version-2024-4-8-16-21-13.md b/.chronus/changes/tcgc_fix_api_version-2024-4-8-16-21-13.md new file mode 100644 index 0000000000..59c9f2648f --- /dev/null +++ b/.chronus/changes/tcgc_fix_api_version-2024-4-8-16-21-13.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@azure-tools/typespec-client-generator-core" +--- + +`getDefaultApiVersion` and service version enum hornor api version config \ No newline at end of file diff --git a/packages/typespec-client-generator-core/src/public-utils.ts b/packages/typespec-client-generator-core/src/public-utils.ts index 3d173b3809..dc31fa009d 100644 --- a/packages/typespec-client-generator-core/src/public-utils.ts +++ b/packages/typespec-client-generator-core/src/public-utils.ts @@ -55,7 +55,18 @@ export function getDefaultApiVersion( serviceNamespace: Namespace ): Version | undefined { try { - const versions = getVersions(context.program, serviceNamespace)[1]!.getVersions(); + let versions = getVersions(context.program, serviceNamespace)[1]!.getVersions(); + // filter with specific api version + if ( + context.apiVersion !== undefined && + context.apiVersion !== "latest" && + context.apiVersion !== "all" + ) { + const index = versions.findIndex((version) => version.value === context.apiVersion); + if (index >= 0) { + versions = versions.slice(0, index + 1); + } + } // follow versioning principals of the versioning library and return last in list return versions[versions.length - 1]; } catch (e) { diff --git a/packages/typespec-client-generator-core/src/types.ts b/packages/typespec-client-generator-core/src/types.ts index 0dfb31d5a8..965e3df0c8 100644 --- a/packages/typespec-client-generator-core/src/types.ts +++ b/packages/typespec-client-generator-core/src/types.ts @@ -1479,6 +1479,16 @@ export function getAllModelsWithDiagnostics( if (versionMap && versionMap.getVersions()[0]) { // create sdk enum for versions enum const sdkVersionsEnum = getSdkEnum(context, versionMap.getVersions()[0].enumMember.enum); + if ( + context.apiVersion !== undefined && + context.apiVersion !== "latest" && + context.apiVersion !== "all" + ) { + const index = sdkVersionsEnum.values.findIndex((v) => v.value === context.apiVersion); + if (index >= 0) { + sdkVersionsEnum.values = sdkVersionsEnum.values.slice(0, index + 1); + } + } updateUsageOfModel(context, UsageFlags.ApiVersionEnum, sdkVersionsEnum); } } diff --git a/packages/typespec-client-generator-core/test/decorators.test.ts b/packages/typespec-client-generator-core/test/decorators.test.ts index c1bcb447a3..f864be7928 100644 --- a/packages/typespec-client-generator-core/test/decorators.test.ts +++ b/packages/typespec-client-generator-core/test/decorators.test.ts @@ -3010,7 +3010,7 @@ describe("typespec-client-generator-core: decorators", () => { ok(versions); deepStrictEqual( versions.values.map((v) => v.value), - ["v1", "v2", "v3"] + ["v1", "v2"] ); }); @@ -3099,7 +3099,7 @@ describe("typespec-client-generator-core: decorators", () => { ok(versions); deepStrictEqual( versions.values.map((v) => v.value), - ["v1", "v2", "v3"] + ["v1"] ); }); diff --git a/packages/typespec-client-generator-core/test/public-utils.test.ts b/packages/typespec-client-generator-core/test/public-utils.test.ts index 1afc6e7f67..b26677aa44 100644 --- a/packages/typespec-client-generator-core/test/public-utils.test.ts +++ b/packages/typespec-client-generator-core/test/public-utils.test.ts @@ -2,6 +2,7 @@ import { AzureCoreTestLibrary } from "@azure-tools/typespec-azure-core/testing"; import { Model, ModelProperty, + Namespace, Operation, ignoreDiagnostics, listServices, @@ -146,6 +147,81 @@ describe("typespec-client-generator-core: public-utils", () => { const serviceNamespace = getServiceNamespace(); ok(!getDefaultApiVersion(runner.context, serviceNamespace)); }); + + it("get with all", async () => { + const runnerWithVersion = await createSdkTestRunner({ + "api-version": "all", + emitterName: "@azure-tools/typespec-python", + }); + + const { MyService } = await runnerWithVersion.compile(` + enum Versions { + v1_0_0: "1.0", + v1_0_1: "1.0.1", + v1_1_0: "1.1.0", + } + + @versioned(Versions) + @service({}) + @test namespace MyService {}; + `); + const defaultApiVersion = getDefaultApiVersion( + runnerWithVersion.context, + MyService as Namespace + ); + ok(defaultApiVersion); + strictEqual(defaultApiVersion.value, "1.1.0"); + }); + + it("get with latest", async () => { + const runnerWithVersion = await createSdkTestRunner({ + "api-version": "latest", + emitterName: "@azure-tools/typespec-python", + }); + + const { MyService } = await runnerWithVersion.compile(` + enum Versions { + v1_0_0: "1.0", + v1_0_1: "1.0.1", + v1_1_0: "1.1.0", + } + + @versioned(Versions) + @service({}) + @test namespace MyService {}; + `); + const defaultApiVersion = getDefaultApiVersion( + runnerWithVersion.context, + MyService as Namespace + ); + ok(defaultApiVersion); + strictEqual(defaultApiVersion.value, "1.1.0"); + }); + + it("get with specific version", async () => { + const runnerWithVersion = await createSdkTestRunner({ + "api-version": "1.0.1", + emitterName: "@azure-tools/typespec-python", + }); + + const { MyService } = await runnerWithVersion.compile(` + enum Versions { + v1_0_0: "1.0", + v1_0_1: "1.0.1", + v1_1_0: "1.1.0", + } + + @versioned(Versions) + @service({}) + @test namespace MyService {}; + `); + const defaultApiVersion = getDefaultApiVersion( + runnerWithVersion.context, + MyService as Namespace + ); + ok(defaultApiVersion); + strictEqual(defaultApiVersion.value, "1.0.1"); + }); }); describe("isApiVersion", () => { it("is api version query", async () => { diff --git a/packages/typespec-client-generator-core/test/types.test.ts b/packages/typespec-client-generator-core/test/types.test.ts index e27e4bd31f..2f105c057b 100644 --- a/packages/typespec-client-generator-core/test/types.test.ts +++ b/packages/typespec-client-generator-core/test/types.test.ts @@ -1710,6 +1710,94 @@ describe("typespec-client-generator-core: types", () => { strictEqual(enums.length, 1); strictEqual(enums[0].name, "Versions"); strictEqual(enums[0].usage, UsageFlags.ApiVersionEnum); + deepStrictEqual( + enums[0].values.map((x) => x.value), + ["v1", "v2"] + ); + }); + + it("versioned enums with all", async () => { + const runnerWithVersion = await createSdkTestRunner({ + "api-version": "all", + emitterName: "@azure-tools/typespec-python", + }); + + await runnerWithVersion.compile( + ` + @versioned(Versions) + @service() + namespace DemoService; + + enum Versions { + v1, + v2, + } + ` + ); + const enums = runnerWithVersion.context.experimental_sdkPackage.enums; + strictEqual(enums.length, 1); + strictEqual(enums[0].name, "Versions"); + strictEqual(enums[0].usage, UsageFlags.ApiVersionEnum); + deepStrictEqual( + enums[0].values.map((x) => x.value), + ["v1", "v2"] + ); + }); + + it("versioned enums with latest", async () => { + const runnerWithVersion = await createSdkTestRunner({ + "api-version": "latest", + emitterName: "@azure-tools/typespec-python", + }); + + await runnerWithVersion.compile( + ` + @versioned(Versions) + @service() + namespace DemoService; + + enum Versions { + v1, + v2, + } + ` + ); + const enums = runnerWithVersion.context.experimental_sdkPackage.enums; + strictEqual(enums.length, 1); + strictEqual(enums[0].name, "Versions"); + strictEqual(enums[0].usage, UsageFlags.ApiVersionEnum); + deepStrictEqual( + enums[0].values.map((x) => x.value), + ["v1", "v2"] + ); + }); + + it("versioned enums with specific version", async () => { + const runnerWithVersion = await createSdkTestRunner({ + "api-version": "v1", + emitterName: "@azure-tools/typespec-python", + }); + + await runnerWithVersion.compile( + ` + @versioned(Versions) + @service() + namespace DemoService; + + enum Versions { + v1, + v2, + } + ` + ); + const enums = runnerWithVersion.context.experimental_sdkPackage.enums; + strictEqual(enums.length, 1); + strictEqual(enums[0].name, "Versions"); + strictEqual(enums[0].usage, UsageFlags.ApiVersionEnum); + deepStrictEqual( + enums[0].values.map((x) => x.value), + ["v1"] + ); }); it("usage propagation for enum value", async () => {