Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ $ npm install -g @apimatic/cli
$ apimatic COMMAND
running command...
$ apimatic (--version)
@apimatic/cli/1.1.0-beta.7 win32-x64 node-v23.4.0
@apimatic/cli/1.1.0-beta.8 win32-x64 node-v23.4.0
$ apimatic --help [COMMAND]
USAGE
$ apimatic COMMAND
Expand Down Expand Up @@ -411,8 +411,8 @@ Generate an SDK for your API

```
USAGE
$ apimatic sdk generate -l csharp|java|php|python|ruby|typescript|go [-i <value>] [-d <value>] [-f] [--zip] [-k
<value>]
$ apimatic sdk generate -l csharp|java|php|python|ruby|typescript|go [-i <value>] [-d <value>] [--api-version
<value>] [-f] [--zip] [-k <value>]

FLAGS
-d, --destination=<value> directory where the SDK will be generated
Expand All @@ -422,7 +422,8 @@ FLAGS
-k, --auth-key=<value> override current authentication state with an authentication key.
-l, --language=<option> (required) programming language for SDK generation
<options: csharp|java|php|python|ruby|typescript|go>
--zip download the generated SDK as a .zip archive
--api-version=<value> Version of the API to use for SDK generation (if multiple versions exist)
--zip Download the generated SDK as a .zip archive

DESCRIPTION
Generate an SDK for your API
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 26 additions & 7 deletions src/actions/sdk/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,41 @@ export class GenerateAction {
sdkDirectory: DirectoryPath,
language: Language,
force: boolean,
zipSdk: boolean
zipSdk: boolean,
apiVersion?: string
): Promise<ActionResult> => {
if (buildDirectory.isEqual(sdkDirectory)) {
this.prompts.sameBuildAndSdkDir(buildDirectory);
return ActionResult.failed();
}

const versionedBuildContext = new VersionedBuildContext(buildDirectory);
if (await versionedBuildContext.exists()) {
const resolvedDirectory = await versionedBuildContext.getResolvedBuildDirectory();
if (!resolvedDirectory) {
this.prompts.versionedBuildEmpty();
const versionedBuildResult = await versionedBuildContext.validate();
if (versionedBuildResult.isValid) {
if (versionedBuildResult.versions.length === 0) {
this.prompts.versionedBuildEmpty(versionedBuildResult.versionsDirectory);
return ActionResult.failed();
}
buildDirectory = resolvedDirectory;
this.prompts.versionedBuild(versionedBuildContext.getRelativePath(resolvedDirectory));

let version: string;
if (apiVersion) {
if (!versionedBuildResult.versions.includes(apiVersion)) {
this.prompts.versionNotFound();
return ActionResult.failed();
}
version = apiVersion;
} else if (versionedBuildResult.versions.length === 1) {
version = versionedBuildResult.versions[0];
} else {
const selectedVersion = await this.prompts.selectVersion(versionedBuildResult.versions);
if (!selectedVersion) {
return ActionResult.cancelled();
}
version = selectedVersion;
}

buildDirectory = versionedBuildResult.versionsDirectory.join(version);
sdkDirectory = sdkDirectory.join(version);
}

const specDirectory = buildDirectory.join("spec");
Expand Down
7 changes: 5 additions & 2 deletions src/commands/sdk/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ Supports multiple programming languages including Java, C#, Python, JavaScript,
char: "d",
description: "Directory where the SDK will be generated"
}),
"api-version": Flags.string({
description: "Version of the API to use for SDK generation (if multiple versions exist)"
}),
...FlagsProvider.force,
zip: Flags.boolean({
default: false,
Expand All @@ -44,7 +47,7 @@ Supports multiple programming languages including Java, C#, Python, JavaScript,

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

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

intro("Generate SDK");
const action = new GenerateAction(this.getConfigDir(), commandMetadata, authKey);
const result = await action.execute(buildDirectory, sdkDirectory, language as Language, force, zipSdk);
const result = await action.execute(buildDirectory, sdkDirectory, language as Language, force, zipSdk, apiVersion);
outro(result);
}

Expand Down
23 changes: 18 additions & 5 deletions src/prompts/sdk/generate.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isCancel, confirm, log } from "@clack/prompts";
import { isCancel, confirm, log, select } from "@clack/prompts";
import { DirectoryPath } from "../../types/file/directoryPath.js";
import { format as f, } from "../format.js";
import { Result } from "neverthrow";
Expand Down Expand Up @@ -47,13 +47,26 @@ export class SdkGeneratePrompts {
log.error(serviceError.errorMessage);
}

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

public versionedBuild(relativePath: string) {
log.warning(`SDK Generation for multi-versioned builds is not supported. Generating SDK for ${f.var(relativePath)} instead.`);
public versionNotFound() {
this.logGenerationError(`The API version is invalid.`);
}

public async selectVersion(versions: string[]): Promise<string | undefined> {
const version = await select({
message: "Select an API version for SDK generation:",
options: versions.map((v) => ({ label: v, value: v }))
});

if (isCancel(version)) {
return undefined;
}

return version;
}

public sdkGenerated(sdk: DirectoryPath) {
Expand Down
42 changes: 26 additions & 16 deletions src/types/versioned-build-context.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,37 @@
import * as path from "path";
import { FileService } from "../infrastructure/file-service.js";
import { DirectoryPath } from "./file/directoryPath.js";
import { BuildContext } from "./build-context.js";

type VersionedBuildValidateResult = { isValid: false; } | {
isValid: true;
versionsDirectory: DirectoryPath;
versions: string[];
};

export class VersionedBuildContext {
private readonly fileService = new FileService();
private readonly versionedDocsDir: DirectoryPath;
private readonly buildDirectory: DirectoryPath;

constructor(buildDirectory: DirectoryPath) {
this.versionedDocsDir = buildDirectory.join("versioned_docs");
}

public async exists(): Promise<boolean> {
return this.fileService.directoryExists(this.versionedDocsDir);
}

public async getResolvedBuildDirectory(): Promise<DirectoryPath | null> {
const subDirs = await this.fileService.getSubDirectoriesPaths(this.versionedDocsDir);
if (subDirs.length === 0)
return null;
return subDirs[0];
this.buildDirectory = buildDirectory;
}

public getRelativePath(resolvedDirectory: DirectoryPath): string {
return path.join(".", "src", "versioned_docs", resolvedDirectory.leafName());
public async validate(): Promise<VersionedBuildValidateResult> {
const buildContext = new BuildContext(this.buildDirectory);
if (!(await buildContext.validate())) {
return { isValid: false };
}
const config = await buildContext.getBuildFileContents();
if (!("generateVersionedPortal" in config)) {
return { isValid: false };
}
const versionsPath = (config.versionsPath as string) ?? "versioned_docs";
const versionsDirectory = this.buildDirectory.join(versionsPath);
if (!(await this.fileService.directoryExists(versionsDirectory))) {
return { isValid: false };
}
const versionsDirs = await this.fileService.getSubDirectoriesPaths(versionsDirectory);
const versions = versionsDirs.map((dir) => dir.leafName());
return { isValid: true, versionsDirectory, versions };
}
}
Loading