@oss-autopilot/core 0.42.0 → 0.42.2
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/cli.bundle.cjs +1026 -1018
- package/dist/cli.js +18 -30
- package/dist/commands/check-integration.js +5 -4
- package/dist/commands/comments.js +24 -24
- package/dist/commands/daily.d.ts +0 -1
- package/dist/commands/daily.js +18 -16
- package/dist/commands/dashboard-components.d.ts +33 -0
- package/dist/commands/dashboard-components.js +57 -0
- package/dist/commands/dashboard-data.js +7 -6
- package/dist/commands/dashboard-formatters.d.ts +20 -0
- package/dist/commands/dashboard-formatters.js +33 -0
- package/dist/commands/dashboard-scripts.d.ts +7 -0
- package/dist/commands/dashboard-scripts.js +281 -0
- package/dist/commands/dashboard-server.js +3 -2
- package/dist/commands/dashboard-styles.d.ts +5 -0
- package/dist/commands/dashboard-styles.js +765 -0
- package/dist/commands/dashboard-templates.d.ts +6 -18
- package/dist/commands/dashboard-templates.js +30 -1134
- package/dist/commands/dashboard.js +2 -1
- package/dist/commands/dismiss.d.ts +6 -6
- package/dist/commands/dismiss.js +13 -13
- package/dist/commands/local-repos.js +2 -1
- package/dist/commands/parse-list.js +2 -1
- package/dist/commands/startup.js +6 -16
- package/dist/commands/validation.d.ts +3 -1
- package/dist/commands/validation.js +12 -6
- package/dist/core/errors.d.ts +9 -0
- package/dist/core/errors.js +17 -0
- package/dist/core/github-stats.d.ts +14 -21
- package/dist/core/github-stats.js +84 -138
- package/dist/core/http-cache.d.ts +6 -0
- package/dist/core/http-cache.js +16 -4
- package/dist/core/index.d.ts +3 -2
- package/dist/core/index.js +3 -2
- package/dist/core/issue-conversation.js +4 -4
- package/dist/core/issue-discovery.d.ts +5 -0
- package/dist/core/issue-discovery.js +70 -93
- package/dist/core/issue-vetting.js +17 -17
- package/dist/core/logger.d.ts +5 -0
- package/dist/core/logger.js +8 -0
- package/dist/core/pr-monitor.d.ts +6 -20
- package/dist/core/pr-monitor.js +16 -52
- package/dist/core/review-analysis.js +8 -6
- package/dist/core/state.js +4 -5
- package/dist/core/test-utils.d.ts +14 -0
- package/dist/core/test-utils.js +125 -0
- package/dist/core/utils.d.ts +11 -0
- package/dist/core/utils.js +21 -0
- package/dist/formatters/json.d.ts +0 -1
- package/package.json +1 -1
package/dist/core/pr-monitor.js
CHANGED
|
@@ -15,7 +15,7 @@ import { getOctokit } from './github.js';
|
|
|
15
15
|
import { getStateManager } from './state.js';
|
|
16
16
|
import { daysBetween, parseGitHubUrl, extractOwnerRepo } from './utils.js';
|
|
17
17
|
import { runWorkerPool } from './concurrency.js';
|
|
18
|
-
import { ConfigurationError, ValidationError } from './errors.js';
|
|
18
|
+
import { ConfigurationError, ValidationError, errorMessage, getHttpStatusCode } from './errors.js';
|
|
19
19
|
import { paginateAll } from './pagination.js';
|
|
20
20
|
import { debug, warn, timed } from './logger.js';
|
|
21
21
|
import { getHttpCache, cachedRequest } from './http-cache.js';
|
|
@@ -114,9 +114,9 @@ export class PRMonitor {
|
|
|
114
114
|
prs.push(pr);
|
|
115
115
|
}
|
|
116
116
|
catch (error) {
|
|
117
|
-
const
|
|
118
|
-
warn('pr-monitor', `Error fetching ${item.html_url}: ${
|
|
119
|
-
failures.push({ prUrl: item.html_url, error:
|
|
117
|
+
const errMsg = errorMessage(error);
|
|
118
|
+
warn('pr-monitor', `Error fetching ${item.html_url}: ${errMsg}`);
|
|
119
|
+
failures.push({ prUrl: item.html_url, error: errMsg });
|
|
120
120
|
}
|
|
121
121
|
}, MAX_CONCURRENT_REQUESTS);
|
|
122
122
|
});
|
|
@@ -162,14 +162,14 @@ export class PRMonitor {
|
|
|
162
162
|
paginateAll((page) => this.octokit.issues.listComments({ owner, repo, issue_number: number, per_page: 100, page })),
|
|
163
163
|
this.octokit.pulls.listReviews({ owner, repo, pull_number: number }),
|
|
164
164
|
paginateAll((page) => this.octokit.pulls.listReviewComments({ owner, repo, pull_number: number, per_page: 100, page })).catch((err) => {
|
|
165
|
-
const status = err
|
|
165
|
+
const status = getHttpStatusCode(err);
|
|
166
166
|
// Rate limit errors must propagate — silently swallowing them hides
|
|
167
167
|
// a systemic problem and produces misleading results (#229).
|
|
168
168
|
if (status === 429) {
|
|
169
169
|
throw err;
|
|
170
170
|
}
|
|
171
171
|
if (status === 403) {
|
|
172
|
-
const msg = (err
|
|
172
|
+
const msg = errorMessage(err).toLowerCase();
|
|
173
173
|
if (msg.includes('rate limit') || msg.includes('abuse detection')) {
|
|
174
174
|
throw err;
|
|
175
175
|
}
|
|
@@ -283,6 +283,11 @@ export class PRMonitor {
|
|
|
283
283
|
// If the contributor pushed a commit after the maintainer's comment,
|
|
284
284
|
// the changes have been addressed — waiting for maintainer re-review
|
|
285
285
|
if (latestCommitDate && lastMaintainerCommentDate && latestCommitDate > lastMaintainerCommentDate) {
|
|
286
|
+
// Safety net (#431): if a CHANGES_REQUESTED review was submitted after
|
|
287
|
+
// the commit, the maintainer still expects changes — don't mask it
|
|
288
|
+
if (latestChangesRequestedDate && latestCommitDate < latestChangesRequestedDate) {
|
|
289
|
+
return 'needs_response';
|
|
290
|
+
}
|
|
286
291
|
if (ciStatus === 'failing')
|
|
287
292
|
return 'failing_ci';
|
|
288
293
|
return 'changes_addressed';
|
|
@@ -349,7 +354,7 @@ export class PRMonitor {
|
|
|
349
354
|
this.octokit.repos.getCombinedStatusForRef({ owner, repo, ref: sha }),
|
|
350
355
|
// 404 is expected for repos without check runs configured; log other errors for debugging
|
|
351
356
|
this.octokit.checks.listForRef({ owner, repo, ref: sha }).catch((err) => {
|
|
352
|
-
const status = err
|
|
357
|
+
const status = getHttpStatusCode(err);
|
|
353
358
|
if (status === 404) {
|
|
354
359
|
debug('pr-monitor', `Check runs 404 for ${owner}/${repo}@${sha.slice(0, 7)} (no checks configured)`);
|
|
355
360
|
}
|
|
@@ -378,8 +383,8 @@ export class PRMonitor {
|
|
|
378
383
|
return mergeStatuses(checkRunAnalysis, combinedAnalysis, checkRuns.length);
|
|
379
384
|
}
|
|
380
385
|
catch (error) {
|
|
381
|
-
const statusCode = error
|
|
382
|
-
const
|
|
386
|
+
const statusCode = getHttpStatusCode(error);
|
|
387
|
+
const errMsg = errorMessage(error);
|
|
383
388
|
if (statusCode === 401) {
|
|
384
389
|
warn('pr-monitor', `CI check failed for ${owner}/${repo}: Invalid token`);
|
|
385
390
|
}
|
|
@@ -392,7 +397,7 @@ export class PRMonitor {
|
|
|
392
397
|
return { status: 'unknown', failingCheckNames: [], failingCheckConclusions: new Map() };
|
|
393
398
|
}
|
|
394
399
|
else {
|
|
395
|
-
warn('pr-monitor', `Failed to check CI for ${owner}/${repo}@${sha.slice(0, 7)}: ${
|
|
400
|
+
warn('pr-monitor', `Failed to check CI for ${owner}/${repo}@${sha.slice(0, 7)}: ${errMsg}`);
|
|
396
401
|
}
|
|
397
402
|
return { status: 'unknown', failingCheckNames: [], failingCheckConclusions: new Map() };
|
|
398
403
|
}
|
|
@@ -451,7 +456,7 @@ export class PRMonitor {
|
|
|
451
456
|
}
|
|
452
457
|
else {
|
|
453
458
|
chunkFailures++;
|
|
454
|
-
warn(MODULE, `Failed to fetch stars for ${chunk[j]}: ${result.reason
|
|
459
|
+
warn(MODULE, `Failed to fetch stars for ${chunk[j]}: ${errorMessage(result.reason)}`);
|
|
455
460
|
}
|
|
456
461
|
}
|
|
457
462
|
// If entire chunk failed, likely a systemic issue (rate limit, auth, outage) — abort remaining
|
|
@@ -466,47 +471,6 @@ export class PRMonitor {
|
|
|
466
471
|
debug(MODULE, `Fetched star counts for ${results.size}/${repos.length} repos`);
|
|
467
472
|
return results;
|
|
468
473
|
}
|
|
469
|
-
/**
|
|
470
|
-
* Shared helper: search for recent PRs and filter out own repos, excluded repos/orgs.
|
|
471
|
-
* Returns parsed search results that pass all filters.
|
|
472
|
-
*/
|
|
473
|
-
async fetchRecentPRs(query, label, days, mapItem) {
|
|
474
|
-
const config = this.stateManager.getState().config;
|
|
475
|
-
if (!config.githubUsername) {
|
|
476
|
-
warn(MODULE, `Skipping recently ${label} PRs fetch: no githubUsername configured. Run /setup-oss to configure.`);
|
|
477
|
-
return [];
|
|
478
|
-
}
|
|
479
|
-
const sinceDate = new Date();
|
|
480
|
-
sinceDate.setDate(sinceDate.getDate() - days);
|
|
481
|
-
const since = sinceDate.toISOString().split('T')[0]; // YYYY-MM-DD
|
|
482
|
-
debug(MODULE, `Fetching recently ${label} PRs for @${config.githubUsername} (since ${since})...`);
|
|
483
|
-
const { data } = await this.octokit.search.issuesAndPullRequests({
|
|
484
|
-
q: query.replace('{username}', config.githubUsername).replace('{since}', since),
|
|
485
|
-
sort: 'updated',
|
|
486
|
-
order: 'desc',
|
|
487
|
-
per_page: 100,
|
|
488
|
-
});
|
|
489
|
-
const results = [];
|
|
490
|
-
for (const item of data.items) {
|
|
491
|
-
const parsed = parseGitHubUrl(item.html_url);
|
|
492
|
-
if (!parsed) {
|
|
493
|
-
warn(MODULE, `Could not parse GitHub URL from API response: ${item.html_url}`);
|
|
494
|
-
continue;
|
|
495
|
-
}
|
|
496
|
-
const repo = `${parsed.owner}/${parsed.repo}`;
|
|
497
|
-
// Skip own repos
|
|
498
|
-
if (parsed.owner.toLowerCase() === config.githubUsername.toLowerCase())
|
|
499
|
-
continue;
|
|
500
|
-
// Skip excluded repos and orgs
|
|
501
|
-
if (config.excludeRepos.includes(repo))
|
|
502
|
-
continue;
|
|
503
|
-
if (config.excludeOrgs?.some((org) => parsed.owner.toLowerCase() === org.toLowerCase()))
|
|
504
|
-
continue;
|
|
505
|
-
results.push(mapItem(item, { owner: parsed.owner, repo, number: parsed.number }));
|
|
506
|
-
}
|
|
507
|
-
debug(MODULE, `Found ${results.length} recently ${label} PRs`);
|
|
508
|
-
return results;
|
|
509
|
-
}
|
|
510
474
|
/**
|
|
511
475
|
* Fetch PRs closed without merge in the last N days.
|
|
512
476
|
* Delegates to github-stats module.
|
|
@@ -101,11 +101,11 @@ export function checkUnrespondedComments(comments, reviews, reviewComments, user
|
|
|
101
101
|
if (!review.submitted_at)
|
|
102
102
|
continue;
|
|
103
103
|
const body = (review.body || '').trim();
|
|
104
|
-
// Include COMMENTED reviews even without body text —
|
|
105
|
-
// inline review comments were posted and
|
|
106
|
-
//
|
|
107
|
-
// as those are state changes
|
|
108
|
-
if (!body && review.state !== 'COMMENTED')
|
|
104
|
+
// Include COMMENTED and CHANGES_REQUESTED reviews even without body text —
|
|
105
|
+
// they indicate inline review comments were posted and need a response (#151, #431).
|
|
106
|
+
// CHANGES_REQUESTED with only inline comments is actionable maintainer feedback.
|
|
107
|
+
// Skip other empty-body reviews (APPROVED, DISMISSED) as those are state changes.
|
|
108
|
+
if (!body && review.state !== 'COMMENTED' && review.state !== 'CHANGES_REQUESTED')
|
|
109
109
|
continue;
|
|
110
110
|
const author = review.user?.login || 'unknown';
|
|
111
111
|
// For inline-only COMMENTED reviews, skip pure self-replies (#199)
|
|
@@ -117,7 +117,9 @@ export function checkUnrespondedComments(comments, reviews, reviewComments, user
|
|
|
117
117
|
// Resolve body: prefer actual text, then inline comment text, then synthetic placeholder
|
|
118
118
|
const resolvedBody = body ||
|
|
119
119
|
(review.id != null ? getInlineCommentBody(review.id, reviewComments) : undefined) ||
|
|
120
|
-
|
|
120
|
+
(review.state === 'CHANGES_REQUESTED'
|
|
121
|
+
? '(requested changes via inline review comments)'
|
|
122
|
+
: '(posted inline review comments)');
|
|
121
123
|
timeline.push({
|
|
122
124
|
author,
|
|
123
125
|
body: resolvedBody,
|
package/dist/core/state.js
CHANGED
|
@@ -6,7 +6,7 @@ import * as fs from 'fs';
|
|
|
6
6
|
import * as path from 'path';
|
|
7
7
|
import { INITIAL_STATE, } from './types.js';
|
|
8
8
|
import { getStatePath, getBackupDir, getDataDir } from './utils.js';
|
|
9
|
-
import { ValidationError } from './errors.js';
|
|
9
|
+
import { ValidationError, errorMessage } from './errors.js';
|
|
10
10
|
import { debug, warn } from './logger.js';
|
|
11
11
|
const MODULE = 'state';
|
|
12
12
|
// Current state version
|
|
@@ -272,8 +272,7 @@ export class StateManager {
|
|
|
272
272
|
return true;
|
|
273
273
|
}
|
|
274
274
|
catch (error) {
|
|
275
|
-
|
|
276
|
-
warn(MODULE, `Failed to migrate state: ${errorMessage}`);
|
|
275
|
+
warn(MODULE, `Failed to migrate state: ${errorMessage(error)}`);
|
|
277
276
|
// Clean up partial migration to avoid inconsistent state
|
|
278
277
|
const newStatePath = getStatePath();
|
|
279
278
|
if (fs.existsSync(newStatePath) && fs.existsSync(LEGACY_STATE_FILE)) {
|
|
@@ -471,12 +470,12 @@ export class StateManager {
|
|
|
471
470
|
fs.unlinkSync(path.join(backupDir, file));
|
|
472
471
|
}
|
|
473
472
|
catch (error) {
|
|
474
|
-
warn(MODULE, `Could not delete old backup ${file}:`, error
|
|
473
|
+
warn(MODULE, `Could not delete old backup ${file}:`, errorMessage(error));
|
|
475
474
|
}
|
|
476
475
|
}
|
|
477
476
|
}
|
|
478
477
|
catch (error) {
|
|
479
|
-
warn(MODULE, 'Could not clean up backups:', error
|
|
478
|
+
warn(MODULE, 'Could not clean up backups:', errorMessage(error));
|
|
480
479
|
}
|
|
481
480
|
}
|
|
482
481
|
/**
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared test factories for oss-autopilot.
|
|
3
|
+
*
|
|
4
|
+
* Centralises mock object construction so that when types gain new required
|
|
5
|
+
* fields we only update one place. Every factory accepts a `Partial<T>`
|
|
6
|
+
* override bag — callers only specify the fields relevant to their test.
|
|
7
|
+
*/
|
|
8
|
+
import type { FetchedPR, DailyDigest, ShelvedPRRef, AgentState } from './types.js';
|
|
9
|
+
import type { CapacityAssessment } from '../formatters/json.js';
|
|
10
|
+
export declare function makeFetchedPR(overrides?: Partial<FetchedPR>): FetchedPR;
|
|
11
|
+
export declare function makeDailyDigest(overrides?: Partial<DailyDigest>): DailyDigest;
|
|
12
|
+
export declare function makeShelvedPRRef(overrides?: Partial<ShelvedPRRef>): ShelvedPRRef;
|
|
13
|
+
export declare function makeCapacityAssessment(overrides?: Partial<CapacityAssessment>): CapacityAssessment;
|
|
14
|
+
export declare function makeAgentState(overrides?: Partial<AgentState>): AgentState;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared test factories for oss-autopilot.
|
|
3
|
+
*
|
|
4
|
+
* Centralises mock object construction so that when types gain new required
|
|
5
|
+
* fields we only update one place. Every factory accepts a `Partial<T>`
|
|
6
|
+
* override bag — callers only specify the fields relevant to their test.
|
|
7
|
+
*/
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// FetchedPR
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
export function makeFetchedPR(overrides = {}) {
|
|
12
|
+
const repo = overrides.repo ?? 'owner/repo';
|
|
13
|
+
const number = overrides.number ?? 1;
|
|
14
|
+
return {
|
|
15
|
+
id: 1,
|
|
16
|
+
url: `https://github.com/${repo}/pull/${number}`,
|
|
17
|
+
repo,
|
|
18
|
+
number,
|
|
19
|
+
title: 'Test PR',
|
|
20
|
+
status: 'healthy',
|
|
21
|
+
displayLabel: '[Healthy]',
|
|
22
|
+
displayDescription: 'Everything looks good',
|
|
23
|
+
createdAt: '2025-06-01T00:00:00Z',
|
|
24
|
+
updatedAt: '2025-06-15T00:00:00Z',
|
|
25
|
+
daysSinceActivity: 2,
|
|
26
|
+
ciStatus: 'passing',
|
|
27
|
+
failingCheckNames: [],
|
|
28
|
+
classifiedChecks: [],
|
|
29
|
+
hasMergeConflict: false,
|
|
30
|
+
reviewDecision: 'approved',
|
|
31
|
+
hasUnrespondedComment: false,
|
|
32
|
+
hasIncompleteChecklist: false,
|
|
33
|
+
maintainerActionHints: [],
|
|
34
|
+
...overrides,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// DailyDigest
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
export function makeDailyDigest(overrides = {}) {
|
|
41
|
+
return {
|
|
42
|
+
generatedAt: '2025-06-20T00:00:00Z',
|
|
43
|
+
openPRs: [],
|
|
44
|
+
prsNeedingResponse: [],
|
|
45
|
+
ciFailingPRs: [],
|
|
46
|
+
ciBlockedPRs: [],
|
|
47
|
+
ciNotRunningPRs: [],
|
|
48
|
+
mergeConflictPRs: [],
|
|
49
|
+
needsRebasePRs: [],
|
|
50
|
+
missingRequiredFilesPRs: [],
|
|
51
|
+
incompleteChecklistPRs: [],
|
|
52
|
+
needsChangesPRs: [],
|
|
53
|
+
changesAddressedPRs: [],
|
|
54
|
+
waitingOnMaintainerPRs: [],
|
|
55
|
+
approachingDormant: [],
|
|
56
|
+
dormantPRs: [],
|
|
57
|
+
healthyPRs: [],
|
|
58
|
+
recentlyClosedPRs: [],
|
|
59
|
+
recentlyMergedPRs: [],
|
|
60
|
+
shelvedPRs: [],
|
|
61
|
+
autoUnshelvedPRs: [],
|
|
62
|
+
summary: {
|
|
63
|
+
totalActivePRs: 0,
|
|
64
|
+
totalNeedingAttention: 0,
|
|
65
|
+
totalMergedAllTime: 0,
|
|
66
|
+
mergeRate: 0,
|
|
67
|
+
},
|
|
68
|
+
...overrides,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// ShelvedPRRef
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
export function makeShelvedPRRef(overrides = {}) {
|
|
75
|
+
return {
|
|
76
|
+
number: 1,
|
|
77
|
+
url: 'https://github.com/owner/repo/pull/1',
|
|
78
|
+
title: 'Shelved PR',
|
|
79
|
+
repo: 'owner/repo',
|
|
80
|
+
daysSinceActivity: 45,
|
|
81
|
+
status: 'healthy',
|
|
82
|
+
...overrides,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
// CapacityAssessment
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
export function makeCapacityAssessment(overrides = {}) {
|
|
89
|
+
return {
|
|
90
|
+
hasCapacity: true,
|
|
91
|
+
activePRCount: 3,
|
|
92
|
+
maxActivePRs: 10,
|
|
93
|
+
shelvedPRCount: 0,
|
|
94
|
+
criticalIssueCount: 0,
|
|
95
|
+
reason: 'You have capacity',
|
|
96
|
+
...overrides,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// AgentState (partial — for tests that need a state object)
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
export function makeAgentState(overrides = {}) {
|
|
103
|
+
return {
|
|
104
|
+
version: 2,
|
|
105
|
+
repoScores: {},
|
|
106
|
+
config: {
|
|
107
|
+
setupComplete: false,
|
|
108
|
+
githubUsername: 'testuser',
|
|
109
|
+
excludeRepos: [],
|
|
110
|
+
maxActivePRs: 10,
|
|
111
|
+
dormantThresholdDays: 30,
|
|
112
|
+
approachingDormantDays: 25,
|
|
113
|
+
maxIssueAgeDays: 90,
|
|
114
|
+
languages: [],
|
|
115
|
+
labels: [],
|
|
116
|
+
trustedProjects: [],
|
|
117
|
+
minRepoScoreThreshold: 4,
|
|
118
|
+
starredRepos: [],
|
|
119
|
+
},
|
|
120
|
+
events: [],
|
|
121
|
+
lastRunAt: '2025-06-20T00:00:00Z',
|
|
122
|
+
activeIssues: [],
|
|
123
|
+
...overrides,
|
|
124
|
+
};
|
|
125
|
+
}
|
package/dist/core/utils.d.ts
CHANGED
|
@@ -157,6 +157,17 @@ export declare function splitRepo(repoFullName: string): {
|
|
|
157
157
|
owner: string;
|
|
158
158
|
repo: string;
|
|
159
159
|
};
|
|
160
|
+
/**
|
|
161
|
+
* Case-insensitive check whether a repo owner matches the given GitHub username.
|
|
162
|
+
* Used to skip a user's own repos (PRs to your own repos aren't OSS contributions).
|
|
163
|
+
*/
|
|
164
|
+
export declare function isOwnRepo(owner: string, username: string): boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Read the CLI package version from package.json relative to the running CLI bundle.
|
|
167
|
+
* Resolves `../package.json` from `process.argv[1]` (the bundle entry point).
|
|
168
|
+
* Falls back to '0.0.0' if the file is unreadable.
|
|
169
|
+
*/
|
|
170
|
+
export declare function getCLIVersion(): string;
|
|
160
171
|
/**
|
|
161
172
|
* Formats a timestamp as a human-readable relative time string.
|
|
162
173
|
*
|
package/dist/core/utils.js
CHANGED
|
@@ -228,6 +228,27 @@ export function splitRepo(repoFullName) {
|
|
|
228
228
|
const [owner, repo] = repoFullName.split('/');
|
|
229
229
|
return { owner, repo };
|
|
230
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* Case-insensitive check whether a repo owner matches the given GitHub username.
|
|
233
|
+
* Used to skip a user's own repos (PRs to your own repos aren't OSS contributions).
|
|
234
|
+
*/
|
|
235
|
+
export function isOwnRepo(owner, username) {
|
|
236
|
+
return owner.toLowerCase() === username.toLowerCase();
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Read the CLI package version from package.json relative to the running CLI bundle.
|
|
240
|
+
* Resolves `../package.json` from `process.argv[1]` (the bundle entry point).
|
|
241
|
+
* Falls back to '0.0.0' if the file is unreadable.
|
|
242
|
+
*/
|
|
243
|
+
export function getCLIVersion() {
|
|
244
|
+
try {
|
|
245
|
+
const pkgPath = path.join(path.dirname(process.argv[1]), '..', 'package.json');
|
|
246
|
+
return JSON.parse(fs.readFileSync(pkgPath, 'utf-8')).version;
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
return '0.0.0';
|
|
250
|
+
}
|
|
251
|
+
}
|
|
231
252
|
/**
|
|
232
253
|
* Formats a timestamp as a human-readable relative time string.
|
|
233
254
|
*
|