Checks if git is installed and has a user configured
Signed-off-by: Leonardo Maier <leonarmaier@gmail.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': minor
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Initializes a git repository when creating an app using @packages/create-app
|
||||
|
||||
@@ -33,6 +33,7 @@ const checkPathExistsMock = jest.spyOn(tasks, 'checkPathExistsTask');
|
||||
const templatingMock = jest.spyOn(tasks, 'templatingTask');
|
||||
const checkAppExistsMock = jest.spyOn(tasks, 'checkAppExistsTask');
|
||||
const initGitRepositoryMock = jest.spyOn(tasks, 'initGitRepository');
|
||||
const checkForGitSetup = jest.spyOn(tasks, 'checkForGitSetup');
|
||||
const createTemporaryAppFolderMock = jest.spyOn(
|
||||
tasks,
|
||||
'createTemporaryAppFolderTask',
|
||||
@@ -57,6 +58,7 @@ describe('command entrypoint', () => {
|
||||
name: 'MyApp',
|
||||
dbType: 'PostgreSQL',
|
||||
});
|
||||
checkForGitSetup.mockResolvedValue(true);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -88,4 +90,11 @@ describe('command entrypoint', () => {
|
||||
await createApp(cmd);
|
||||
expect(buildAppMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not call `initGitRepository` when `isGitConfigured` is false', async () => {
|
||||
const cmd = {} as unknown as Command;
|
||||
checkForGitSetup.mockResolvedValue(false);
|
||||
await createApp(cmd);
|
||||
expect(initGitRepositoryMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -29,37 +29,41 @@ import {
|
||||
moveAppTask,
|
||||
templatingTask,
|
||||
initGitRepository,
|
||||
checkForGitSetup,
|
||||
} from './lib/tasks';
|
||||
|
||||
export default async (opts: OptionValues): Promise<void> => {
|
||||
/* eslint-disable-next-line no-restricted-syntax */
|
||||
const paths = findPaths(__dirname);
|
||||
|
||||
const answers: Answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: chalk.blue('Enter a name for the app [required]'),
|
||||
validate: (value: any) => {
|
||||
if (!value) {
|
||||
return chalk.red('Please enter a name for the app');
|
||||
} else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {
|
||||
return chalk.red(
|
||||
'App name must be lowercase and contain only letters, digits, and dashes.',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
const answers: Answers = await inquirer.prompt(
|
||||
[
|
||||
{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: chalk.blue('Enter a name for the app [required]'),
|
||||
validate: (value: any) => {
|
||||
if (!value) {
|
||||
return chalk.red('Please enter a name for the app');
|
||||
} else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {
|
||||
return chalk.red(
|
||||
'App name must be lowercase and contain only letters, digits, and dashes.',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
when: (a: Answers) => {
|
||||
const envName = process.env.BACKSTAGE_APP_NAME;
|
||||
if (envName) {
|
||||
a.name = envName;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
when: (a: Answers) => {
|
||||
const envName = process.env.BACKSTAGE_APP_NAME;
|
||||
if (envName) {
|
||||
a.name = envName;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
]);
|
||||
],
|
||||
{ defaultBranch: 'master' },
|
||||
);
|
||||
|
||||
const templateDir = paths.resolveOwn('templates/default-app');
|
||||
const tempDir = resolvePath(os.tmpdir(), answers.name);
|
||||
@@ -74,14 +78,18 @@ export default async (opts: OptionValues): Promise<void> => {
|
||||
Task.log('Creating the app...');
|
||||
|
||||
try {
|
||||
const isGitConfigured = await checkForGitSetup();
|
||||
|
||||
if (opts.path) {
|
||||
// Template directly to specified path
|
||||
|
||||
Task.section('Checking that supplied path exists');
|
||||
await checkPathExistsTask(appDir);
|
||||
|
||||
Task.section('Initializing git repository');
|
||||
await initGitRepository(appDir, answers);
|
||||
if (isGitConfigured) {
|
||||
Task.section('Initializing git repository');
|
||||
await initGitRepository(appDir, answers);
|
||||
}
|
||||
|
||||
Task.section('Preparing files');
|
||||
await templatingTask(templateDir, opts.path, answers);
|
||||
@@ -94,8 +102,10 @@ export default async (opts: OptionValues): Promise<void> => {
|
||||
Task.section('Creating a temporary app directory');
|
||||
await createTemporaryAppFolderTask(tempDir);
|
||||
|
||||
Task.section('Initializing git repository');
|
||||
await initGitRepository(tempDir, answers);
|
||||
if (isGitConfigured) {
|
||||
Task.section('Initializing git repository');
|
||||
await initGitRepository(tempDir, answers);
|
||||
}
|
||||
|
||||
Task.section('Preparing files');
|
||||
await templatingTask(templateDir, tempDir, answers);
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
Task,
|
||||
buildAppTask,
|
||||
checkAppExistsTask,
|
||||
checkForGitSetup,
|
||||
checkPathExistsTask,
|
||||
createTemporaryAppFolderTask,
|
||||
initGitRepository,
|
||||
@@ -348,6 +349,33 @@ describe('buildAppTask', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('checkForGitSetup', () => {
|
||||
it('should check if git package is installed and configured', async () => {
|
||||
mockExec.mockImplementation((_command, callback) => {
|
||||
callback(null, { stdout: 'main' }, 'standard error');
|
||||
});
|
||||
|
||||
await checkForGitSetup();
|
||||
|
||||
expect(mockExec).toHaveBeenCalledTimes(3);
|
||||
expect(mockExec).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'which git',
|
||||
expect.any(Function),
|
||||
);
|
||||
expect(mockExec).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'git config user.name',
|
||||
expect.any(Function),
|
||||
);
|
||||
expect(mockExec).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
'git config user.email',
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('initGitRepository', () => {
|
||||
it('should initialize a git repository at the given path', async () => {
|
||||
const destinationDir = 'tmp/mockApp/';
|
||||
|
||||
@@ -237,6 +237,33 @@ export async function moveAppTask(
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if git package is installed and git credentials exists
|
||||
*
|
||||
* @throws if `exec` fails
|
||||
*/
|
||||
export async function checkForGitSetup(): Promise<boolean> {
|
||||
const runCmd = (cmd: string) =>
|
||||
exec(cmd).catch(error => {
|
||||
process.stdout.write(error.stderr);
|
||||
process.stdout.write(error.stdout);
|
||||
throw new Error(`Could not execute command ${chalk.cyan(cmd)}`);
|
||||
});
|
||||
|
||||
try {
|
||||
await runCmd('which git');
|
||||
|
||||
const [gitUsername, gitEmail] = await Promise.all([
|
||||
runCmd('git config user.name'),
|
||||
runCmd('git config user.email'),
|
||||
]);
|
||||
|
||||
return Boolean(gitUsername.stdout?.trim() && gitEmail.stdout?.trim());
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a git repository in the destination folder
|
||||
*
|
||||
@@ -245,25 +272,23 @@ export async function moveAppTask(
|
||||
* @throws if `exec` fails
|
||||
*/
|
||||
export async function initGitRepository(dir: string, context: any) {
|
||||
const runCmd = async (cmd: string) => {
|
||||
let cmdResponse = { stdout: '', stderr: '' };
|
||||
await Task.forItem('executing', cmd, async () => {
|
||||
process.chdir(dir);
|
||||
cmdResponse = await exec(cmd).catch(error => {
|
||||
process.stdout.write(error.stderr);
|
||||
process.stdout.write(error.stdout);
|
||||
throw new Error(`Could not execute command ${chalk.cyan(cmd)}`);
|
||||
});
|
||||
const runCmd = (cmd: string) =>
|
||||
exec(cmd).catch(error => {
|
||||
process.stdout.write(error.stderr);
|
||||
process.stdout.write(error.stdout);
|
||||
throw new Error(`Could not execute command ${chalk.cyan(cmd)}`);
|
||||
});
|
||||
return cmdResponse;
|
||||
};
|
||||
|
||||
await runCmd('git init');
|
||||
await runCmd('git commit --allow-empty -m "Initial commit"');
|
||||
await Task.forItem('init', 'git repository', async () => {
|
||||
process.chdir(dir);
|
||||
|
||||
const defaultBranch = await runCmd('git branch --format="%(refname:short)"');
|
||||
await runCmd('git init');
|
||||
await runCmd('git commit --allow-empty -m "Initial commit"');
|
||||
|
||||
context.defaultBranch = defaultBranch.stdout
|
||||
? defaultBranch.stdout.trim()
|
||||
: 'master';
|
||||
const defaultBranch = await runCmd(
|
||||
'git branch --format="%(refname:short)"',
|
||||
);
|
||||
|
||||
context.defaultBranch = defaultBranch.stdout?.trim() || 'master';
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user