Skip to content

Commit

Permalink
Merge pull request #1217 from contentstack/feat/CS-42980
Browse files Browse the repository at this point in the history
Feat/CS-42980 - Added Preview token in bootstrap command and preview host
  • Loading branch information
cs-raj authored Jan 4, 2024
2 parents 85c0507 + 4c85166 commit 69789e8
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 59 deletions.
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.

2 changes: 1 addition & 1 deletion packages/contentstack-bootstrap/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@contentstack/cli-cm-bootstrap",
"description": "Bootstrap contentstack apps",
"version": "1.7.1",
"version": "1.8.0",
"author": "Contentstack",
"bugs": "https://github.com/contentstack/cli/issues",
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Stream } from 'stream';
import * as zlib from 'zlib';
import * as tar from 'tar';
import * as mkdirp from 'mkdirp';
const mkdirp = require('mkdirp')
import { HttpRequestConfig, HttpClient } from '@contentstack/cli-utilities';

import GithubError from './github-error';
Expand Down
11 changes: 11 additions & 0 deletions packages/contentstack-bootstrap/src/bootstrap/interactive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,14 @@ export async function inquireLivePreviewSupport() {
});
return livePreviewEnabled;
}

export async function continueBootstrapCommand() {
const { shouldContinue } = await inquirer.prompt({
type: 'list',
name: 'shouldContinue',
message: `Do you still want to complete the bootstrap command with Live Preview Disabled?`,
choices: ['yes', 'no'],
loop: false,
});
return shouldContinue;
}
140 changes: 94 additions & 46 deletions packages/contentstack-bootstrap/src/bootstrap/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as fs from 'fs';
import * as path from 'path';
import { cliux } from '@contentstack/cli-utilities';

import { continueBootstrapCommand } from '../bootstrap/interactive';
import { AppConfig } from '../config';
import messageHandler from '../messages';

Expand All @@ -10,6 +10,7 @@ interface EnviornmentVariables {
deliveryToken: string;
environment: string;
livePreviewEnabled?: boolean;
preview_token: string;
}

