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

[create-sitecore-jss] Quick follow up for new Angular SXP/XMC journey #1881

Merged
merged 24 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
499d459
Fix JSS-3797 (prompt for proxy asked when only proxy initalized)
art-alexeyenko Aug 7, 2024
af5c33d
apply correct proxy name matcher
art-alexeyenko Aug 7, 2024
bb89673
Fix jss-3805: add incompatibility for xmcloud/sxp
art-alexeyenko Aug 7, 2024
3e4e950
fix test
art-alexeyenko Aug 7, 2024
5174dcb
JSS-3827: grammar in next-steps
art-alexeyenko Aug 7, 2024
b25b51e
fix JSS-3833: correct use of monorepo by installed proxy
art-alexeyenko Aug 7, 2024
79c3bae
Fix JSS-3824: move fetchWith to SXP prompts
art-alexeyenko Aug 8, 2024
182b20b
fix JSS-3850: ensure ejsData.xmcloud always represents correct presen…
art-alexeyenko Aug 8, 2024
34d08bf
Fix JSS-3825: ensure only base initializers' appNames are stored for …
art-alexeyenko Aug 8, 2024
33202a7
fix JSS-3850 better: ensure xmcloud is set in prompt
art-alexeyenko Aug 8, 2024
31cfcb7
small fallback for appname prompt
art-alexeyenko Aug 9, 2024
c2e3b9a
Fix JSS-3826: Move proxyAppDestination prompt into initializer
art-alexeyenko Aug 9, 2024
c122551
Fix JSS-3826 better: ensure args updated with proxy path
art-alexeyenko Aug 10, 2024
cee4ab1
correct version for xmcloud-proxy template
art-alexeyenko Aug 10, 2024
57eac8e
slightly better flow in transform function
art-alexeyenko Aug 10, 2024
d313e16
changelog
art-alexeyenko Aug 10, 2024
43890ee
Merge branch 'dev' of https://github.com/Sitecore/jss into bug/jss-35…
art-alexeyenko Aug 10, 2024
dbdfa6b
Ensure proxy app input cannot match main destination
art-alexeyenko Aug 10, 2024
ef31f1a
validate proxy path input in prompt logic
art-alexeyenko Aug 12, 2024
c574310
move cjs/destination assignments out of transformer logic
art-alexeyenko Aug 12, 2024
dc96c91
unit test proxy prompts
art-alexeyenko Aug 12, 2024
4dcbca4
correct double backslash replace
art-alexeyenko Aug 12, 2024
44de4c0
fix types issues in proxy prompt
art-alexeyenko Aug 12, 2024
cbef826
no message
art-alexeyenko Aug 12, 2024
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
7 changes: 3 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,12 @@ Our versioning strategy is as follows:
* Add SXA styles to xmcloud addon
* `[create-sitecore-jss]` `[template/angular]` `[template/angular-xmcloud]` `[template/node-xmcloud-proxy]` Edge Proxy / Context Id support ([#1875](https://github.com/Sitecore/jss/pull/1875))

* `[create-sitecore-jss]` Rework Angular initializer to support XMCloud and SXP journeys ([#1845](https://github.com/Sitecore/jss/pull/1845))([#1858](https://github.com/Sitecore/jss/pull/1858))([#1868](https://github.com/Sitecore/jss/pull/1868)) ([#1882](https://github.com/Sitecore/jss/pull/1882))
* `[create-sitecore-jss]` Rework Angular initializer to support XMCloud and SXP journeys ([#1845](https://github.com/Sitecore/jss/pull/1845))([#1858](https://github.com/Sitecore/jss/pull/1858))([#1868](https://github.com/Sitecore/jss/pull/1868))([#1881](https://github.com/Sitecore/jss/pull/1881))([#1882](https://github.com/Sitecore/jss/pull/1882))
* `[create-sitecore-jss]` Allow node-xmcloud-proxy app to be installed alongside Angular SPA application
* `nodeAppDestination` arg can be passed into `create-sitecore-jss` command to define path for proxy to be installed in
* `proxyAppDestination` arg can be passed into `create-sitecore-jss` command to define path for proxy to be installed in
* `[create-sitecore-jss]``[template/angular-xmcloud]` Angular SXA components ([#1864](https://github.com/Sitecore/jss/pull/1864))
* `[sitecore-jss-angular]` Angular placeholder now supports SXA components ([#1870](https://github.com/Sitecore/jss/pull/1870))
* `[template/angular-xmcloud]` Angular SXA layout ([#1873](https://github.com/Sitecore/jss/pull/1873))
([#1880](https://github.com/Sitecore/jss/pull/1880))
* `[template/angular-xmcloud]` Angular SXA layout ([#1873](https://github.com/Sitecore/jss/pull/1873))([#1880](https://github.com/Sitecore/jss/pull/1880))

### 🛠 Breaking Change

Expand Down
98 changes: 8 additions & 90 deletions packages/create-sitecore-jss/src/bin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import { sep } from 'path';
import chalk from 'chalk';
import inquirer from 'inquirer';
import { ParsedArgs } from 'minimist';
import { parseArgs, main, promptDestination, getDestinations } from './bin';
import { parseArgs, main, promptDestination, getDestination } from './bin';
import * as helpers from './common/utils/helpers';
import * as initRunner from './init-runner';
import { getDefaultProxyDestination } from './common/utils/helpers';

describe('bin', () => {
describe('parseArgs', () => {
Expand Down Expand Up @@ -286,31 +285,15 @@ describe('bin', () => {
});
});

describe('getDestinations', () => {
describe('getDestination', () => {
const testTemplates = ['foo', 'bar'];

it('should return base args.destination value only when provided', async () => {
const testPath = 'test\\path';
const testArgs = mockArgs({
destination: testPath,
});
expect(await getDestinations(testArgs, testTemplates)).to.deep.equal({
destination: testPath,
});
});

it('should return base and proxy destinations from args when templates contain proxy app', async () => {
const testPath = 'test\\path';
const proxyPath = 'proxy\\path';
const testArgs = mockArgs({
destination: testPath,
proxyAppDestination: proxyPath,
});
const templatesWithProxy = [...testTemplates, 'node-xmcloud-proxy-proxy'];
expect(await getDestinations(testArgs, templatesWithProxy)).to.deep.equal({
destination: testPath,
proxyAppDestination: proxyPath,
});
expect(await getDestination(testArgs, testTemplates)).to.equal(testPath);
});

it('should prompt to get base destination when args.destination is empty', async () => {
Expand All @@ -321,47 +304,20 @@ describe('bin', () => {
const testArgs = mockArgs({
destination: undefined,
});
await getDestinations(testArgs, testTemplates);
await getDestination(testArgs, testTemplates);
expect(inquirerPromptStub).to.have.been.calledOnce;
expect(inquirerPromptStub.getCall(0).args[0].message).to.be.equal(
'Where would you like your new app created?'
);
});

it('should prompt for both base and proxy when destinations are missing in args and templates contain proxy app', async () => {
art-alexeyenko marked this conversation as resolved.
Show resolved Hide resolved
const testPath = 'test\\path';
const proxyPath = 'proxy\\path';
inquirerPromptStub.onCall(0).returns({
destination: testPath,
});
// avoid paths being equal - this case is tested further down
inquirerPromptStub.onCall(1).returns({
destination: proxyPath,
});
const testArgs = mockArgs({
destination: undefined,
proxyAppDestination: undefined,
});
const templatesWithProxy = [...testTemplates, 'node-xmcloud-proxy'];
await getDestinations(testArgs, templatesWithProxy);
expect(inquirerPromptStub).to.have.been.calledTwice;
expect(inquirerPromptStub.getCall(0).args[0].message).to.be.equal(
'Where would you like your new app created?'
);
expect(inquirerPromptStub.getCall(1).args[0].message).to.be.equal(
'Where would you like your proxy app created?'
);
});

it('should return default base destination with base template when --yes arg is used', async () => {
const testArgs = mockArgs({
destination: undefined,
yes: true,
});
const expectedDestination = `${process.cwd()}${sep + testTemplates[0]}`;
expect(await getDestinations(testArgs, testTemplates)).to.deep.equal({
destination: expectedDestination,
});
expect(await getDestination(testArgs, testTemplates)).to.deep.equal(expectedDestination);
});

it('should return default base destination with args.appName when provided and --yes arg is used', async () => {
Expand All @@ -372,47 +328,12 @@ describe('bin', () => {
yes: true,
});
const expectedDestination = `${process.cwd()}${sep + testAppName}`;
expect(await getDestinations(testArgs, testTemplates)).to.deep.equal({
destination: expectedDestination,
});
});

it('should return default proxy destination when -- yes arg is used', async () => {
const testPath = 'test\\path';
const testArgs = mockArgs({
destination: testPath,
yes: true,
});
const templatesWithProxy = [...testTemplates, 'node-xmcloud-proxy'];
const expectedProxyDestination = getDefaultProxyDestination(testPath, 'node-xmcloud-proxy');
expect(await getDestinations(testArgs, templatesWithProxy)).to.deep.equal({
destination: testPath,
proxyAppDestination: expectedProxyDestination,
});
});

it('should prompt for proxy destination again if proxy destination is the same as base destination', async () => {
const testPath = 'test\\path';
const proxyPath = 'proxy\\path';
// avoid paths being equal - this case is tested further down
inquirerPromptStub.onCall(0).returns({
destination: proxyPath,
});
const testArgs = mockArgs({
destination: testPath,
proxyAppDestination: testPath,
});
const templatesWithProxy = [...testTemplates, 'node-xmcloud-proxy'];
await getDestinations(testArgs, templatesWithProxy);
expect(inquirerPromptStub).to.have.been.calledOnce;
expect(inquirerPromptStub.getCall(0).args[0].message).to.be.equal(
'Proxy app and base app cannot be located in the same folder. Please input another path for proxy'
);
expect(await getDestination(testArgs, testTemplates)).to.deep.equal(expectedDestination);
});

it('should throw when templates are empty', async () => {
const testArgs = mockArgs();
await getDestinations(testArgs, []).catch((error) => {
await getDestination(testArgs, []).catch((error) => {
expect(error.message).to.be.equal(
'Unable to get destinations, provided templates are empty'
);
Expand All @@ -423,19 +344,17 @@ describe('bin', () => {
// this partially duplicates tests for getDestinations, but we need to ensure initRunnerStub is called with correct values
// no way around it however - sinon cannot mock getDestinations on its own, which could've prevented this
describe('main with destinations from args', () => {
it('should call initRunnerStub with values from getDestinations', async () => {
it('should call initRunnerStub with value from getDestination', async () => {
getAllTemplatesStub.returns(['foo', 'bar']);
getBaseTemplatesStub.returns(['foo']);
fsExistsSyncStub.returns(false);
fsReaddirSyncStub.returns([]);

const mockDestination = 'my\\path';
const proxyDestination = 'my\\proxy';

const args = mockArgs({
templates: 'foo',
destination: mockDestination,
proxyAppDestination: proxyDestination,
});
const expectedTemplates = ['foo'];

Expand All @@ -444,7 +363,6 @@ describe('bin', () => {
expect(initRunnerStub).to.have.been.calledWith(expectedTemplates, {
...args,
destination: mockDestination,
proxyAppDestination: proxyDestination,
templates: expectedTemplates,
});
});
Expand Down
61 changes: 14 additions & 47 deletions packages/create-sitecore-jss/src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import inquirer from 'inquirer';
import { initRunner } from './init-runner';
import minimist, { ParsedArgs } from 'minimist';
import { getAllTemplates, getBaseTemplates } from './common';
import { proxyAppMatcher, getDefaultProxyDestination } from './common/utils/helpers';

export const parseArgs = (): ParsedArgs => {
// parse any command line arguments passed into `init sitecore-jss`
Expand Down Expand Up @@ -35,7 +34,7 @@ export const parseArgs = (): ParsedArgs => {
return args;
};

export const getDestinations = async (args: ParsedArgs, templates: string[]) => {
export const getDestination = async (args: ParsedArgs, templates: string[]) => {
if (templates.length === 0) {
throw new Error('Unable to get destinations, provided templates are empty');
}
Expand All @@ -52,36 +51,7 @@ export const getDestinations = async (args: ParsedArgs, templates: string[]) =>
defaultBaseDestination
);
}

// work with node-proxy destination if needed
const proxyApp = templates.find((template) => template.match(proxyAppMatcher));
if (proxyApp) {
// put the proxy alongside main app by default
const defaultProxyDestination = getDefaultProxyDestination(destination, proxyApp);
let proxyAppDestination = args.proxyAppDestination;
if (!proxyAppDestination) {
proxyAppDestination = args.yes
? defaultProxyDestination
: await promptDestination(
'Where would you like your proxy app created?',
defaultProxyDestination
);
}
while (path.resolve(proxyAppDestination) === path.resolve(destination)) {
proxyAppDestination = await promptDestination(
'Proxy app and base app cannot be located in the same folder. Please input another path for proxy',
defaultProxyDestination
);
}
return {
destination,
proxyAppDestination,
};
}

return {
destination,
};
return destination;
};

export const promptDestination = async (prompt: string, defaultDestination: string) => {
Expand Down Expand Up @@ -133,22 +103,19 @@ export const main = async (args: ParsedArgs) => {
templates.push(answer.template);
}

const destinations = await getDestinations(args, templates);
const destination = await getDestination(args, templates);

for (const destination of [destinations.destination, destinations.proxyAppDestination]) {
if (!destination) continue;
if (!args.force && fs.existsSync(destination) && fs.readdirSync(destination).length > 0) {
const answer = await inquirer.prompt({
type: 'confirm',
name: 'continue',
message: `Directory '${destination}' not empty. Are you sure you want to continue?`,
});
if (!answer.continue) {
process.exit();
}
} else {
args.force = true;
if (!args.force && fs.existsSync(destination) && fs.readdirSync(destination).length > 0) {
const answer = await inquirer.prompt({
type: 'confirm',
name: 'continue',
message: `Directory '${destination}' not empty. Are you sure you want to continue?`,
});
if (!answer.continue) {
process.exit();
}
} else {
args.force = true;
}

if (!args.yes) {
Expand All @@ -169,7 +136,7 @@ export const main = async (args: ParsedArgs) => {
}

try {
await initRunner(templates.slice(), { ...args, ...destinations, templates });
await initRunner(templates.slice(), { ...args, destination, templates });
} catch (error) {
console.log(chalk.red('An error occurred: ', error));
process.exit(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('next', () => {
calls.some(
(call) =>
call.args[0] ===
`JSS application(s) ${chalk.green('my-cool-app, second-app')} is ready!`
`JSS application(s) ${chalk.green('my-cool-app, second-app')} are ready!`
)
).to.equal(true);
});
Expand Down
6 changes: 5 additions & 1 deletion packages/create-sitecore-jss/src/common/processes/next.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ export const nextSteps = async (appNames: string[], nextStepsArr: string[]) => {
console.log(chalk.white(' / // /\\ \\_\\ \\ '));
console.log(chalk.white(' \\___/___/___/'));
console.log();
console.log(`JSS application(s) ${chalk.green(appNames.join(', '))} is ready!`);
console.log(
`JSS application(s) ${chalk.green(appNames.join(', '))} ${
appNames.length > 1 ? 'are' : 'is'
} ready!`
);
console.log();
console.log(chalk.yellow('Next steps:'));
nextStepsArr.forEach((step) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import sinon, { SinonStub } from 'sinon';
import { currentPkg, partialPkg } from '../test-data/pkg';
import * as transform from './transform';
import * as helpers from '../utils/helpers';
import { populateEjsData } from './transform';

const {
transformFilename,
Expand Down Expand Up @@ -465,23 +464,6 @@ describe('transform', () => {
});
});

describe('populateEjsData', () => {
it('should populate relative proxy path (with trailing slash) in helper, if proxyAppDestination populated', () => {
const answers = {
appName: 'JssNextWeb',
hostName: 'http://jssnextweb',
destination: 'samples/next',
proxyAppDestination: 'samples/proxy',
fetchWith: 'REST',
force: false,
templates: [],
language: 'en',
};
const result = populateEjsData(answers);
expect(result.helper.relativeProxyAppDestination).to.equal(`..${sep}proxy${sep}`);
});
});

describe('transform', () => {
let fsMkdirsSyncStub: SinonStub;
let fsCopySyncStub: SinonStub;
Expand Down Expand Up @@ -551,43 +533,6 @@ describe('transform', () => {
});
});

it('should transform file in proxy destination when processing proxy and proxy location destination', async () => {
const templatePath = path.resolve('templates/node-app-proxy');
const destinationPath = path.resolve('samples/next');
const destinationProxy = path.resolve('samples/proxy');
const file = 'file.ts';
const renderFileOutput = 'file output';

globSyncStub = sinon.stub(glob, 'sync').returns([file]);
ejsRenderFileStub = sinon.stub(ejs, 'renderFile').returns(Promise.resolve(renderFileOutput));
diffAndWriteFilesStub = sinon.stub(transform, 'diffAndWriteFiles');

const answers = {
destination: destinationPath,
proxyAppDestination: destinationProxy,
templates: [],
appPrefix: false,
force: false,
};

await transformFunc(templatePath, answers);

expect(ejsRenderFileStub).to.have.been.calledOnceWith(path.join(templatePath, file), {
...answers,
helper: {
isDev: false,
getPascalCaseName: helpers.getPascalCaseName,
getAppPrefix: helpers.getAppPrefix,
relativeProxyAppDestination: `..${sep}proxy${sep}`,
},
});
expect(diffAndWriteFilesStub).to.have.been.calledOnceWith({
rendered: renderFileOutput,
pathToNewFile: path.join(destinationProxy, file),
answers,
});
});

it('should skip if isFileForSkip', async () => {
const templatePath = path.resolve('templates/next');
const destinationPath = path.resolve('samples/next');
Expand Down
Loading
Loading