From 8353d1317c2340b5b67eb1092b6c1ec82f6ccf7e Mon Sep 17 00:00:00 2001 From: Matt Travi Date: Mon, 29 Jul 2024 15:41:37 -0500 Subject: [PATCH] feat(vcs-host): expect vcs-host scaffolder to return details under the `vcs` results object --- src/scaffolder.js | 21 +++--- src/scaffolder.test.js | 70 +++++++++++++------ src/vcs/git/git.js | 12 ++-- src/vcs/git/git.test.js | 4 +- .../features/step_definitions/common-steps.js | 2 +- vitest.config.ts | 2 +- 6 files changed, 71 insertions(+), 40 deletions(-) diff --git a/src/scaffolder.js b/src/scaffolder.js index e252db7a..68c92700 100644 --- a/src/scaffolder.js +++ b/src/scaffolder.js @@ -5,7 +5,7 @@ import {reportResults} from '@form8ion/results-reporter'; import {scaffold as scaffoldReadme} from '@form8ion/readme'; import {info} from '@travi/cli-messages'; -import {scaffold as scaffoldLanguage, prompt as promptForLanguageDetails} from './language/index.js'; +import {prompt as promptForLanguageDetails, scaffold as scaffoldLanguage} from './language/index.js'; import {initialize as scaffoldGit, scaffold as liftGit} from './vcs/git/git.js'; import {scaffold as scaffoldLicense} from './license/index.js'; import {scaffold as scaffoldVcsHost} from './vcs/host/index.js'; @@ -56,7 +56,7 @@ export async function scaffold(options) { ]) : []; - const gitResults = gitRepo && await liftGit({projectRoot, origin: vcsHostResults}); + const gitResults = gitRepo && await liftGit({projectRoot, vcs: vcsHostResults.vcs}); const {[questionNames.PROJECT_LANGUAGE]: projectLanguage} = await promptForLanguageDetails(languages, decisions); @@ -66,9 +66,15 @@ export async function scaffold(options) { {projectRoot, projectName, vcs, visibility, license: chosenLicense || 'UNLICENSED', description} ); - const contributors = [license, language, dependencyUpdaterResults, contributing, gitResults].filter(Boolean); + const mergedResults = deepmerge.all([ + license, + language, + dependencyUpdaterResults, + contributing, + gitResults + ].filter(Boolean)); - await lift({projectRoot, vcs, results: deepmerge.all(contributors), enhancers: {...dependencyUpdaters, ...vcsHosts}}); + await lift({projectRoot, vcs, results: mergedResults, enhancers: {...dependencyUpdaters, ...vcsHosts}}); if (language && language.verificationCommand) { info('Verifying the generated project'); @@ -78,10 +84,5 @@ export async function scaffold(options) { await subprocess; } - const contributedTasks = contributors - .map(contributor => contributor.nextSteps) - .filter(Boolean) - .reduce((acc, contributedNextSteps) => ([...acc, ...contributedNextSteps]), []); - - reportResults({nextSteps: contributedTasks}); + reportResults({nextSteps: mergedResults.nextSteps}); } diff --git a/src/scaffolder.test.js b/src/scaffolder.test.js index 0fbb249e..a315d1c1 100644 --- a/src/scaffolder.test.js +++ b/src/scaffolder.test.js @@ -9,7 +9,7 @@ import any from '@travi/any'; import {when} from 'jest-when'; import {scaffold as liftGit, initialize as scaffoldGit} from './vcs/git/git.js'; -import * as vcsHostScaffolder from './vcs/host/scaffolder.js'; +import {scaffold as scaffoldVcsHost} from './vcs/host/index.js'; import * as licenseScaffolder from './license/scaffolder.js'; import scaffoldLanguage from './language/scaffolder.js'; import * as languagePrompt from './language/prompt.js'; @@ -27,7 +27,7 @@ vi.mock('@form8ion/execa-wrapper'); vi.mock('@form8ion/results-reporter'); vi.mock('./readme'); vi.mock('./vcs/git/git.js'); -vi.mock('./vcs/host/scaffolder'); +vi.mock('./vcs/host/index.js'); vi.mock('./license/scaffolder'); vi.mock('./language/scaffolder'); vi.mock('./language/prompt'); @@ -53,6 +53,7 @@ describe('project scaffolder', () => { const documentation = any.simpleObject(); const vcs = any.simpleObject(); const vcsOriginDetails = any.simpleObject(); + const vcsHostResults = {...any.simpleObject(), vcs: vcsOriginDetails}; const tags = any.listOf(any.word); const visibility = any.word(); const vcsIgnore = any.simpleObject(); @@ -117,7 +118,7 @@ describe('project scaffolder', () => { when(licenseScaffolder.default) .calledWith({projectRoot: projectPath, license, copyright}) .mockResolvedValue(licenseResults); - when(vcsHostScaffolder.default) + when(scaffoldVcsHost) .calledWith( vcsHosts, { @@ -127,7 +128,7 @@ describe('project scaffolder', () => { visibility } ) - .mockResolvedValue(vcsOriginDetails); + .mockResolvedValue(vcsHostResults); scaffoldLanguage.mockResolvedValue(languageResults); when(dependencyUpdaterScaffolder.default) .calledWith(dependencyUpdaters, decisions, {projectRoot: projectPath, vcs}) @@ -138,7 +139,7 @@ describe('project scaffolder', () => { expect(liftGit).toHaveBeenCalledWith({ projectRoot: projectPath, - origin: vcsOriginDetails + vcs: vcsOriginDetails }); expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description}); expect(dependencyUpdaterScaffolder.default).toHaveBeenCalledWith( @@ -173,7 +174,20 @@ describe('project scaffolder', () => { [coreQuestionNames.PROJECT_NAME]: projectName, [questionNames.GIT_REPO]: gitRepoShouldBeInitialized }); + + when(scaffoldGit).mockResolvedValue(vcs); languagePrompt.default.mockResolvedValue({}); + when(scaffoldVcsHost) + .calledWith( + {}, + { + ...vcs, + projectRoot: projectPath, + description: undefined, + visibility: undefined + } + ) + .mockResolvedValue(vcsHostResults); await scaffold(); @@ -184,9 +198,10 @@ describe('project scaffolder', () => { it('should consider each option except the plugins map optional', async () => { const emptyOptions = {}; when(optionsValidator.validate).calledWith(emptyOptions).mockReturnValue({plugins: {}}); - when(prompts.promptForBaseDetails).calledWith(projectPath, undefined, undefined).mockResolvedValue({}); + when(prompts.promptForBaseDetails).calledWith(projectPath, undefined).mockResolvedValue({}); languagePrompt.default.mockResolvedValue({}); scaffoldGit.mockResolvedValue({}); + scaffoldVcsHost.mockResolvedValue(vcsHostResults); await scaffold(emptyOptions); }); @@ -213,18 +228,36 @@ describe('project scaffolder', () => { contribution: any.simpleObject() }; const languageResults = {badges: languageBadges, vcsIgnore, documentation}; + when(optionsValidator.validate).calledWith(options).mockReturnValue({plugins: {vcsHosts}}); when(prompts.promptForBaseDetails) - .calledWith(projectPath, undefined, undefined) - .mockResolvedValue({[coreQuestionNames.VISIBILITY]: visibility}); + .calledWith(projectPath, undefined) + .mockResolvedValue({ + [coreQuestionNames.DESCRIPTION]: description, + [questionNames.GIT_REPO]: true, + [coreQuestionNames.PROJECT_NAME]: projectName, + [coreQuestionNames.VISIBILITY]: visibility + }); when(scaffoldContributing).calledWith({visibility}).mockReturnValue({badges: contributingBadges}); scaffoldLanguage.mockResolvedValue(languageResults); - vcsHostScaffolder.default.mockResolvedValue(vcsOriginDetails); + when(scaffoldVcsHost) + .calledWith( + vcsHosts, + { + ...vcs, + projectRoot: projectPath, + description, + visibility + } + ) + .mockResolvedValue(vcsHostResults); dependencyUpdaterScaffolder.default.mockResolvedValue({badges: dependencyUpdaterBadges}); licenseScaffolder.default.mockResolvedValue({badges: licenseBadges}); + languagePrompt.default.mockResolvedValue({}); + when(scaffoldGit).mockResolvedValue(vcs); await scaffold(options); - expect(liftGit).toHaveBeenCalledWith({projectRoot: projectPath, origin: vcsOriginDetails}); + expect(liftGit).toHaveBeenCalledWith({projectRoot: projectPath, vcs: vcsOriginDetails}); expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description}); }); @@ -238,7 +271,7 @@ describe('project scaffolder', () => { await scaffold(options); expect(liftGit).not.toHaveBeenCalled(); - expect(vcsHostScaffolder.default).not.toHaveBeenCalled(); + expect(scaffoldVcsHost).not.toHaveBeenCalled(); expect(dependencyUpdaterScaffolder.default).not.toHaveBeenCalled(); }); @@ -287,18 +320,15 @@ describe('project scaffolder', () => { vcs, description }).mockResolvedValue(languageResults); - when(vcsHostScaffolder.default).calledWith( + when(scaffoldVcsHost).calledWith( vcsHosts, { ...vcs, projectRoot: projectPath, description, - homepage, - visibility, - nextSteps: languageNextSteps, - tags + visibility } - ).mockResolvedValue(vcsOriginDetails); + ).mockResolvedValue(vcsHostResults); when(execa).calledWith(verificationCommand, {shell: true}).mockReturnValue({stdout: {pipe: execaPipe}}); dependencyUpdaterScaffolder.default.mockResolvedValue({}); licenseScaffolder.default.mockResolvedValue({}); @@ -306,7 +336,7 @@ describe('project scaffolder', () => { await scaffold(options); - expect(liftGit).toHaveBeenCalledWith({projectRoot: projectPath, origin: vcsOriginDetails}); + expect(liftGit).toHaveBeenCalledWith({projectRoot: projectPath, vcs: vcsOriginDetails}); expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description}); expect(execaPipe).toHaveBeenCalledWith(process.stdout); expect(resultsReporter.reportResults).toHaveBeenCalledWith({nextSteps: [...languageNextSteps, ...gitNextSteps]}); @@ -327,7 +357,7 @@ describe('project scaffolder', () => { when(languagePrompt.default) .calledWith(languages, decisions) .mockResolvedValue({[questionNames.PROJECT_LANGUAGE]: projectLanguage}); - vcsHostScaffolder.default.mockResolvedValue(vcsOriginDetails); + scaffoldVcsHost.mockResolvedValue(vcsHostResults); scaffoldLanguage.mockResolvedValue({}); dependencyUpdaterScaffolder.default.mockResolvedValue({}); licenseScaffolder.default.mockResolvedValue({}); @@ -335,7 +365,7 @@ describe('project scaffolder', () => { await scaffold(options); - expect(liftGit).toHaveBeenCalledWith({projectRoot: projectPath, origin: vcsOriginDetails}); + expect(liftGit).toHaveBeenCalledWith({projectRoot: projectPath, vcs: vcsOriginDetails}); expect(scaffoldReadme).toHaveBeenCalledWith({projectName, projectRoot: projectPath, description}); expect(execa).not.toHaveBeenCalled(); }); diff --git a/src/vcs/git/git.js b/src/vcs/git/git.js index bede3829..192ca604 100644 --- a/src/vcs/git/git.js +++ b/src/vcs/git/git.js @@ -18,7 +18,7 @@ async function getExistingRemotes(git) { } } -async function defineRemoteOrigin(projectRoot, origin) { +async function defineRemoteOrigin(projectRoot, vcs) { const git = simpleGit({baseDir: projectRoot}); const existingRemotes = await getExistingRemotes(git); @@ -28,10 +28,10 @@ async function defineRemoteOrigin(projectRoot, origin) { return {nextSteps: []}; } - if (origin.sshUrl) { - info(`Setting remote origin to ${origin.sshUrl}`, {level: 'secondary'}); + if (vcs.sshUrl) { + info(`Setting remote origin to ${vcs.sshUrl}`, {level: 'secondary'}); - await git.addRemote('origin', origin.sshUrl); + await git.addRemote('origin', vcs.sshUrl); // info('Setting the local `master` branch to track `origin/master`'); // @@ -82,10 +82,10 @@ export async function initialize( return undefined; } -export async function scaffold({projectRoot, origin}) { +export async function scaffold({projectRoot, vcs}) { info('Finishing Git Configuration'); - const remoteOriginResults = await defineRemoteOrigin(projectRoot, origin); + const remoteOriginResults = await defineRemoteOrigin(projectRoot, vcs); return {nextSteps: [{summary: 'Commit scaffolded files'}, ...remoteOriginResults.nextSteps]}; } diff --git a/src/vcs/git/git.test.js b/src/vcs/git/git.test.js index d941ede6..4db4ac53 100644 --- a/src/vcs/git/git.test.js +++ b/src/vcs/git/git.test.js @@ -91,7 +91,7 @@ describe('git', () => { it('should scaffold the git repo', async () => { listRemote.mockRejectedValue(new Error('fatal: No remote configured to list refs from.\n')); - const result = await scaffold({projectRoot, origin: {}, results}); + const result = await scaffold({projectRoot, vcs: {}, results}); expect(result.nextSteps).toEqual([{summary: 'Commit scaffolded files'}]); }); @@ -109,7 +109,7 @@ describe('git', () => { // gitBranch.lookup.withArgs(repository, 'master', gitBranch.BRANCH.LOCAL).resolves(branch); listRemote.mockResolvedValue(any.listOf(any.word)); - const result = await scaffold({projectRoot, origin: {sshUrl}}); + const result = await scaffold({projectRoot, vcs: {sshUrl}}); expect(addRemote).toHaveBeenCalledWith('origin', sshUrl); expect(result.nextSteps).toEqual([ diff --git a/test/integration/features/step_definitions/common-steps.js b/test/integration/features/step_definitions/common-steps.js index 56c49bd6..f4149d27 100644 --- a/test/integration/features/step_definitions/common-steps.js +++ b/test/integration/features/step_definitions/common-steps.js @@ -73,7 +73,7 @@ When(/^the project is scaffolded$/, async function () { ...vcsHost && { vcsHosts: { [vcsHost]: { - scaffold: ({name, owner}) => ({sshUrl: this.remoteOriginUrl, name, owner}), + scaffold: ({name, owner}) => ({vcs: {sshUrl: this.remoteOriginUrl, name, owner}}), prompt: () => undefined } } diff --git a/vitest.config.ts b/vitest.config.ts index 0f65ec76..0349add9 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,3 +1,3 @@ import {defineConfig} from 'vitest/config'; -export default defineConfig({test: {globals: true}}); +export default defineConfig({test: {globals: true, restoreMocks: true}});