@form8ion/project 22.0.0-beta.1 → 22.0.0-beta.11

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.
@@ -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,8 @@ 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 decisions = any.simpleObject();
54
+ const prompt = () => undefined;
55
+ const logger = {info: () => {}};
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({decisions, plugins: {dependencyUpdaters, languages, vcsHosts}});
98
+ .thenReturn({plugins: {dependencyUpdaters, languages, vcsHosts}});
99
99
  when(prompts.promptForBaseDetails)
100
- .calledWith(projectPath, decisions)
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, decisions, vcsHosts, visibility, description})
110
+ .calledWith({projectRoot: projectPath, projectName, vcsHosts, visibility, description}, {prompt, logger})
111
111
  .thenResolve(vcsResults);
112
112
  when(licenseScaffolder.default)
113
- .calledWith({projectRoot: projectPath, license, copyright})
113
+ .calledWith({projectRoot: projectPath, license, copyright}, {logger})
114
114
  .thenResolve(licenseResults);
115
115
  scaffoldLanguage.mockResolvedValue(languageResults);
116
116
  when(dependencyUpdaterScaffolder.default)
117
- .calledWith(dependencyUpdaters, decisions, {projectRoot: projectPath, vcs})
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
+ expect(await scaffold(options, {prompt, logger})).toEqual(mergedResults);
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,
@@ -133,7 +128,6 @@ describe('project scaffolder', () => {
133
128
  results: mergedResults,
134
129
  enhancers: {...dependencyUpdaters, ...vcsHosts, ...languages}
135
130
  });
136
- expect(resultsReporter.reportResults).toHaveBeenCalledWith(mergedResults);
137
131
  });
138
132
 
