@form8ion/project 22.0.0-beta.1 → 22.0.0-beta.10
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 +106 -83
- package/lib/index.js.map +1 -1
- package/package.json +24 -26
- 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 +7 -11
- 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 +9 -10
- package/src/scaffolder.test.js +20 -30
- package/src/vcs/git/remotes.js +3 -3
- package/src/vcs/git/remotes.test.js +30 -11
- 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 +4 -8
- package/src/vcs/scaffolder.test.js +8 -8
- package/src/options-schemas.js +0 -3
- package/src/options-schemas.test.js +0 -20
|
@@ -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
|
-
import {promptForDependencyUpdaterChoice} from './prompt.js';
|
|
5
|
+
import {DEPENDENCY_UPDATER_PROMPT_ID, promptForDependencyUpdaterChoice} from './prompt.js';
|
|
8
6
|
import {questionNames} from '../index.js';
|
|
9
7
|
|
|
10
8
|
vi.mock('@form8ion/overridable-prompts');
|
|
11
9
|
|
|
12
10
|
describe('dependency updater prompt', () => {
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
vi.clearAllMocks();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
11
|
it('should enable choosing the preferred updater', async () => {
|
|
12
|
+
const prompt = vi.fn();
|
|
18
13
|
const answers = any.simpleObject();
|
|
19
14
|
const updaters = any.simpleObject();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
when(prompt).calledWith({
|
|
16
|
+
id: DEPENDENCY_UPDATER_PROMPT_ID,
|
|
17
|
+
questions: [{
|
|
18
|
+
name: questionNames.DEPENDENCY_UPDATER,
|
|
19
|
+
type: 'list',
|
|
20
|
+
message: 'Which dependency-update service do you want to manage this project?',
|
|
21
|
+
choices: [...Object.keys(updaters), 'Other']
|
|
22
|
+
}]
|
|
23
|
+
}).thenResolve(answers);
|
|
27
24
|
|
|
28
|
-
expect(await promptForDependencyUpdaterChoice(updaters,
|
|
25
|
+
expect(await promptForDependencyUpdaterChoice(updaters, {prompt})).toEqual(answers);
|
|
29
26
|
});
|
|
30
27
|
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {questionNames} from '../prompts/question-names.js';
|
|
2
2
|
import {promptForDependencyUpdaterChoice} from './prompt.js';
|
|
3
3
|
|
|
4
|
-
export default async function (plugins,
|
|
4
|
+
export default async function (plugins, options, {prompt}) {
|
|
5
5
|
if (!Object.keys(plugins).length) return undefined;
|
|
6
6
|
|
|
7
7
|
const plugin = plugins[
|
|
8
|
-
(await promptForDependencyUpdaterChoice(plugins,
|
|
8
|
+
(await promptForDependencyUpdaterChoice(plugins, {prompt}))[questionNames.DEPENDENCY_UPDATER]
|
|
9
9
|
];
|
|
10
10
|
|
|
11
11
|
if (plugin) return plugin.scaffold(options);
|
|
@@ -1,32 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {describe, expect, it, vi} from 'vitest';
|
|
2
2
|
import any from '@travi/any';
|
|
3
3
|
import {when} from 'vitest-when';
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import {promptForDependencyUpdaterChoice} from './prompt.js';
|
|
6
6
|
import scaffoldUpdater from './scaffolder.js';
|
|
7
7
|
import {questionNames} from '../index.js';
|
|
8
|
-
import {promptForDependencyUpdaterChoice} from './prompt.js';
|
|
9
8
|
|
|
10
|
-
vi.mock('./prompt');
|
|
9
|
+
vi.mock('./prompt.js');
|
|
11
10
|
|
|
12
11
|
describe('dependency-updater scaffolder', () => {
|
|
13
|
-
|
|
14
|
-
vi.clearAllMocks();
|
|
15
|
-
});
|
|
12
|
+
const prompt = () => undefined;
|
|
16
13
|
|
|
17
14
|
it('should execute the chosen scaffolder with the appropriate options', async () => {
|
|
18
|
-
const decisions = any.simpleObject();
|
|
19
15
|
const options = any.simpleObject();
|
|
20
16
|
const chosenUpdater = any.word();
|
|
21
17
|
const chosenUpdaterScaffolder = vi.fn();
|
|
22
18
|
const plugins = {...any.simpleObject(), [chosenUpdater]: {scaffold: chosenUpdaterScaffolder}};
|
|
23
19
|
const scaffolderResult = any.simpleObject();
|
|
24
|
-
when(
|
|
25
|
-
.calledWith(plugins,
|
|
20
|
+
when(promptForDependencyUpdaterChoice)
|
|
21
|
+
.calledWith(plugins, {prompt})
|
|
26
22
|
.thenResolve({[questionNames.DEPENDENCY_UPDATER]: chosenUpdater});
|
|
27
23
|
when(chosenUpdaterScaffolder).calledWith(options).thenResolve(scaffolderResult);
|
|
28
24
|
|
|
29
|
-
expect(await scaffoldUpdater(plugins,
|
|
25
|
+
expect(await scaffoldUpdater(plugins, options, {prompt})).toEqual(scaffolderResult);
|
|
30
26
|
});
|
|
31
27
|
|
|
32
28
|
it('should not present a prompt if no updaters are registered', async () => {
|
package/src/index.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {questionNames as projectScaffolderQuestionNames} from './prompts/question-names.js';
|
|
1
|
+
import {ids} from './prompts/index.js';
|
|
3
2
|
|
|
4
3
|
export * from './scaffolder.js';
|
|
5
4
|
export {default as lift} from './lift.js';
|
|
6
|
-
export const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
};
|
|
5
|
+
export const promptConstants = {ids};
|
|
6
|
+
|
|
7
|
+
export {questionNames} from './prompts/index.js';
|
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
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import deepmerge from 'deepmerge';
|
|
2
2
|
import {execa} from 'execa';
|
|
3
3
|
import {questionNames as coreQuestionNames} from '@form8ion/core';
|
|
4
|
-
import {reportResults} from '@form8ion/results-reporter';
|
|
5
4
|
import {scaffold as scaffoldReadme} from '@form8ion/readme';
|
|
6
5
|
import {info} from '@travi/cli-messages';
|
|
7
6
|
|
|
@@ -15,9 +14,9 @@ import {scaffold as scaffoldEditorConfig} from './editorconfig/index.js';
|
|
|
15
14
|
import {scaffold as scaffoldContributing} from './contributing/index.js';
|
|
16
15
|
import lift from './lift.js';
|
|
17
16
|
|
|
18
|
-
export async function scaffold(options) {
|
|
17
|
+
export async function scaffold(options, {prompt}) {
|
|
19
18
|
const projectRoot = process.cwd();
|
|
20
|
-
const {
|
|
19
|
+
const {plugins: {dependencyUpdaters, languages, vcsHosts = {}}} = validate(options);
|
|
21
20
|
|
|
22
21
|
const {
|
|
23
22
|
[coreQuestionNames.PROJECT_NAME]: projectName,
|
|
@@ -26,11 +25,11 @@ export async function scaffold(options) {
|
|
|
26
25
|
[coreQuestionNames.DESCRIPTION]: description,
|
|
27
26
|
[coreQuestionNames.COPYRIGHT_YEAR]: copyrightYear,
|
|
28
27
|
[coreQuestionNames.COPYRIGHT_HOLDER]: copyHolder
|
|
29
|
-
} = await promptForBaseDetails(projectRoot,
|
|
28
|
+
} = await promptForBaseDetails(projectRoot, {prompt});
|
|
30
29
|
const copyright = {year: copyrightYear, holder: copyHolder};
|
|
31
30
|
|
|
32
31
|
const [vcsResults, contributing, license] = await Promise.all([
|
|
33
|
-
scaffoldVcs({projectRoot, projectName,
|
|
32
|
+
scaffoldVcs({projectRoot, projectName, vcsHosts, visibility, description}, {prompt}),
|
|
34
33
|
scaffoldContributing({visibility}),
|
|
35
34
|
scaffoldLicense({projectRoot, license: chosenLicense, copyright}),
|
|
36
35
|
scaffoldReadme({projectName, projectRoot, description}),
|
|
@@ -39,14 +38,14 @@ export async function scaffold(options) {
|
|
|
39
38
|
|
|
40
39
|
const dependencyUpdaterResults = vcsResults.vcs && await scaffoldDependencyUpdater(
|
|
41
40
|
dependencyUpdaters,
|
|
42
|
-
|
|
43
|
-
{
|
|
41
|
+
{projectRoot},
|
|
42
|
+
{prompt}
|
|
44
43
|
);
|
|
45
44
|
|
|
46
45
|
const language = await scaffoldLanguage(
|
|
47
46
|
languages,
|
|
48
|
-
|
|
49
|
-
{
|
|
47
|
+
{projectRoot, projectName, vcs: vcsResults.vcs, visibility, license: chosenLicense || 'UNLICENSED', description},
|
|
48
|
+
{prompt}
|
|
50
49
|
);
|
|
51
50
|
|
|
52
51
|
const mergedResults = deepmerge.all([
|
|
@@ -72,5 +71,5 @@ export async function scaffold(options) {
|
|
|
72
71
|
await subprocess;
|
|
73
72
|
}
|
|
74
73
|
|
|
75
|
-
|
|
74
|
+
return mergedResults;
|
|
76
75
|
}
|
package/src/scaffolder.test.js
CHANGED
|
@@ -2,7 +2,6 @@ import deepmerge from 'deepmerge';
|
|
|
2
2
|
import {execa} from 'execa';
|
|
3
3
|
import {questionNames as coreQuestionNames} from '@form8ion/core';
|
|
4
4
|
import {scaffold as scaffoldReadme} from '@form8ion/readme';
|
|
5
|
-
import * as resultsReporter from '@form8ion/results-reporter';
|
|
6
5
|
|
|
7
6
|
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
|
|
8
7
|
import any from '@travi/any';
|
|
@@ -52,7 +51,7 @@ describe('project scaffolder', () => {
|
|
|
52
51
|
const tags = any.listOf(any.word);
|
|
53
52
|
const visibility = any.word();
|
|
54
53
|
const vcsIgnore = any.simpleObject();
|
|
55
|
-
const
|
|
54
|
+
const prompt = () => undefined;
|
|
56
55
|
|
|
57
56
|
beforeEach(() => {
|
|
58
57
|
process.cwd = vi.fn();
|
|
@@ -95,9 +94,9 @@ describe('project scaffolder', () => {
|
|
|
95
94
|
]);
|
|
96
95
|
when(optionsValidator.validate)
|
|
97
96
|
.calledWith(options)
|
|
98
|
-
.thenReturn({
|
|
97
|
+
.thenReturn({plugins: {dependencyUpdaters, languages, vcsHosts}});
|
|
99
98
|
when(prompts.promptForBaseDetails)
|
|
100
|
-
.calledWith(projectPath,
|
|
99
|
+
.calledWith(projectPath, {prompt})
|
|
101
100
|
.thenResolve({
|
|
102
101
|
[coreQuestionNames.PROJECT_NAME]: projectName,
|
|
103
102
|
[coreQuestionNames.LICENSE]: license,
|
|
@@ -107,25 +106,20 @@ describe('project scaffolder', () => {
|
|
|
107
106
|
[coreQuestionNames.VISIBILITY]: visibility
|
|
108
107
|
});
|
|
109
108
|
when(scaffoldVcs)
|
|
110
|
-
.calledWith({projectRoot: projectPath, projectName,
|
|
109
|
+
.calledWith({projectRoot: projectPath, projectName, vcsHosts, visibility, description}, {prompt})
|
|
111
110
|
.thenResolve(vcsResults);
|
|
112
111
|
when(licenseScaffolder.default)
|
|
113
112
|
.calledWith({projectRoot: projectPath, license, copyright})
|
|
114
113
|
.thenResolve(licenseResults);
|
|
115
114
|
scaffoldLanguage.mockResolvedValue(languageResults);
|
|
116
115
|
when(dependencyUpdaterScaffolder.default)
|
|
117
|
-
.calledWith(dependencyUpdaters,
|
|
116
|
+
.calledWith(dependencyUpdaters, {projectRoot: projectPath}, {prompt})
|
|
118
117
|
.thenResolve(dependencyUpdaterResults);
|
|
119
118
|
when(scaffoldContributing).calledWith({visibility}).thenReturn(contributingResults);
|
|
120
119
|
|
|
121
|
-
await scaffold(options);
|
|
120
|
+
expect(await scaffold(options, {prompt})).toEqual(mergedResults);
|
|
122
121
|
|
|
123
122
|
expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description});
|
|
124
|
-
expect(dependencyUpdaterScaffolder.default).toHaveBeenCalledWith(
|
|
125
|
-
dependencyUpdaters,
|
|
126
|
-
decisions,
|
|
127
|
-
{projectRoot: projectPath, vcs}
|
|
128
|
-
);
|
|
129
123
|
expect(scaffoldEditorconfig).toHaveBeenCalledWith({projectRoot: projectPath});
|
|
130
124
|
expect(lift).toHaveBeenCalledWith({
|
|
131
125
|
projectRoot: projectPath,
|
|
@@ -133,7 +127,6 @@ describe('project scaffolder', () => {
|
|
|
133
127
|
results: mergedResults,
|
|
134
128
|
enhancers: {...dependencyUpdaters, ...vcsHosts, ...languages}
|
|
135
129
|
});
|
|
136
|
-
expect(resultsReporter.reportResults).toHaveBeenCalledWith(mergedResults);
|
|
137
130
|
});
|
|
138
131
|
|
|
139
132
|
it('should pass the lists of badges from contributors to the readme', async () => {
|
|
@@ -160,7 +153,7 @@ describe('project scaffolder', () => {
|
|
|
160
153
|
const languageResults = {badges: languageBadges, vcsIgnore, documentation};
|
|
161
154
|
when(optionsValidator.validate).calledWith(options).thenReturn({plugins: {vcsHosts}});
|
|
162
155
|
when(prompts.promptForBaseDetails)
|
|
163
|
-
.calledWith(projectPath,
|
|
156
|
+
.calledWith(projectPath, {prompt})
|
|
164
157
|
.thenResolve({
|
|
165
158
|
[coreQuestionNames.DESCRIPTION]: description,
|
|
166
159
|
[questionNames.GIT_REPO]: true,
|
|
@@ -173,7 +166,7 @@ describe('project scaffolder', () => {
|
|
|
173
166
|
licenseScaffolder.default.mockResolvedValue({badges: licenseBadges});
|
|
174
167
|
scaffoldVcs.mockResolvedValue(vcsResults);
|
|
175
168
|
|
|
176
|
-
await scaffold(options);
|
|
169
|
+
await scaffold(options, {prompt});
|
|
177
170
|
|
|
178
171
|
expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description});
|
|
179
172
|
});
|
|
@@ -184,7 +177,7 @@ describe('project scaffolder', () => {
|
|
|
184
177
|
scaffoldReadme.mockResolvedValue();
|
|
185
178
|
scaffoldVcs.mockResolvedValue({});
|
|
186
179
|
|
|
187
|
-
await scaffold(options);
|
|
180
|
+
await scaffold(options, {prompt});
|
|
188
181
|
|
|
189
182
|
expect(dependencyUpdaterScaffolder.default).not.toHaveBeenCalled();
|
|
190
183
|
});
|
|
@@ -209,9 +202,7 @@ describe('project scaffolder', () => {
|
|
|
209
202
|
nextSteps: languageNextSteps,
|
|
210
203
|
tags
|
|
211
204
|
};
|
|
212
|
-
when(optionsValidator.validate)
|
|
213
|
-
.calledWith(options)
|
|
214
|
-
.thenReturn({decisions, plugins: {languages, vcsHosts}});
|
|
205
|
+
when(optionsValidator.validate).calledWith(options).thenReturn({plugins: {languages, vcsHosts}});
|
|
215
206
|
scaffoldVcs.mockResolvedValue(vcsResults);
|
|
216
207
|
prompts.promptForBaseDetails.mockResolvedValue({
|
|
217
208
|
[coreQuestionNames.PROJECT_NAME]: projectName,
|
|
@@ -220,30 +211,29 @@ describe('project scaffolder', () => {
|
|
|
220
211
|
[coreQuestionNames.LICENSE]: license,
|
|
221
212
|
[coreQuestionNames.DESCRIPTION]: description
|
|
222
213
|
});
|
|
223
|
-
when(scaffoldLanguage).calledWith(languages,
|
|
214
|
+
when(scaffoldLanguage).calledWith(languages, {
|
|
224
215
|
projectName,
|
|
225
216
|
projectRoot: projectPath,
|
|
226
217
|
visibility,
|
|
227
218
|
license,
|
|
228
219
|
vcs,
|
|
229
220
|
description
|
|
230
|
-
}).thenResolve(languageResults);
|
|
221
|
+
}, {prompt}).thenResolve(languageResults);
|
|
231
222
|
when(execa).calledWith(verificationCommand, {shell: true}).thenReturn({stdout: {pipe: execaPipe}});
|
|
232
223
|
dependencyUpdaterScaffolder.default.mockResolvedValue({});
|
|
233
224
|
licenseScaffolder.default.mockResolvedValue({});
|
|
234
225
|
scaffoldContributing.mockResolvedValue({});
|
|
235
226
|
|
|
236
|
-
await scaffold(options);
|
|
227
|
+
await scaffold(options, {prompt});
|
|
237
228
|
|
|
238
229
|
expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description});
|
|
239
230
|
expect(execaPipe).toHaveBeenCalledWith(process.stdout);
|
|
240
|
-
expect(resultsReporter.reportResults).toHaveBeenCalledWith(deepmerge.all([languageResults, vcsResults]));
|
|
241
231
|
});
|
|
242
232
|
|
|
243
233
|
it('should consider the language details to be optional', async () => {
|
|
244
234
|
when(optionsValidator.validate)
|
|
245
235
|
.calledWith(options)
|
|
246
|
-
.thenReturn({vcsHosts,
|
|
236
|
+
.thenReturn({vcsHosts, plugins: {languages}});
|
|
247
237
|
scaffoldVcs.mockResolvedValue(vcsResults);
|
|
248
238
|
prompts.promptForBaseDetails.mockResolvedValue({
|
|
249
239
|
[coreQuestionNames.PROJECT_NAME]: projectName,
|
|
@@ -257,22 +247,21 @@ describe('project scaffolder', () => {
|
|
|
257
247
|
licenseScaffolder.default.mockResolvedValue({});
|
|
258
248
|
scaffoldContributing.mockResolvedValue({});
|
|
259
249
|
|
|
260
|
-
await scaffold(options);
|
|
250
|
+
await scaffold(options, {prompt});
|
|
261
251
|
|
|
262
252
|
expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description});
|
|
263
253
|
expect(execa).not.toHaveBeenCalled();
|
|
264
254
|
});
|
|
265
255
|
|
|
266
256
|
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}
|
|
257
|
+
when(optionsValidator.validate).calledWith(options).thenReturn({plugins: {languages}});
|
|
268
258
|
prompts.promptForBaseDetails.mockResolvedValue({});
|
|
269
259
|
scaffoldVcs.mockResolvedValue(vcsResults);
|
|
270
260
|
|
|
271
|
-
await scaffold(options);
|
|
261
|
+
await scaffold(options, {prompt});
|
|
272
262
|
|
|
273
263
|
expect(scaffoldLanguage).toHaveBeenCalledWith(
|
|
274
264
|
languages,
|
|
275
|
-
decisions,
|
|
276
265
|
{
|
|
277
266
|
license: 'UNLICENSED',
|
|
278
267
|
description: undefined,
|
|
@@ -280,7 +269,8 @@ describe('project scaffolder', () => {
|
|
|
280
269
|
projectRoot: projectPath,
|
|
281
270
|
vcs,
|
|
282
271
|
visibility: undefined
|
|
283
|
-
}
|
|
272
|
+
},
|
|
273
|
+
{prompt}
|
|
284
274
|
);
|
|
285
275
|
});
|
|
286
276
|
|
|
@@ -290,7 +280,7 @@ describe('project scaffolder', () => {
|
|
|
290
280
|
scaffoldVcs.mockResolvedValue({});
|
|
291
281
|
scaffoldLanguage.mockResolvedValue({badges: {}, projectDetails: {}});
|
|
292
282
|
|
|
293
|
-
await scaffold(options);
|
|
283
|
+
await scaffold(options, {prompt});
|
|
294
284
|
|
|
295
285
|
expect(execa).not.toHaveBeenCalled();
|
|
296
286
|
});
|
package/src/vcs/git/remotes.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {simpleGit} from 'simple-git';
|
|
2
|
-
import
|
|
2
|
+
import parseGitUrl from 'git-url-parse';
|
|
3
3
|
import {warn} from '@travi/cli-messages';
|
|
4
4
|
|
|
5
5
|
async function getExistingRemotes(git) {
|
|
@@ -17,9 +17,9 @@ async function getExistingRemotes(git) {
|
|
|
17
17
|
export async function determineExistingVcsDetails({projectRoot}) {
|
|
18
18
|
const git = simpleGit({baseDir: projectRoot});
|
|
19
19
|
const remoteOrigin = await git.remote(['get-url', 'origin']);
|
|
20
|
-
const {
|
|
20
|
+
const {owner, name, host} = parseGitUrl(remoteOrigin.trimEnd());
|
|
21
21
|
|
|
22
|
-
return {vcs: {owner
|
|
22
|
+
return {vcs: {owner, name, host: 'github.com' === host ? 'github' : host}};
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export async function defineRemoteOrigin(projectRoot, sshUrl) {
|
|
@@ -1,35 +1,54 @@
|
|
|
1
1
|
import {simpleGit} from 'simple-git';
|
|
2
|
-
import
|
|
2
|
+
import parseGitUrl from 'git-url-parse';
|
|
3
3
|
|
|
4
|
-
import {describe, vi, it, expect} from 'vitest';
|
|
4
|
+
import {describe, vi, it, expect, beforeEach} from 'vitest';
|
|
5
5
|
import {when} from 'vitest-when';
|
|
6
6
|
import any from '@travi/any';
|
|
7
7
|
|
|
8
8
|
import {determineExistingVcsDetails, defineRemoteOrigin} from './remotes.js';
|
|
9
9
|
|
|
10
10
|
vi.mock('simple-git');
|
|
11
|
-
vi.mock('
|
|
11
|
+
vi.mock('git-url-parse');
|
|
12
12
|
|
|
13
13
|
describe('Git remote', () => {
|
|
14
14
|
const projectRoot = any.string();
|
|
15
15
|
|
|
16
16
|
describe('determine', () => {
|
|
17
|
+
const remote = vi.fn();
|
|
18
|
+
const remoteOrigin = any.url();
|
|
19
|
+
const repoName = any.word();
|
|
20
|
+
const vcsHostAccount = any.word();
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
when(simpleGit).calledWith({baseDir: projectRoot}).thenReturn({remote});
|
|
24
|
+
});
|
|
25
|
+
|
|
17
26
|
it('should determine existing vcs details from the remote origin definition of the local repository', async () => {
|
|
18
|
-
const remote = vi.fn();
|
|
19
|
-
const remoteOrigin = any.url();
|
|
20
|
-
const repoName = any.word();
|
|
21
27
|
const vcsHost = `F${any.word()})O${any.word()}O`;
|
|
22
|
-
|
|
23
|
-
when(
|
|
24
|
-
when(remote).calledWith(['get-url', 'origin']).thenResolve(remoteOrigin);
|
|
25
|
-
when(hostedGitInfo.fromUrl)
|
|
28
|
+
when(remote).calledWith(['get-url', 'origin']).thenResolve(`${remoteOrigin}\n`);
|
|
29
|
+
when(parseGitUrl)
|
|
26
30
|
.calledWith(remoteOrigin)
|
|
27
|
-
.thenReturn({
|
|
31
|
+
.thenReturn({owner: vcsHostAccount, name: repoName, host: vcsHost.toLowerCase()});
|
|
28
32
|
|
|
29
33
|
const {vcs: hostDetails} = await determineExistingVcsDetails({projectRoot});
|
|
30
34
|
|
|
31
35
|
expect(hostDetails).toEqual({host: vcsHost.toLowerCase(), owner: vcsHostAccount, name: repoName});
|
|
32
36
|
});
|
|
37
|
+
|
|
38
|
+
it(
|
|
39
|
+
'should return `github` when the host is determined to be `github.com` until that can be a breaking change',
|
|
40
|
+
async () => {
|
|
41
|
+
when(simpleGit).calledWith({baseDir: projectRoot}).thenReturn({remote});
|
|
42
|
+
when(remote).calledWith(['get-url', 'origin']).thenResolve(`${remoteOrigin}\n`);
|
|
43
|
+
when(parseGitUrl)
|
|
44
|
+
.calledWith(remoteOrigin)
|
|
45
|
+
.thenReturn({owner: vcsHostAccount, name: repoName, host: 'github.com'});
|
|
46
|
+
|
|
47
|
+
const {vcs: hostDetails} = await determineExistingVcsDetails({projectRoot});
|
|
48
|
+
|
|
49
|
+
expect(hostDetails).toEqual({host: 'github', owner: vcsHostAccount, name: repoName});
|
|
50
|
+
}
|
|
51
|
+
);
|
|
33
52
|
});
|
|
34
53
|
|
|
35
54
|
describe('define', () => {
|