Skip to content

Commit 2750491

Browse files
aliasghar98sohail2721Shield-Jaguarsaeedjamshaid
authored
feat: add sdk quickstart flow and other various improvements (#210)
- Added a new command `apimatic quickstart` to replace `apimatic portal quickstart`, which allows users to get started with either SDK or Portal. - Fixed invalid `api transform` command examples. - Improved portal generation to avoid timeout errors. - Improved note wrapping to cater smaller terminal screens. - Updated APIMatic API SDK dependency version to the latest. - Streamlined CLI output messages for CI/CD workflows. --------- Co-authored-by: Muhammad Sohail <62895181+sohail2721@users.noreply.github.com> Co-authored-by: Mujahid Daud Khan <37825767+Shield-Jaguar@users.noreply.github.com> Co-authored-by: Shield-Jaguar <mujahiddaudkhan@gmail.com> Co-authored-by: saeedjamshaid <saeed.jamshaid@outlook.com>
1 parent 3facbb7 commit 2750491

54 files changed

Lines changed: 11470 additions & 5049 deletions

Some content is hidden

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

README.md

Lines changed: 436 additions & 436 deletions
Large diffs are not rendered by default.

package-lock.json

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

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"test": "tsx node_modules/mocha/bin/_mocha --forbid-only \"test/**/*.test.ts\" --timeout 99999"
4848
},
4949
"dependencies": {
50-
"@apimatic/sdk": "^0.2.0-alpha.4",
50+
"@apimatic/sdk": "^0.2.0-alpha.5",
5151
"@clack/prompts": "1.0.0-alpha.1",
5252
"@oclif/core": "^4.2.8",
5353
"@oclif/plugin-autocomplete": "^3.2.24",
@@ -64,6 +64,7 @@
6464
"form-data": "^4.0.2",
6565
"fs-extra": "^11.3.0",
6666
"get-port": "^7.1.0",
67+
"is-in-ci": "^2.0.0",
6768
"livereload": "^0.9.3",
6869
"neverthrow": "^8.2.0",
6970
"open": "^8.4.0",
@@ -145,7 +146,7 @@
145146
}
146147
},
147148
"topicSeparator": " ",
148-
"state": "Alpha"
149+
"state": "beta"
149150
},
150151
"lint-staged": {
151152
"*.js": "eslint --cache --fix",

src/actions/portal/generate.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { withDirPath } from "../../infrastructure/tmp-extensions.js";
88
import { LauncherService } from "../../infrastructure/launcher-service.js";
99
import { TempContext } from "../../types/temp-context.js";
1010
import { CommandMetadata } from "../../types/common/command-metadata.js";
11+
import { ServiceError } from "../../infrastructure/service-error.js";
1112

1213
export class GenerateAction {
1314
private readonly prompts: PortalGeneratePrompts = new PortalGeneratePrompts();
@@ -57,7 +58,10 @@ export class GenerateAction {
5758

5859
if (response.isErr()) {
5960
const error = response.error;
60-
if (typeof error === "string") {
61+
if (error instanceof ServiceError) {
62+
this.prompts.portalGenerationServiceError(error);
63+
}
64+
else if (typeof error === "string") {
6165
this.prompts.portalGenerationError(error);
6266
} else {
6367
const errorZipPath = await tempContext.save(error);

src/actions/portal/quickstart.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { getLanguagesConfig } from "../../types/build/build.js";
1717
import { FilePath } from "../../types/file/filePath.js";
1818
import { SpecContext } from "../../types/spec-context.js";
1919

20-
2120
const defaultPort: number = 3000 as const;
2221

2322
export class PortalQuickstartAction {
@@ -27,21 +26,19 @@ export class PortalQuickstartAction {
2726
private readonly configDir: DirectoryPath;
2827
private readonly commandMetadata: CommandMetadata;
2928
private readonly fileDownloadService = new FileDownloadService();
30-
private readonly buildFileUrl = new UrlPath(`https://github.com/apimatic/static-portal-workflow/archive/refs/heads/master.zip`);
31-
private readonly defaultSpecUrl = new UrlPath(`https://raw.githubusercontent.com/apimatic/static-portal-workflow/refs/heads/master/spec/openapi.json`);
32-
private readonly repositoryFolderName = "static-portal-workflow-master" as const;
29+
private readonly buildFileUrl = new UrlPath(`https://github.com/apimatic/sample-docs-as-code-portal/archive/refs/heads/master.zip`);
30+
private readonly defaultSpecUrl = new UrlPath(`https://raw.githubusercontent.com/apimatic/sample-docs-as-code-portal/refs/heads/master/src/spec/openapi.json`);
31+
private readonly repositoryFolderName = "sample-docs-as-code-portal-master/src" as const;
3332

3433
constructor(configDir: DirectoryPath, commandMetadata: CommandMetadata) {
3534
this.configDir = configDir;
3635
this.commandMetadata = commandMetadata;
3736
}
3837

3938
public readonly execute = async (): Promise<ActionResult> => {
40-
this.prompts.welcomeMessage();
41-
4239
const storedAuth = await getAuthInfo(this.configDir.toString());
4340
if (!storedAuth?.authKey) {
44-
const loginResult = await new LoginAction(this.configDir, this.commandMetadata).execute();
41+
const loginResult = await new LoginAction(this.configDir, this.commandMetadata).execute();
4542
if (loginResult.isFailed()) {
4643
return ActionResult.failed();
4744
}
@@ -66,7 +63,7 @@ export class PortalQuickstartAction {
6663
if (downloadFileResult.isErr()) {
6764
this.prompts.serviceError(downloadFileResult.error);
6865
} else {
69-
const specContext = new SpecContext(tempDirectory)
66+
const specContext = new SpecContext(tempDirectory);
7067
specPath = await specContext.save(downloadFileResult.value.stream, downloadFileResult.value.filename);
7168
}
7269
} else {
@@ -96,7 +93,7 @@ export class PortalQuickstartAction {
9693
if (downloadFileResult.isErr()) {
9794
this.prompts.serviceError(downloadFileResult.error);
9895
} else {
99-
const specContext = new SpecContext(tempDirectory)
96+
const specContext = new SpecContext(tempDirectory);
10097
specPath = await specContext.save(downloadFileResult.value.stream, downloadFileResult.value.filename);
10198
}
10299
}
@@ -145,7 +142,6 @@ export class PortalQuickstartAction {
145142
const extractedFolder = tempDirectory.join(this.repositoryFolderName);
146143

147144
const tempBuildContext = new BuildContext(extractedFolder);
148-
await tempBuildContext.replaceDefaultSpec(specPath);
149145
await tempBuildContext.deleteWorkflowDir();
150146

151147
const buildFile = await tempBuildContext.getBuildFileContents();
@@ -155,6 +151,10 @@ export class PortalQuickstartAction {
155151
const sourceDirectory = inputDirectory.join("src");
156152
await this.fileService.copyDirectoryContents(extractedFolder, sourceDirectory);
157153

154+
const specDirectory = sourceDirectory.join("spec");
155+
const specContext = new SpecContext(specDirectory);
156+
await specContext.replaceDefaultSpec(specPath);
157+
158158
const buildDirectoryStructure = await this.fileService.getDirectory(sourceDirectory);
159159
this.prompts.printDirectoryStructure(inputDirectory, buildDirectoryStructure);
160160

src/actions/portal/recipe/new-recipe.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,11 @@ export class PortalRecipeAction {
6565

6666
// Setup recipe context
6767
const recipeContext = new RecipeContext(recipeName);
68-
const recipeFileName = recipeContext.getRecipeName();
68+
const recipeScriptFileName = recipeContext.getRecipeScriptFileName();
69+
const recipeMarkdownFileName = recipeContext.getRecipeMarkdownFileName();
6970

7071
// Check if the recipe already exists
71-
const recipeAlreadyExists = recipeContext.exists(tocData, recipeName, recipeFileName);
72+
const recipeAlreadyExists = recipeContext.exists(tocData, recipeName, recipeMarkdownFileName);
7273
if (recipeAlreadyExists && !(await this.prompts.overwriteApiRecipeInTocPrompt(recipeName))) {
7374
return ActionResult.cancelled();
7475
}
@@ -106,7 +107,9 @@ export class PortalRecipeAction {
106107
const specFileStream = await this.fileService.getStream(specZipPath);
107108

108109
try {
109-
return await this.prompts.generateSdl(this.portalService.generateSdl(specFileStream, this.configDirectory, this.commandMetadata))
110+
return await this.prompts.generateSdl(
111+
this.portalService.generateSdl(specFileStream, this.configDirectory, this.commandMetadata)
112+
);
110113
} finally {
111114
specFileStream.close();
112115
}
@@ -144,12 +147,13 @@ export class PortalRecipeAction {
144147
tocData,
145148
tocContext.tocPath,
146149
recipeName,
147-
recipeFileName,
150+
recipeScriptFileName,
151+
recipeMarkdownFileName,
148152
buildContext,
149153
buildDirectory
150154
);
151155

152-
const tocStructure = this.getTocStructure(recipeFileName);
156+
const tocStructure = this.getTocStructure(recipeScriptFileName);
153157
this.prompts.recipeCreated();
154158
this.prompts.displayRecipeStructure(tocStructure);
155159
this.prompts.nextSteps();

src/actions/portal/serve.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ export class PortalServeAction {
2222
private readonly configDir: DirectoryPath;
2323
private readonly commandMetadata: CommandMetadata;
2424
private readonly authKey: string | null;
25-
private isPortalServed: boolean = false;
2625

2726
public constructor(configDir: DirectoryPath, commandMetadata: CommandMetadata, authKey: string | null = null) {
2827
this.configDir = configDir;
@@ -50,7 +49,7 @@ export class PortalServeAction {
5049
}
5150

5251
const liveReloadPort = await this.networkService.getServerPort([35729, 35730, 35731, 35732]);
53-
const liveReloadServer = createLiveReloadServer({ port: liveReloadPort});
52+
const liveReloadServer = createLiveReloadServer({ port: liveReloadPort });
5453
const server = this.application
5554
.use(connectLiveReload())
5655
.use(express.static(portalDirectory.toString(), { extensions: ["html"] }))
@@ -136,7 +135,6 @@ export class PortalServeAction {
136135

137136
await watcher.close();
138137
debounceService.close();
139-
140138
liveReloadServer.close();
141139
server.close();
142140
return ActionResult.success();

src/actions/portal/toc/new-toc.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { err, ok, Result } from "neverthrow";
1+
import { ok } from "neverthrow";
22
import { PortalNewTocPrompts } from "../../../prompts/portal/toc/new-toc.js";
33
import { TocStructureGenerator } from "../../../application/portal/toc/toc-structure-generator.js";
44
import { TocEndpoint, TocGroup, TocModel } from "../../../types/toc/toc.js";
@@ -7,7 +7,6 @@ import { CommandMetadata } from "../../../types/common/command-metadata.js";
77
import { ActionResult } from "../../action-result.js";
88
import { TocContext } from "../../../types/toc-context.js";
99
import { FileService } from "../../../infrastructure/file-service.js";
10-
import { FilePath } from "../../../types/file/filePath.js";
1110
import { BuildContext } from "../../../types/build-context.js";
1211
import { getEndpointGroupsAndModels } from "../../../types/sdl/sdl.js";
1312
import { withDirPath } from "../../../infrastructure/tmp-extensions.js";

src/actions/quickstart.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { QuickstartPrompts } from "../prompts/quickstart.js";
2+
import { CommandMetadata } from "../types/common/command-metadata.js";
3+
import { DirectoryPath } from "../types/file/directoryPath.js";
4+
import { ActionResult } from "./action-result.js";
5+
import { PortalQuickstartAction } from "./portal/quickstart.js";
6+
import { SdkQuickstartAction } from "./sdk/quickstart.js";
7+
8+
export class QuickstartAction {
9+
private readonly prompts = new QuickstartPrompts();
10+
11+
public constructor(private readonly configDir: DirectoryPath, private readonly commandMetadata: CommandMetadata) {}
12+
13+
public readonly execute = async (): Promise<ActionResult> => {
14+
this.prompts.welcomeMessage();
15+
const selectedFlow = await this.prompts.selectQuickstartFlow();
16+
switch (selectedFlow) {
17+
case "portal": {
18+
const action = new PortalQuickstartAction(this.configDir, this.commandMetadata);
19+
return await action.execute();
20+
}
21+
case "sdk": {
22+
const action = new SdkQuickstartAction(this.configDir, this.commandMetadata);
23+
return await action.execute();
24+
}
25+
case undefined: {
26+
this.prompts.noQuickstartFlowSelected();
27+
return ActionResult.cancelled();
28+
}
29+
}
30+
};
31+
}

0 commit comments

Comments
 (0)