@form8ion/project 22.0.0-beta.2 → 22.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -24
- package/lib/index.js +101 -77
- package/lib/index.js.map +1 -1
- package/package.json +1 -2
- package/src/dependency-updater/prompt.js +12 -8
- package/src/dependency-updater/prompt.test.js +13 -16
- package/src/dependency-updater/scaffolder.js +2 -2
- package/src/dependency-updater/scaffolder.test.js +6 -10
- package/src/index.js +4 -6
- package/src/language/prompt.js +12 -9
- package/src/language/prompt.test.js +13 -16
- package/src/language/scaffolder.js +2 -2
- package/src/language/scaffolder.test.js +3 -3
- package/src/options-validator.js +0 -2
- package/src/options-validator.test.js +1 -5
- package/src/prompts/index.js +21 -0
- package/src/prompts/questions.js +7 -3
- package/src/prompts/questions.test.js +5 -6
- package/src/scaffolder.js +8 -8
- package/src/scaffolder.test.js +20 -22
- package/src/vcs/host/prompt.js +12 -9
- package/src/vcs/host/prompt.test.js +27 -23
- package/src/vcs/host/scaffolder.js +2 -2
- package/src/vcs/host/scaffolder.test.js +5 -5
- package/src/vcs/prompt.js +8 -8
- package/src/vcs/prompt.test.js +12 -11
- package/src/vcs/scaffolder.js +3 -7
- package/src/vcs/scaffolder.test.js +8 -8
- package/src/options-schemas.js +0 -3
- package/src/options-schemas.test.js +0 -20
package/src/language/prompt.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import {prompt} from '@form8ion/overridable-prompts';
|
|
2
|
-
|
|
3
1
|
import {questionNames} from '../prompts/question-names.js';
|
|
4
2
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
export const PROJECT_LANGUAGE_PROMPT_ID = 'PROJECT_LANGUAGE';
|
|
4
|
+
|
|
5
|
+
export default function promptForProjectLanguage(languages, {prompt}) {
|
|
6
|
+
return prompt({
|
|
7
|
+
id: PROJECT_LANGUAGE_PROMPT_ID,
|
|
8
|
+
questions: [{
|
|
9
|
+
name: questionNames.PROJECT_LANGUAGE,
|
|
10
|
+
type: 'list',
|
|
11
|
+
message: 'What type of project is this?',
|
|
12
|
+
choices: [...Object.keys(languages), 'Other']
|
|
13
|
+
}]
|
|
14
|
+
});
|
|
12
15
|
}
|
|
@@ -1,30 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {afterEach, describe, expect, it, vi} from 'vitest';
|
|
1
|
+
import {describe, expect, it, vi} from 'vitest';
|
|
4
2
|
import any from '@travi/any';
|
|
5
3
|
import {when} from 'vitest-when';
|
|
6
4
|
|
|
7
5
|
import {questionNames} from '../prompts/question-names.js';
|
|
8
|
-
import promptForLanguageDetails from './prompt.js';
|
|
6
|
+
import promptForLanguageDetails, {PROJECT_LANGUAGE_PROMPT_ID} from './prompt.js';
|
|
9
7
|
|
|
10
8
|
vi.mock('@form8ion/overridable-prompts');
|
|
11
9
|
|
|
12
10
|
describe('language prompt', () => {
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
vi.clearAllMocks();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
11
|
it('should prompt for the language details', async () => {
|
|
12
|
+
const prompt = vi.fn();
|
|
18
13
|
const answers = any.simpleObject();
|
|
19
|
-
const decisions = any.simpleObject();
|
|
20
14
|
const languages = any.simpleObject();
|
|
21
|
-
when(prompt).calledWith(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
when(prompt).calledWith({
|
|
16
|
+
id: PROJECT_LANGUAGE_PROMPT_ID,
|
|
17
|
+
questions: [{
|
|
18
|
+
name: questionNames.PROJECT_LANGUAGE,
|
|
19
|
+
type: 'list',
|
|
20
|
+
message: 'What type of project is this?',
|
|
21
|
+
choices: [...Object.keys(languages), 'Other']
|
|
22
|
+
}]
|
|
23
|
+
}).thenResolve(answers);
|
|
27
24
|
|
|
28
|
-
expect(await promptForLanguageDetails(languages,
|
|
25
|
+
expect(await promptForLanguageDetails(languages, {prompt})).toEqual(answers);
|
|
29
26
|
});
|
|
30
27
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {questionNames} from '../prompts/question-names.js';
|
|
2
2
|
import promptForLanguageDetails from './prompt.js';
|
|
3
3
|
|
|
4
|
-
export default async function (languagePlugins,
|
|
5
|
-
const {[questionNames.PROJECT_LANGUAGE]: chosenLanguage} = await promptForLanguageDetails(languagePlugins,
|
|
4
|
+
export default async function (languagePlugins, options, {prompt}) {
|
|
5
|
+
const {[questionNames.PROJECT_LANGUAGE]: chosenLanguage} = await promptForLanguageDetails(languagePlugins, {prompt});
|
|
6
6
|
|
|
7
7
|
const plugin = languagePlugins[chosenLanguage];
|
|
8
8
|
|
|
@@ -13,15 +13,15 @@ describe('language scaffolder', () => {
|
|
|
13
13
|
const options = any.simpleObject();
|
|
14
14
|
const chosenLanguage = any.word();
|
|
15
15
|
const scaffolderResult = any.simpleObject();
|
|
16
|
-
const
|
|
16
|
+
const prompt = () => undefined;
|
|
17
17
|
const chosenLanguageScaffolder = vi.fn();
|
|
18
18
|
const plugins = {...any.simpleObject(), [chosenLanguage]: {scaffold: chosenLanguageScaffolder}};
|
|
19
19
|
when(languagePrompt.default)
|
|
20
|
-
.calledWith(plugins,
|
|
20
|
+
.calledWith(plugins, {prompt})
|
|
21
21
|
.thenResolve({[questionNames.PROJECT_LANGUAGE]: chosenLanguage});
|
|
22
22
|
when(chosenLanguageScaffolder).calledWith(options).thenResolve(scaffolderResult);
|
|
23
23
|
|
|
24
|
-
expect(await scaffold(plugins,
|
|
24
|
+
expect(await scaffold(plugins, options, {prompt})).toEqual(scaffolderResult);
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
it('should not result in an error when choosing a language without a defined scaffolder', async () => {
|
package/src/options-validator.js
CHANGED
|
@@ -4,11 +4,9 @@ import joi from 'joi';
|
|
|
4
4
|
import languagePluginsSchema from './language/schema.js';
|
|
5
5
|
import vcsHostPluginsSchema from './vcs/host/schema.js';
|
|
6
6
|
import dependencyUpdaterPluginsSchema from './dependency-updater/schema.js';
|
|
7
|
-
import {decisionsSchema} from './options-schemas.js';
|
|
8
7
|
|
|
9
8
|
export function validate(options) {
|
|
10
9
|
return validateOptions(joi.object({
|
|
11
|
-
decisions: decisionsSchema,
|
|
12
10
|
plugins: joi.object({
|
|
13
11
|
dependencyUpdaters: dependencyUpdaterPluginsSchema,
|
|
14
12
|
languages: languagePluginsSchema,
|
|
@@ -6,7 +6,6 @@ import any from '@travi/any';
|
|
|
6
6
|
import {when} from 'vitest-when';
|
|
7
7
|
|
|
8
8
|
import languagePluginsSchema from './language/schema.js';
|
|
9
|
-
import {decisionsSchema} from './options-schemas.js';
|
|
10
9
|
import vcsHostPluginsSchema from './vcs/host/schema.js';
|
|
11
10
|
import dependencyUpdaterPluginsSchema from './dependency-updater/schema.js';
|
|
12
11
|
import {validate} from './options-validator.js';
|
|
@@ -39,10 +38,7 @@ describe('options validator', () => {
|
|
|
39
38
|
vcsHosts: vcsHostPluginsSchema
|
|
40
39
|
})
|
|
41
40
|
.thenReturn(pluginsSchema);
|
|
42
|
-
when(joi.object).calledWith({
|
|
43
|
-
decisions: decisionsSchema,
|
|
44
|
-
plugins: pluginsSchema
|
|
45
|
-
}).thenReturn(fullSchema);
|
|
41
|
+
when(joi.object).calledWith({plugins: pluginsSchema}).thenReturn(fullSchema);
|
|
46
42
|
when(core.validateOptions).calledWith(fullSchema, options).thenReturn(validatedOptions);
|
|
47
43
|
|
|
48
44
|
expect(validate(options)).toEqual(validatedOptions);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {questionNames as coreQuestionNames} from '@form8ion/core';
|
|
2
|
+
|
|
3
|
+
import {BASE_DETAILS_PROMPT_ID} from './questions.js';
|
|
4
|
+
import {GIT_REPOSITORY_PROMPT_ID} from '../vcs/prompt.js';
|
|
5
|
+
import {PROJECT_LANGUAGE_PROMPT_ID} from '../language/prompt.js';
|
|
6
|
+
import {REPOSITORY_HOST_PROMPT_ID} from '../vcs/host/prompt.js';
|
|
7
|
+
import {DEPENDENCY_UPDATER_PROMPT_ID} from '../dependency-updater/prompt.js';
|
|
8
|
+
import {questionNames as projectScaffolderQuestionNames} from './question-names.js';
|
|
9
|
+
|
|
10
|
+
export const ids = {
|
|
11
|
+
BASE_DETAILS: BASE_DETAILS_PROMPT_ID,
|
|
12
|
+
GIT_REPOSITORY: GIT_REPOSITORY_PROMPT_ID,
|
|
13
|
+
REPOSITORY_HOST: REPOSITORY_HOST_PROMPT_ID,
|
|
14
|
+
PROJECT_LANGUAGE: PROJECT_LANGUAGE_PROMPT_ID,
|
|
15
|
+
DEPENDENCY_UPDATER: DEPENDENCY_UPDATER_PROMPT_ID
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const questionNames = {
|
|
19
|
+
...coreQuestionNames,
|
|
20
|
+
...projectScaffolderQuestionNames
|
|
21
|
+
};
|
package/src/prompts/questions.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import {questionsForBaseDetails} from '@form8ion/core';
|
|
2
|
-
import {prompt} from '@form8ion/overridable-prompts';
|
|
3
2
|
|
|
4
|
-
export
|
|
5
|
-
|
|
3
|
+
export const BASE_DETAILS_PROMPT_ID = 'BASE_DETAILS';
|
|
4
|
+
|
|
5
|
+
export function promptForBaseDetails(projectRoot, {prompt}) {
|
|
6
|
+
return prompt({
|
|
7
|
+
id: BASE_DETAILS_PROMPT_ID,
|
|
8
|
+
questions: questionsForBaseDetails(projectRoot)
|
|
9
|
+
});
|
|
6
10
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import * as core from '@form8ion/core';
|
|
2
|
-
import * as prompts from '@form8ion/overridable-prompts';
|
|
3
2
|
|
|
4
3
|
import {describe, expect, it, vi} from 'vitest';
|
|
5
4
|
import any from '@travi/any';
|
|
6
5
|
import {when} from 'vitest-when';
|
|
7
6
|
|
|
8
|
-
import {promptForBaseDetails} from './questions.js';
|
|
7
|
+
import {promptForBaseDetails, BASE_DETAILS_PROMPT_ID} from './questions.js';
|
|
9
8
|
|
|
10
9
|
vi.mock('@form8ion/core');
|
|
11
10
|
vi.mock('@form8ion/overridable-prompts');
|
|
@@ -13,13 +12,13 @@ vi.mock('@form8ion/overridable-prompts');
|
|
|
13
12
|
describe('base details prompt', () => {
|
|
14
13
|
const projectPath = any.string();
|
|
15
14
|
const answers = any.simpleObject();
|
|
16
|
-
const decisions = any.simpleObject();
|
|
17
15
|
const questions = any.listOf(any.simpleObject);
|
|
16
|
+
const prompt = vi.fn();
|
|
18
17
|
|
|
19
18
|
it('should prompt for the necessary details', async () => {
|
|
20
|
-
when(core.questionsForBaseDetails).calledWith(
|
|
21
|
-
when(
|
|
19
|
+
when(core.questionsForBaseDetails).calledWith(projectPath).thenReturn(questions);
|
|
20
|
+
when(prompt).calledWith({id: BASE_DETAILS_PROMPT_ID, questions}).thenResolve(answers);
|
|
22
21
|
|
|
23
|
-
expect(await promptForBaseDetails(projectPath,
|
|
22
|
+
expect(await promptForBaseDetails(projectPath, {prompt})).toEqual(answers);
|
|
24
23
|
});
|
|
25
24
|
});
|
package/src/scaffolder.js
CHANGED
|
@@ -15,9 +15,9 @@ import {scaffold as scaffoldEditorConfig} from './editorconfig/index.js';
|
|
|
15
15
|
import {scaffold as scaffoldContributing} from './contributing/index.js';
|
|
16
16
|
import lift from './lift.js';
|
|
17
17
|
|
|
18
|
-
export async function scaffold(options) {
|
|
18
|
+
export async function scaffold(options, {prompt}) {
|
|
19
19
|
const projectRoot = process.cwd();
|
|
20
|
-
const {
|
|
20
|
+
const {plugins: {dependencyUpdaters, languages, vcsHosts = {}}} = validate(options);
|
|
21
21
|
|
|
22
22
|
const {
|
|
23
23
|
[coreQuestionNames.PROJECT_NAME]: projectName,
|
|
@@ -26,11 +26,11 @@ export async function scaffold(options) {
|
|
|
26
26
|
[coreQuestionNames.DESCRIPTION]: description,
|
|
27
27
|
[coreQuestionNames.COPYRIGHT_YEAR]: copyrightYear,
|
|
28
28
|
[coreQuestionNames.COPYRIGHT_HOLDER]: copyHolder
|
|
29
|
-
} = await promptForBaseDetails(projectRoot,
|
|
29
|
+
} = await promptForBaseDetails(projectRoot, {prompt});
|
|
30
30
|
const copyright = {year: copyrightYear, holder: copyHolder};
|
|
31
31
|
|
|
32
32
|
const [vcsResults, contributing, license] = await Promise.all([
|
|
33
|
-
scaffoldVcs({projectRoot, projectName,
|
|
33
|
+
scaffoldVcs({projectRoot, projectName, vcsHosts, visibility, description}, {prompt}),
|
|
34
34
|
scaffoldContributing({visibility}),
|
|
35
35
|
scaffoldLicense({projectRoot, license: chosenLicense, copyright}),
|
|
36
36
|
scaffoldReadme({projectName, projectRoot, description}),
|
|
@@ -39,14 +39,14 @@ export async function scaffold(options) {
|
|
|
39
39
|
|
|
40
40
|
const dependencyUpdaterResults = vcsResults.vcs && await scaffoldDependencyUpdater(
|
|
41
41
|
dependencyUpdaters,
|
|
42
|
-
|
|
43
|
-
{
|
|
42
|
+
{projectRoot},
|
|
43
|
+
{prompt}
|
|
44
44
|
);
|
|
45
45
|
|
|
46
46
|
const language = await scaffoldLanguage(
|
|
47
47
|
languages,
|
|
48
|
-
|
|
49
|
-
{
|
|
48
|
+
{projectRoot, projectName, vcs: vcsResults.vcs, visibility, license: chosenLicense || 'UNLICENSED', description},
|
|
49
|
+
{prompt}
|
|
50
50
|
);
|
|
51
51
|
|
|
52
52
|
const mergedResults = deepmerge.all([
|
package/src/scaffolder.test.js
CHANGED
|
@@ -52,7 +52,7 @@ describe('project scaffolder', () => {
|
|
|
52
52
|
const tags = any.listOf(any.word);
|
|
53
53
|
const visibility = any.word();
|
|
54
54
|
const vcsIgnore = any.simpleObject();
|
|
55
|
-
const
|
|
55
|
+
const prompt = () => undefined;
|
|
56
56
|
|
|
57
57
|
beforeEach(() => {
|
|
58
58
|
process.cwd = vi.fn();
|
|
@@ -95,9 +95,9 @@ describe('project scaffolder', () => {
|
|
|
95
95
|
]);
|
|
96
96
|
when(optionsValidator.validate)
|
|
97
97
|
.calledWith(options)
|
|
98
|
-
.thenReturn({
|
|
98
|
+
.thenReturn({plugins: {dependencyUpdaters, languages, vcsHosts}});
|
|
99
99
|
when(prompts.promptForBaseDetails)
|
|
100
|
-
.calledWith(projectPath,
|
|
100
|
+
.calledWith(projectPath, {prompt})
|
|
101
101
|
.thenResolve({
|
|
102
102
|
[coreQuestionNames.PROJECT_NAME]: projectName,
|
|
103
103
|
[coreQuestionNames.LICENSE]: license,
|
|
@@ -107,18 +107,18 @@ describe('project scaffolder', () => {
|
|
|
107
107
|
[coreQuestionNames.VISIBILITY]: visibility
|
|
108
108
|
});
|
|
109
109
|
when(scaffoldVcs)
|
|
110
|
-
.calledWith({projectRoot: projectPath, projectName,
|
|
110
|
+
.calledWith({projectRoot: projectPath, projectName, vcsHosts, visibility, description}, {prompt})
|
|
111
111
|
.thenResolve(vcsResults);
|
|
112
112
|
when(licenseScaffolder.default)
|
|
113
113
|
.calledWith({projectRoot: projectPath, license, copyright})
|
|
114
114
|
.thenResolve(licenseResults);
|
|
115
115
|
scaffoldLanguage.mockResolvedValue(languageResults);
|
|
116
116
|
when(dependencyUpdaterScaffolder.default)
|
|
117
|
-
.calledWith(dependencyUpdaters,
|
|
117
|
+
.calledWith(dependencyUpdaters, {projectRoot: projectPath}, {prompt})
|
|
118
118
|
.thenResolve(dependencyUpdaterResults);
|
|
119
119
|
when(scaffoldContributing).calledWith({visibility}).thenReturn(contributingResults);
|
|
120
120
|
|
|
121
|
-
await scaffold(options);
|
|
121
|
+
await scaffold(options, {prompt});
|
|
122
122
|
|
|
123
123
|
expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description});
|
|
124
124
|
expect(scaffoldEditorconfig).toHaveBeenCalledWith({projectRoot: projectPath});
|
|
@@ -155,7 +155,7 @@ describe('project scaffolder', () => {
|
|
|
155
155
|
const languageResults = {badges: languageBadges, vcsIgnore, documentation};
|
|
156
156
|
when(optionsValidator.validate).calledWith(options).thenReturn({plugins: {vcsHosts}});
|
|
157
157
|
when(prompts.promptForBaseDetails)
|
|
158
|
-
.calledWith(projectPath,
|
|
158
|
+
.calledWith(projectPath, {prompt})
|
|
159
159
|
.thenResolve({
|
|
160
160
|
[coreQuestionNames.DESCRIPTION]: description,
|
|
161
161
|
[questionNames.GIT_REPO]: true,
|
|
@@ -168,7 +168,7 @@ describe('project scaffolder', () => {
|
|
|
168
168
|
licenseScaffolder.default.mockResolvedValue({badges: licenseBadges});
|
|
169
169
|
scaffoldVcs.mockResolvedValue(vcsResults);
|
|
170
170
|
|
|
171
|
-
await scaffold(options);
|
|
171
|
+
await scaffold(options, {prompt});
|
|
172
172
|
|
|
173
173
|
expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description});
|
|
174
174
|
});
|
|
@@ -179,7 +179,7 @@ describe('project scaffolder', () => {
|
|
|
179
179
|
scaffoldReadme.mockResolvedValue();
|
|
180
180
|
scaffoldVcs.mockResolvedValue({});
|
|
181
181
|
|
|
182
|
-
await scaffold(options);
|
|
182
|
+
await scaffold(options, {prompt});
|
|
183
183
|
|
|
184
184
|
expect(dependencyUpdaterScaffolder.default).not.toHaveBeenCalled();
|
|
185
185
|
});
|
|
@@ -204,9 +204,7 @@ describe('project scaffolder', () => {
|
|
|
204
204
|
nextSteps: languageNextSteps,
|
|
205
205
|
tags
|
|
206
206
|
};
|
|
207
|
-
when(optionsValidator.validate)
|
|
208
|
-
.calledWith(options)
|
|
209
|
-
.thenReturn({decisions, plugins: {languages, vcsHosts}});
|
|
207
|
+
when(optionsValidator.validate).calledWith(options).thenReturn({plugins: {languages, vcsHosts}});
|
|
210
208
|
scaffoldVcs.mockResolvedValue(vcsResults);
|
|
211
209
|
prompts.promptForBaseDetails.mockResolvedValue({
|
|
212
210
|
[coreQuestionNames.PROJECT_NAME]: projectName,
|
|
@@ -215,20 +213,20 @@ describe('project scaffolder', () => {
|
|
|
215
213
|
[coreQuestionNames.LICENSE]: license,
|
|
216
214
|
[coreQuestionNames.DESCRIPTION]: description
|
|
217
215
|
});
|
|
218
|
-
when(scaffoldLanguage).calledWith(languages,
|
|
216
|
+
when(scaffoldLanguage).calledWith(languages, {
|
|
219
217
|
projectName,
|
|
220
218
|
projectRoot: projectPath,
|
|
221
219
|
visibility,
|
|
222
220
|
license,
|
|
223
221
|
vcs,
|
|
224
222
|
description
|
|
225
|
-
}).thenResolve(languageResults);
|
|
223
|
+
}, {prompt}).thenResolve(languageResults);
|
|
226
224
|
when(execa).calledWith(verificationCommand, {shell: true}).thenReturn({stdout: {pipe: execaPipe}});
|
|
227
225
|
dependencyUpdaterScaffolder.default.mockResolvedValue({});
|
|
228
226
|
licenseScaffolder.default.mockResolvedValue({});
|
|
229
227
|
scaffoldContributing.mockResolvedValue({});
|
|
230
228
|
|
|
231
|
-
await scaffold(options);
|
|
229
|
+
await scaffold(options, {prompt});
|
|
232
230
|
|
|
233
231
|
expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description});
|
|
234
232
|
expect(execaPipe).toHaveBeenCalledWith(process.stdout);
|
|
@@ -238,7 +236,7 @@ describe('project scaffolder', () => {
|
|
|
238
236
|
it('should consider the language details to be optional', async () => {
|
|
239
237
|
when(optionsValidator.validate)
|
|
240
238
|
.calledWith(options)
|
|
241
|
-
.thenReturn({vcsHosts,
|
|
239
|
+
.thenReturn({vcsHosts, plugins: {languages}});
|
|
242
240
|
scaffoldVcs.mockResolvedValue(vcsResults);
|
|
243
241
|
prompts.promptForBaseDetails.mockResolvedValue({
|
|
244
242
|
[coreQuestionNames.PROJECT_NAME]: projectName,
|
|
@@ -252,22 +250,21 @@ describe('project scaffolder', () => {
|
|
|
252
250
|
licenseScaffolder.default.mockResolvedValue({});
|
|
253
251
|
scaffoldContributing.mockResolvedValue({});
|
|
254
252
|
|
|
255
|
-
await scaffold(options);
|
|
253
|
+
await scaffold(options, {prompt});
|
|
256
254
|
|
|
257
255
|
expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description});
|
|
258
256
|
expect(execa).not.toHaveBeenCalled();
|
|
259
257
|
});
|
|
260
258
|
|
|
261
259
|
it('should pass the license to the language scaffolder as `UNLICENSED` when no license was chosen', async () => {
|
|
262
|
-
when(optionsValidator.validate).calledWith(options).thenReturn({plugins: {languages}
|
|
260
|
+
when(optionsValidator.validate).calledWith(options).thenReturn({plugins: {languages}});
|
|
263
261
|
prompts.promptForBaseDetails.mockResolvedValue({});
|
|
264
262
|
scaffoldVcs.mockResolvedValue(vcsResults);
|
|
265
263
|
|
|
266
|
-
await scaffold(options);
|
|
264
|
+
await scaffold(options, {prompt});
|
|
267
265
|
|
|
268
266
|
expect(scaffoldLanguage).toHaveBeenCalledWith(
|
|
269
267
|
languages,
|
|
270
|
-
decisions,
|
|
271
268
|
{
|
|
272
269
|
license: 'UNLICENSED',
|
|
273
270
|
description: undefined,
|
|
@@ -275,7 +272,8 @@ describe('project scaffolder', () => {
|
|
|
275
272
|
projectRoot: projectPath,
|
|
276
273
|
vcs,
|
|
277
274
|
visibility: undefined
|
|
278
|
-
}
|
|
275
|
+
},
|
|
276
|
+
{prompt}
|
|
279
277
|
);
|
|
280
278
|
});
|
|
281
279
|
|
|
@@ -285,7 +283,7 @@ describe('project scaffolder', () => {
|
|
|
285
283
|
scaffoldVcs.mockResolvedValue({});
|
|
286
284
|
scaffoldLanguage.mockResolvedValue({badges: {}, projectDetails: {}});
|
|
287
285
|
|
|
288
|
-
await scaffold(options);
|
|
286
|
+
await scaffold(options, {prompt});
|
|
289
287
|
|
|
290
288
|
expect(execa).not.toHaveBeenCalled();
|
|
291
289
|
});
|
package/src/vcs/host/prompt.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import {prompt} from '@form8ion/overridable-prompts';
|
|
2
|
-
|
|
3
1
|
import {questionNames} from '../../prompts/question-names.js';
|
|
4
2
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
export const REPOSITORY_HOST_PROMPT_ID = 'REPOSITORY_HOST';
|
|
4
|
+
|
|
5
|
+
export default async function promptForVcsHostChoice(hosts, {prompt}) {
|
|
6
|
+
const answers = await prompt({
|
|
7
|
+
id: REPOSITORY_HOST_PROMPT_ID,
|
|
8
|
+
questions: [{
|
|
9
|
+
name: questionNames.REPO_HOST,
|
|
10
|
+
type: 'list',
|
|
11
|
+
message: 'Where will the repository be hosted?',
|
|
12
|
+
choices: Object.keys(hosts)
|
|
13
|
+
}]
|
|
14
|
+
});
|
|
12
15
|
const host = hosts[answers[questionNames.REPO_HOST]];
|
|
13
16
|
|
|
14
17
|
return {...answers, ...host};
|
|
@@ -1,21 +1,19 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {afterEach, describe, expect, it, vi} from 'vitest';
|
|
1
|
+
import {beforeEach, describe, expect, it, vi} from 'vitest';
|
|
4
2
|
import any from '@travi/any';
|
|
5
3
|
import {when} from 'vitest-when';
|
|
6
4
|
|
|
7
5
|
import {questionNames} from '../../prompts/question-names.js';
|
|
8
|
-
import promptForVcsHostDetails from './prompt.js';
|
|
6
|
+
import promptForVcsHostDetails, {REPOSITORY_HOST_PROMPT_ID} from './prompt.js';
|
|
9
7
|
|
|
10
8
|
vi.mock('@form8ion/overridable-prompts');
|
|
11
9
|
vi.mock('../../prompts/conditionals');
|
|
12
10
|
|
|
13
11
|
describe('vcs host details prompt', () => {
|
|
12
|
+
let prompt;
|
|
14
13
|
const answers = any.simpleObject();
|
|
15
|
-
const decisions = any.simpleObject();
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
vi.
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
prompt = vi.fn();
|
|
19
17
|
});
|
|
20
18
|
|
|
21
19
|
it('should prompt for the vcs hosting details', async () => {
|
|
@@ -23,25 +21,31 @@ describe('vcs host details prompt', () => {
|
|
|
23
21
|
const hostNames = [...any.listOf(any.string), host];
|
|
24
22
|
const hosts = any.objectWithKeys(hostNames, {factory: () => ({})});
|
|
25
23
|
const answersWithHostChoice = {...answers, [questionNames.REPO_HOST]: host};
|
|
26
|
-
when(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
when(prompt).calledWith({
|
|
25
|
+
id: REPOSITORY_HOST_PROMPT_ID,
|
|
26
|
+
questions: [{
|
|
27
|
+
name: questionNames.REPO_HOST,
|
|
28
|
+
type: 'list',
|
|
29
|
+
message: 'Where will the repository be hosted?',
|
|
30
|
+
choices: hostNames
|
|
31
|
+
}]
|
|
32
|
+
}).thenResolve(answersWithHostChoice);
|
|
33
|
+
|
|
34
|
+
expect(await promptForVcsHostDetails(hosts, {prompt})).toEqual(answersWithHostChoice);
|
|
34
35
|
});
|
|
35
36
|
|
|
36
37
|
it('should not throw an error when `Other` is chosen as the host', async () => {
|
|
37
38
|
const answersWithHostChoice = {...answers, [questionNames.REPO_HOST]: 'Other'};
|
|
38
|
-
when(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
when(prompt).calledWith({
|
|
40
|
+
id: REPOSITORY_HOST_PROMPT_ID,
|
|
41
|
+
questions: [{
|
|
42
|
+
name: questionNames.REPO_HOST,
|
|
43
|
+
type: 'list',
|
|
44
|
+
message: 'Where will the repository be hosted?',
|
|
45
|
+
choices: []
|
|
46
|
+
}]
|
|
47
|
+
}).thenResolve(answersWithHostChoice);
|
|
48
|
+
|
|
49
|
+
expect(await promptForVcsHostDetails({}, {prompt})).toEqual(answersWithHostChoice);
|
|
46
50
|
});
|
|
47
51
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {questionNames} from '../../prompts/question-names.js';
|
|
2
2
|
import promptForVcsHostDetails from './prompt.js';
|
|
3
3
|
|
|
4
|
-
export default async function scaffoldVcsHost(hosts,
|
|
5
|
-
const {[questionNames.REPO_HOST]: chosenHost} = await promptForVcsHostDetails(hosts,
|
|
4
|
+
export default async function scaffoldVcsHost(hosts, options, {prompt}) {
|
|
5
|
+
const {[questionNames.REPO_HOST]: chosenHost} = await promptForVcsHostDetails(hosts, {prompt});
|
|
6
6
|
|
|
7
7
|
const lowercasedHosts = Object.fromEntries(
|
|
8
8
|
Object.entries(hosts).map(([name, details]) => [name.toLowerCase(), details])
|
|
@@ -10,7 +10,7 @@ vi.mock('./prompt');
|
|
|
10
10
|
|
|
11
11
|
describe('vcs host scaffolder', () => {
|
|
12
12
|
const options = any.simpleObject();
|
|
13
|
-
const
|
|
13
|
+
const prompt = () => undefined;
|
|
14
14
|
|
|
15
15
|
it('should scaffold the chosen vcs host', async () => {
|
|
16
16
|
const chosenHost = `${any.word()}CAPITAL${any.word()}`;
|
|
@@ -19,19 +19,19 @@ describe('vcs host scaffolder', () => {
|
|
|
19
19
|
const hostPlugins = {...any.simpleObject(), [chosenHost.toLowerCase()]: {scaffold: chosenHostScaffolder}};
|
|
20
20
|
const owner = any.word;
|
|
21
21
|
when(promptForVcsHostDetails)
|
|
22
|
-
.calledWith(hostPlugins,
|
|
22
|
+
.calledWith(hostPlugins, {prompt})
|
|
23
23
|
.thenResolve({[questionNames.REPO_HOST]: chosenHost, [questionNames.REPO_OWNER]: owner});
|
|
24
24
|
when(chosenHostScaffolder).calledWith(options).thenResolve(results);
|
|
25
25
|
|
|
26
|
-
expect(await scaffoldVcsHost(hostPlugins,
|
|
26
|
+
expect(await scaffoldVcsHost(hostPlugins, options, {prompt})).toEqual(results);
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
it('should return empty `vcs` results when no matching host is available', async () => {
|
|
30
30
|
const hostPlugins = any.simpleObject();
|
|
31
31
|
when(promptForVcsHostDetails)
|
|
32
|
-
.calledWith(hostPlugins,
|
|
32
|
+
.calledWith(hostPlugins, {prompt})
|
|
33
33
|
.thenResolve({[questionNames.REPO_HOST]: any.word()});
|
|
34
34
|
|
|
35
|
-
expect(await scaffoldVcsHost(hostPlugins,
|
|
35
|
+
expect(await scaffoldVcsHost(hostPlugins, options, {prompt})).toEqual({vcs: {}});
|
|
36
36
|
});
|
|
37
37
|
});
|
package/src/vcs/prompt.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import {prompt} from '@form8ion/overridable-prompts';
|
|
2
|
-
|
|
3
1
|
import {questionNames} from '../prompts/question-names.js';
|
|
4
2
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
export const GIT_REPOSITORY_PROMPT_ID = 'GIT_REPOSITORY';
|
|
4
|
+
|
|
5
|
+
export default async function promptForRepoCreation({prompt}) {
|
|
6
|
+
const {[questionNames.GIT_REPO]: gitRepoShouldBeCreated} = await prompt({
|
|
7
|
+
id: GIT_REPOSITORY_PROMPT_ID,
|
|
8
|
+
questions: [{
|
|
8
9
|
name: questionNames.GIT_REPO,
|
|
9
10
|
type: 'confirm',
|
|
10
11
|
default: true,
|
|
11
12
|
message: 'Should a git repository be initialized?'
|
|
12
|
-
}]
|
|
13
|
-
|
|
14
|
-
);
|
|
13
|
+
}]
|
|
14
|
+
});
|
|
15
15
|
|
|
16
16
|
return gitRepoShouldBeCreated;
|
|
17
17
|
}
|
package/src/vcs/prompt.test.js
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
|
-
import {prompt} from '@form8ion/overridable-prompts';
|
|
2
|
-
|
|
3
1
|
import {describe, vi, it, expect} from 'vitest';
|
|
4
2
|
import {when} from 'vitest-when';
|
|
5
3
|
import any from '@travi/any';
|
|
6
4
|
|
|
7
5
|
import {questionNames} from '../prompts/question-names.js';
|
|
8
|
-
import promptForRepoCreation from './prompt.js';
|
|
6
|
+
import promptForRepoCreation, {GIT_REPOSITORY_PROMPT_ID} from './prompt.js';
|
|
9
7
|
|
|
10
8
|
vi.mock('@form8ion/overridable-prompts');
|
|
11
9
|
|
|
12
10
|
describe('git prompt', () => {
|
|
13
11
|
it('should ask whether a repository should be created', async () => {
|
|
14
|
-
const
|
|
12
|
+
const prompt = vi.fn();
|
|
15
13
|
const repoShouldBeCreated = any.boolean();
|
|
16
14
|
when(prompt)
|
|
17
|
-
.calledWith(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
.calledWith({
|
|
16
|
+
id: GIT_REPOSITORY_PROMPT_ID,
|
|
17
|
+
questions: [{
|
|
18
|
+
name: questionNames.GIT_REPO,
|
|
19
|
+
type: 'confirm',
|
|
20
|
+
default: true,
|
|
21
|
+
message: 'Should a git repository be initialized?'
|
|
22
|
+
}]
|
|
23
|
+
})
|
|
23
24
|
.thenResolve({[questionNames.GIT_REPO]: repoShouldBeCreated});
|
|
24
25
|
|
|
25
|
-
expect(await promptForRepoCreation(
|
|
26
|
+
expect(await promptForRepoCreation({prompt})).toBe(repoShouldBeCreated);
|
|
26
27
|
});
|
|
27
28
|
});
|
package/src/vcs/scaffolder.js
CHANGED
|
@@ -5,8 +5,8 @@ import repositoryShouldBeCreated from './prompt.js';
|
|
|
5
5
|
import {determineExistingVcsDetails, defineRemoteOrigin} from './git/index.js';
|
|
6
6
|
import {scaffold as scaffoldVcsHost} from './host/index.js';
|
|
7
7
|
|
|
8
|
-
export default async function scaffoldVcs({projectRoot, projectName,
|
|
9
|
-
if (await repositoryShouldBeCreated(
|
|
8
|
+
export default async function scaffoldVcs({projectRoot, projectName, vcsHosts, visibility, description}, {prompt}) {
|
|
9
|
+
if (await repositoryShouldBeCreated({prompt})) {
|
|
10
10
|
if (await alreadyVersionedByGit({projectRoot})) {
|
|
11
11
|
info('Git repository already exists');
|
|
12
12
|
|
|
@@ -14,11 +14,7 @@ export default async function scaffoldVcs({projectRoot, projectName, decisions,
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
const [{vcs: {host, owner, name, sshUrl}}] = await Promise.all([
|
|
17
|
-
scaffoldVcsHost(
|
|
18
|
-
vcsHosts,
|
|
19
|
-
decisions,
|
|
20
|
-
{projectName, projectRoot, description, visibility}
|
|
21
|
-
),
|
|
17
|
+
scaffoldVcsHost(vcsHosts, {projectName, projectRoot, description, visibility}, {prompt}),
|
|
22
18
|
scaffoldGit({projectRoot})
|
|
23
19
|
]);
|
|
24
20
|
|