git-watchtower 1.8.2 → 1.8.3
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/bin/git-watchtower.js +101 -83
- package/package.json +1 -1
package/bin/git-watchtower.js
CHANGED
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
const http = require('http');
|
|
57
57
|
const fs = require('fs');
|
|
58
58
|
const path = require('path');
|
|
59
|
-
const {
|
|
59
|
+
const { execFile, execSync, spawn } = require('child_process');
|
|
60
60
|
const readline = require('readline');
|
|
61
61
|
|
|
62
62
|
// Casino mode - Vegas-style feedback effects
|
|
@@ -82,7 +82,7 @@ const { parseGitHubPr, parseGitLabMr, parseGitHubPrList, parseGitLabMrList, isBa
|
|
|
82
82
|
// Security & Validation (imported from src/git/branch.js and src/git/commands.js)
|
|
83
83
|
// ============================================================================
|
|
84
84
|
const { isValidBranchName, sanitizeBranchName, getGoneBranches, deleteGoneBranches } = require('../src/git/branch');
|
|
85
|
-
const { isGitAvailable: checkGitAvailable } = require('../src/git/commands');
|
|
85
|
+
const { isGitAvailable: checkGitAvailable, execGit, execGitSilent, getDiffStats: getDiffStatsSafe } = require('../src/git/commands');
|
|
86
86
|
|
|
87
87
|
// ============================================================================
|
|
88
88
|
// Configuration (imports from src/config/, inline wizard kept here)
|
|
@@ -436,7 +436,7 @@ function openInBrowser(url) {
|
|
|
436
436
|
|
|
437
437
|
async function getRemoteWebUrl(branchName) {
|
|
438
438
|
try {
|
|
439
|
-
const { stdout } = await
|
|
439
|
+
const { stdout } = await execGit(['remote', 'get-url', REMOTE_NAME], { cwd: PROJECT_ROOT });
|
|
440
440
|
const parsed = parseRemoteUrl(stdout);
|
|
441
441
|
return buildWebUrl(parsed, branchName);
|
|
442
442
|
} catch (e) {
|
|
@@ -446,20 +446,21 @@ async function getRemoteWebUrl(branchName) {
|
|
|
446
446
|
|
|
447
447
|
// Extract Claude Code session URL from the most recent commit on a branch
|
|
448
448
|
async function getSessionUrl(branchName) {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
449
|
+
// Try remote branch first, fall back to local
|
|
450
|
+
const result = await execGitSilent(
|
|
451
|
+
['log', `${REMOTE_NAME}/${branchName}`, '-1', '--format=%B'],
|
|
452
|
+
{ cwd: PROJECT_ROOT }
|
|
453
|
+
) || await execGitSilent(
|
|
454
|
+
['log', branchName, '-1', '--format=%B'],
|
|
455
|
+
{ cwd: PROJECT_ROOT }
|
|
456
|
+
);
|
|
457
|
+
return result ? extractSessionUrl(result.stdout) : null;
|
|
457
458
|
}
|
|
458
459
|
|
|
459
460
|
// Check if a CLI tool is available
|
|
460
461
|
async function hasCommand(cmd) {
|
|
461
462
|
try {
|
|
462
|
-
await
|
|
463
|
+
await execCli('which', [cmd]);
|
|
463
464
|
return true;
|
|
464
465
|
} catch (e) {
|
|
465
466
|
return false;
|
|
@@ -472,17 +473,18 @@ async function hasCommand(cmd) {
|
|
|
472
473
|
async function getPrInfo(branchName, platform, hasGh, hasGlab) {
|
|
473
474
|
if (platform === 'github' && hasGh) {
|
|
474
475
|
try {
|
|
475
|
-
const { stdout } = await
|
|
476
|
-
|
|
477
|
-
|
|
476
|
+
const { stdout } = await execCli('gh', [
|
|
477
|
+
'pr', 'list', '--head', branchName, '--state', 'all',
|
|
478
|
+
'--json', 'number,title,state,reviewDecision,statusCheckRollup', '--limit', '1',
|
|
479
|
+
]);
|
|
478
480
|
return parseGitHubPr(JSON.parse(stdout));
|
|
479
481
|
} catch (e) { /* gh not authed or other error */ }
|
|
480
482
|
}
|
|
481
483
|
if (platform === 'gitlab' && hasGlab) {
|
|
482
484
|
try {
|
|
483
|
-
const { stdout } = await
|
|
484
|
-
|
|
485
|
-
);
|
|
485
|
+
const { stdout } = await execCli('glab', [
|
|
486
|
+
'mr', 'list', `--source-branch=${branchName}`, '--state', 'all', '--output', 'json',
|
|
487
|
+
]);
|
|
486
488
|
return parseGitLabMr(JSON.parse(stdout));
|
|
487
489
|
} catch (e) { /* glab not authed or other error */ }
|
|
488
490
|
}
|
|
@@ -492,11 +494,7 @@ async function getPrInfo(branchName, platform, hasGh, hasGlab) {
|
|
|
492
494
|
// Check if gh/glab CLI is authenticated
|
|
493
495
|
async function checkCliAuth(cmd) {
|
|
494
496
|
try {
|
|
495
|
-
|
|
496
|
-
await execAsync('gh auth status 2>&1');
|
|
497
|
-
} else if (cmd === 'glab') {
|
|
498
|
-
await execAsync('glab auth status 2>&1');
|
|
499
|
-
}
|
|
497
|
+
await execCli(cmd, ['auth', 'status']);
|
|
500
498
|
return true;
|
|
501
499
|
} catch (e) {
|
|
502
500
|
return false;
|
|
@@ -510,18 +508,19 @@ async function fetchAllPrStatuses() {
|
|
|
510
508
|
|
|
511
509
|
if (platform === 'github' && hasGh && ghAuthed) {
|
|
512
510
|
try {
|
|
513
|
-
const { stdout } = await
|
|
514
|
-
'
|
|
515
|
-
|
|
511
|
+
const { stdout } = await execCli('gh', [
|
|
512
|
+
'pr', 'list', '--state', 'all',
|
|
513
|
+
'--json', 'headRefName,number,title,state', '--limit', '200',
|
|
514
|
+
]);
|
|
516
515
|
return parseGitHubPrList(JSON.parse(stdout));
|
|
517
516
|
} catch (e) { /* gh error */ }
|
|
518
517
|
}
|
|
519
518
|
|
|
520
519
|
if (platform === 'gitlab' && hasGlab && glabAuthed) {
|
|
521
520
|
try {
|
|
522
|
-
const { stdout } = await
|
|
523
|
-
'
|
|
524
|
-
);
|
|
521
|
+
const { stdout } = await execCli('glab', [
|
|
522
|
+
'mr', 'list', '--state', 'all', '--output', 'json',
|
|
523
|
+
]);
|
|
525
524
|
return parseGitLabMrList(JSON.parse(stdout));
|
|
526
525
|
} catch (e) { /* glab error */ }
|
|
527
526
|
}
|
|
@@ -815,22 +814,30 @@ const LIVE_RELOAD_SCRIPT = `
|
|
|
815
814
|
// Utility Functions
|
|
816
815
|
// ============================================================================
|
|
817
816
|
|
|
818
|
-
// Default timeout for
|
|
817
|
+
// Default timeout for CLI commands (30 seconds) — prevents hung commands
|
|
819
818
|
// from permanently blocking the polling loop
|
|
820
|
-
const
|
|
819
|
+
const CLI_TIMEOUT = 30000;
|
|
821
820
|
|
|
822
|
-
|
|
823
|
-
|
|
821
|
+
/**
|
|
822
|
+
* Execute a non-git CLI command safely using execFile (no shell interpolation).
|
|
823
|
+
* For git commands, use execGit/execGitSilent from src/git/commands.js instead.
|
|
824
|
+
* @param {string} cmd - The executable (e.g. 'gh', 'glab', 'which')
|
|
825
|
+
* @param {string[]} args - Arguments array (no shell interpolation)
|
|
826
|
+
* @param {Object} [options] - Execution options
|
|
827
|
+
* @param {number} [options.timeout] - Command timeout in ms
|
|
828
|
+
* @returns {Promise<{stdout: string, stderr: string}>}
|
|
829
|
+
*/
|
|
830
|
+
function execCli(cmd, args = [], options = {}) {
|
|
831
|
+
const { timeout = CLI_TIMEOUT, ...restOptions } = options;
|
|
824
832
|
return new Promise((resolve, reject) => {
|
|
825
|
-
const child =
|
|
833
|
+
const child = execFile(cmd, args, { cwd: PROJECT_ROOT, timeout, ...restOptions }, (error, stdout, stderr) => {
|
|
826
834
|
if (error) {
|
|
827
835
|
reject({ error, stdout, stderr });
|
|
828
836
|
} else {
|
|
829
837
|
resolve({ stdout: stdout.trim(), stderr: stderr.trim() });
|
|
830
838
|
}
|
|
831
839
|
});
|
|
832
|
-
//
|
|
833
|
-
// but doesn't guarantee cleanup of process trees)
|
|
840
|
+
// Force-kill if process outlives timeout grace period
|
|
834
841
|
if (timeout > 0) {
|
|
835
842
|
const killTimer = setTimeout(() => {
|
|
836
843
|
try { child.kill('SIGKILL'); } catch (e) { /* already dead */ }
|
|
@@ -841,18 +848,13 @@ function execAsync(command, options = {}) {
|
|
|
841
848
|
}
|
|
842
849
|
|
|
843
850
|
/**
|
|
844
|
-
* Get diff stats between two commits
|
|
851
|
+
* Get diff stats between two commits (delegates to src/git/commands.js)
|
|
845
852
|
* @param {string} fromCommit - Starting commit
|
|
846
853
|
* @param {string} toCommit - Ending commit (default HEAD)
|
|
847
854
|
* @returns {Promise<{added: number, deleted: number}>}
|
|
848
855
|
*/
|
|
849
856
|
async function getDiffStats(fromCommit, toCommit = 'HEAD') {
|
|
850
|
-
|
|
851
|
-
const { stdout } = await execAsync(`git diff --stat ${fromCommit}..${toCommit}`);
|
|
852
|
-
return parseDiffStats(stdout);
|
|
853
|
-
} catch (e) {
|
|
854
|
-
return { added: 0, deleted: 0 };
|
|
855
|
-
}
|
|
857
|
+
return getDiffStatsSafe(fromCommit, toCommit, { cwd: PROJECT_ROOT });
|
|
856
858
|
}
|
|
857
859
|
|
|
858
860
|
// formatTimeAgo imported from src/utils/time.js
|
|
@@ -945,10 +947,15 @@ async function refreshAllSparklines() {
|
|
|
945
947
|
for (const branch of currentBranches.slice(0, 20)) { // Limit to top 20
|
|
946
948
|
if (branch.isDeleted) continue;
|
|
947
949
|
|
|
948
|
-
// Get commit counts for last 7 days
|
|
949
|
-
const
|
|
950
|
-
|
|
951
|
-
|
|
950
|
+
// Get commit counts for last 7 days (try remote, fall back to local)
|
|
951
|
+
const sparkResult = await execGitSilent(
|
|
952
|
+
['log', `origin/${branch.name}`, '--since=7 days ago', '--format=%ad', '--date=format:%Y-%m-%d'],
|
|
953
|
+
{ cwd: PROJECT_ROOT }
|
|
954
|
+
) || await execGitSilent(
|
|
955
|
+
['log', branch.name, '--since=7 days ago', '--format=%ad', '--date=format:%Y-%m-%d'],
|
|
956
|
+
{ cwd: PROJECT_ROOT }
|
|
957
|
+
);
|
|
958
|
+
const stdout = sparkResult ? sparkResult.stdout : '';
|
|
952
959
|
|
|
953
960
|
// Count commits per day
|
|
954
961
|
const dayCounts = new Map();
|
|
@@ -978,10 +985,15 @@ async function refreshAllSparklines() {
|
|
|
978
985
|
|
|
979
986
|
async function getPreviewData(branchName) {
|
|
980
987
|
try {
|
|
981
|
-
// Get last 5 commits
|
|
982
|
-
const
|
|
983
|
-
|
|
984
|
-
|
|
988
|
+
// Get last 5 commits (try remote, fall back to local)
|
|
989
|
+
const logResult = await execGitSilent(
|
|
990
|
+
['log', `origin/${branchName}`, '-5', '--oneline'],
|
|
991
|
+
{ cwd: PROJECT_ROOT }
|
|
992
|
+
) || await execGitSilent(
|
|
993
|
+
['log', branchName, '-5', '--oneline'],
|
|
994
|
+
{ cwd: PROJECT_ROOT }
|
|
995
|
+
);
|
|
996
|
+
const logOutput = logResult ? logResult.stdout : '';
|
|
985
997
|
|
|
986
998
|
const commits = logOutput.split('\n').filter(Boolean).map(line => {
|
|
987
999
|
const [hash, ...msgParts] = line.split(' ');
|
|
@@ -990,13 +1002,15 @@ async function getPreviewData(branchName) {
|
|
|
990
1002
|
|
|
991
1003
|
// Get files changed (comparing to current branch)
|
|
992
1004
|
let filesChanged = [];
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1005
|
+
const diffResult = await execGitSilent(
|
|
1006
|
+
['diff', '--stat', '--name-only', `HEAD...origin/${branchName}`],
|
|
1007
|
+
{ cwd: PROJECT_ROOT }
|
|
1008
|
+
) || await execGitSilent(
|
|
1009
|
+
['diff', '--stat', '--name-only', `HEAD...${branchName}`],
|
|
1010
|
+
{ cwd: PROJECT_ROOT }
|
|
1011
|
+
);
|
|
1012
|
+
if (diffResult) {
|
|
1013
|
+
filesChanged = diffResult.stdout.split('\n').filter(Boolean).slice(0, 8);
|
|
1000
1014
|
}
|
|
1001
1015
|
|
|
1002
1016
|
return { commits, filesChanged };
|
|
@@ -1312,12 +1326,12 @@ function hideStashConfirm() {
|
|
|
1312
1326
|
|
|
1313
1327
|
async function getCurrentBranch() {
|
|
1314
1328
|
try {
|
|
1315
|
-
const { stdout } = await
|
|
1329
|
+
const { stdout } = await execGit(['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: PROJECT_ROOT });
|
|
1316
1330
|
// Check for detached HEAD state
|
|
1317
1331
|
if (stdout === 'HEAD') {
|
|
1318
1332
|
store.setState({ isDetachedHead: true });
|
|
1319
1333
|
// Get the short commit hash instead
|
|
1320
|
-
const { stdout: commitHash } = await
|
|
1334
|
+
const { stdout: commitHash } = await execGit(['rev-parse', '--short', 'HEAD'], { cwd: PROJECT_ROOT });
|
|
1321
1335
|
return `HEAD@${commitHash}`;
|
|
1322
1336
|
}
|
|
1323
1337
|
store.setState({ isDetachedHead: false });
|
|
@@ -1329,7 +1343,7 @@ async function getCurrentBranch() {
|
|
|
1329
1343
|
|
|
1330
1344
|
async function checkRemoteExists() {
|
|
1331
1345
|
try {
|
|
1332
|
-
const { stdout } = await
|
|
1346
|
+
const { stdout } = await execGit(['remote'], { cwd: PROJECT_ROOT });
|
|
1333
1347
|
const remotes = stdout.split('\n').filter(Boolean);
|
|
1334
1348
|
return remotes.length > 0;
|
|
1335
1349
|
} catch (e) {
|
|
@@ -1339,7 +1353,7 @@ async function checkRemoteExists() {
|
|
|
1339
1353
|
|
|
1340
1354
|
async function hasUncommittedChanges() {
|
|
1341
1355
|
try {
|
|
1342
|
-
const { stdout } = await
|
|
1356
|
+
const { stdout } = await execGit(['status', '--porcelain'], { cwd: PROJECT_ROOT, timeout: 5000 });
|
|
1343
1357
|
return stdout.length > 0;
|
|
1344
1358
|
} catch (e) {
|
|
1345
1359
|
return false;
|
|
@@ -1350,14 +1364,15 @@ async function hasUncommittedChanges() {
|
|
|
1350
1364
|
|
|
1351
1365
|
async function getAllBranches() {
|
|
1352
1366
|
try {
|
|
1353
|
-
await
|
|
1367
|
+
await execGitSilent(['fetch', '--all', '--prune'], { cwd: PROJECT_ROOT, timeout: 60000 });
|
|
1354
1368
|
|
|
1355
1369
|
const branchList = [];
|
|
1356
1370
|
const seenBranches = new Set();
|
|
1357
1371
|
|
|
1358
1372
|
// Get local branches
|
|
1359
|
-
const { stdout: localOutput } = await
|
|
1360
|
-
'
|
|
1373
|
+
const { stdout: localOutput } = await execGit(
|
|
1374
|
+
['for-each-ref', '--sort=-committerdate', '--format=%(refname:short)|%(committerdate:iso8601)|%(objectname:short)|%(subject)', 'refs/heads/'],
|
|
1375
|
+
{ cwd: PROJECT_ROOT }
|
|
1361
1376
|
);
|
|
1362
1377
|
|
|
1363
1378
|
for (const line of localOutput.split('\n').filter(Boolean)) {
|
|
@@ -1377,9 +1392,11 @@ async function getAllBranches() {
|
|
|
1377
1392
|
}
|
|
1378
1393
|
|
|
1379
1394
|
// Get remote branches (using configured remote name)
|
|
1380
|
-
const
|
|
1381
|
-
|
|
1382
|
-
|
|
1395
|
+
const remoteResult = await execGitSilent(
|
|
1396
|
+
['for-each-ref', '--sort=-committerdate', '--format=%(refname:short)|%(committerdate:iso8601)|%(objectname:short)|%(subject)', `refs/remotes/${REMOTE_NAME}/`],
|
|
1397
|
+
{ cwd: PROJECT_ROOT }
|
|
1398
|
+
);
|
|
1399
|
+
const remoteOutput = remoteResult ? remoteResult.stdout : '';
|
|
1383
1400
|
|
|
1384
1401
|
const remotePrefix = `${REMOTE_NAME}/`;
|
|
1385
1402
|
for (const line of remoteOutput.split('\n').filter(Boolean)) {
|
|
@@ -1442,13 +1459,14 @@ async function switchToBranch(branchName, recordHistory = true) {
|
|
|
1442
1459
|
addLog(`Switching to ${safeBranchName}...`, 'update');
|
|
1443
1460
|
render();
|
|
1444
1461
|
|
|
1445
|
-
const { stdout: localBranches } = await
|
|
1446
|
-
const hasLocal = localBranches.split('\n').some(b => b.trim().replace(
|
|
1462
|
+
const { stdout: localBranches } = await execGit(['branch', '--list'], { cwd: PROJECT_ROOT });
|
|
1463
|
+
const hasLocal = localBranches.split('\n').some(b => b.trim().replace(/^\* /, '') === safeBranchName);
|
|
1447
1464
|
|
|
1448
1465
|
if (hasLocal) {
|
|
1449
|
-
await
|
|
1466
|
+
await execGitSilent(['checkout', '--', '.'], { cwd: PROJECT_ROOT });
|
|
1467
|
+
await execGit(['checkout', safeBranchName], { cwd: PROJECT_ROOT });
|
|
1450
1468
|
} else {
|
|
1451
|
-
await
|
|
1469
|
+
await execGit(['checkout', '-b', safeBranchName, `${REMOTE_NAME}/${safeBranchName}`], { cwd: PROJECT_ROOT });
|
|
1452
1470
|
}
|
|
1453
1471
|
|
|
1454
1472
|
store.setState({ currentBranch: safeBranchName, isDetachedHead: false });
|
|
@@ -1540,7 +1558,7 @@ async function pullCurrentBranch() {
|
|
|
1540
1558
|
addLog(`Pulling from ${REMOTE_NAME}/${branch}...`, 'update');
|
|
1541
1559
|
render();
|
|
1542
1560
|
|
|
1543
|
-
await
|
|
1561
|
+
await execGit(['pull', REMOTE_NAME, branch], { cwd: PROJECT_ROOT, timeout: 60000 });
|
|
1544
1562
|
addLog('Pulled successfully', 'success');
|
|
1545
1563
|
pendingDirtyOperation = null;
|
|
1546
1564
|
notifyClients();
|
|
@@ -1867,12 +1885,12 @@ async function pollGitChanges() {
|
|
|
1867
1885
|
const oldCommit = currentInfo.commit;
|
|
1868
1886
|
|
|
1869
1887
|
try {
|
|
1870
|
-
await
|
|
1888
|
+
await execGit(['pull', REMOTE_NAME, autoPullBranchName], { cwd: PROJECT_ROOT, timeout: 60000 });
|
|
1871
1889
|
addLog(`Pulled successfully from ${autoPullBranchName}`, 'success');
|
|
1872
1890
|
currentInfo.hasUpdates = false;
|
|
1873
1891
|
store.setState({ hasMergeConflict: false });
|
|
1874
1892
|
// Update the stored commit to the new one
|
|
1875
|
-
const newCommit = await
|
|
1893
|
+
const newCommit = await execGit(['rev-parse', '--short', 'HEAD'], { cwd: PROJECT_ROOT });
|
|
1876
1894
|
currentInfo.commit = newCommit.stdout.trim();
|
|
1877
1895
|
previousBranchStates.set(autoPullBranchName, newCommit.stdout.trim());
|
|
1878
1896
|
// Reload browsers
|
|
@@ -2273,9 +2291,9 @@ function setupKeyboardInput() {
|
|
|
2273
2291
|
try {
|
|
2274
2292
|
let result;
|
|
2275
2293
|
if (platform === 'gitlab') {
|
|
2276
|
-
result = await
|
|
2294
|
+
result = await execCli('glab', ['mr', 'create', `--source-branch=${aBranch.name}`, '--fill', '--yes']);
|
|
2277
2295
|
} else {
|
|
2278
|
-
result = await
|
|
2296
|
+
result = await execCli('gh', ['pr', 'create', '--head', aBranch.name, '--fill']);
|
|
2279
2297
|
}
|
|
2280
2298
|
addLog(`${prLabel} created: ${(result.stdout || '').trim().split('\n').pop()}`, 'success');
|
|
2281
2299
|
// Invalidate cache and refresh modal data
|
|
@@ -2314,9 +2332,9 @@ function setupKeyboardInput() {
|
|
|
2314
2332
|
render();
|
|
2315
2333
|
try {
|
|
2316
2334
|
if (platform === 'gitlab') {
|
|
2317
|
-
await
|
|
2335
|
+
await execCli('glab', ['mr', 'approve', String(prInfo.number)]);
|
|
2318
2336
|
} else {
|
|
2319
|
-
await
|
|
2337
|
+
await execCli('gh', ['pr', 'review', String(prInfo.number), '--approve']);
|
|
2320
2338
|
}
|
|
2321
2339
|
addLog(`${prLabel} #${prInfo.number} approved`, 'success');
|
|
2322
2340
|
// Refresh PR info to show updated status
|
|
@@ -2334,9 +2352,9 @@ function setupKeyboardInput() {
|
|
|
2334
2352
|
render();
|
|
2335
2353
|
try {
|
|
2336
2354
|
if (platform === 'gitlab') {
|
|
2337
|
-
await
|
|
2355
|
+
await execCli('glab', ['mr', 'merge', String(prInfo.number), '--squash', '--remove-source-branch', '--yes']);
|
|
2338
2356
|
} else {
|
|
2339
|
-
await
|
|
2357
|
+
await execCli('gh', ['pr', 'merge', String(prInfo.number), '--squash', '--delete-branch']);
|
|
2340
2358
|
}
|
|
2341
2359
|
addLog(`${prLabel} #${prInfo.number} merged`, 'success');
|
|
2342
2360
|
store.setState({ actionMode: false, actionData: null, actionLoading: false });
|
|
@@ -2356,13 +2374,13 @@ function setupKeyboardInput() {
|
|
|
2356
2374
|
render();
|
|
2357
2375
|
try {
|
|
2358
2376
|
if (platform === 'gitlab') {
|
|
2359
|
-
const result = await
|
|
2377
|
+
const result = await execCli('glab', ['ci', 'status', '--branch', aBranch.name]);
|
|
2360
2378
|
const lines = (result.stdout || '').trim().split('\n');
|
|
2361
2379
|
for (const line of lines.slice(0, 3)) {
|
|
2362
2380
|
addLog(line.trim(), 'info');
|
|
2363
2381
|
}
|
|
2364
2382
|
} else if (prInfo) {
|
|
2365
|
-
const result = await
|
|
2383
|
+
const result = await execCli('gh', ['pr', 'checks', String(prInfo.number)]);
|
|
2366
2384
|
const lines = (result.stdout || '').trim().split('\n');
|
|
2367
2385
|
for (const line of lines.slice(0, 5)) {
|
|
2368
2386
|
addLog(line.trim(), 'info');
|
package/package.json
CHANGED