Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/CS-42980 - Added Preview token in bootstrap command and preview host #1217

Merged
merged 13 commits into from
Jan 4, 2024
Merged
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({
cs-raj marked this conversation as resolved.
Show resolved Hide resolved
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;
}
138 changes: 92 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');
cs-raj marked this conversation as resolved.
Show resolved Hide resolved
}
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,27 @@ 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 +217,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 +236,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.