-
-
Notifications
You must be signed in to change notification settings - Fork 56
/
git.ts
119 lines (101 loc) · 3.37 KB
/
git.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import { ExecOutput, getExecOutput } from '@nx-tools/core';
import { RepoMetadata, RunnerContext } from '../interfaces';
export class Git {
public static async context(): Promise<RunnerContext> {
return {
name: 'GIT',
actor: await Git.getCommitUserEmail(),
eventName: 'push',
job: 'build',
payload: {},
ref: await Git.ref(),
runId: 0,
runNumber: 0,
repoUrl: await Git.remoteURL(),
sha: await Git.fullCommit(),
};
}
public static async remoteURL(): Promise<string> {
return await Git.exec(['remote', 'get-url', 'origin']).then((rurl) => {
if (rurl.length == 0) {
return Git.exec(['remote', 'get-url', 'upstream']).then((rurl) => {
if (rurl.length == 0) {
throw new Error(`Cannot find remote URL for origin or upstream`);
}
return rurl;
});
}
return rurl;
});
}
public static async ref(): Promise<string> {
const isHeadDetached = await Git.isHeadDetached();
if (isHeadDetached) {
return await Git.getDetachedRef();
}
return await Git.exec(['symbolic-ref', 'HEAD']);
}
public static async fullCommit(): Promise<string> {
return await Git.exec(['show', '--format=%H', 'HEAD', '--quiet', '--']);
}
public static async tag(): Promise<string> {
return await Git.exec(['tag', '--points-at', 'HEAD', '--sort', '-version:creatordate']).then((tags) => {
if (tags.length == 0) {
return Git.exec(['describe', '--tags', '--abbrev=0']);
}
return tags.split('\n')[0];
});
}
public static async getCommitUserEmail(): Promise<string> {
return await Git.exec(['log', '-1', '--pretty=format:%ae']);
}
private static async isHeadDetached(): Promise<boolean> {
return await Git.exec(['branch', '--show-current']).then((res) => {
return res.length == 0;
});
}
private static async getDetachedRef(): Promise<string> {
const res = await Git.exec(['show', '-s', '--pretty=%D']);
// Can be "HEAD, <tagname>" or "grafted, HEAD, <tagname>"
const refMatch = res.match(/^(grafted, )?HEAD, (.*)$/);
if (!refMatch || !refMatch[2]) {
throw new Error(`Cannot find detached HEAD ref in "${res}"`);
}
const ref = refMatch[2].trim();
// Tag refs are formatted as "tag: <tagname>"
if (ref.startsWith('tag: ')) {
return `refs/tags/${ref.split(':')[1].trim()}`;
}
// Branch refs are formatted as "<origin>/<branch-name>, <branch-name>"
const branchMatch = ref.match(/^[^/]+\/[^/]+, (.+)$/);
if (branchMatch) {
return `refs/heads/${branchMatch[1].trim()}`;
}
// Pull request merge refs are formatted as "pull/<number>/<state>"
const prMatch = ref.match(/^pull\/\d+\/(head|merge)$/);
if (prMatch) {
return `refs/${ref}`;
}
throw new Error(`Unsupported detached HEAD ref in "${res}"`);
}
private static async exec(args: string[] = []): Promise<string> {
return await getExecOutput(`git`, args, {
ignoreReturnCode: true,
silent: true,
}).then((res: ExecOutput) => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr);
}
return res.stdout.trim();
});
}
}
export async function repo(): Promise<RepoMetadata> {
return {
default_branch: '',
description: '',
html_url: await Git.remoteURL(),
license: null,
name: '',
};
}