Skip to content

Commit 1528339

Browse files
feat: added more boilerplate template apps
1 parent 0640d31 commit 1528339

File tree

6 files changed

+68
-11
lines changed

6 files changed

+68
-11
lines changed

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.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@contentstack/apps-cli",
3-
"version": "1.2.1",
3+
"version": "1.2.2",
44
"description": "App ClI",
55
"author": "Contentstack CLI",
66
"homepage": "https://github.com/contentstack/contentstack-apps-cli",

src/commands/app/create.ts

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ import {
3232
getAppName,
3333
getDirName,
3434
getOrgAppUiLocation,
35-
sanitizePath
35+
sanitizePath,
36+
selectedBoilerplate,
3637
} from "../../util";
3738

3839
export default class Create extends BaseCommand<typeof Create> {
@@ -96,7 +97,15 @@ export default class Create extends BaseCommand<typeof Create> {
9697
message: this.messages.CONFIRM_CLONE_BOILERPLATE,
9798
}))
9899
) {
99-
await this.boilerplateFlow();
100+
const boilerplate = await selectedBoilerplate();
101+
if (boilerplate) {
102+
this.sharedConfig.boilerplateName = boilerplate.name
103+
.toLowerCase()
104+
.replace(/ /g, "-");
105+
this.sharedConfig.appBoilerplateGithubUrl = boilerplate.link;
106+
this.sharedConfig.appName = this.sharedConfig.boilerplateName;
107+
await this.boilerplateFlow();
108+
}
100109
} else {
101110
this.manageManifestToggeling();
102111
await this.registerTheAppOnDeveloperHub(false);
@@ -120,6 +129,12 @@ export default class Create extends BaseCommand<typeof Create> {
120129
await this.unZipBoilerplate(await this.cloneBoilerplate());
121130
tmp.setGracefulCleanup(); // NOTE If graceful cleanup is set, tmp will remove all controlled temporary objects on process exit
122131

132+
// Update the sharedConfig.appName with the actual folder name
133+
this.sharedConfig.appName =
134+
this.sharedConfig.folderPath.split("/").pop() ||
135+
this.sharedConfig.appName;
136+
this.tempAppData.name = this.sharedConfig.appName;
137+
123138
this.manageManifestToggeling();
124139

125140
// NOTE Step 2: Registering the app
@@ -198,7 +213,11 @@ export default class Create extends BaseCommand<typeof Create> {
198213
const zip = new AdmZip(filepath);
199214
const dataDir = this.flags["data-dir"] ?? process.cwd();
200215
let targetPath = resolve(dataDir, this.sharedConfig.appName);
201-
const sourcePath = resolve(dataDir, this.sharedConfig.boilerplateName);
216+
217+
// Get the directory inside the zip file
218+
const zipEntries = zip.getEntries();
219+
const firstEntry = zipEntries[0];
220+
const sourcePath = resolve(dataDir, firstEntry.entryName.split("/")[0]);
202221

203222
if (this.flags["data-dir"] && !existsSync(this.flags["data-dir"])) {
204223
mkdirSync(this.flags["data-dir"], { recursive: true });
@@ -225,6 +244,10 @@ export default class Create extends BaseCommand<typeof Create> {
225244
reject(error);
226245
});
227246
});
247+
// Update the app name and folder path
248+
this.sharedConfig.appName =
249+
this.sharedConfig.folderPath.split("/").pop() ||
250+
this.sharedConfig.appName;
228251
}
229252

230253
/**
@@ -236,8 +259,8 @@ export default class Create extends BaseCommand<typeof Create> {
236259
manageManifestToggeling() {
237260
// NOTE Use boilerplate manifest if exist
238261
const manifestPath = resolve(
239-
this.sharedConfig.folderPath || "",
240-
"manifest.json"
262+
this.sharedConfig.folderPath,
263+
`${this.sharedConfig.folderPath}/manifest.json`
241264
);
242265

243266
if (existsSync(manifestPath)) {
@@ -301,7 +324,10 @@ export default class Create extends BaseCommand<typeof Create> {
301324
this.appData = merge(this.appData, pick(response, validKeys));
302325
if (saveManifest) {
303326
writeFileSync(
304-
resolve(this.sharedConfig.folderPath, "manifest.json"),
327+
resolve(
328+
this.sharedConfig.folderPath,
329+
`${this.sharedConfig.folderPath}/manifest.json`
330+
),
305331
JSON.stringify(this.appData),
306332
{
307333
encoding: "utf8",

src/config/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ import { resolve } from "path";
22

33
const config = {
44
defaultAppName: "app-boilerplate",
5-
manifestPath: resolve(__dirname, "manifest.json"),
5+
manifestPath: resolve(__dirname, ""),
66
boilerplateName: "marketplace-app-boilerplate-main",
77
developerHubBaseUrl: "",
88
appBoilerplateGithubUrl:
99
"https://codeload.github.com/contentstack/marketplace-app-boilerplate/zip/refs/heads/main",
1010
defaultAppFileName: "manifest",
11+
boilerplatesUrl: 'https://marketplace-artifacts.contentstack.com/cli/starter-template.json'
1112
};
1213

1314
export default config;

src/util/common-utils.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import {
1919
} from "../types";
2020
import { askProjectName } from "./inquirer";
2121
import { deployAppMsg } from "../messages";
22+
import config from "../config";
23+
import axios from "axios";
2224

2325
export type CommonOptions = {
2426
log: LogFn;
@@ -396,6 +398,15 @@ const handleProjectNameConflict = async (
396398
}
397399
return projectName;
398400
};
401+
async function fetchBoilerplateDetails(): Promise<Record<string, any>[]> {
402+
try {
403+
const url = config.boilerplatesUrl;
404+
const content = await axios.get(url);
405+
return content.data.templates
406+
} catch (error) {
407+
throw error;
408+
}
409+
}
399410

400411
export {
401412
getOrganizations,
@@ -418,4 +429,5 @@ export {
418429
disconnectApp,
419430
formatUrl,
420431
handleProjectNameConflict,
432+
fetchBoilerplateDetails
421433
};

src/util/inquirer.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
fetchApps,
2828
sanitizePath,
2929
MarketPlaceOptions,
30+
fetchBoilerplateDetails,
3031
} from "./common-utils";
3132
import { LaunchProjectRes } from "../types";
3233

@@ -385,6 +386,22 @@ function inquireRequireValidation(input: any): string | boolean {
385386
return true;
386387
}
387388

389+
const selectedBoilerplate = async (): Promise<any> => {
390+
const boilerplates = await fetchBoilerplateDetails();
391+
392+
const response = await cliux
393+
.inquire({
394+
type: "search-list",
395+
name: "App",
396+
choices: boilerplates.map((bp) => bp.name),
397+
message: "Select a boilerplate from search list",
398+
})
399+
.then((name) => {
400+
return find(boilerplates, (boilerplate) => boilerplate.name === name);
401+
});
402+
return response;
403+
};
404+
388405
export {
389406
getOrg,
390407
getAppName,
@@ -399,5 +416,6 @@ export {
399416
askProjectType,
400417
askConfirmation,
401418
selectProject,
402-
askProjectName
419+
askProjectName,
420+
selectedBoilerplate,
403421
};

0 commit comments

Comments
 (0)