made git commands more generic and resusable
Signed-off-by: Jason Froehlich <jfroehlich12@gmail.com>
This commit is contained in:
@@ -19,6 +19,9 @@ import {
|
||||
commitAndPushRepo,
|
||||
initRepoAndPush,
|
||||
commitAndPushBranch,
|
||||
addFiles,
|
||||
createBranch,
|
||||
cloneRepo,
|
||||
} from './gitHelpers';
|
||||
|
||||
jest.mock('@backstage/backend-common', () => ({
|
||||
@@ -312,6 +315,198 @@ describe('commitAndPushRepo', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('cloneRepo', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('with minimal parameters', () => {
|
||||
beforeEach(async () => {
|
||||
await cloneRepo({
|
||||
url: 'git@github.com:test/repo.git',
|
||||
dir: '/tmp/repo/dir/',
|
||||
auth: {
|
||||
username: 'test-user',
|
||||
password: 'test-password',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('clone the repo', () => {
|
||||
expect(mockedGit.clone).toHaveBeenCalledWith({
|
||||
url: 'git@github.com:test/repo.git',
|
||||
dir: '/tmp/repo/dir/',
|
||||
ref: undefined,
|
||||
depth: undefined,
|
||||
noCheckout: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('with token', async () => {
|
||||
await cloneRepo({
|
||||
url: 'git@github.com:test/repo.git',
|
||||
dir: '/tmp/repo/dir/',
|
||||
auth: {
|
||||
token: 'test-token',
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockedGit.clone).toHaveBeenCalledWith({
|
||||
dir: '/tmp/repo/dir/',
|
||||
url: 'git@github.com:test/repo.git',
|
||||
ref: undefined,
|
||||
depth: undefined,
|
||||
noCheckout: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('allows overriding the default branch', async () => {
|
||||
await cloneRepo({
|
||||
url: 'git@github.com:test/repo.git',
|
||||
dir: '/tmp/repo/dir/',
|
||||
ref: 'trunk',
|
||||
auth: {
|
||||
username: 'test-user',
|
||||
password: 'test-password',
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockedGit.clone).toHaveBeenCalledWith({
|
||||
dir: '/tmp/repo/dir/',
|
||||
url: 'git@github.com:test/repo.git',
|
||||
ref: 'trunk',
|
||||
depth: undefined,
|
||||
noCheckout: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('allows overriding the depth', async () => {
|
||||
await cloneRepo({
|
||||
url: 'git@github.com:test/repo.git',
|
||||
dir: '/tmp/repo/dir/',
|
||||
ref: 'trunk',
|
||||
depth: 2,
|
||||
auth: {
|
||||
username: 'test-user',
|
||||
password: 'test-password',
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockedGit.clone).toHaveBeenCalledWith({
|
||||
dir: '/tmp/repo/dir/',
|
||||
url: 'git@github.com:test/repo.git',
|
||||
ref: 'trunk',
|
||||
depth: 2,
|
||||
noCheckout: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('allows overriding the noCheckout', async () => {
|
||||
await cloneRepo({
|
||||
url: 'git@github.com:test/repo.git',
|
||||
dir: '/tmp/repo/dir/',
|
||||
ref: 'trunk',
|
||||
depth: 2,
|
||||
noCheckout: true,
|
||||
auth: {
|
||||
username: 'test-user',
|
||||
password: 'test-password',
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockedGit.clone).toHaveBeenCalledWith({
|
||||
dir: '/tmp/repo/dir/',
|
||||
url: 'git@github.com:test/repo.git',
|
||||
ref: 'trunk',
|
||||
depth: 2,
|
||||
noCheckout: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('createBranch', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('with minimal parameters', () => {
|
||||
beforeEach(async () => {
|
||||
await createBranch({
|
||||
dir: '/tmp/repo/dir/',
|
||||
ref: 'trunk',
|
||||
auth: {
|
||||
username: 'test-user',
|
||||
password: 'test-password',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('create the branch', () => {
|
||||
expect(mockedGit.checkout).toHaveBeenCalledWith({
|
||||
ref: 'trunk',
|
||||
dir: '/tmp/repo/dir/',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('with token', async () => {
|
||||
await createBranch({
|
||||
dir: '/tmp/repo/dir/',
|
||||
ref: 'trunk',
|
||||
auth: {
|
||||
token: 'test-token',
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockedGit.checkout).toHaveBeenCalledWith({
|
||||
ref: 'trunk',
|
||||
dir: '/tmp/repo/dir/',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('addFiles', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('with minimal parameters', () => {
|
||||
beforeEach(async () => {
|
||||
await addFiles({
|
||||
dir: '/tmp/repo/dir/',
|
||||
filepath: '.',
|
||||
auth: {
|
||||
username: 'test-user',
|
||||
password: 'test-password',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('add files', () => {
|
||||
expect(mockedGit.add).toHaveBeenCalledWith({
|
||||
filepath: '.',
|
||||
dir: '/tmp/repo/dir/',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('with token', async () => {
|
||||
await addFiles({
|
||||
dir: '/tmp/repo/dir/',
|
||||
filepath: '.',
|
||||
auth: {
|
||||
token: 'test-token',
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockedGit.add).toHaveBeenCalledWith({
|
||||
filepath: '.',
|
||||
dir: '/tmp/repo/dir/',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('commitAndPushBranch', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
@@ -320,53 +515,19 @@ describe('commitAndPushBranch', () => {
|
||||
describe('with minimal parameters', () => {
|
||||
beforeEach(async () => {
|
||||
await commitAndPushBranch({
|
||||
tempDir: '/tmp/repo/dir/',
|
||||
dir: '/test/repo/dir/',
|
||||
remoteUrl: 'git@github.com:test/repo.git',
|
||||
dir: '/tmp/repo/dir/',
|
||||
auth: {
|
||||
username: 'test-user',
|
||||
password: 'test-password',
|
||||
},
|
||||
commitMessage: 'commit message',
|
||||
gitAuthorInfo: {
|
||||
name: 'Scaffolder',
|
||||
email: 'scaffolder@backstage.io',
|
||||
},
|
||||
logger: getVoidLogger(),
|
||||
});
|
||||
});
|
||||
|
||||
it('clone the repo', () => {
|
||||
expect(mockedGit.clone).toHaveBeenCalledWith({
|
||||
url: 'git@github.com:test/repo.git',
|
||||
dir: '/tmp/repo/dir/',
|
||||
});
|
||||
});
|
||||
|
||||
it('fetch the branches', () => {
|
||||
expect(mockedGit.fetch).toHaveBeenCalledWith({
|
||||
dir: '/tmp/repo/dir/',
|
||||
});
|
||||
});
|
||||
|
||||
it('checkout the branch', () => {
|
||||
expect(mockedGit.checkout).toHaveBeenCalledWith({
|
||||
dir: '/tmp/repo/dir/',
|
||||
ref: 'master',
|
||||
});
|
||||
});
|
||||
|
||||
it('stages all files in the repo', () => {
|
||||
expect(mockedGit.add).toHaveBeenCalledWith({
|
||||
dir: '/tmp/repo/dir/',
|
||||
filepath: '.',
|
||||
});
|
||||
});
|
||||
|
||||
it('creates an commit', () => {
|
||||
it('create commit', () => {
|
||||
expect(mockedGit.commit).toHaveBeenCalledWith({
|
||||
dir: '/tmp/repo/dir/',
|
||||
message: 'commit message',
|
||||
dir: '/tmp/repo/dir/',
|
||||
author: {
|
||||
name: 'Scaffolder',
|
||||
email: 'scaffolder@backstage.io',
|
||||
@@ -389,58 +550,91 @@ describe('commitAndPushBranch', () => {
|
||||
|
||||
it('with token', async () => {
|
||||
await commitAndPushBranch({
|
||||
tempDir: '/tmp/repo/dir/',
|
||||
dir: '/test/repo/dir/',
|
||||
remoteUrl: 'git@github.com:test/repo.git',
|
||||
dir: '/tmp/repo/dir/',
|
||||
auth: {
|
||||
token: 'test-token',
|
||||
},
|
||||
commitMessage: 'commit message',
|
||||
gitAuthorInfo: {
|
||||
name: 'gitCommitter',
|
||||
email: 'gitCommitter@backstage.io',
|
||||
},
|
||||
logger: getVoidLogger(),
|
||||
});
|
||||
|
||||
expect(mockedGit.clone).toHaveBeenCalledWith({
|
||||
expect(mockedGit.commit).toHaveBeenCalledWith({
|
||||
message: 'commit message',
|
||||
dir: '/tmp/repo/dir/',
|
||||
url: 'git@github.com:test/repo.git',
|
||||
author: {
|
||||
name: 'gitCommitter',
|
||||
email: 'gitCommitter@backstage.io',
|
||||
},
|
||||
committer: {
|
||||
name: 'gitCommitter',
|
||||
email: 'gitCommitter@backstage.io',
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockedGit.push).toHaveBeenCalledWith({
|
||||
dir: '/tmp/repo/dir/',
|
||||
remote: 'origin',
|
||||
remoteRef: 'refs/heads/master',
|
||||
});
|
||||
});
|
||||
|
||||
it('allows overriding the default branch', async () => {
|
||||
await commitAndPushBranch({
|
||||
tempDir: '/tmp/repo/dir/',
|
||||
dir: '/test/repo/dir/',
|
||||
branch: 'trunk',
|
||||
remoteUrl: 'git@github.com:test/repo.git',
|
||||
dir: '/tmp/repo/dir/',
|
||||
auth: {
|
||||
username: 'test-user',
|
||||
password: 'test-password',
|
||||
},
|
||||
commitMessage: 'commit message',
|
||||
logger: getVoidLogger(),
|
||||
branch: 'trunk',
|
||||
});
|
||||
|
||||
expect(mockedGit.checkout).toHaveBeenCalledWith({
|
||||
expect(mockedGit.commit).toHaveBeenCalledWith({
|
||||
message: 'commit message',
|
||||
dir: '/tmp/repo/dir/',
|
||||
ref: 'trunk',
|
||||
author: {
|
||||
name: 'Scaffolder',
|
||||
email: 'scaffolder@backstage.io',
|
||||
},
|
||||
committer: {
|
||||
name: 'Scaffolder',
|
||||
email: 'scaffolder@backstage.io',
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockedGit.push).toHaveBeenCalledWith({
|
||||
dir: '/tmp/repo/dir/',
|
||||
remote: 'origin',
|
||||
remoteRef: 'refs/heads/trunk',
|
||||
});
|
||||
});
|
||||
|
||||
it('allows overriding the remoteRef', async () => {
|
||||
await commitAndPushBranch({
|
||||
tempDir: '/tmp/repo/dir/',
|
||||
dir: '/test/repo/dir/',
|
||||
gitAuthorInfo: {
|
||||
name: 'Custom Scaffolder Author',
|
||||
email: 'scaffolder@example.org',
|
||||
},
|
||||
remoteUrl: 'git@github.com:test/repo.git',
|
||||
dir: '/tmp/repo/dir/',
|
||||
auth: {
|
||||
username: 'test-user',
|
||||
password: 'test-password',
|
||||
},
|
||||
remoteRef: 'ABC123',
|
||||
commitMessage: 'commit message',
|
||||
logger: getVoidLogger(),
|
||||
remoteRef: 'ABC123',
|
||||
});
|
||||
|
||||
expect(mockedGit.commit).toHaveBeenCalledWith({
|
||||
message: 'commit message',
|
||||
dir: '/tmp/repo/dir/',
|
||||
author: {
|
||||
name: 'Scaffolder',
|
||||
email: 'scaffolder@backstage.io',
|
||||
},
|
||||
committer: {
|
||||
name: 'Scaffolder',
|
||||
email: 'scaffolder@backstage.io',
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockedGit.push).toHaveBeenCalledWith({
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
import { Git } from '@backstage/backend-common';
|
||||
import { Logger } from 'winston';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
/**
|
||||
* @public
|
||||
@@ -139,49 +138,114 @@ export async function commitAndPushRepo(input: {
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function commitAndPushBranch({
|
||||
tempDir,
|
||||
export async function cloneRepo({
|
||||
url,
|
||||
dir,
|
||||
auth,
|
||||
logger,
|
||||
ref,
|
||||
depth,
|
||||
noCheckout,
|
||||
}: {
|
||||
url: string;
|
||||
dir: string;
|
||||
// For use cases where token has to be used with Basic Auth
|
||||
// it has to be provided as password together with a username
|
||||
// which may be a fixed value defined by the provider.
|
||||
auth: { username: string; password: string } | { token: string };
|
||||
logger?: Logger | undefined;
|
||||
ref?: string | undefined;
|
||||
depth?: number | undefined;
|
||||
noCheckout?: boolean | undefined;
|
||||
}): Promise<void> {
|
||||
const git = Git.fromAuth({
|
||||
...auth,
|
||||
logger,
|
||||
});
|
||||
|
||||
await git.clone({ url, dir, ref, depth, noCheckout });
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function createBranch({
|
||||
dir,
|
||||
auth,
|
||||
logger,
|
||||
ref,
|
||||
}: {
|
||||
dir: string;
|
||||
ref: string;
|
||||
// For use cases where token has to be used with Basic Auth
|
||||
// it has to be provided as password together with a username
|
||||
// which may be a fixed value defined by the provider.
|
||||
auth: { username: string; password: string } | { token: string };
|
||||
logger?: Logger | undefined;
|
||||
}): Promise<void> {
|
||||
const git = Git.fromAuth({
|
||||
...auth,
|
||||
logger,
|
||||
});
|
||||
|
||||
await git.checkout({ dir, ref });
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function addFiles({
|
||||
dir,
|
||||
filepath,
|
||||
auth,
|
||||
logger,
|
||||
}: {
|
||||
dir: string;
|
||||
filepath: string;
|
||||
// For use cases where token has to be used with Basic Auth
|
||||
// it has to be provided as password together with a username
|
||||
// which may be a fixed value defined by the provider.
|
||||
auth: { username: string; password: string } | { token: string };
|
||||
logger?: Logger | undefined;
|
||||
}): Promise<void> {
|
||||
const git = Git.fromAuth({
|
||||
...auth,
|
||||
logger,
|
||||
});
|
||||
|
||||
await git.add({ dir, filepath });
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function commitAndPushBranch({
|
||||
dir,
|
||||
remoteUrl,
|
||||
auth,
|
||||
logger,
|
||||
commitMessage,
|
||||
gitAuthorInfo,
|
||||
branch = 'master',
|
||||
remoteRef,
|
||||
remote = 'origin',
|
||||
}: {
|
||||
tempDir: string;
|
||||
dir: string;
|
||||
remoteUrl: string;
|
||||
// For use cases where token has to be used with Basic Auth
|
||||
// it has to be provided as password together with a username
|
||||
// which may be a fixed value defined by the provider.
|
||||
auth: { username: string; password: string } | { token: string };
|
||||
logger: Logger;
|
||||
logger?: Logger | undefined;
|
||||
commitMessage: string;
|
||||
gitAuthorInfo?: { name?: string; email?: string };
|
||||
branch?: string;
|
||||
remoteRef?: string;
|
||||
remote?: string;
|
||||
}): Promise<{ commitHash: string }> {
|
||||
const git = Git.fromAuth({
|
||||
...auth,
|
||||
logger,
|
||||
});
|
||||
|
||||
await git.clone({ url: remoteUrl, dir: tempDir });
|
||||
await git.fetch({ dir: tempDir });
|
||||
await git.checkout({ dir: tempDir, ref: branch });
|
||||
|
||||
// copy files
|
||||
fs.cpSync(dir, tempDir, {
|
||||
recursive: true,
|
||||
filter: path => {
|
||||
return !(path.indexOf('.git') > -1);
|
||||
},
|
||||
});
|
||||
|
||||
await git.add({ dir: tempDir, filepath: '.' });
|
||||
|
||||
// use provided info if possible, otherwise use fallbacks
|
||||
const authorInfo = {
|
||||
name: gitAuthorInfo?.name ?? 'Scaffolder',
|
||||
@@ -189,15 +253,15 @@ export async function commitAndPushBranch({
|
||||
};
|
||||
|
||||
const commitHash = await git.commit({
|
||||
dir: tempDir,
|
||||
dir,
|
||||
message: commitMessage,
|
||||
author: authorInfo,
|
||||
committer: authorInfo,
|
||||
});
|
||||
|
||||
await git.push({
|
||||
dir: tempDir,
|
||||
remote: 'origin',
|
||||
dir,
|
||||
remote,
|
||||
remoteRef: remoteRef ?? `refs/heads/${branch}`,
|
||||
});
|
||||
|
||||
|
||||
@@ -29,5 +29,8 @@ export {
|
||||
initRepoAndPush,
|
||||
commitAndPushRepo,
|
||||
commitAndPushBranch,
|
||||
addFiles,
|
||||
createBranch,
|
||||
cloneRepo,
|
||||
} from './gitHelpers';
|
||||
export { parseRepoUrl, getRepoSourceDirectory } from './util';
|
||||
|
||||
Reference in New Issue
Block a user