Skip to content

Commit 29fce94

Browse files
Ayeshas09asadali214aliasghar98
authored
feat: add api-version flag in sdk generate (#248)
Closes #249 What was added? - Added optional api-version flag to sdk generate to allow selecting the API version for multi-versioned builds. --------- Co-authored-by: Asad Ali <14asadali@gmail.com> Co-authored-by: Ali Asghar <75574550+aliasghar98@users.noreply.github.com>
1 parent 584fc52 commit 29fce94

6 files changed

Lines changed: 82 additions & 36 deletions

File tree

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ $ npm install -g @apimatic/cli
2424
$ apimatic COMMAND
2525
running command...
2626
$ apimatic (--version)
27-
@apimatic/cli/1.1.0-beta.7 win32-x64 node-v23.4.0
27+
@apimatic/cli/1.1.0-beta.8 win32-x64 node-v23.4.0
2828
$ apimatic --help [COMMAND]
2929
USAGE
3030
$ apimatic COMMAND
@@ -411,8 +411,8 @@ Generate an SDK for your API
411411

412412
```
413413
USAGE
414-
$ apimatic sdk generate -l csharp|java|php|python|ruby|typescript|go [-i <value>] [-d <value>] [-f] [--zip] [-k
415-
<value>]
414+
$ apimatic sdk generate -l csharp|java|php|python|ruby|typescript|go [-i <value>] [-d <value>] [--api-version
415+
<value>] [-f] [--zip] [-k <value>]
416416
417417
FLAGS
418418
-d, --destination=<value> directory where the SDK will be generated
@@ -422,7 +422,8 @@ FLAGS
422422
-k, --auth-key=<value> override current authentication state with an authentication key.
423423
-l, --language=<option> (required) programming language for SDK generation
424424
<options: csharp|java|php|python|ruby|typescript|go>
425-
--zip download the generated SDK as a .zip archive
425+
--api-version=<value> Version of the API to use for SDK generation (if multiple versions exist)
426+
--zip Download the generated SDK as a .zip archive
426427
427428
DESCRIPTION
428429
Generate an SDK for your API

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/actions/sdk/generate.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,41 @@ export class GenerateAction {
2828
sdkDirectory: DirectoryPath,
2929
language: Language,
3030
force: boolean,
31-
zipSdk: boolean
31+
zipSdk: boolean,
32+
apiVersion?: string
3233
): Promise<ActionResult> => {
3334
if (buildDirectory.isEqual(sdkDirectory)) {
3435
this.prompts.sameBuildAndSdkDir(buildDirectory);
3536
return ActionResult.failed();
3637
}
3738

3839
const versionedBuildContext = new VersionedBuildContext(buildDirectory);
39-
if (await versionedBuildContext.exists()) {
40-
const resolvedDirectory = await versionedBuildContext.getResolvedBuildDirectory();
41-
if (!resolvedDirectory) {
42-
this.prompts.versionedBuildEmpty();
40+
const versionedBuildResult = await versionedBuildContext.validate();
41+
if (versionedBuildResult.isValid) {
42+
if (versionedBuildResult.versions.length === 0) {
43+
this.prompts.versionedBuildEmpty(versionedBuildResult.versionsDirectory);
4344
return ActionResult.failed();
4445
}
45-
buildDirectory = resolvedDirectory;
46-
this.prompts.versionedBuild(versionedBuildContext.getRelativePath(resolvedDirectory));
46+
47+
let version: string;
48+
if (apiVersion) {
49+
if (!versionedBuildResult.versions.includes(apiVersion)) {
50+
this.prompts.versionNotFound();
51+
return ActionResult.failed();
52+
}
53+
version = apiVersion;
54+
} else if (versionedBuildResult.versions.length === 1) {
55+
version = versionedBuildResult.versions[0];
56+
} else {
57+
const selectedVersion = await this.prompts.selectVersion(versionedBuildResult.versions);
58+
if (!selectedVersion) {
59+
return ActionResult.cancelled();
60+
}
61+
version = selectedVersion;
62+
}
63+
64+
buildDirectory = versionedBuildResult.versionsDirectory.join(version);
65+
sdkDirectory = sdkDirectory.join(version);
4766
}
4867

4968
const specDirectory = buildDirectory.join("spec");

src/commands/sdk/generate.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ Supports multiple programming languages including Java, C#, Python, JavaScript,
2626
char: "d",
2727
description: "Directory where the SDK will be generated"
2828
}),
29+
"api-version": Flags.string({
30+
description: "Version of the API to use for SDK generation (if multiple versions exist)"
31+
}),
2932
...FlagsProvider.force,
3033
zip: Flags.boolean({
3134
default: false,
@@ -44,7 +47,7 @@ Supports multiple programming languages including Java, C#, Python, JavaScript,
4447

4548
async run() {
4649
const {
47-
flags: { language, input, destination, force, zip: zipSdk, "auth-key": authKey }
50+
flags: { language, input, destination, force, zip: zipSdk, "auth-key": authKey, "api-version": apiVersion }
4851
} = await this.parse(SdkGenerate);
4952

5053
const workingDirectory = DirectoryPath.createInput(input);
@@ -58,7 +61,7 @@ Supports multiple programming languages including Java, C#, Python, JavaScript,
5861

5962
intro("Generate SDK");
6063
const action = new GenerateAction(this.getConfigDir(), commandMetadata, authKey);
61-
const result = await action.execute(buildDirectory, sdkDirectory, language as Language, force, zipSdk);
64+
const result = await action.execute(buildDirectory, sdkDirectory, language as Language, force, zipSdk, apiVersion);
6265
outro(result);
6366
}
6467

src/prompts/sdk/generate.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isCancel, confirm, log } from "@clack/prompts";
1+
import { isCancel, confirm, log, select } from "@clack/prompts";
22
import { DirectoryPath } from "../../types/file/directoryPath.js";
33
import { format as f, } from "../format.js";
44
import { Result } from "neverthrow";
@@ -47,13 +47,26 @@ export class SdkGeneratePrompts {
4747
log.error(serviceError.errorMessage);
4848
}
4949

50-
public versionedBuildEmpty() {
51-
const message = `The ${f.var("versioned_docs")} directory is empty or contains no valid versions.`;
50+
public versionedBuildEmpty(directory: DirectoryPath) {
51+
const message = `The ${f.var(directory.leafName())} directory is either empty or invalid: ${f.path(directory)}`;
5252
this.logGenerationError(message);
5353
}
5454

55-
public versionedBuild(relativePath: string) {
56-
log.warning(`SDK Generation for multi-versioned builds is not supported. Generating SDK for ${f.var(relativePath)} instead.`);
55+
public versionNotFound() {
56+
this.logGenerationError(`The API version is invalid.`);
57+
}
58+
59+
public async selectVersion(versions: string[]): Promise<string | undefined> {
60+
const version = await select({
61+
message: "Select an API version for SDK generation:",
62+
options: versions.map((v) => ({ label: v, value: v }))
63+
});
64+
65+
if (isCancel(version)) {
66+
return undefined;
67+
}
68+
69+
return version;
5770
}
5871

5972
public sdkGenerated(sdk: DirectoryPath) {
Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,37 @@
1-
import * as path from "path";
21
import { FileService } from "../infrastructure/file-service.js";
32
import { DirectoryPath } from "./file/directoryPath.js";
3+
import { BuildContext } from "./build-context.js";
4+
5+
type VersionedBuildValidateResult = { isValid: false; } | {
6+
isValid: true;
7+
versionsDirectory: DirectoryPath;
8+
versions: string[];
9+
};
410

511
export class VersionedBuildContext {
612
private readonly fileService = new FileService();
7-
private readonly versionedDocsDir: DirectoryPath;
13+
private readonly buildDirectory: DirectoryPath;
814

915
constructor(buildDirectory: DirectoryPath) {
10-
this.versionedDocsDir = buildDirectory.join("versioned_docs");
11-
}
12-
13-
public async exists(): Promise<boolean> {
14-
return this.fileService.directoryExists(this.versionedDocsDir);
15-
}
16-
17-
public async getResolvedBuildDirectory(): Promise<DirectoryPath | null> {
18-
const subDirs = await this.fileService.getSubDirectoriesPaths(this.versionedDocsDir);
19-
if (subDirs.length === 0)
20-
return null;
21-
return subDirs[0];
16+
this.buildDirectory = buildDirectory;
2217
}
2318

24-
public getRelativePath(resolvedDirectory: DirectoryPath): string {
25-
return path.join(".", "src", "versioned_docs", resolvedDirectory.leafName());
19+
public async validate(): Promise<VersionedBuildValidateResult> {
20+
const buildContext = new BuildContext(this.buildDirectory);
21+
if (!(await buildContext.validate())) {
22+
return { isValid: false };
23+
}
24+
const config = await buildContext.getBuildFileContents();
25+
if (!("generateVersionedPortal" in config)) {
26+
return { isValid: false };
27+
}
28+
const versionsPath = (config.versionsPath as string) ?? "versioned_docs";
29+
const versionsDirectory = this.buildDirectory.join(versionsPath);
30+
if (!(await this.fileService.directoryExists(versionsDirectory))) {
31+
return { isValid: false };
32+
}
33+
const versionsDirs = await this.fileService.getSubDirectoriesPaths(versionsDirectory);
34+
const versions = versionsDirs.map((dir) => dir.leafName());
35+
return { isValid: true, versionsDirectory, versions };
2636
}
2737
}

0 commit comments

Comments
 (0)