@ffflorian/gh-open 3.6.4 → 3.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/GitHubClient.js +10 -23
- package/dist/cjs/GitHubClient.test.js +6 -15
- package/dist/cjs/RepositoryService.js +67 -84
- package/dist/cjs/cli.js +10 -16
- package/dist/esm/RepositoryService.js +1 -1
- package/dist/esm/cli.js +4 -1
- package/package.json +3 -3
package/dist/cjs/GitHubClient.js
CHANGED
|
@@ -1,36 +1,23 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import axios from 'axios';
|
|
11
2
|
const TWO_SECONDS_IN_MILLIS = 2000;
|
|
12
3
|
export class GitHubClient {
|
|
13
4
|
constructor(timeout = TWO_SECONDS_IN_MILLIS) {
|
|
14
5
|
this.apiClient = axios.create({ baseURL: 'https://api.github.com', timeout });
|
|
15
6
|
}
|
|
16
|
-
getPullRequestByBranch(user, repository, branch) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return pullRequests.find(pr => !!pr.head && pr.head.ref === branch);
|
|
20
|
-
});
|
|
7
|
+
async getPullRequestByBranch(user, repository, branch) {
|
|
8
|
+
const pullRequests = await this.getPullRequests(user, repository);
|
|
9
|
+
return pullRequests.find(pr => !!pr.head && pr.head.ref === branch);
|
|
21
10
|
}
|
|
22
11
|
/**
|
|
23
12
|
* @see https://developer.github.com/v3/pulls/#list-pull-requests
|
|
24
13
|
*/
|
|
25
|
-
getPullRequests(user, repository) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
},
|
|
32
|
-
});
|
|
33
|
-
return response.data;
|
|
14
|
+
async getPullRequests(user, repository) {
|
|
15
|
+
const resourceUrl = `repos/${user}/${repository}/pulls`;
|
|
16
|
+
const response = await this.apiClient.get(resourceUrl, {
|
|
17
|
+
params: {
|
|
18
|
+
state: 'open',
|
|
19
|
+
},
|
|
34
20
|
});
|
|
21
|
+
return response.data;
|
|
35
22
|
}
|
|
36
23
|
}
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { assert, expect, describe, test } from 'vitest';
|
|
11
2
|
import nock from 'nock';
|
|
12
3
|
import { StatusCodes as HTTP_STATUS } from 'http-status-codes';
|
|
@@ -15,7 +6,7 @@ const TEN_SECONDS_IN_MILLIS = 10000;
|
|
|
15
6
|
const HALF_SECOND_IN_MILLIS = 500;
|
|
16
7
|
describe('GitHubClient', () => {
|
|
17
8
|
describe('getPullRequests', () => {
|
|
18
|
-
test('cancels the request after a given time', () =>
|
|
9
|
+
test('cancels the request after a given time', async () => {
|
|
19
10
|
nock('https://api.github.com')
|
|
20
11
|
.get(/repos\/.*\/.*\/pulls/)
|
|
21
12
|
.query(true)
|
|
@@ -23,7 +14,7 @@ describe('GitHubClient', () => {
|
|
|
23
14
|
.reply(HTTP_STATUS.OK);
|
|
24
15
|
const gitHubClient = new GitHubClient(HALF_SECOND_IN_MILLIS);
|
|
25
16
|
try {
|
|
26
|
-
|
|
17
|
+
await gitHubClient.getPullRequests('user', 'repository');
|
|
27
18
|
assert.fail('Should not have resolved');
|
|
28
19
|
}
|
|
29
20
|
catch (error) {
|
|
@@ -32,10 +23,10 @@ describe('GitHubClient', () => {
|
|
|
32
23
|
finally {
|
|
33
24
|
nock.cleanAll();
|
|
34
25
|
}
|
|
35
|
-
})
|
|
26
|
+
});
|
|
36
27
|
});
|
|
37
28
|
describe('getPullRequestsByBranch', () => {
|
|
38
|
-
test('correctly parses pull requests', () =>
|
|
29
|
+
test('correctly parses pull requests', async () => {
|
|
39
30
|
const exampleData = [
|
|
40
31
|
{
|
|
41
32
|
_links: {
|
|
@@ -53,8 +44,8 @@ describe('GitHubClient', () => {
|
|
|
53
44
|
.query(true)
|
|
54
45
|
.reply(HTTP_STATUS.OK, exampleData);
|
|
55
46
|
const gitHubClient = new GitHubClient();
|
|
56
|
-
const result =
|
|
47
|
+
const result = await gitHubClient.getPullRequestByBranch('user', 'repository', 'branch-name');
|
|
57
48
|
expect(result).toEqual(exampleData[0]);
|
|
58
|
-
})
|
|
49
|
+
});
|
|
59
50
|
});
|
|
60
51
|
});
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { promises as fsAsync } from 'fs';
|
|
11
2
|
import path from 'path';
|
|
12
3
|
import logdown from 'logdown';
|
|
@@ -19,7 +10,7 @@ export class RepositoryService {
|
|
|
19
10
|
pullRequest: new RegExp('github\\.com\\/(?<user>[^\\/]+)\\/(?<project>[^/]+)\\/tree\\/(?<branch>.*)'),
|
|
20
11
|
rawUrl: new RegExp('.*url = (?<rawUrl>.*)', 'mi'),
|
|
21
12
|
};
|
|
22
|
-
this.options =
|
|
13
|
+
this.options = { debug: false, timeout: 2000, ...options };
|
|
23
14
|
this.gitHubClient = new GitHubClient(this.options.timeout);
|
|
24
15
|
this.logger = logdown('gh-open', {
|
|
25
16
|
logger: console,
|
|
@@ -27,83 +18,75 @@ export class RepositoryService {
|
|
|
27
18
|
});
|
|
28
19
|
this.logger.state.isEnabled = this.options.debug;
|
|
29
20
|
}
|
|
30
|
-
getFullUrl(gitDir) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return `${parsedUrl}/tree/${gitBranch}`;
|
|
42
|
-
});
|
|
21
|
+
async getFullUrl(gitDir) {
|
|
22
|
+
const rawUrl = await this.parseGitConfig(gitDir);
|
|
23
|
+
const gitBranch = await this.parseGitBranch(gitDir);
|
|
24
|
+
const match = this.parser.fullUrl.exec(rawUrl);
|
|
25
|
+
if (!match) {
|
|
26
|
+
const errorMessage = 'Could not convert raw URL.';
|
|
27
|
+
throw new Error(errorMessage);
|
|
28
|
+
}
|
|
29
|
+
const parsedUrl = rawUrl.replace(this.parser.fullUrl, 'https://$1/$2');
|
|
30
|
+
this.logger.info('Found parsed URL', { parsedUrl });
|
|
31
|
+
return `${parsedUrl}/tree/${gitBranch}`;
|
|
43
32
|
}
|
|
44
|
-
getPullRequestUrl(url) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return pullRequestUrl;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
this.logger.warn(`Request failed: "${error.message}"`);
|
|
33
|
+
async getPullRequestUrl(url) {
|
|
34
|
+
const match = this.parser.pullRequest.exec(url);
|
|
35
|
+
if (!match || !match.groups) {
|
|
36
|
+
const errorMessage = `Could not convert GitHub URL "${url}" to pull request`;
|
|
37
|
+
throw new Error(errorMessage);
|
|
38
|
+
}
|
|
39
|
+
const { user, project, branch } = match.groups;
|
|
40
|
+
try {
|
|
41
|
+
const response = await this.gitHubClient.getPullRequestByBranch(user, project, branch);
|
|
42
|
+
if (response && response._links && response._links.html && response._links.html.href) {
|
|
43
|
+
const pullRequestUrl = response._links.html.href;
|
|
44
|
+
this.logger.info('Got pull request URL', { pullRequestUrl });
|
|
45
|
+
return pullRequestUrl;
|
|
62
46
|
}
|
|
63
|
-
}
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
this.logger.warn(`Request failed: "${error.message}"`);
|
|
50
|
+
}
|
|
64
51
|
}
|
|
65
|
-
parseGitBranch(gitDir) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return match.groups.branch;
|
|
84
|
-
});
|
|
52
|
+
async parseGitBranch(gitDir) {
|
|
53
|
+
const gitHeadFile = path.join(gitDir, 'HEAD');
|
|
54
|
+
let gitHead;
|
|
55
|
+
try {
|
|
56
|
+
gitHead = await fsAsync.readFile(gitHeadFile, 'utf-8');
|
|
57
|
+
gitHead = gitHead.trim();
|
|
58
|
+
this.logger.info('Read git head file', { gitHead });
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
const errorMessage = `Could not find git HEAD file in "${gitDir}".`;
|
|
62
|
+
throw new Error(errorMessage);
|
|
63
|
+
}
|
|
64
|
+
const match = this.parser.gitBranch.exec(gitHead);
|
|
65
|
+
if (!match || !match.groups) {
|
|
66
|
+
const errorMessage = `No branch found in git HEAD file: "${gitHead}"`;
|
|
67
|
+
throw new Error(errorMessage);
|
|
68
|
+
}
|
|
69
|
+
return match.groups.branch;
|
|
85
70
|
}
|
|
86
|
-
parseGitConfig(gitDir) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return rawUrl;
|
|
107
|
-
});
|
|
71
|
+
async parseGitConfig(gitDir) {
|
|
72
|
+
const gitConfigFile = path.join(gitDir, 'config');
|
|
73
|
+
let gitConfig;
|
|
74
|
+
try {
|
|
75
|
+
gitConfig = await fsAsync.readFile(gitConfigFile, 'utf-8');
|
|
76
|
+
gitConfig = gitConfig.trim();
|
|
77
|
+
this.logger.info('Read git config file', { gitConfigFile });
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
const errorMessage = `Could not find git config file: "${gitConfigFile}"`;
|
|
81
|
+
throw new Error(errorMessage);
|
|
82
|
+
}
|
|
83
|
+
const match = this.parser.rawUrl.exec(gitConfig);
|
|
84
|
+
if (!match || !match.groups) {
|
|
85
|
+
const errorMessage = `No URL found in git config file: "${gitConfigFile}"`;
|
|
86
|
+
throw new Error(errorMessage);
|
|
87
|
+
}
|
|
88
|
+
const rawUrl = match.groups.rawUrl;
|
|
89
|
+
this.logger.info('Found raw URL', { rawUrl });
|
|
90
|
+
return rawUrl;
|
|
108
91
|
}
|
|
109
92
|
}
|
package/dist/cjs/cli.js
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
import path from 'path';
|
|
12
3
|
import { program as commander } from 'commander';
|
|
13
4
|
import { findUp } from 'find-up';
|
|
@@ -28,16 +19,19 @@ commander
|
|
|
28
19
|
.parse(process.argv);
|
|
29
20
|
const resolvedBaseDir = path.resolve(commander.args[0] || '.');
|
|
30
21
|
const commanderOptions = commander.opts();
|
|
31
|
-
void (() =>
|
|
22
|
+
void (async () => {
|
|
32
23
|
try {
|
|
33
|
-
const gitDir =
|
|
24
|
+
const gitDir = await findUp('.git', { cwd: resolvedBaseDir, type: 'directory' });
|
|
34
25
|
if (!gitDir) {
|
|
35
26
|
throw new Error(`Could not find a git repository in "${resolvedBaseDir}".`);
|
|
36
27
|
}
|
|
37
|
-
const repositoryService = new RepositoryService(
|
|
38
|
-
|
|
28
|
+
const repositoryService = new RepositoryService({
|
|
29
|
+
...(commanderOptions.debug && { debug: commanderOptions.debug }),
|
|
30
|
+
...(commanderOptions.timeout && { timeout: parseInt(commanderOptions.timeout, 10) }),
|
|
31
|
+
});
|
|
32
|
+
let fullUrl = await repositoryService.getFullUrl(gitDir);
|
|
39
33
|
if (!commanderOptions.branch) {
|
|
40
|
-
const pullRequestUrl =
|
|
34
|
+
const pullRequestUrl = await repositoryService.getPullRequestUrl(fullUrl);
|
|
41
35
|
if (pullRequestUrl) {
|
|
42
36
|
fullUrl = pullRequestUrl;
|
|
43
37
|
}
|
|
@@ -46,7 +40,7 @@ void (() => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
46
40
|
console.info(fullUrl);
|
|
47
41
|
}
|
|
48
42
|
else {
|
|
49
|
-
|
|
43
|
+
await open(fullUrl);
|
|
50
44
|
}
|
|
51
45
|
process.exit();
|
|
52
46
|
}
|
|
@@ -54,4 +48,4 @@ void (() => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
54
48
|
console.error(error.message);
|
|
55
49
|
process.exit(1);
|
|
56
50
|
}
|
|
57
|
-
})
|
|
51
|
+
})();
|
|
@@ -10,7 +10,7 @@ export class RepositoryService {
|
|
|
10
10
|
pullRequest: new RegExp('github\\.com\\/(?<user>[^\\/]+)\\/(?<project>[^/]+)\\/tree\\/(?<branch>.*)'),
|
|
11
11
|
rawUrl: new RegExp('.*url = (?<rawUrl>.*)', 'mi'),
|
|
12
12
|
};
|
|
13
|
-
this.options =
|
|
13
|
+
this.options = { debug: false, timeout: 2000, ...options };
|
|
14
14
|
this.gitHubClient = new GitHubClient(this.options.timeout);
|
|
15
15
|
this.logger = logdown('gh-open', {
|
|
16
16
|
logger: console,
|
package/dist/esm/cli.js
CHANGED
|
@@ -25,7 +25,10 @@ void (async () => {
|
|
|
25
25
|
if (!gitDir) {
|
|
26
26
|
throw new Error(`Could not find a git repository in "${resolvedBaseDir}".`);
|
|
27
27
|
}
|
|
28
|
-
const repositoryService = new RepositoryService(
|
|
28
|
+
const repositoryService = new RepositoryService({
|
|
29
|
+
...(commanderOptions.debug && { debug: commanderOptions.debug }),
|
|
30
|
+
...(commanderOptions.timeout && { timeout: parseInt(commanderOptions.timeout, 10) }),
|
|
31
|
+
});
|
|
29
32
|
let fullUrl = await repositoryService.getFullUrl(gitDir);
|
|
30
33
|
if (!commanderOptions.branch) {
|
|
31
34
|
const pullRequestUrl = await repositoryService.getPullRequestUrl(fullUrl);
|
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"http-status-codes": "2.3.0",
|
|
14
14
|
"nock": "13.5.4",
|
|
15
15
|
"rimraf": "5.0.7",
|
|
16
|
-
"typescript": "5.
|
|
16
|
+
"typescript": "5.5.2",
|
|
17
17
|
"vitest": "1.6.0"
|
|
18
18
|
},
|
|
19
19
|
"engines": {
|
|
@@ -51,6 +51,6 @@
|
|
|
51
51
|
"test": "vitest run"
|
|
52
52
|
},
|
|
53
53
|
"type": "module",
|
|
54
|
-
"version": "3.6.
|
|
55
|
-
"gitHead": "
|
|
54
|
+
"version": "3.6.5",
|
|
55
|
+
"gitHead": "f7a6a79286e4eb85392b5f2d33942ab166142109"
|
|
56
56
|
}
|