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
64 changes: 54 additions & 10 deletions src/commands/app/create.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as tmp from "tmp";
import AdmZip from "adm-zip";
import omit from "lodash/omit";
import pick from "lodash/pick";
import * as shell from "shelljs";
import merge from "lodash/merge";
Expand All @@ -14,7 +15,13 @@ import {
writeFileSync,
createWriteStream,
} from "fs";
import { ux, cliux, flags, HttpClient, configHandler } from "@contentstack/cli-utilities";
import {
ux,
cliux,
flags,
HttpClient,
configHandler,
} from "@contentstack/cli-utilities";

import { BaseCommand } from "../../base-command";
import { AppManifest, AppType } from "../../types";
Expand All @@ -28,6 +35,11 @@ import {

export default class Create extends BaseCommand<typeof Create> {
private appData!: AppManifest;
private tempAppData = {
name: "",
target_type: "",
ui_location: { locations: undefined },
} as any;

static description =
"Create a new app in Developer Hub and optionally clone a boilerplate locally.";
Expand Down Expand Up @@ -62,15 +74,14 @@ export default class Create extends BaseCommand<typeof Create> {
async run(): Promise<void> {
this.sharedConfig.org = this.flags.org;
this.sharedConfig.appName = this.flags.name;
this.appData = require(this.sharedConfig.manifestPath);

await this.flagsPromptQueue();

this.appData.name = this.sharedConfig.appName;
this.appData.target_type = this.flags["app-type"] as AppType;
this.tempAppData.name = this.sharedConfig.appName;
this.tempAppData.target_type = this.flags["app-type"] as AppType;

if (this.flags["app-type"] === AppType.ORGANIZATION) {
this.appData.ui_location.locations = getOrgAppUiLocation();
this.tempAppData.ui_location.locations = getOrgAppUiLocation();
}

try {
Expand All @@ -84,6 +95,7 @@ export default class Create extends BaseCommand<typeof Create> {
) {
await this.boilerplateFlow();
} else {
this.manageManifestToggeling();
await this.registerTheAppOnDeveloperHub(false);
}
} catch (error: Error | any) {
Expand All @@ -105,6 +117,8 @@ export default class Create extends BaseCommand<typeof Create> {
await this.unZipBoilerplate(await this.cloneBoilerplate());
tmp.setGracefulCleanup(); // NOTE If graceful cleanup is set, tmp will remove all controlled temporary objects on process exit

this.manageManifestToggeling();

// NOTE Step 2: Registering the app
await this.registerTheAppOnDeveloperHub();

Expand All @@ -114,7 +128,7 @@ export default class Create extends BaseCommand<typeof Create> {
ux.action.stop();
this.log(
this.$t(this.messages.START_APP_COMMAND, {
command: `cd ${this.sharedConfig.folderPath} && npm run start`,
command: `cd "${this.sharedConfig.folderPath}" && npm run start`,
}),
"info"
);
Expand All @@ -133,10 +147,12 @@ export default class Create extends BaseCommand<typeof Create> {
}

//Auto select org in case of oauth
this.sharedConfig.org = configHandler.get('oauthOrgUid') ?? (await getOrg(this.flags, {
log: this.log,
managementSdk: this.managementSdk,
}));
this.sharedConfig.org =
configHandler.get("oauthOrgUid") ??
(await getOrg(this.flags, {
log: this.log,
managementSdk: this.managementSdk,
}));
}

/**
Expand Down Expand Up @@ -208,6 +224,34 @@ export default class Create extends BaseCommand<typeof Create> {
});
}

/**
* @method manageManifestToggeling
*
* The function manages toggling of the manifest file based on the app type, removing the
* "ui_location" property if the app type is an organization.
*/
manageManifestToggeling() {
// NOTE Use boilerplate manifest if exist
const manifestPath = resolve(
this.sharedConfig.folderPath || "",
"manifest.json"
);

if (existsSync(manifestPath)) {
this.sharedConfig.manifestPath = manifestPath;
}

let manifest = require(this.sharedConfig.manifestPath);

if (this.flags["app-type"] === AppType.ORGANIZATION) {
manifest = omit(manifest, ["ui_location"]);
} else {
this.tempAppData = omit(this.tempAppData, ["ui_location"]);
}

this.appData = merge(manifest, this.tempAppData);
}

/**
* @method registerTheAppOnDeveloperHub
*
Expand Down
12 changes: 7 additions & 5 deletions src/commands/app/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { existsSync, readFileSync, writeFileSync } from "fs";

import { $t, appUpdate } from "../../messages";
import { fetchApp, getApp, getOrg } from "../../util";
import {AppCLIBaseCommand} from "../../app-cli-base-coomand";
import { AppCLIBaseCommand } from "../../app-cli-base-coomand";

export default class Update extends AppCLIBaseCommand {
private orgUid!: string;
Expand All @@ -28,12 +28,14 @@ export default class Update extends AppCLIBaseCommand {

async run(): Promise<void> {
try {
//if working directory isn't app directory
if(!this.manifestData){
// if working directory isn't app directory
if (!this.manifestData) {
await this.validateManifest();
}
this.flags["app-manifest"] = this.manifestPath ?? this.flags["app-manifest"];
this.orgUid = this.flags.org ?? this.manifestData?.organization_uid;

this.flags["app-manifest"] =
this.manifestPath ?? this.flags["app-manifest"];
this.orgUid = this.flags.org ?? this.manifestData?.organization_uid;
this.sharedConfig.org = await getOrg(
{ org: this.orgUid as any },
{
Expand Down
76 changes: 56 additions & 20 deletions src/config/manifest.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"icon": "",
"description": "",
"target_type": "stack",
"icon": "",
"name": "",
"visibility": "private",
"organization_uid": "",
"target_type": "stack",
"visibility": "private",
"uid": "",
"ui_location": {
"signed": false,
"base_url": "http://localhost:3000",
Expand All @@ -13,20 +14,22 @@
"type": "cs.cm.stack.custom_field",
"meta": [
{
"path": "/custom-field",
"signed": true,
"multiple": false,
"path": "/#/custom-field",
"signed": false,
"enabled": true,
"data_type": "number"
"data_type": "json"
}
]
},
{
"type": "cs.cm.stack.config",
"type": "cs.cm.stack.dashboard",
"meta": [
{
"path": "/app-configuration",
"signed": true,
"enabled": true
"path": "/#/stack-dashboard",
"signed": false,
"enabled": true,
"default_width": "half"
}
]
},
Expand All @@ -35,35 +38,68 @@
"meta": [
{
"blur": false,
"path": "/asset-sidebar",
"signed": true,
"path": "/#/asset-sidebar",
"signed": false,
"enabled": true,
"width": 500
}
]
},
{
"type": "cs.cm.stack.dashboard",
"type": "cs.cm.stack.sidebar",
"meta": [
{
"path": "/stack-dashboard",
"signed": true,
"path": "/#/entry-sidebar",
"signed": false,
"enabled": true
}
]
},
{
"type": "cs.cm.stack.full_page",
"meta": [
{
"path": "/#/full-page",
"signed": false,
"enabled": true
}
]
},
{
"type": "cs.cm.stack.field_modifier",
"meta": [
{
"path": "/#/field-modifier",
"signed": false,
"enabled": true,
"default_width": "half"
"allowed_types": ["$all"]
}
]
},
{
"type": "cs.cm.stack.sidebar",
"type": "cs.cm.stack.config",
"meta": [
{
"path": "/#/app-configuration",
"signed": false,
"enabled": true
}
]
},
{
"type": "cs.cm.stack.rte",
"meta": [
{
"path": "/entry-sidebar",
"signed": true,
"path": "/json-rte.js",
"signed": false,
"enabled": true
}
]
}
]
},
"uid": ""
"hosting": {
"provider": "external",
"deployment_url": "http://localhost:3000"
}
}
26 changes: 8 additions & 18 deletions test/unit/commands/app/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import messages from "../../../../src/messages";
import * as mock from "../../mock/common.mock.json";
import manifestData from "../../../../src/config/manifest.json";

const gitHubHost = "https://github.com";
const { origin, pathname } = new URL(config.appBoilerplateGithubUrl);
const zipPath = join(process.cwd(), "test", "unit", "mock", "boilerplate.zip");
const region: { cma: string; name: string; cda: string } =
configHandler.get("region");
Expand Down Expand Up @@ -50,10 +50,8 @@ describe("app:create", () => {

return (cases as Record<string, any>)[prompt.name];
})
.nock(gitHubHost, (api) =>
api
.get(config.appBoilerplateGithubUrl.replace(gitHubHost, ""))
.reply(200, { data: "test-data" })
.nock(origin, (api) =>
api.get(pathname).reply(200, { data: "test-data" })
)
.nock(region.cma, (api) =>
api
Expand Down Expand Up @@ -98,10 +96,8 @@ describe("app:create", () => {

return (cases as Record<string, any>)[prompt.name];
})
.nock(gitHubHost, (api) =>
api
.get(config.appBoilerplateGithubUrl.replace(gitHubHost, ""))
.reply(200, { data: "test-data" })
.nock(origin, (api) =>
api.get(pathname).reply(200, { data: "test-data" })
)
.nock(region.cma, (api) =>
api
Expand Down Expand Up @@ -195,11 +191,7 @@ describe("app:create", () => {

return (cases as Record<string, any>)[prompt.name];
})
.nock(gitHubHost, (api) =>
api
.get(config.appBoilerplateGithubUrl.replace(gitHubHost, ""))
.reply(200)
)
.nock(origin, (api) => api.get(pathname).reply(200))
.nock(region.cma, (api) =>
api
.get("/v3/organizations?limit=100&asc=name&include_count=true&skip=0")
Expand Down Expand Up @@ -305,10 +297,8 @@ describe("app:create", () => {

return (cases as Record<string, any>)[prompt.name];
})
.nock(gitHubHost, (api) =>
api
.get(config.appBoilerplateGithubUrl.replace(gitHubHost, ""))
.reply(200, { data: "test-data" })
.nock(origin, (api) =>
api.get(pathname).reply(200, { data: "test-data" })
)
.nock(region.cma, (api) =>
api
Expand Down