@form8ion/project 22.0.0-beta.1 → 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 -27
- 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,25 +107,20 @@ 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
|
-
expect(dependencyUpdaterScaffolder.default).toHaveBeenCalledWith(
|
|
125
|
-
dependencyUpdaters,
|
|
126
|
-
decisions,
|
|
127
|
-
{projectRoot: projectPath, vcs}
|
|
128
|
-
);
|
|
129
124
|
expect(scaffoldEditorconfig).toHaveBeenCalledWith({projectRoot: projectPath});
|
|
130
125
|
expect(lift).toHaveBeenCalledWith({
|
|
131
126
|
projectRoot: projectPath,
|
|
@@ -160,7 +155,7 @@ describe('project scaffolder', () => {
|
|
|
160
155
|
const languageResults = {badges: languageBadges, vcsIgnore, documentation};
|
|
161
156
|
when(optionsValidator.validate).calledWith(options).thenReturn({plugins: {vcsHosts}});
|
|
162
157
|
when(prompts.promptForBaseDetails)
|
|
163
|
-
.calledWith(projectPath,
|
|
158
|
+
.calledWith(projectPath, {prompt})
|
|
164
159
|
.thenResolve({
|
|
165
160
|
[coreQuestionNames.DESCRIPTION]: description,
|
|
166
161
|
[questionNames.GIT_REPO]: true,
|
|
@@ -173,7 +168,7 @@ describe('project scaffolder', () => {
|
|
|
173
168
|
licenseScaffolder.default.mockResolvedValue({badges: licenseBadges});
|
|
174
169
|
scaffoldVcs.mockResolvedValue(vcsResults);
|
|
175
170
|
|
|
176
|
-
await scaffold(options);
|
|
171
|
+
await scaffold(options, {prompt});
|
|
177
172
|
|
|
178
173
|
expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description});
|
|
179
174
|
});
|
|
@@ -184,7 +179,7 @@ describe('project scaffolder', () => {
|
|
|
184
179
|
scaffoldReadme.mockResolvedValue();
|
|
185
180
|
scaffoldVcs.mockResolvedValue({});
|
|
186
181
|
|
|
187
|
-
await scaffold(options);
|
|
182
|
+
await scaffold(options, {prompt});
|
|
188
183
|
|
|
189
184
|
expect(dependencyUpdaterScaffolder.default).not.toHaveBeenCalled();
|
|
190
185
|
});
|
|
@@ -209,9 +204,7 @@ describe('project scaffolder', () => {
|
|
|
209
204
|
nextSteps: languageNextSteps,
|
|
210
205
|
tags
|
|
211
206
|
};
|
|
212
|
-
when(optionsValidator.validate)
|
|
213
|
-
.calledWith(options)
|
|
214
|
-
.thenReturn({decisions, plugins: {languages, vcsHosts}});
|
|
207
|
+
when(optionsValidator.validate).calledWith(options).thenReturn({plugins: {languages, vcsHosts}});
|
|
215
208
|
scaffoldVcs.mockResolvedValue(vcsResults);
|
|
216
209
|
prompts.promptForBaseDetails.mockResolvedValue({
|
|
217
210
|
[coreQuestionNames.PROJECT_NAME]: projectName,
|
|
@@ -220,20 +213,20 @@ describe('project scaffolder', () => {
|
|
|
220
213
|
[coreQuestionNames.LICENSE]: license,
|
|
221
214
|
[coreQuestionNames.DESCRIPTION]: description
|
|
222
215
|
});
|
|
223
|
-
when(scaffoldLanguage).calledWith(languages,
|
|
216
|
+
when(scaffoldLanguage).calledWith(languages, {
|
|
224
217
|
projectName,
|
|
225
218
|
projectRoot: projectPath,
|
|
226
219
|
visibility,
|
|
227
220
|
license,
|
|
228
221
|
vcs,
|
|
229
222
|
description
|
|
230
|
-
}).thenResolve(languageResults);
|
|
223
|
+
}, {prompt}).thenResolve(languageResults);
|
|
231
224
|
when(execa).calledWith(verificationCommand, {shell: true}).thenReturn({stdout: {pipe: execaPipe}});
|
|
232
225
|
dependencyUpdaterScaffolder.default.mockResolvedValue({});
|
|
233
226
|
licenseScaffolder.default.mockResolvedValue({});
|
|
234
227
|
scaffoldContributing.mockResolvedValue({});
|
|
235
228
|
|
|
236
|
-
await scaffold(options);
|
|
229
|
+
await scaffold(options, {prompt});
|
|
237
230
|
|
|
238
231
|
expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description});
|
|
239
232
|
expect(execaPipe).toHaveBeenCalledWith(process.stdout);
|
|
@@ -243,7 +236,7 @@ describe('project scaffolder', () => {
|
|
|
243
236
|
it('should consider the language details to be optional', async () => {
|
|
244
237
|
when(optionsValidator.validate)
|
|
245
238
|
.calledWith(options)
|
|
246
|
-
.thenReturn({vcsHosts,
|
|
239
|
+
.thenReturn({vcsHosts, plugins: {languages}});
|
|
247
240
|
scaffoldVcs.mockResolvedValue(vcsResults);
|
|
248
241
|
prompts.promptForBaseDetails.mockResolvedValue({
|
|
249
242
|
[coreQuestionNames.PROJECT_NAME]: projectName,
|
|
@@ -257,22 +250,21 @@ describe('project scaffolder', () => {
|
|
|
257
250
|
licenseScaffolder.default.mockResolvedValue({});
|
|
258
251
|
scaffoldContributing.mockResolvedValue({});
|
|
259
252
|
|
|
260
|
-
await scaffold(options);
|
|
253
|
+
await scaffold(options, {prompt});
|
|
261
254
|
|
|
262
255
|
expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description});
|
|
263
256
|
expect(execa).not.toHaveBeenCalled();
|
|
264
257
|
});
|
|
265
258
|
|
|
266
259
|
it('should pass the license to the language scaffolder as `UNLICENSED` when no license was chosen', async () => {
|
|
267
|
-
when(optionsValidator.validate).calledWith(options).thenReturn({plugins: {languages}
|
|
260
|
+
when(optionsValidator.validate).calledWith(options).thenReturn({plugins: {languages}});
|
|
268
261
|
prompts.promptForBaseDetails.mockResolvedValue({});
|
|
269
262
|
scaffoldVcs.mockResolvedValue(vcsResults);
|
|
270
263
|
|
|
271
|
-
await scaffold(options);
|
|
264
|
+
await scaffold(options, {prompt});
|
|
272
265
|
|
|
273
266
|
expect(scaffoldLanguage).toHaveBeenCalledWith(
|
|
274
267
|
languages,
|
|
275
|
-
decisions,
|
|
276
268
|
{
|
|
277
269
|
license: 'UNLICENSED',
|
|
278
270
|
description: undefined,
|
|
@@ -280,7 +272,8 @@ describe('project scaffolder', () => {
|
|
|
280
272
|
projectRoot: projectPath,
|
|
281
273
|
vcs,
|
|
282
274
|
visibility: undefined
|
|
283
|
-
}
|
|
275
|
+
},
|
|
276
|
+
{prompt}
|
|
284
277
|
);
|
|
285
278
|
});
|
|
286
279
|
|
|
@@ -290,7 +283,7 @@ describe('project scaffolder', () => {
|
|
|
290
283
|
scaffoldVcs.mockResolvedValue({});
|
|
291
284
|
scaffoldLanguage.mockResolvedValue({badges: {}, projectDetails: {}});
|
|
292
285
|
|
|
293
|
-
await scaffold(options);
|
|
286
|
+
await scaffold(options, {prompt});
|
|
294
287
|
|
|
295
288
|
expect(execa).not.toHaveBeenCalled();
|
|
296
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
|
|