139
133
  it('should pass the lists of badges from contributors to the readme', async () => {
@@ -160,7 +154,7 @@ describe('project scaffolder', () => {
160
154
  const languageResults = {badges: languageBadges, vcsIgnore, documentation};
161
155
  when(optionsValidator.validate).calledWith(options).thenReturn({plugins: {vcsHosts}});
162
156
  when(prompts.promptForBaseDetails)
163
- .calledWith(projectPath, undefined)
157
+ .calledWith(projectPath, {prompt})
164
158
  .thenResolve({
165
159
  [coreQuestionNames.DESCRIPTION]: description,
166
160
  [questionNames.GIT_REPO]: true,
@@ -173,7 +167,7 @@ describe('project scaffolder', () => {
173
167
  licenseScaffolder.default.mockResolvedValue({badges: licenseBadges});
174
168
  scaffoldVcs.mockResolvedValue(vcsResults);
175
169
 
176
- await scaffold(options);
170
+ await scaffold(options, {prompt});
177
171
 
178
172
  expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description});
179
173
  });
@@ -184,7 +178,7 @@ describe('project scaffolder', () => {
184
178
  scaffoldReadme.mockResolvedValue();
185
179
  scaffoldVcs.mockResolvedValue({});
186
180
 
187
- await scaffold(options);
181
+ await scaffold(options, {prompt});
188
182
 
189
183
  expect(dependencyUpdaterScaffolder.default).not.toHaveBeenCalled();
190
184
  });
@@ -209,9 +203,7 @@ describe('project scaffolder', () => {
209
203
  nextSteps: languageNextSteps,
210
204
  tags
211
205
  };
212
- when(optionsValidator.validate)
213
- .calledWith(options)
214
- .thenReturn({decisions, plugins: {languages, vcsHosts}});
206
+ when(optionsValidator.validate).calledWith(options).thenReturn({plugins: {languages, vcsHosts}});
215
207
  scaffoldVcs.mockResolvedValue(vcsResults);
216
208
  prompts.promptForBaseDetails.mockResolvedValue({
217
209
  [coreQuestionNames.PROJECT_NAME]: projectName,
@@ -220,30 +212,29 @@ describe('project scaffolder', () => {
220
212
  [coreQuestionNames.LICENSE]: license,
221
213
  [coreQuestionNames.DESCRIPTION]: description
222
214
  });
223
- when(scaffoldLanguage).calledWith(languages, decisions, {
215
+ when(scaffoldLanguage).calledWith(languages, {
224
216
  projectName,
225
217
  projectRoot: projectPath,
226
218
  visibility,
227
219
  license,
228
220
  vcs,
229
221
  description
230
- }).thenResolve(languageResults);
222
+ }, {prompt}).thenResolve(languageResults);
231
223
  when(execa).calledWith(verificationCommand, {shell: true}).thenReturn({stdout: {pipe: execaPipe}});
232
224
  dependencyUpdaterScaffolder.default.mockResolvedValue({});
233
225
  licenseScaffolder.default.mockResolvedValue({});
234
226
  scaffoldContributing.mockResolvedValue({});
235
227
 
236
- await scaffold(options);
228
+ await scaffold(options, {prompt, logger});
237
229
 
238
230
  expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description});
239
231
  expect(execaPipe).toHaveBeenCalledWith(process.stdout);
240
- expect(resultsReporter.reportResults).toHaveBeenCalledWith(deepmerge.all([languageResults, vcsResults]));
241
232
  });
242
233
 
243
234
  it('should consider the language details to be optional', async () => {
244
235
  when(optionsValidator.validate)
245
236
  .calledWith(options)
246
- .thenReturn({vcsHosts, decisions, plugins: {languages}});
237
+ .thenReturn({vcsHosts, plugins: {languages}});
247
238
  scaffoldVcs.mockResolvedValue(vcsResults);
248
239
  prompts.promptForBaseDetails.mockResolvedValue({
249
240
  [coreQuestionNames.PROJECT_NAME]: projectName,
@@ -257,22 +248,21 @@ describe('project scaffolder', () => {
257
248
  licenseScaffolder.default.mockResolvedValue({});
258
249
  scaffoldContributing.mockResolvedValue({});
259
250
 
260
- await scaffold(options);
251
+ await scaffold(options, {prompt});
261
252
 
262
253
  expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description});
263
254
  expect(execa).not.toHaveBeenCalled();
264
255
  });
265
256
 
266
257
  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}, decisions});
258
+ when(optionsValidator.validate).calledWith(options).thenReturn({plugins: {languages}});
268
259
  prompts.promptForBaseDetails.mockResolvedValue({});
269
260
  scaffoldVcs.mockResolvedValue(vcsResults);
270
261
 
271
- await scaffold(options);
262
+ await scaffold(options, {prompt});
272
263
 
273
264
  expect(scaffoldLanguage).toHaveBeenCalledWith(
274
265
  languages,
275
- decisions,
276
266
  {
277
267
  license: 'UNLICENSED',
278
268
  description: undefined,
@@ -280,7 +270,8 @@ describe('project scaffolder', () => {
280
270
  projectRoot: projectPath,
281
271
  vcs,
282
272
  visibility: undefined
283
- }
273
+ },
274
+ {prompt}
284
275
  );
285
276
  });
286
277
 
@@ -290,7 +281,7 @@ describe('project scaffolder', () => {
290
281
  scaffoldVcs.mockResolvedValue({});
291
282
  scaffoldLanguage.mockResolvedValue({badges: {}, projectDetails: {}});
292
283
 
293
- await scaffold(options);
284
+ await scaffold(options, {prompt});
294
285
 
295
286
  expect(execa).not.toHaveBeenCalled();
296
287
  });
@@ -1,6 +1,5 @@
1
1
  import {simpleGit} from 'simple-git';
2
- import hostedGitInfo from 'hosted-git-info';
3
- import {warn} from '@travi/cli-messages';
2
+ import parseGitUrl from 'git-url-parse';
4
3
 
5
4
  async function getExistingRemotes(git) {
6
5
  try {
@@ -17,14 +16,14 @@ async function getExistingRemotes(git) {
17
16
  export async function determineExistingVcsDetails({projectRoot}) {
18
17
  const git = simpleGit({baseDir: projectRoot});
19
18
  const remoteOrigin = await git.remote(['get-url', 'origin']);
20
- const {user, project, type} = hostedGitInfo.fromUrl(remoteOrigin);
19
+ const {owner, name, host} = parseGitUrl(remoteOrigin.trimEnd());
21
20
 
22
- return {vcs: {owner: user, name: project, host: type}};
21
+ return {vcs: {owner, name, host: 'github.com' === host ? 'github' : host}};
23
22
  }
24
23
 
25
- export async function defineRemoteOrigin(projectRoot, sshUrl) {
24
+ export async function defineRemoteOrigin(projectRoot, sshUrl, {logger}) {
26
25
  if (!sshUrl) {
27
- warn('URL not available to configure remote `origin`');
26
+ logger.warn('URL not available to configure remote `origin`');
28
27
 
29
28
  return {nextSteps: []};
30
29
  }
@@ -33,7 +32,7 @@ export async function defineRemoteOrigin(projectRoot, sshUrl) {
33
32
  const existingRemotes = await getExistingRemotes(git);
34
33
 
35
34
  if (existingRemotes.includes('origin')) {
36
- warn('The `origin` remote is already defined for this repository');
35
+ logger.warn('The `origin` remote is already defined for this repository');
37
36
 
38
37
  return {nextSteps: []};
39
38
  }
@@ -1,39 +1,59 @@
1
1
  import {simpleGit} from 'simple-git';
2
- import hostedGitInfo from 'hosted-git-info';
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('hosted-git-info');
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
- const vcsHostAccount = any.word();
23
- when(simpleGit).calledWith({baseDir: projectRoot}).thenReturn({remote});
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({user: vcsHostAccount, project: repoName, type: vcsHost.toLowerCase()});
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', () => {
36
55
  const sshUrl = any.url();
56
+ const logger = {warn: () => {}};
37
57
 
38
58
  it('should define the remote origin', async () => {
39
59
  const listRemote = vi.fn();
@@ -41,7 +61,7 @@ describe('Git remote', () => {
41
61
  when(simpleGit).calledWith({baseDir: projectRoot}).thenReturn({listRemote, addRemote});
42
62
  when(listRemote).calledWith().thenResolve(any.listOf(any.word));
43
63
 
44
- const {nextSteps} = await defineRemoteOrigin(projectRoot, sshUrl);
64
+ const {nextSteps} = await defineRemoteOrigin(projectRoot, sshUrl, {logger});
45
65
 
46
66
  expect(addRemote).toHaveBeenCalledWith('origin', sshUrl);
47
67
  expect(nextSteps).toEqual([{summary: 'Set local `master` branch to track upstream `origin/master`'}]);
@@ -53,7 +73,7 @@ describe('Git remote', () => {
53
73
  when(simpleGit).calledWith({baseDir: projectRoot}).thenReturn({listRemote, addRemote});
54
74
  when(listRemote).calledWith().thenThrow(new Error('fatal: No remote configured to list refs from.\n'));
55
75
 
56
- const {nextSteps} = await defineRemoteOrigin(projectRoot, sshUrl);
76
+ const {nextSteps} = await defineRemoteOrigin(projectRoot, sshUrl, {logger});
57
77
 
58
78
  expect(nextSteps).toEqual([{summary: 'Set local `master` branch to track upstream `origin/master`'}]);
59
79
  });
@@ -64,7 +84,7 @@ describe('Git remote', () => {
64
84
  when(simpleGit).calledWith({baseDir: projectRoot}).thenReturn({listRemote});
65
85
  when(listRemote).calledWith().thenThrow(error);
66
86
 
67
- await expect(defineRemoteOrigin(projectRoot, sshUrl)).rejects.toThrow(error);
87
+ await expect(defineRemoteOrigin(projectRoot, sshUrl, {logger})).rejects.toThrow(error);
68
88
  });
69
89
 
70
90
  it('should return no next-steps when the remote origin is already defined', async () => {
@@ -72,13 +92,13 @@ describe('Git remote', () => {
72
92
  when(simpleGit).calledWith({baseDir: projectRoot}).thenReturn({listRemote});
73
93
  when(listRemote).calledWith().thenResolve([...any.listOf(any.word), 'origin', ...any.listOf(any.word)]);
74
94
 
75
- const {nextSteps} = await defineRemoteOrigin(projectRoot, sshUrl);
95
+ const {nextSteps} = await defineRemoteOrigin(projectRoot, sshUrl, {logger});
76
96
 
77
97
  expect(nextSteps).toEqual([]);
78
98
  });
79
99
 
80
100
  it('should return no next-steps when no `sshUrl` is provided', async () => {
81
- const {nextSteps} = await defineRemoteOrigin(projectRoot);
101
+ const {nextSteps} = await defineRemoteOrigin(projectRoot, undefined, {logger});
82
102
 
83
103
  expect(nextSteps).toEqual([]);
84
104
  });
@@ -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 default async function (hosts, decisions) {
6
- const answers = await prompt([{
7
- name: questionNames.REPO_HOST,
8
- type: 'list',
9
- message: 'Where will the repository be hosted?',
10
- choices: Object.keys(hosts)
11
- }], decisions);
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 * as prompts from '@form8ion/overridable-prompts';
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
- afterEach(() => {
18
- vi.clearAllMocks();
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(prompts.prompt).calledWith([{
27
- name: questionNames.REPO_HOST,
28
- type: 'list',
29
- message: 'Where will the repository be hosted?',
30
- choices: hostNames
31
- }], decisions).thenResolve(answersWithHostChoice);
32
-
33
- expect(await promptForVcsHostDetails(hosts, decisions)).toEqual(answersWithHostChoice);
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(prompts.prompt).calledWith([{
39
- name: questionNames.REPO_HOST,
40
- type: 'list',
41
- message: 'Where will the repository be hosted?',
42
- choices: []
43
- }], decisions).thenResolve(answersWithHostChoice);
44
-
45
- expect(await promptForVcsHostDetails({}, decisions)).toEqual(answersWithHostChoice);
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, decisions, options) {
5
- const {[questionNames.REPO_HOST]: chosenHost} = await promptForVcsHostDetails(hosts, decisions);
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 decisions = any.simpleObject();
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, decisions)
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, decisions, options)).toEqual(results);
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, decisions)
32
+ .calledWith(hostPlugins, {prompt})
33
33
  .thenResolve({[questionNames.REPO_HOST]: any.word()});
34
34
 
35
- expect(await scaffoldVcsHost(hostPlugins, decisions, options)).toEqual({vcs: {}});
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 default async function promptForRepoCreation(decisions) {
6
- const {[questionNames.GIT_REPO]: gitRepoShouldBeCreated} = await prompt(
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
- decisions
14
- );
13
+ }]
14
+ });
15
15
 
16
16
  return gitRepoShouldBeCreated;
17
17
  }
@@ -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 decisions = any.simpleObject();
12
+ const prompt = vi.fn();
15
13
  const repoShouldBeCreated = any.boolean();
16
14
  when(prompt)
17
- .calledWith([{
18
- name: questionNames.GIT_REPO,
19
- type: 'confirm',
20
- default: true,
21
- message: 'Should a git repository be initialized?'
22
- }], decisions)
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(decisions)).toBe(repoShouldBeCreated);
26
+ expect(await promptForRepoCreation({prompt})).toBe(repoShouldBeCreated);
26
27
  });
27
28
  });
@@ -1,28 +1,26 @@
1
- import {info} from '@travi/cli-messages';
2
1
  import {scaffold as scaffoldGit, test as alreadyVersionedByGit} from '@form8ion/git';
3
2
 
4
3
  import repositoryShouldBeCreated from './prompt.js';
5
4
  import {determineExistingVcsDetails, defineRemoteOrigin} from './git/index.js';
6
5
  import {scaffold as scaffoldVcsHost} from './host/index.js';
7
6
 
8
- export default async function scaffoldVcs({projectRoot, projectName, decisions, vcsHosts, visibility, description}) {
9
- if (await repositoryShouldBeCreated(decisions)) {
7
+ export default async function scaffoldVcs(
8
+ {projectRoot, projectName, vcsHosts, visibility, description},
9
+ {prompt, logger}
10
+ ) {
11
+ if (await repositoryShouldBeCreated({prompt})) {
10
12
  if (await alreadyVersionedByGit({projectRoot})) {
11
- info('Git repository already exists');
13
+ logger.info('Git repository already exists');
12
14
 
13
- return {vcs: await determineExistingVcsDetails({projectRoot})};
15
+ return determineExistingVcsDetails({projectRoot});
14
16
  }
15
17
 
16
18
  const [{vcs: {host, owner, name, sshUrl}}] = await Promise.all([
17
- scaffoldVcsHost(
18
- vcsHosts,
19
- decisions,
20
- {projectName, projectRoot, description, visibility}
21
- ),
19
+ scaffoldVcsHost(vcsHosts, {projectName, projectRoot, description, visibility}, {prompt}),
22
20
  scaffoldGit({projectRoot})
23
21
  ]);
24
22
 
25
- const remoteOriginResults = await defineRemoteOrigin(projectRoot, sshUrl);
23
+ const remoteOriginResults = await defineRemoteOrigin(projectRoot, sshUrl, {logger});
26
24
 
27
25
  return {
28
26
  vcs: {host, owner, name},
@@ -16,7 +16,8 @@ vi.mock('./prompt.js');
16
16
 
17
17
  describe('vcs scaffolder', () => {
18
18
  const projectRoot = any.string();
19
- const decisions = any.simpleObject();
19
+ const prompt = () => undefined;
20
+ const logger = {info: () => {}};
20
21
 
21
22
  it('should scaffold the repository and vcs host details', async () => {
22
23
  const host = any.word();
@@ -29,14 +30,14 @@ describe('vcs scaffolder', () => {
29
30
  const vcsHostDetails = {host, owner, name};
30
31
  const sshUrl = any.url();
31
32
  const remoteOriginNextSteps = any.listOf(any.simpleObject);
32
- when(promptForRepoCreation).calledWith(decisions).thenResolve(true);
33
+ when(promptForRepoCreation).calledWith({prompt}).thenResolve(true);
33
34
  when(alreadyVersionedByGit).calledWith({projectRoot}).thenResolve(false);
34
35
  when(scaffoldVcsHost)
35
- .calledWith(vcsHosts, decisions, {projectName, projectRoot, description, visibility})
36
+ .calledWith(vcsHosts, {projectName, projectRoot, description, visibility}, {prompt})
36
37
  .thenResolve({vcs: {...vcsHostDetails, sshUrl, ...any.simpleObject()}});
37
- when(defineRemoteOrigin).calledWith(projectRoot, sshUrl).thenResolve({nextSteps: remoteOriginNextSteps});
38
+ when(defineRemoteOrigin).calledWith(projectRoot, sshUrl, {logger}).thenResolve({nextSteps: remoteOriginNextSteps});
38
39
 
39
- expect(await scaffoldVcs({projectRoot, projectName, decisions, vcsHosts, visibility, description})).toEqual({
40
+ expect(await scaffoldVcs({projectRoot, projectName, vcsHosts, visibility, description}, {prompt, logger})).toEqual({
40
41
  vcs: vcsHostDetails,
41
42
  nextSteps: [{summary: 'Commit scaffolded files'}, ...remoteOriginNextSteps]
42
43
  });
@@ -45,16 +46,16 @@ describe('vcs scaffolder', () => {
45
46
 
46
47
  it('should not scaffold a repository or vcs host details when the project is already versioned by git', async () => {
47
48
  const existingVcsDetails = any.simpleObject();
48
- when(promptForRepoCreation).calledWith(decisions).thenResolve(true);
49
+ when(promptForRepoCreation).calledWith({prompt}).thenResolve(true);
49
50
  when(alreadyVersionedByGit).calledWith({projectRoot}).thenResolve(true);
50
51
  when(determineExistingVcsDetails).calledWith({projectRoot}).thenResolve(existingVcsDetails);
51
52
 
52
- expect(await scaffoldVcs({projectRoot, decisions})).toEqual({vcs: existingVcsDetails});
53
+ expect(await scaffoldVcs({projectRoot}, {prompt, logger})).toEqual(existingVcsDetails);
53
54
  });
54
55
 
55
56
  it('should not scaffold a repository or vcs host details when a repository should not be created', async () => {
56
- when(promptForRepoCreation).calledWith(decisions).thenResolve(false);
57
+ when(promptForRepoCreation).calledWith({prompt}).thenResolve(false);
57
58
 
58
- expect(await scaffoldVcs({projectRoot, decisions})).toEqual({});
59
+ expect(await scaffoldVcs({projectRoot}, {prompt})).toEqual({});
59
60
  });
60
61
  });
@@ -1,3 +0,0 @@
1
- import joi from 'joi';
2
-
3
- export const decisionsSchema = joi.object();
@@ -1,20 +0,0 @@
1
- import {validateOptions} from '@form8ion/core';
2
-
3
- import {describe, expect, it} from 'vitest';
4
- import any from '@travi/any';
5
-
6
- import {decisionsSchema} from './options-schemas.js';
7
-
8
- describe('generic options schemas', () => {
9
- describe('decisions', () => {
10
- it('should return the validated options', () => {
11
- const options = any.simpleObject();
12
-
13
- expect(validateOptions(decisionsSchema, options)).toEqual(options);
14
- });
15
-
16
- it('should require the decisions to be defined as a map', () => {
17
- expect(() => validateOptions(decisionsSchema, any.word())).toThrowError('must be of type object');
18
- });
19
- });
20
- });