-
Notifications
You must be signed in to change notification settings - Fork 16
/
gitInfo.ts
95 lines (92 loc) · 3.61 KB
/
gitInfo.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
import * as fs from "fs-extra";
import * as path from "path";
import { logger } from "../util/logger";
/**
* Return Git remote origin URL, branch, and sha for provided
* directory. If provided directory is not a Git repository, empty
* strings will be returned for the repository, branch, and sha.
*
* @param directory path to local Git repository
* @return Git URL, branch, and sha
*/
export function obtainGitInfo(directory: string): Promise<GitInformation> {
const gitInfo: GitInformation = {
sha: "",
branch: "",
repository: "",
};
const gitPath = path.join(directory, ".git");
const headPath = path.join(gitPath, "HEAD");
const refsPath = path.join(gitPath, "refs", "heads");
const configPath = path.join(gitPath, "config");
return fs.readFile(headPath)
.then(headLine => {
const head = headLine.toString().trim();
const refHead = "ref: refs/heads/";
if (head.indexOf(refHead) === 0) {
const branch = head.replace(refHead, "");
if (!branch) {
throw new Error(`failed to get branch from ${headPath}: ${head}`);
}
gitInfo.branch = branch;
const branchPath = path.join(refsPath, branch);
return fs.readFile(branchPath)
.then(ref => {
const sha = ref.toString().trim();
if (!sha) {
throw new Error(`failed to get SHA from ${branchPath}`);
}
gitInfo.sha = sha;
});
} else {
gitInfo.sha = head;
gitInfo.branch = head;
}
})
.then(() => {
return fs.readFile(configPath)
.then(config => {
const configLines = config.toString().split("\n");
for (let i = 0; i < configLines.length; i++) {
if (/^\[remote "origin"\]$/.test(configLines[i])) {
for (let j = i + 1; i < configLines.length; j++) {
if (/^\s+url\s*=/.test(configLines[j])) {
const url = configLines[j].replace(/.*?=\s*/, "");
if (!url) {
continue;
}
gitInfo.repository = cleanGitUrl(url);
i = configLines.length;
break;
} else if (/^\S/.test(configLines[j])) {
i = j;
break;
}
}
}
}
if (!gitInfo.repository) {
throw new Error(`failed to get remote origin URL from ${configPath}`);
}
});
})
.then(() => Promise.resolve(gitInfo), err => {
logger.info(`failed to fully populate git information: ${err.message}`);
return Promise.resolve(gitInfo);
});
}
/*
* Information about current Git commit and remote.
*/
export interface GitInformation {
sha: string;
branch: string;
repository: string;
}
export function cleanGitUrl(url: string): string {
const gitUrlParse = require("git-url-parse");
const gitUrl = gitUrlParse(url);
gitUrl.user = undefined;
gitUrl.git_suffix = true;
return gitUrl.toString("ssh");
}