/**
Expand Down Expand Up @@ -54,30 +55,45 @@ export const setupEnvironments = async (
],
},
};
if (!managementToken) {
try {
const tokenResult = await managementAPIClient.stack({ api_key }).deliveryToken().create(body);
if (tokenResult.token) {
const environmentVariables: EnviornmentVariables = {
api_key,
deliveryToken: tokenResult.token,
environment: environment.name,
livePreviewEnabled,
};
await envFileHandler(
appConfig.appConfigKey || '',
environmentVariables,
clonedDirectory,
region,
livePreviewEnabled,
);
} else {
cliux.print(messageHandler.parse('CLI_BOOTSTRAP_APP_FAILED_TO_CREATE_TOKEN_FOR_ENV', environment.name));
try {
const tokenResult = !managementToken
? await managementAPIClient
.stack({ api_key })
.deliveryToken()
.create(body, livePreviewEnabled ? { create_with_preview_token: true } : {})
: {};
if (livePreviewEnabled && !tokenResult.preview_token && !managementToken) {
cliux.print(
`warning: Live Preview using the Preview token is not available in your plan please contact the admin.`,
{
color: 'yellow',
}
);
if ((await continueBootstrapCommand()) === 'no') {
return;
}
} catch (error) {
console.log('error', error);
cliux.print(messageHandler.parse('CLI_BOOTSTRAP_APP_FAILED_TO_CREATE_ENV_FILE_FOR_ENV', environment.name));
}
if (tokenResult.token) {
const environmentVariables: EnviornmentVariables = {
api_key,
deliveryToken: tokenResult.token ?? '',
environment: environment.name,
livePreviewEnabled,
preview_token: tokenResult.preview_token ?? '',
};
await envFileHandler(
appConfig.appConfigKey || '',
environmentVariables,
clonedDirectory,
region,
livePreviewEnabled,
);
} else {
cliux.print(messageHandler.parse('CLI_BOOTSTRAP_APP_FAILED_TO_CREATE_TOKEN_FOR_ENV', environment.name));
}
} catch (error) {
console.log('error', error);
cliux.print(messageHandler.parse('CLI_BOOTSTRAP_APP_FAILED_TO_CREATE_ENV_FILE_FOR_ENV', environment.name));
}
} else {
cliux.print('No environments name found for the environment');
Expand Down Expand Up @@ -123,11 +139,13 @@ const envFileHandler = async (
let filePath;
let fileName;
let customHost;
let previewHost: string;
const regionName = region && region.name && region.name.toLowerCase();
const managementAPIHost = region.cma && region.cma.substring('8');
previewHost = region.cda?.substring(8).replace('cdn', 'rest-preview');
const isUSRegion = regionName === 'us' || regionName === 'na';
if (regionName !== 'eu' && !isUSRegion) {
customHost = region.cma && region.cma.substring('8');
customHost = region.cda && region.cda.substring(8);
customHost = customHost.replace('cdn', 'rest-preview');
}
const production = environmentVariables.environment === 'production' ? true : false;
switch (appConfigKey) {
Expand All @@ -137,11 +155,13 @@ const envFileHandler = async (
filePath = path.join(clonedDirectory, fileName);
content = `REACT_APP_CONTENTSTACK_API_KEY=${
environmentVariables.api_key
}\nREACT_APP_CONTENTSTACK_DELIVERY_TOKEN=${
environmentVariables.deliveryToken
}\nREACT_APP_CONTENTSTACK_ENVIRONMENT=${environmentVariables.environment}${
customHost ? '\nREACT_APP_CONTENTSTACK_API_HOST=' + customHost : ''
}${
}\nREACT_APP_CONTENTSTACK_DELIVERY_TOKEN=${environmentVariables.deliveryToken}${
livePreviewEnabled
? `\nREACT_APP_CONTENTSTACK_PREVIEW_TOKEN=${
environmentVariables.preview_token || `''`
}\nREACT_APP_CONTENTSTACK_PREVIEW_HOST=${customHost ?? previewHost}\n`
: '\n'
}REACT_APP_CONTENTSTACK_APP_HOST=''\nREACT_APP_CONTENTSTACK_ENVIRONMENT=${environmentVariables.environment}${
!isUSRegion && !customHost ? '\nREACT_APP_CONTENTSTACK_REGION=' + region.name : ''
}\nSKIP_PREFLIGHT_CHECK=true\nREACT_APP_CONTENTSTACK_LIVE_PREVIEW=${livePreviewEnabled}`;
result = await writeEnvFile(content, filePath);
Expand All @@ -152,9 +172,13 @@ const envFileHandler = async (
filePath = path.join(clonedDirectory, fileName);
content = `CONTENTSTACK_API_KEY=${environmentVariables.api_key}\nCONTENTSTACK_DELIVERY_TOKEN=${
environmentVariables.deliveryToken
}\nCONTENTSTACK_ENVIRONMENT=${environmentVariables.environment}\nCONTENTSTACK_API_HOST=${
customHost ? customHost : managementAPIHost
}${
}\n${
livePreviewEnabled
? `\nCONTENTSTACK_PREVIEW_TOKEN=${environmentVariables.preview_token || `''`}\nCONTENTSTACK_PREVIEW_HOST=${
customHost ?? previewHost
}\n`
: '\n'
}CONTENTSTACK_ENVIRONMENT=${environmentVariables.environment}\n${
!isUSRegion && !customHost ? '\nCONTENTSTACK_REGION=' + region.name : ''
}\nCONTENTSTACK_LIVE_PREVIEW=${livePreviewEnabled}\nCONTENTSTACK_MANAGEMENT_TOKEN=''\nCONTENTSTACK_APP_HOST=''\nCONTENTSTACK_LIVE_EDIT_TAGS=false`;
result = await writeEnvFile(content, filePath);
Expand All @@ -163,15 +187,29 @@ const envFileHandler = async (
case 'gatsby-starter':
fileName = `.env.${environmentVariables.environment}`;
filePath = path.join(clonedDirectory, fileName);
content = `CONTENTSTACK_API_KEY=${environmentVariables.api_key}\nCONTENTSTACK_DELIVERY_TOKEN=${environmentVariables.deliveryToken}\nCONTENTSTACK_ENVIRONMENT=${environmentVariables.environment}\nCONTENTSTACK_API_HOST=${managementAPIHost}\nCONTENTSTACK_LIVE_PREVIEW=${livePreviewEnabled}`;
content = `CONTENTSTACK_API_KEY=${environmentVariables.api_key}\nCONTENTSTACK_DELIVERY_TOKEN=${
environmentVariables.deliveryToken
}\n${
livePreviewEnabled
? `\nCONTENTSTACK_PREVIEW_TOKEN=${environmentVariables.preview_token || `''`}\nCONTENTSTACK_PREVIEW_HOST=${
customHost ?? previewHost
}\n`
: '\n'
}CONTENTSTACK_APP_HOST=''\nCONTENTSTACK_ENVIRONMENT=${
environmentVariables.environment
}\nCONTENTSTACK_LIVE_PREVIEW=${livePreviewEnabled}`;
result = await writeEnvFile(content, filePath);
break;
case 'angular':
content = `export const environment = { \n\tproduction:${
environmentVariables.environment === 'production' ? true : false
}, \n\tconfig : { \n\t\tapi_key: '${environmentVariables.api_key}', \n\t\tdelivery_token: '${
environmentVariables.deliveryToken
}', \n\t\tenvironment: '${environmentVariables.environment}'${
}',\n${
livePreviewEnabled
? `\npreivew_token=${environmentVariables.preview_token || `''`}\npreview_host=${customHost ?? previewHost}\n`
: '\n'
},\tapp_host: '',\n\t\tenvironment: '${environmentVariables.environment}'${
!isUSRegion && !customHost ? `,\n\t\tregion: '${region.name}'` : ''
} \n\t } \n };`;
fileName = `environment${environmentVariables.environment === 'production' ? '.prod.' : '.'}ts`;
Expand All @@ -181,11 +219,13 @@ const envFileHandler = async (
case 'angular-starter':
content = `export const environment = { \n\tproduction: true \n}; \nexport const Config = { \n\tapi_key: '${
environmentVariables.api_key
}', \n\tdelivery_token: '${environmentVariables.deliveryToken}', \n\tenvironment: '${
environmentVariables.environment
}'${!isUSRegion && !customHost ? `,\n\tregion: '${region.name}'` : ''},\n\tapi_host: '${
customHost ? customHost : managementAPIHost
}',\n\tapp_host: '',\n\tmanagement_token: '',\n\tlive_preview: ${livePreviewEnabled}\n};`;
}', \n\tdelivery_token: '${environmentVariables.deliveryToken}',\n\t${
livePreviewEnabled
? `\npreview_token=${environmentVariables.preview_token || `''`}\npreview_host=${customHost ?? previewHost}\n`
: '\n'
},\n\tenvironment: '${environmentVariables.environment}'${
!isUSRegion && !customHost ? `,\n\tregion: '${region.name}'` : ''
},\n\t\n\tapp_host: '',\n\tmanagement_token: '',\n\tlive_preview: ${livePreviewEnabled}\n};`;
fileName = `environment${environmentVariables.environment === 'production' ? '.prod.' : '.'}ts`;
filePath = path.join(clonedDirectory, 'src', 'environments', fileName);
result = await writeEnvFile(content, filePath);
Expand All @@ -198,21 +238,29 @@ const envFileHandler = async (
// Note: Stencil app needs all the env variables, even if they are not having values otherwise the rollup does not work properly and throws process in undefined error.
content = `CONTENTSTACK_API_KEY=${environmentVariables.api_key}\nCONTENTSTACK_DELIVERY_TOKEN=${
environmentVariables.deliveryToken
}\n${
livePreviewEnabled
? `\nCONTENTSTACK_PREVIEW_TOKEN=${environmentVariables.preview_token || `''`}\nCONTENTSTACK_PREVIEW_HOST=${
customHost ?? previewHost
}\n`
: '\n'
}\nCONTENTSTACK_ENVIRONMENT=${environmentVariables.environment}${
!isUSRegion && !customHost ? '\nCONTENTSTACK_REGION=' + region.name : ''
}\nCONTENTSTACK_LIVE_PREVIEW=${livePreviewEnabled}\nCONTENTSTACK_MANAGEMENT_TOKEN=''\nCONTENTSTACK_API_HOST='${
customHost ? customHost : managementAPIHost
}'\nCONTENTSTACK_APP_HOST=''\nCONTENTSTACK_LIVE_EDIT_TAGS=false`;
}\nCONTENTSTACK_LIVE_PREVIEW=${livePreviewEnabled}\n\nCONTENTSTACK_APP_HOST=''\nCONTENTSTACK_LIVE_EDIT_TAGS=false`;
result = await writeEnvFile(content, filePath);
break;
case 'vue-starter':
fileName = '.env';
filePath = path.join(clonedDirectory, fileName);
content = `VUE_APP_CONTENTSTACK_API_KEY=${environmentVariables.api_key}\nVUE_APP_CONTENTSTACK_DELIVERY_TOKEN=${
environmentVariables.deliveryToken
}\nVUE_APP_CONTENTSTACK_ENVIRONMENT=${environmentVariables.environment}${
customHost ? '\nVUE_APP_CONTENTSTACK_API_HOST=' + customHost : ''
}${
}\n${
livePreviewEnabled
? `\nVUE_APP_CONTENTSTACK_PREVIEW_TOKEN=${
environmentVariables.preview_token || `''`
}\nVUE_APP_CONTENTSTACK_PREVIEW_HOST=${customHost ?? previewHost}\n`
: '\n'
}VUE_APP_CONTENTSTACK_APP_HOST=''\nVUE_APP_CONTENTSTACK_ENVIRONMENT=${environmentVariables.environment}${
!isUSRegion && !customHost ? '\nVUE_APP_CONTENTSTACK_REGION=' + region.name : ''
}\nVUE_APP_CONTENTSTACK_LIVE_PREVIEW=${livePreviewEnabled}`;
result = await writeEnvFile(content, filePath);
Expand Down
2 changes: 1 addition & 1 deletion packages/contentstack-bootstrap/test/github.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe('Github Client', function () {
it('Git Tarball url creation', () => {
const repo = GitHubClient.parsePath('contentstack/contentstack-nextjs-react-universal-demo');
const gClient = new GitHubClient(repo);
expect(gClient.gitTarBallUrl).to.be.equal('https://api.github.com/repos/contentstack/contentstack-nextjs-react-universal-demo/tarball/master')
expect(gClient.gitTarBallUrl).to.be.equal('https://api.github.com/repos/contentstack/contentstack-nextjs-react-universal-demo/tarball/cli-use')
})

it('Clone the source repo', async function () {
Expand Down
60 changes: 54 additions & 6 deletions packages/contentstack-bootstrap/test/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,66 @@ function getFileContent(_path) {

describe('Utils', () => {
describe('#setupEnvironments', () => {
it('Create env file for a stack', async () => {
it('Create env file for a stack with live preview enabled', async () => {
const environments = { items: [{ name: 'production' }, { name: 'development' }] };
const token = 'mock-delivery-token';
const api_key = 'mock-api-key';
const appConfig = {
appConfigKey: 'reactjs',
};
const livePreviewEnabled= true;
const clonedDirectory = await getDirectory();
const region = {
name: 'NA',
cda: 'https://app.contentstack.com',
cda: 'https://cdn.contentstack.com',
cma: 'https://app.contentstack.com',
};
const managementAPIClient = {
stack: () => {
return {
environment: () => {
return {
query: () => {
return {
find: () => Promise.resolve(environments),
};
},
};
},
deliveryToken: () => {
return {
create: () => Promise.resolve({ token, preview_token: "mock_preview_token" }),
};
},
};
},
};
await setupEnvironments(managementAPIClient, api_key, appConfig,clonedDirectory, region,livePreviewEnabled);
const files = await getDirFiles(clonedDirectory);
expect(files).to.have.length(2);
let devEnvFile = await getFileContent(path.join(clonedDirectory, '.env.development.local'));
devEnvFile = devEnvFile.replace(/\n/g, ',');
expect(devEnvFile).equal(
'REACT_APP_CONTENTSTACK_API_KEY=mock-api-key,REACT_APP_CONTENTSTACK_DELIVERY_TOKEN=mock-delivery-token,REACT_APP_CONTENTSTACK_PREVIEW_TOKEN=mock_preview_token,REACT_APP_CONTENTSTACK_PREVIEW_HOST=https://rest-preview.contentstack.com,REACT_APP_CONTENTSTACK_ENVIRONMENT=development,SKIP_PREFLIGHT_CHECK=true,REACT_APP_CONTENTSTACK_LIVE_PREVIEW=true',
);
let prodEnvFile = await getFileContent(path.join(clonedDirectory, '.env.production.local'));
prodEnvFile = prodEnvFile.replace(/\n/g, ',');
expect(prodEnvFile).equal(
'REACT_APP_CONTENTSTACK_API_KEY=mock-api-key,REACT_APP_CONTENTSTACK_DELIVERY_TOKEN=mock-delivery-token,REACT_APP_CONTENTSTACK_PREVIEW_TOKEN=mock_preview_token,REACT_APP_CONTENTSTACK_PREVIEW_HOST=https://rest-preview.contentstack.com,REACT_APP_CONTENTSTACK_ENVIRONMENT=production,SKIP_PREFLIGHT_CHECK=true,REACT_APP_CONTENTSTACK_LIVE_PREVIEW=true',
);
});
it('Create env file for a stack with live preview disabled', async () => {
const environments = { items: [{ name: 'production' }, { name: 'development' }] };
const token = 'mock-delivery-token';
const api_key = 'mock-api-key';
const appConfig = {
appConfigKey: 'reactjs',
};
const livePreviewEnabled= false;
const clonedDirectory = await getDirectory();
const region = {
name: 'NA',
cda: 'https://cdn.contentstack.com',
cma: 'https://app.contentstack.com',
};
const managementAPIClient = {
Expand All @@ -66,19 +115,18 @@ describe('Utils', () => {
};
},
};

await setupEnvironments(managementAPIClient, api_key, appConfig, clonedDirectory, region);
await setupEnvironments(managementAPIClient, api_key, appConfig,clonedDirectory, region,livePreviewEnabled);
const files = await getDirFiles(clonedDirectory);
expect(files).to.have.length(2);
let devEnvFile = await getFileContent(path.join(clonedDirectory, '.env.development.local'));
devEnvFile = devEnvFile.replace(/\n/g, ',');
expect(devEnvFile).equal(
'REACT_APP_APIKEY=mock-api-key,REACT_APP_DELIVERY_TOKEN=mock-delivery-token,REACT_APP_ENVIRONMENT=development,REACT_APP_REGION=NA',
'REACT_APP_CONTENTSTACK_API_KEY=mock-api-key,REACT_APP_CONTENTSTACK_DELIVERY_TOKEN=mock-delivery-token,REACT_APP_CONTENTSTACK_ENVIRONMENT=development,SKIP_PREFLIGHT_CHECK=true,REACT_APP_CONTENTSTACK_LIVE_PREVIEW=false'
);
let prodEnvFile = await getFileContent(path.join(clonedDirectory, '.env.production.local'));
prodEnvFile = prodEnvFile.replace(/\n/g, ',');
expect(prodEnvFile).equal(
'REACT_APP_APIKEY=mock-api-key,REACT_APP_DELIVERY_TOKEN=mock-delivery-token,REACT_APP_ENVIRONMENT=production,REACT_APP_REGION=NA',
'REACT_APP_CONTENTSTACK_API_KEY=mock-api-key,REACT_APP_CONTENTSTACK_DELIVERY_TOKEN=mock-delivery-token,REACT_APP_CONTENTSTACK_ENVIRONMENT=production,SKIP_PREFLIGHT_CHECK=true,REACT_APP_CONTENTSTACK_LIVE_PREVIEW=false'
);
});
it('Create env with invalid environments, should throw an error', async () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/contentstack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"dependencies": {
"@contentstack/cli-audit": "~1.3.2",
"@contentstack/cli-auth": "~1.3.17",
"@contentstack/cli-cm-bootstrap": "~1.7.1",
"@contentstack/cli-cm-bootstrap": "~1.8.0",
"@contentstack/cli-cm-branches": "~1.0.19",
"@contentstack/cli-cm-bulk-publish": "~1.4.0",
"@contentstack/cli-cm-clone": "~1.8.0",
Expand Down
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

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

0 comments on commit 69789e8

Please sign in to comment.