Skip to content

Commit fa415d1

Browse files
authored
fix(git): checkout fails if branch does not exist (#1333)
* fix(git): checkout fails if branch does not exist * fix the issue
1 parent b45f7af commit fa415d1

File tree

3 files changed

+96
-61
lines changed

3 files changed

+96
-61
lines changed

src/help/git.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ export function push(ref: string) {
136136
export function checkout(branch: string, options: { createIfMissing?: boolean } ) {
137137
if (options.createIfMissing) {
138138
try {
139-
shell.run(`git show-branch origin/${branch}`);
139+
shell.run(`git show-branch origin/${branch}`, { capture: true });
140140
} catch (e) {
141141
if (e instanceof Error && e.message.includes('fatal: bad sha1 reference')) {
142142
console.log('Remote branch not found, creating new branch.');

test/targets/git-mocked.test.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import * as git from '../../src/help/git';
2+
import * as shell from '../../src/help/shell';
3+
4+
// mock shell.run
5+
jest.mock('../../src/help/shell');
6+
const mockedShellRun = (shell.run as unknown) as jest.Mock<typeof shell.run>;
7+
8+
// restore env after each test
9+
const OLD_ENV = process.env;
10+
11+
beforeEach(() => {
12+
jest.resetModules(); // Most important - it clears the cache
13+
process.env = { ...OLD_ENV }; // Make a copy
14+
});
15+
16+
afterAll(() => {
17+
process.env = OLD_ENV; // Restore old environment
18+
});
19+
20+
// test
21+
test('clone with token', () => {
22+
process.env.GITHUB_TOKEN = 'my-token';
23+
24+
git.clone('github.com/cdklabs/publib', 'target');
25+
26+
expect(mockedShellRun.mock.calls).toHaveLength(1);
27+
expect(mockedShellRun.mock.calls[0]).toEqual(['git clone https://[email protected]/cdklabs/publib.git target']);
28+
});
29+
30+
test('clone with ssh', () => {
31+
process.env.GITHUB_USE_SSH = '1';
32+
33+
git.clone('github.com/cdklabs/publib', 'target');
34+
35+
expect(mockedShellRun.mock.calls).toHaveLength(1);
36+
expect(mockedShellRun.mock.calls[0]).toEqual(['git clone [email protected]:cdklabs/publib.git target']);
37+
});
38+
39+
test('throw exception without token or ssh', () => {
40+
const t = () => git.clone('github.com/cdklabs/publib', 'target');
41+
expect(t).toThrow('GITHUB_TOKEN env variable is required when GITHUB_USE_SSH env variable is not used');
42+
});
43+
44+
test('throw exception without ghe authentication for github enterprise repo', () => {
45+
const t = () => git.clone('github.corporate-enterprise.com/cdklabs/publib', 'target');
46+
expect(t).toThrow('GITHUB_TOKEN env variable is required when GITHUB_USE_SSH env variable is not used');
47+
});
48+
49+
test('throw exception with incomplete ghe authentication for github enterprise repo', () => {
50+
process.env.GITHUB_ENTERPRISE_TOKEN = 'valid-token';
51+
const t = () => git.clone('github.corporate-enterprise.com/cdklabs/publib', 'target');
52+
expect(t).toThrow('GITHUB_TOKEN env variable is required when GITHUB_USE_SSH env variable is not used');
53+
});
54+
55+
test('clone with provided ghe authentication for github enterprise repo but no set github api url', () => {
56+
process.env.GH_ENTERPRISE_TOKEN = 'valid-token';
57+
process.env.GH_HOST = 'github.corporate-enterprise.com';
58+
git.clone('github.corporate-enterprise.com/cdklabs/publib', 'target');
59+
expect(mockedShellRun.mock.calls).toHaveLength(1);
60+
expect(mockedShellRun.mock.calls[0]).toEqual(['git clone https://[email protected]/cdklabs/publib.git target']);
61+
});
62+
63+
test('clone with provided ghe authentication for github enterprise repo and with non-public github api url', () => {
64+
process.env.GH_ENTERPRISE_TOKEN = 'valid-token';
65+
process.env.GH_HOST = 'github.corporate-enterprise.com';
66+
process.env.GITHUB_API_URL = 'https://api.github.corporate-enterprise.com';
67+
git.clone('github.corporate-enterprise.com/cdklabs/publib', 'target');
68+
expect(mockedShellRun.mock.calls).toHaveLength(1);
69+
expect(mockedShellRun.mock.calls[0]).toEqual(['git clone https://[email protected]/cdklabs/publib.git target']);
70+
});

test/targets/git.test.ts

Lines changed: 25 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,35 @@
1+
import * as fs from 'node:fs';
2+
import * as os from 'node:os';
3+
import * as path from 'node:path';
14
import * as git from '../../src/help/git';
25
import * as shell from '../../src/help/shell';
36

4-
// mock shell.run
5-
jest.mock('../../src/help/shell');
6-
const mockedShellRun = (shell.run as unknown) as jest.Mock<typeof shell.run>;
7-
8-
// restore env after each test
9-
const OLD_ENV = process.env;
10-
7+
let shellRunSpy: jest.SpyInstance<string, Parameters<typeof shell.run>>;
118
beforeEach(() => {
12-
jest.resetModules(); // Most important - it clears the cache
13-
process.env = { ...OLD_ENV }; // Make a copy
9+
shellRunSpy = jest.spyOn(shell, 'run');
1410
});
15-
16-
afterAll(() => {
17-
process.env = OLD_ENV; // Restore old environment
11+
afterEach(() => {
12+
jest.clearAllMocks();
1813
});
1914

20-
// test
21-
test('clone with token', () => {
22-
process.env.GITHUB_TOKEN = 'my-token';
2315

24-
git.clone('github.com/cdklabs/publib', 'target');
25-
26-
expect(mockedShellRun.mock.calls).toHaveLength(1);
27-
expect(mockedShellRun.mock.calls[0]).toEqual(['git clone https://[email protected]/cdklabs/publib.git target']);
16+
test('checkout with createIfMissing', () => {
17+
withTmpDir(() => {
18+
git.init();
19+
git.checkout('main', { createIfMissing: true });
20+
});
21+
expect(shellRunSpy.mock.calls).toHaveLength(3); // init, show-branch, checkout -B
22+
expect(shellRunSpy.mock.calls[2]).toEqual(['git checkout -B main']);
2823
});
2924

30-
test('clone with ssh', () => {
31-
process.env.GITHUB_USE_SSH = '1';
32-
33-
git.clone('github.com/cdklabs/publib', 'target');
34-
35-
expect(mockedShellRun.mock.calls).toHaveLength(1);
36-
expect(mockedShellRun.mock.calls[0]).toEqual(['git clone [email protected]:cdklabs/publib.git target']);
37-
});
38-
39-
test('throw exception without token or ssh', () => {
40-
const t = () => git.clone('github.com/cdklabs/publib', 'target');
41-
expect(t).toThrow('GITHUB_TOKEN env variable is required when GITHUB_USE_SSH env variable is not used');
42-
});
43-
44-
test('throw exception without ghe authentication for github enterprise repo', () => {
45-
const t = () => git.clone('github.corporate-enterprise.com/cdklabs/publib', 'target');
46-
expect(t).toThrow('GITHUB_TOKEN env variable is required when GITHUB_USE_SSH env variable is not used');
47-
});
48-
49-
test('throw exception with incomplete ghe authentication for github enterprise repo', () => {
50-
process.env.GITHUB_ENTERPRISE_TOKEN = 'valid-token';
51-
const t = () => git.clone('github.corporate-enterprise.com/cdklabs/publib', 'target');
52-
expect(t).toThrow('GITHUB_TOKEN env variable is required when GITHUB_USE_SSH env variable is not used');
53-
});
54-
55-
test('clone with provided ghe authentication for github enterprise repo but no set github api url', () => {
56-
process.env.GH_ENTERPRISE_TOKEN = 'valid-token';
57-
process.env.GH_HOST = 'github.corporate-enterprise.com';
58-
git.clone('github.corporate-enterprise.com/cdklabs/publib', 'target');
59-
expect(mockedShellRun.mock.calls).toHaveLength(1);
60-
expect(mockedShellRun.mock.calls[0]).toEqual(['git clone https://[email protected]/cdklabs/publib.git target']);
61-
});
62-
63-
test('clone with provided ghe authentication for github enterprise repo and with non-public github api url', () => {
64-
process.env.GH_ENTERPRISE_TOKEN = 'valid-token';
65-
process.env.GH_HOST = 'github.corporate-enterprise.com';
66-
process.env.GITHUB_API_URL = 'https://api.github.corporate-enterprise.com';
67-
git.clone('github.corporate-enterprise.com/cdklabs/publib', 'target');
68-
expect(mockedShellRun.mock.calls).toHaveLength(1);
69-
expect(mockedShellRun.mock.calls[0]).toEqual(['git clone https://[email protected]/cdklabs/publib.git target']);
70-
});
25+
function withTmpDir(fn: (tmpDir: string) => void) {
26+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-'));
27+
const cwd = process.cwd();
28+
try {
29+
process.chdir(tmpDir);
30+
fn(tmpDir);
31+
} finally {
32+
fs.rmSync(tmpDir, { recursive: true, force: true });
33+
process.chdir(cwd);
34+
}
35+
}

0 commit comments

Comments
 (0)