feat(core): move git commit from generators to create-nx-workspace (#11633)
* fix(core): move git commit to create-nx-workspace * fix(core): add git init to create-nx-plugin
This commit is contained in:
parent
657b2bff5a
commit
15d83258fe
@ -47,6 +47,26 @@ Choices: [nx, angular]
|
||||
|
||||
CLI to power the Nx workspace
|
||||
|
||||
### commit.email
|
||||
|
||||
Type: string
|
||||
|
||||
E-mail of the committer
|
||||
|
||||
### commit.message
|
||||
|
||||
Type: string
|
||||
|
||||
Default: Initial commit
|
||||
|
||||
Commit message
|
||||
|
||||
### commit.name
|
||||
|
||||
Type: string
|
||||
|
||||
Name of the committer
|
||||
|
||||
### defaultBase
|
||||
|
||||
Type: string
|
||||
@ -95,6 +115,14 @@ Type: string
|
||||
|
||||
Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular", "angular-nest", "react", "react-express", "react-native", "next", "nest", "express"]. To build your own see https://nx.dev/packages/nx-plugin#preset
|
||||
|
||||
### skipGit
|
||||
|
||||
Type: boolean
|
||||
|
||||
Default: false
|
||||
|
||||
Skip initializing a git repository.
|
||||
|
||||
### style
|
||||
|
||||
Type: string
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
"name": "create-nx-workspace",
|
||||
"id": "create-nx-workspace",
|
||||
"file": "generated/cli/create-nx-workspace",
|
||||
"content": "---\ntitle: 'create-nx-workspace - CLI command'\ndescription: 'Create a new Nx workspace'\n---\n\n# create-nx-workspace\n\nCreate a new Nx workspace\n\n## Usage\n\n```bash\ncreate-nx-workspace [name] [options]\n```\n\nInstall `create-nx-workspace` globally to invoke the command directly, or use `npx create-nx-workspace`, `yarn create nx-workspace`, or `pnpx create-nx-workspace`.\n\n## Options\n\n### allPrompts\n\nType: boolean\n\nDefault: false\n\nShow all prompts\n\n### appName\n\nType: string\n\nThe name of the application when a preset with pregenerated app is selected\n\n### ci\n\nType: string\n\nChoices: [github, circleci, azure]\n\nGenerate a CI workflow file\n\n### cli\n\nType: string\n\nChoices: [nx, angular]\n\nCLI to power the Nx workspace\n\n### defaultBase\n\nType: string\n\nDefault: main\n\nDefault base to use for new projects\n\n### help\n\nType: boolean\n\nShow help\n\n### interactive\n\nType: boolean\n\nEnable interactive mode with presets\n\n### name\n\nType: string\n\nWorkspace name (e.g. org name)\n\n### nxCloud\n\nType: boolean\n\nSet up distributed caching using Nx Cloud (It's free and doesn't require registration.)\n\n### packageManager\n\nType: string\n\nChoices: [npm, pnpm, yarn]\n\nDefault: npm\n\nPackage manager to use\n\n### preset\n\nType: string\n\nCustomizes the initial content of your workspace. Default presets include: [\"apps\", \"empty\", \"core\", \"npm\", \"ts\", \"web-components\", \"angular\", \"angular-nest\", \"react\", \"react-express\", \"react-native\", \"next\", \"nest\", \"express\"]. To build your own see https://nx.dev/packages/nx-plugin#preset\n\n### style\n\nType: string\n\nStyle option to be used when a preset with pregenerated app is selected\n\n### version\n\nType: boolean\n\nShow version number\n"
|
||||
"content": "---\ntitle: 'create-nx-workspace - CLI command'\ndescription: 'Create a new Nx workspace'\n---\n\n# create-nx-workspace\n\nCreate a new Nx workspace\n\n## Usage\n\n```bash\ncreate-nx-workspace [name] [options]\n```\n\nInstall `create-nx-workspace` globally to invoke the command directly, or use `npx create-nx-workspace`, `yarn create nx-workspace`, or `pnpx create-nx-workspace`.\n\n## Options\n\n### allPrompts\n\nType: boolean\n\nDefault: false\n\nShow all prompts\n\n### appName\n\nType: string\n\nThe name of the application when a preset with pregenerated app is selected\n\n### ci\n\nType: string\n\nChoices: [github, circleci, azure]\n\nGenerate a CI workflow file\n\n### cli\n\nType: string\n\nChoices: [nx, angular]\n\nCLI to power the Nx workspace\n\n### commit.email\n\nType: string\n\nE-mail of the committer\n\n### commit.message\n\nType: string\n\nDefault: Initial commit\n\nCommit message\n\n### commit.name\n\nType: string\n\nName of the committer\n\n### defaultBase\n\nType: string\n\nDefault: main\n\nDefault base to use for new projects\n\n### help\n\nType: boolean\n\nShow help\n\n### interactive\n\nType: boolean\n\nEnable interactive mode with presets\n\n### name\n\nType: string\n\nWorkspace name (e.g. org name)\n\n### nxCloud\n\nType: boolean\n\nSet up distributed caching using Nx Cloud (It's free and doesn't require registration.)\n\n### packageManager\n\nType: string\n\nChoices: [npm, pnpm, yarn]\n\nDefault: npm\n\nPackage manager to use\n\n### preset\n\nType: string\n\nCustomizes the initial content of your workspace. Default presets include: [\"apps\", \"empty\", \"core\", \"npm\", \"ts\", \"web-components\", \"angular\", \"angular-nest\", \"react\", \"react-express\", \"react-native\", \"next\", \"nest\", \"express\"]. To build your own see https://nx.dev/packages/nx-plugin#preset\n\n### skipGit\n\nType: boolean\n\nDefault: false\n\nSkip initializing a git repository.\n\n### style\n\nType: string\n\nStyle option to be used when a preset with pregenerated app is selected\n\n### version\n\nType: boolean\n\nShow version number\n"
|
||||
},
|
||||
{
|
||||
"name": "init",
|
||||
|
||||
@ -79,28 +79,6 @@
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipGit": {
|
||||
"description": "Skip initializing a git repository.",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"alias": "g"
|
||||
},
|
||||
"commit": {
|
||||
"description": "Initial repository commit information.",
|
||||
"oneOf": [
|
||||
{ "type": "boolean" },
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"email": { "type": "string", "format": "email" },
|
||||
"message": { "type": "string" }
|
||||
},
|
||||
"required": ["name", "email"]
|
||||
}
|
||||
],
|
||||
"default": true
|
||||
},
|
||||
"packageManager": {
|
||||
"description": "The package manager used to install dependencies.",
|
||||
"type": "string",
|
||||
@ -342,28 +320,6 @@
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipGit": {
|
||||
"description": "Skip initializing a git repository.",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"alias": "g"
|
||||
},
|
||||
"commit": {
|
||||
"description": "Initial repository commit information.",
|
||||
"oneOf": [
|
||||
{ "type": "boolean" },
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"email": { "type": "string", "format": "email" },
|
||||
"message": { "type": "string" }
|
||||
},
|
||||
"required": ["name", "email"]
|
||||
}
|
||||
],
|
||||
"default": true
|
||||
},
|
||||
"preset": {
|
||||
"description": "What to create in the new workspace.",
|
||||
"type": "string"
|
||||
|
||||
@ -13,6 +13,7 @@ describe('create-nx-plugin', () => {
|
||||
it('should be able to create a plugin repo and run plugin e2e', () => {
|
||||
const wsName = uniq('ws-plugin');
|
||||
const pluginName = uniq('plugin');
|
||||
|
||||
runCreatePlugin(wsName, {
|
||||
packageManager,
|
||||
pluginName,
|
||||
|
||||
@ -12,7 +12,7 @@ import { execSync } from 'child_process';
|
||||
import { removeSync } from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { dirSync } from 'tmp';
|
||||
import { showNxWarning } from './shared';
|
||||
import { initializeGitRepo, showNxWarning } from './shared';
|
||||
import {
|
||||
detectInvokedPackageManager,
|
||||
PackageManager,
|
||||
@ -123,17 +123,6 @@ function updateWorkspace(workspaceName: string) {
|
||||
removeSync(path.join(workspaceName, 'libs'));
|
||||
}
|
||||
|
||||
function commitChanges(workspaceName) {
|
||||
execSync('git add .', {
|
||||
cwd: workspaceName,
|
||||
stdio: 'ignore',
|
||||
});
|
||||
execSync('git commit --amend --no-edit', {
|
||||
cwd: workspaceName,
|
||||
stdio: 'ignore',
|
||||
});
|
||||
}
|
||||
|
||||
function determineWorkspaceName(parsedArgs: any): Promise<string> {
|
||||
const workspaceName: string = parsedArgs._[2];
|
||||
|
||||
@ -215,7 +204,8 @@ determineWorkspaceName(parsedArgs).then((workspaceName) => {
|
||||
createWorkspace(tmpDir, packageManager, parsedArgs, workspaceName);
|
||||
updateWorkspace(workspaceName);
|
||||
createNxPlugin(workspaceName, pluginName, packageManager, parsedArgs);
|
||||
commitChanges(workspaceName);
|
||||
showNxWarning(workspaceName);
|
||||
return initializeGitRepo(workspaceName).then(() => {
|
||||
showNxWarning(workspaceName);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import * as path from 'path';
|
||||
import { execSync } from 'child_process';
|
||||
import { execSync, spawn, SpawnOptions } from 'child_process';
|
||||
import { output } from '@nrwl/devkit';
|
||||
|
||||
export function showNxWarning(workspaceName: string) {
|
||||
@ -21,3 +21,86 @@ export function showNxWarning(workspaceName: string) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Because we don't want to depend on @nrwl/workspace
|
||||
* we duplicate the helper functions from @nrwl/workspace in this file.
|
||||
*/
|
||||
export function deduceDefaultBase(): string {
|
||||
const nxDefaultBase = 'main';
|
||||
try {
|
||||
return (
|
||||
execSync('git config --get init.defaultBranch').toString().trim() ||
|
||||
nxDefaultBase
|
||||
);
|
||||
} catch {
|
||||
return nxDefaultBase;
|
||||
}
|
||||
}
|
||||
|
||||
function checkGitVersion(): string | null {
|
||||
try {
|
||||
let gitVersionOutput = execSync('git --version').toString().trim();
|
||||
return gitVersionOutput.match(/[0-9]+\.[0-9]+\.+[0-9]+/)[0];
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Because we don't want to depend on create-nx-workspace
|
||||
* we duplicate the helper functions from create-nx-workspace in this file.
|
||||
*/
|
||||
export async function initializeGitRepo(directory: string) {
|
||||
const execute = (args: ReadonlyArray<string>, ignoreErrorStream = false) => {
|
||||
const errorStream = ignoreErrorStream ? 'ignore' : process.stderr;
|
||||
const spawnOptions: SpawnOptions = {
|
||||
stdio: [process.stdin, 'ignore', errorStream],
|
||||
shell: true,
|
||||
cwd: directory,
|
||||
env: process.env,
|
||||
};
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
spawn('git', args, spawnOptions).on('close', (code) => {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(code);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
const gitVersion = checkGitVersion();
|
||||
if (!gitVersion) {
|
||||
return;
|
||||
}
|
||||
const insideRepo = await execute(
|
||||
['rev-parse', '--is-inside-work-tree'],
|
||||
true
|
||||
).then(
|
||||
() => true,
|
||||
() => false
|
||||
);
|
||||
if (insideRepo) {
|
||||
output.log({
|
||||
title:
|
||||
'Directory is already under version control. Skipping initialization of git.',
|
||||
});
|
||||
return;
|
||||
}
|
||||
const defaultBase = deduceDefaultBase();
|
||||
const [gitMajor, gitMinor] = gitVersion.split('.');
|
||||
|
||||
if (+gitMajor > 2 || (+gitMajor === 2 && +gitMinor >= 28)) {
|
||||
await execute(['init', '-b', defaultBase]);
|
||||
} else {
|
||||
await execute(['init']);
|
||||
await execute(['checkout', '-b', defaultBase]); // Git < 2.28 doesn't support -b on git init.
|
||||
}
|
||||
await execute(['add', '.']);
|
||||
const message = 'Initial commit';
|
||||
await execute(['commit', `-m "${message}"`]);
|
||||
output.log({
|
||||
title: 'Successfully initialized git.',
|
||||
});
|
||||
}
|
||||
|
||||
@ -21,6 +21,8 @@ import { getFileName, stringifyCollection } from './utils';
|
||||
import { yargsDecorator } from './decorator';
|
||||
import chalk = require('chalk');
|
||||
import { ciList } from './ci';
|
||||
import { join } from 'path';
|
||||
import { initializeGitRepo } from './git';
|
||||
|
||||
type Arguments = {
|
||||
name: string;
|
||||
@ -33,6 +35,12 @@ type Arguments = {
|
||||
packageManager: PackageManager;
|
||||
defaultBase: string;
|
||||
ci: string;
|
||||
skipGit: boolean;
|
||||
commit: {
|
||||
message: string;
|
||||
name: string;
|
||||
email: string;
|
||||
};
|
||||
};
|
||||
|
||||
enum Preset {
|
||||
@ -121,7 +129,7 @@ export const commandsObject: yargs.Argv<Arguments> = yargs
|
||||
.wrap(yargs.terminalWidth())
|
||||
.parserConfiguration({
|
||||
'strip-dashed': true,
|
||||
'dot-notation': false,
|
||||
'dot-notation': true,
|
||||
})
|
||||
.command(
|
||||
// this is the default and only command
|
||||
@ -187,6 +195,25 @@ export const commandsObject: yargs.Argv<Arguments> = yargs
|
||||
defaultDescription: 'main',
|
||||
describe: chalk.dim`Default base to use for new projects`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('skipGit', {
|
||||
describe: chalk.dim`Skip initializing a git repository.`,
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
alias: 'g',
|
||||
})
|
||||
.option('commit.name', {
|
||||
describe: chalk.dim`Name of the committer`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('commit.email', {
|
||||
describe: chalk.dim`E-mail of the committer`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('commit.message', {
|
||||
describe: chalk.dim`Commit message`,
|
||||
type: 'string',
|
||||
default: 'Initial commit',
|
||||
}),
|
||||
async (argv: yargs.ArgumentsCamelCase<Arguments>) => {
|
||||
await main(argv).catch((error) => {
|
||||
@ -218,6 +245,8 @@ async function main(parsedArgs: yargs.Arguments<Arguments>) {
|
||||
packageManager,
|
||||
defaultBase,
|
||||
ci,
|
||||
skipGit,
|
||||
commit,
|
||||
} = parsedArgs;
|
||||
|
||||
output.log({
|
||||
@ -230,15 +259,20 @@ async function main(parsedArgs: yargs.Arguments<Arguments>) {
|
||||
|
||||
const tmpDir = await createSandbox(packageManager);
|
||||
|
||||
await createApp(tmpDir, name, packageManager as PackageManager, {
|
||||
...parsedArgs,
|
||||
cli,
|
||||
preset,
|
||||
appName,
|
||||
style,
|
||||
nxCloud,
|
||||
defaultBase,
|
||||
});
|
||||
const directory = await createApp(
|
||||
tmpDir,
|
||||
name,
|
||||
packageManager as PackageManager,
|
||||
{
|
||||
...parsedArgs,
|
||||
cli,
|
||||
preset,
|
||||
appName,
|
||||
style,
|
||||
nxCloud,
|
||||
defaultBase,
|
||||
}
|
||||
);
|
||||
|
||||
let nxCloudInstallRes;
|
||||
if (nxCloud) {
|
||||
@ -255,6 +289,16 @@ async function main(parsedArgs: yargs.Arguments<Arguments>) {
|
||||
nxCloud && nxCloudInstallRes.code === 0
|
||||
);
|
||||
}
|
||||
if (!skipGit) {
|
||||
try {
|
||||
await initializeGitRepo(directory, { defaultBase, commit });
|
||||
} catch (e) {
|
||||
output.error({
|
||||
title: 'Could not initialize git repository',
|
||||
bodyLines: [e.message],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
showNxWarning(name);
|
||||
pointToTutorialAndCourse(preset as Preset);
|
||||
@ -745,7 +789,7 @@ async function createApp(
|
||||
name: string,
|
||||
packageManager: PackageManager,
|
||||
parsedArgs: any
|
||||
) {
|
||||
): Promise<string> {
|
||||
const { _, cli, ...restArgs } = parsedArgs;
|
||||
|
||||
// Ensure to use packageManager for args
|
||||
@ -760,7 +804,8 @@ async function createApp(
|
||||
|
||||
const command = `new ${name} ${args} --collection=@nrwl/workspace/generators.json --cli=${cli}`;
|
||||
|
||||
let nxWorkspaceRoot = `"${process.cwd().replace(/\\/g, '/')}"`;
|
||||
const workingDir = process.cwd().replace(/\\/g, '/');
|
||||
let nxWorkspaceRoot = `"${workingDir}"`;
|
||||
|
||||
// If path contains spaces there is a problem in Windows for npm@6.
|
||||
// In this case we have to escape the wrapping quotes.
|
||||
@ -791,6 +836,7 @@ async function createApp(
|
||||
} finally {
|
||||
workspaceSetupSpinner.stop();
|
||||
}
|
||||
return join(workingDir, name);
|
||||
}
|
||||
|
||||
async function setupNxCloud(name: string, packageManager: PackageManager) {
|
||||
|
||||
28
packages/create-nx-workspace/bin/git.spec.ts
Normal file
28
packages/create-nx-workspace/bin/git.spec.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { checkGitVersion } from './git';
|
||||
import * as cp from 'child_process';
|
||||
|
||||
describe('checkGitVersion', () => {
|
||||
const execSyncSpy = jest.spyOn(cp, 'execSync');
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('should work with text before semver', () => {
|
||||
execSyncSpy.mockReturnValue(Buffer.from(`git version 2.33.0`));
|
||||
const result = checkGitVersion();
|
||||
expect(result).toEqual('2.33.0');
|
||||
});
|
||||
|
||||
it('should work with 4 digit versions', () => {
|
||||
execSyncSpy.mockReturnValue(Buffer.from(`git version 2.33.0.5`));
|
||||
const result = checkGitVersion();
|
||||
expect(result).toEqual('2.33.0');
|
||||
});
|
||||
|
||||
it('should work with msysgit versions', () => {
|
||||
execSyncSpy.mockReturnValue(Buffer.from(`git version 1.8.3.msysgit.0`));
|
||||
const result = checkGitVersion();
|
||||
expect(result).toEqual('1.8.3');
|
||||
});
|
||||
});
|
||||
89
packages/create-nx-workspace/bin/git.ts
Normal file
89
packages/create-nx-workspace/bin/git.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import { execSync, spawn, SpawnOptions } from 'child_process';
|
||||
import { deduceDefaultBase } from './default-base';
|
||||
import { output } from './output';
|
||||
|
||||
export function checkGitVersion(): string | null {
|
||||
try {
|
||||
let gitVersionOutput = execSync('git --version').toString().trim();
|
||||
return gitVersionOutput.match(/[0-9]+\.[0-9]+\.+[0-9]+/)[0];
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function initializeGitRepo(
|
||||
directory: string,
|
||||
options: {
|
||||
defaultBase: string;
|
||||
commit: { message: string; name: string; email: string };
|
||||
}
|
||||
) {
|
||||
const execute = (args: ReadonlyArray<string>, ignoreErrorStream = false) => {
|
||||
const outputStream = 'ignore';
|
||||
const errorStream = ignoreErrorStream ? 'ignore' : process.stderr;
|
||||
const spawnOptions: SpawnOptions = {
|
||||
stdio: [process.stdin, outputStream, errorStream],
|
||||
shell: true,
|
||||
cwd: directory,
|
||||
env: {
|
||||
...process.env,
|
||||
...(options.commit.name
|
||||
? {
|
||||
GIT_AUTHOR_NAME: options.commit.name,
|
||||
GIT_COMMITTER_NAME: options.commit.name,
|
||||
}
|
||||
: {}),
|
||||
...(options.commit.email
|
||||
? {
|
||||
GIT_AUTHOR_EMAIL: options.commit.email,
|
||||
GIT_COMMITTER_EMAIL: options.commit.email,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
};
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
spawn('git', args, spawnOptions).on('close', (code) => {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(code);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
const gitVersion = checkGitVersion();
|
||||
if (!gitVersion) {
|
||||
return;
|
||||
}
|
||||
const insideRepo = await execute(
|
||||
['rev-parse', '--is-inside-work-tree'],
|
||||
true
|
||||
).then(
|
||||
() => true,
|
||||
() => false
|
||||
);
|
||||
if (insideRepo) {
|
||||
output.log({
|
||||
title:
|
||||
'Directory is already under version control. Skipping initialization of git.',
|
||||
});
|
||||
return;
|
||||
}
|
||||
const defaultBase = options.defaultBase || deduceDefaultBase();
|
||||
const [gitMajor, gitMinor] = gitVersion.split('.');
|
||||
|
||||
if (+gitMajor > 2 || (+gitMajor === 2 && +gitMinor >= 28)) {
|
||||
await execute(['init', '-b', defaultBase]);
|
||||
} else {
|
||||
await execute(['init']);
|
||||
await execute(['checkout', '-b', defaultBase]); // Git < 2.28 doesn't support -b on git init.
|
||||
}
|
||||
await execute(['add', '.']);
|
||||
if (options.commit) {
|
||||
const message = options.commit.message || 'initial commit';
|
||||
await execute(['commit', `-m "${message}"`]);
|
||||
}
|
||||
output.log({
|
||||
title: 'Successfully initialized git.',
|
||||
});
|
||||
}
|
||||
@ -8,7 +8,6 @@ const defaultOptions: Omit<Schema, 'name' | 'directory' | 'appName'> = {
|
||||
cli: 'nx',
|
||||
preset: Preset.Apps,
|
||||
skipInstall: false,
|
||||
skipGit: false,
|
||||
linter: Linter.EsLint,
|
||||
defaultBase: 'main',
|
||||
};
|
||||
|
||||
@ -13,17 +13,10 @@ import {
|
||||
|
||||
import { join } from 'path';
|
||||
import * as yargsParser from 'yargs-parser';
|
||||
import { spawn, SpawnOptions } from 'child_process';
|
||||
|
||||
import { gte } from 'semver';
|
||||
|
||||
import { spawn } from 'child_process';
|
||||
import { workspaceGenerator } from '../workspace/workspace';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { Preset } from '../utils/presets';
|
||||
import {
|
||||
checkGitVersion,
|
||||
deduceDefaultBase,
|
||||
} from '../../utilities/default-base';
|
||||
import { getNpmPackageVersion } from '../utils/get-npm-package-version';
|
||||
|
||||
export interface Schema {
|
||||
@ -33,11 +26,9 @@ export interface Schema {
|
||||
appName: string;
|
||||
npmScope?: string;
|
||||
skipInstall?: boolean;
|
||||
skipGit?: boolean;
|
||||
style?: string;
|
||||
nxCloud?: boolean;
|
||||
preset: string;
|
||||
commit?: { name: string; email: string; message?: string };
|
||||
defaultBase: string;
|
||||
linter: 'tslint' | 'eslint';
|
||||
packageManager?: PackageManager;
|
||||
@ -116,76 +107,6 @@ function generatePreset(host: Tree, opts: NormalizedSchema) {
|
||||
}
|
||||
}
|
||||
|
||||
async function initializeGitRepo(
|
||||
host: Tree,
|
||||
rootDirectory: string,
|
||||
options: Schema
|
||||
) {
|
||||
const execute = (args: ReadonlyArray<string>, ignoreErrorStream = false) => {
|
||||
const outputStream = 'ignore';
|
||||
const errorStream = ignoreErrorStream ? 'ignore' : process.stderr;
|
||||
const spawnOptions: SpawnOptions = {
|
||||
stdio: [process.stdin, outputStream, errorStream],
|
||||
shell: true,
|
||||
cwd: join(host.root, rootDirectory),
|
||||
env: {
|
||||
...process.env,
|
||||
...(options.commit.name
|
||||
? {
|
||||
GIT_AUTHOR_NAME: options.commit.name,
|
||||
GIT_COMMITTER_NAME: options.commit.name,
|
||||
}
|
||||
: {}),
|
||||
...(options.commit.email
|
||||
? {
|
||||
GIT_AUTHOR_EMAIL: options.commit.email,
|
||||
GIT_COMMITTER_EMAIL: options.commit.email,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
};
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
spawn('git', args, spawnOptions).on('close', (code) => {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(code);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
const gitVersion = checkGitVersion();
|
||||
if (!gitVersion) {
|
||||
return;
|
||||
}
|
||||
const insideRepo = await execute(
|
||||
['rev-parse', '--is-inside-work-tree'],
|
||||
true
|
||||
).then(
|
||||
() => true,
|
||||
() => false
|
||||
);
|
||||
if (insideRepo) {
|
||||
console.info(
|
||||
`Directory is already under version control. Skipping initialization of git.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
const defaultBase = options.defaultBase || deduceDefaultBase();
|
||||
if (gte(gitVersion, '2.28.0')) {
|
||||
await execute(['init', '-b', defaultBase]);
|
||||
} else {
|
||||
await execute(['init']);
|
||||
await execute(['checkout', '-b', defaultBase]); // Git < 2.28 doesn't support -b on git init.
|
||||
}
|
||||
await execute(['add', '.']);
|
||||
if (options.commit) {
|
||||
const message = options.commit.message || 'initial commit';
|
||||
await execute(['commit', `-m "${message}"`]);
|
||||
}
|
||||
console.info('Successfully initialized git.');
|
||||
}
|
||||
|
||||
export async function newGenerator(host: Tree, options: Schema) {
|
||||
if (
|
||||
options.skipInstall &&
|
||||
@ -229,15 +150,6 @@ export async function newGenerator(host: Tree, options: Schema) {
|
||||
return async () => {
|
||||
installPackagesTask(host, false, options.directory, options.packageManager);
|
||||
await generatePreset(host, options);
|
||||
if (!options.skipGit) {
|
||||
try {
|
||||
await initializeGitRepo(host, options.directory, options);
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Could not initialize git repository. Error: ${e.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -39,37 +39,6 @@
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipGit": {
|
||||
"description": "Skip initializing a git repository.",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"alias": "g"
|
||||
},
|
||||
"commit": {
|
||||
"description": "Initial repository commit information.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name", "email"]
|
||||
}
|
||||
],
|
||||
"default": true
|
||||
},
|
||||
"preset": {
|
||||
"description": "What to create in the new workspace.",
|
||||
"type": "string"
|
||||
|
||||
@ -62,35 +62,6 @@
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipGit": {
|
||||
"description": "Skip initializing a git repository.",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"alias": "g"
|
||||
},
|
||||
"commit": {
|
||||
"description": "Initial repository commit information.",
|
||||
"oneOf": [
|
||||
{ "type": "boolean" },
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name", "email"]
|
||||
}
|
||||
],
|
||||
"default": true
|
||||
},
|
||||
"packageManager": {
|
||||
"description": "The package manager used to install dependencies.",
|
||||
"type": "string",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import * as cp from 'child_process';
|
||||
import { checkGitVersion, deduceDefaultBase } from './default-base';
|
||||
import { deduceDefaultBase } from './default-base';
|
||||
|
||||
describe('deduceDefaultBase', () => {
|
||||
const execSyncSpy = jest.spyOn(cp, 'execSync');
|
||||
@ -29,29 +29,3 @@ describe('deduceDefaultBase', () => {
|
||||
expect(result).toEqual('some-other-default-branch');
|
||||
});
|
||||
});
|
||||
|
||||
describe('checkGitVersion', () => {
|
||||
const execSyncSpy = jest.spyOn(cp, 'execSync');
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('should work with text before semver', () => {
|
||||
execSyncSpy.mockReturnValue(Buffer.from(`git version 2.33.0`));
|
||||
const result = checkGitVersion();
|
||||
expect(result).toEqual('2.33.0');
|
||||
});
|
||||
|
||||
it('should work with 4 digit versions', () => {
|
||||
execSyncSpy.mockReturnValue(Buffer.from(`git version 2.33.0.5`));
|
||||
const result = checkGitVersion();
|
||||
expect(result).toEqual('2.33.0');
|
||||
});
|
||||
|
||||
it('should work with msysgit versions', () => {
|
||||
execSyncSpy.mockReturnValue(Buffer.from(`git version 1.8.3.msysgit.0`));
|
||||
const result = checkGitVersion();
|
||||
expect(result).toEqual('1.8.3');
|
||||
});
|
||||
});
|
||||
|
||||
@ -11,12 +11,3 @@ export function deduceDefaultBase(): string {
|
||||
return nxDefaultBase;
|
||||
}
|
||||
}
|
||||
|
||||
export function checkGitVersion(): string | null {
|
||||
try {
|
||||
let gitVersionOutput = execSync('git --version').toString().trim();
|
||||
return gitVersionOutput.match(/[0-9]+\.[0-9]+\.+[0-9]+/)[0];
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user