threadlines 0.2.6 → 0.2.9
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/api/client.js +2 -17
- package/dist/commands/check.js +26 -41
- package/dist/commands/init.js +10 -1
- package/dist/git/bitbucket.js +23 -92
- package/dist/git/diff.js +0 -196
- package/dist/git/file.js +2 -1
- package/dist/git/github.js +32 -52
- package/dist/git/gitlab.js +23 -49
- package/dist/git/local.js +2 -2
- package/dist/git/vercel.js +2 -2
- package/dist/index.js +18 -7
- package/dist/utils/config-file.js +118 -0
- package/dist/utils/config.js +98 -57
- package/dist/utils/context.js +4 -184
- package/dist/utils/logger.js +65 -0
- package/dist/validators/experts.js +2 -1
- package/package.json +1 -1
- package/dist/git/repo.js +0 -253
package/dist/utils/context.js
CHANGED
|
@@ -1,190 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Review Context
|
|
3
|
+
* Review Context Types
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* - PR/MR:
|
|
7
|
-
* -
|
|
8
|
-
* - Commit: Single commit changes
|
|
5
|
+
* Type definitions for the different code review contexts:
|
|
6
|
+
* - PR/MR: Comparing source branch vs target branch (branch-level diff)
|
|
7
|
+
* - Commit: Single commit changes (any push without PR/MR)
|
|
9
8
|
* - Local: Staged/unstaged changes in working directory
|
|
10
|
-
*
|
|
11
|
-
* Context detection is environment-specific - each CI platform
|
|
12
|
-
* provides different environment variables.
|
|
13
9
|
*/
|
|
14
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.detectContext = detectContext;
|
|
16
|
-
/**
|
|
17
|
-
* Detects the review context based on the environment.
|
|
18
|
-
*
|
|
19
|
-
* Each environment has different environment variables available,
|
|
20
|
-
* so detection logic is environment-specific.
|
|
21
|
-
*/
|
|
22
|
-
function detectContext(environment) {
|
|
23
|
-
switch (environment) {
|
|
24
|
-
case 'github':
|
|
25
|
-
return detectGitHubContext();
|
|
26
|
-
case 'gitlab':
|
|
27
|
-
return detectGitLabContext();
|
|
28
|
-
case 'bitbucket':
|
|
29
|
-
return detectBitbucketContext();
|
|
30
|
-
case 'vercel':
|
|
31
|
-
return detectVercelContext();
|
|
32
|
-
case 'local':
|
|
33
|
-
return { type: 'local' };
|
|
34
|
-
default:
|
|
35
|
-
return { type: 'local' };
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* GitHub Actions context detection
|
|
40
|
-
*
|
|
41
|
-
* Environment Variables:
|
|
42
|
-
* - PR: GITHUB_EVENT_NAME='pull_request', GITHUB_BASE_REF, GITHUB_HEAD_REF, GITHUB_EVENT_NUMBER
|
|
43
|
-
* - Branch: GITHUB_REF_NAME
|
|
44
|
-
* - Commit: GITHUB_SHA
|
|
45
|
-
*/
|
|
46
|
-
function detectGitHubContext() {
|
|
47
|
-
// 1. Check for PR context
|
|
48
|
-
if (process.env.GITHUB_EVENT_NAME === 'pull_request') {
|
|
49
|
-
const targetBranch = process.env.GITHUB_BASE_REF;
|
|
50
|
-
const sourceBranch = process.env.GITHUB_HEAD_REF;
|
|
51
|
-
const prNumber = process.env.GITHUB_EVENT_PULL_REQUEST_NUMBER || process.env.GITHUB_EVENT_NUMBER;
|
|
52
|
-
if (targetBranch && sourceBranch && prNumber) {
|
|
53
|
-
return {
|
|
54
|
-
type: 'pr',
|
|
55
|
-
prNumber,
|
|
56
|
-
sourceBranch,
|
|
57
|
-
targetBranch
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
// 2. Check for branch context
|
|
62
|
-
if (process.env.GITHUB_REF_NAME) {
|
|
63
|
-
return {
|
|
64
|
-
type: 'branch',
|
|
65
|
-
branchName: process.env.GITHUB_REF_NAME
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
// 3. Check for commit context
|
|
69
|
-
if (process.env.GITHUB_SHA) {
|
|
70
|
-
return {
|
|
71
|
-
type: 'commit',
|
|
72
|
-
commitSha: process.env.GITHUB_SHA
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
// 4. Fallback to local
|
|
76
|
-
return { type: 'local' };
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* GitLab CI context detection
|
|
80
|
-
*
|
|
81
|
-
* Environment Variables:
|
|
82
|
-
* - MR: CI_MERGE_REQUEST_IID, CI_MERGE_REQUEST_TARGET_BRANCH_NAME, CI_MERGE_REQUEST_SOURCE_BRANCH_NAME, CI_MERGE_REQUEST_TITLE
|
|
83
|
-
* - Branch: CI_COMMIT_REF_NAME
|
|
84
|
-
* - Commit: CI_COMMIT_SHA
|
|
85
|
-
*/
|
|
86
|
-
function detectGitLabContext() {
|
|
87
|
-
// 1. Check for MR context
|
|
88
|
-
if (process.env.CI_MERGE_REQUEST_IID) {
|
|
89
|
-
const targetBranch = process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME;
|
|
90
|
-
const sourceBranch = process.env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME;
|
|
91
|
-
const mrNumber = process.env.CI_MERGE_REQUEST_IID;
|
|
92
|
-
const mrTitle = process.env.CI_MERGE_REQUEST_TITLE;
|
|
93
|
-
if (targetBranch && sourceBranch && mrNumber) {
|
|
94
|
-
return {
|
|
95
|
-
type: 'mr',
|
|
96
|
-
mrNumber,
|
|
97
|
-
sourceBranch,
|
|
98
|
-
targetBranch,
|
|
99
|
-
prTitle: mrTitle || undefined
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
// 2. Check for branch context
|
|
104
|
-
if (process.env.CI_COMMIT_REF_NAME) {
|
|
105
|
-
return {
|
|
106
|
-
type: 'branch',
|
|
107
|
-
branchName: process.env.CI_COMMIT_REF_NAME
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
// 3. Check for commit context
|
|
111
|
-
if (process.env.CI_COMMIT_SHA) {
|
|
112
|
-
return {
|
|
113
|
-
type: 'commit',
|
|
114
|
-
commitSha: process.env.CI_COMMIT_SHA
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
// 4. Fallback to local
|
|
118
|
-
return { type: 'local' };
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Vercel context detection
|
|
122
|
-
*
|
|
123
|
-
* Environment Variables:
|
|
124
|
-
* - Branch: VERCEL_GIT_COMMIT_REF
|
|
125
|
-
* - Commit: VERCEL_GIT_COMMIT_SHA
|
|
126
|
-
*
|
|
127
|
-
* Vercel Limitation:
|
|
128
|
-
* Vercel performs shallow clones of the repository, typically fetching only the
|
|
129
|
-
* specific commit being deployed. The git repository in Vercel's build environment
|
|
130
|
-
* does not contain the full git history or remote branch references (e.g., origin/main).
|
|
131
|
-
* This means branch-based diff operations (comparing feature branch against base branch)
|
|
132
|
-
* are not possible because the base branch refs are not available in the repository.
|
|
133
|
-
*
|
|
134
|
-
* Solution:
|
|
135
|
-
* We hardcode commit context for Vercel, using VERCEL_GIT_COMMIT_SHA to get a
|
|
136
|
-
* commit-based diff (comparing the commit against its parent). This works within
|
|
137
|
-
* Vercel's constraints since we only need the commit SHA, not branch references.
|
|
138
|
-
*/
|
|
139
|
-
function detectVercelContext() {
|
|
140
|
-
// Hardcode commit context for Vercel due to shallow clone limitations
|
|
141
|
-
// Vercel's git repository doesn't have base branch refs available
|
|
142
|
-
if (process.env.VERCEL_GIT_COMMIT_SHA) {
|
|
143
|
-
return {
|
|
144
|
-
type: 'commit',
|
|
145
|
-
commitSha: process.env.VERCEL_GIT_COMMIT_SHA
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
// Fallback to local
|
|
149
|
-
return { type: 'local' };
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Bitbucket Pipelines context detection
|
|
153
|
-
*
|
|
154
|
-
* Environment Variables (all tested 2026-01-18):
|
|
155
|
-
* - Branch: BITBUCKET_BRANCH
|
|
156
|
-
* - Commit: BITBUCKET_COMMIT
|
|
157
|
-
* - PR: BITBUCKET_PR_ID, BITBUCKET_PR_DESTINATION_BRANCH
|
|
158
|
-
*
|
|
159
|
-
* Note: Bitbucket does not provide PR title as an environment variable.
|
|
160
|
-
*/
|
|
161
|
-
function detectBitbucketContext() {
|
|
162
|
-
// PR context
|
|
163
|
-
const prId = process.env.BITBUCKET_PR_ID;
|
|
164
|
-
const prDestinationBranch = process.env.BITBUCKET_PR_DESTINATION_BRANCH;
|
|
165
|
-
const sourceBranch = process.env.BITBUCKET_BRANCH;
|
|
166
|
-
if (prId && prDestinationBranch && sourceBranch) {
|
|
167
|
-
return {
|
|
168
|
-
type: 'pr',
|
|
169
|
-
prNumber: prId,
|
|
170
|
-
sourceBranch,
|
|
171
|
-
targetBranch: prDestinationBranch
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
// Branch context
|
|
175
|
-
if (process.env.BITBUCKET_BRANCH) {
|
|
176
|
-
return {
|
|
177
|
-
type: 'branch',
|
|
178
|
-
branchName: process.env.BITBUCKET_BRANCH
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
// Commit context
|
|
182
|
-
if (process.env.BITBUCKET_COMMIT) {
|
|
183
|
-
return {
|
|
184
|
-
type: 'commit',
|
|
185
|
-
commitSha: process.env.BITBUCKET_COMMIT
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
// Fallback to local
|
|
189
|
-
return { type: 'local' };
|
|
190
|
-
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.logger = void 0;
|
|
7
|
+
exports.enableDebug = enableDebug;
|
|
8
|
+
exports.isDebugEnabled = isDebugEnabled;
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
/**
|
|
11
|
+
* Global debug flag - set when --debug is passed to CLI
|
|
12
|
+
*/
|
|
13
|
+
let debugEnabled = false;
|
|
14
|
+
/**
|
|
15
|
+
* Enable debug logging (called when --debug flag is set)
|
|
16
|
+
*/
|
|
17
|
+
function enableDebug() {
|
|
18
|
+
debugEnabled = true;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Check if debug logging is enabled
|
|
22
|
+
*/
|
|
23
|
+
function isDebugEnabled() {
|
|
24
|
+
return debugEnabled;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Logger utility for CLI output
|
|
28
|
+
*
|
|
29
|
+
* - debug/info: Only shown when --debug flag is set
|
|
30
|
+
* - warn/error: Always shown (critical information)
|
|
31
|
+
*/
|
|
32
|
+
exports.logger = {
|
|
33
|
+
/**
|
|
34
|
+
* Debug-level log (technical details, internal state)
|
|
35
|
+
* Only shown with --debug flag
|
|
36
|
+
*/
|
|
37
|
+
debug: (message) => {
|
|
38
|
+
if (debugEnabled) {
|
|
39
|
+
console.log(chalk_1.default.gray(`[DEBUG] ${message}`));
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
/**
|
|
43
|
+
* Info-level log (what's happening, progress updates)
|
|
44
|
+
* Only shown with --debug flag
|
|
45
|
+
*/
|
|
46
|
+
info: (message) => {
|
|
47
|
+
if (debugEnabled) {
|
|
48
|
+
console.log(chalk_1.default.blue(`[INFO] ${message}`));
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
/**
|
|
52
|
+
* Warning (non-fatal issues, recommendations)
|
|
53
|
+
* Always shown
|
|
54
|
+
*/
|
|
55
|
+
warn: (message) => {
|
|
56
|
+
console.log(chalk_1.default.yellow(`⚠️ ${message}`));
|
|
57
|
+
},
|
|
58
|
+
/**
|
|
59
|
+
* Error (failures, problems)
|
|
60
|
+
* Always shown
|
|
61
|
+
*/
|
|
62
|
+
error: (message) => {
|
|
63
|
+
console.error(chalk_1.default.red(`❌ ${message}`));
|
|
64
|
+
}
|
|
65
|
+
};
|
|
@@ -38,6 +38,7 @@ exports.validateThreadline = validateThreadline;
|
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
40
|
const yaml = __importStar(require("js-yaml"));
|
|
41
|
+
const logger_1 = require("../utils/logger");
|
|
41
42
|
const REQUIRED_FIELDS = ['id', 'version', 'patterns'];
|
|
42
43
|
/**
|
|
43
44
|
* Find and validate all threadlines in the threadlines folder.
|
|
@@ -61,7 +62,7 @@ async function findThreadlines(searchRoot, gitRoot) {
|
|
|
61
62
|
threadlines.push(result.threadline);
|
|
62
63
|
}
|
|
63
64
|
else {
|
|
64
|
-
|
|
65
|
+
logger_1.logger.warn(`Skipping ${file}: ${result.errors?.join(', ')}`);
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
return threadlines;
|
package/package.json
CHANGED
package/dist/git/repo.js
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.getGitHubRepoName = getGitHubRepoName;
|
|
40
|
-
exports.getVercelRepoName = getVercelRepoName;
|
|
41
|
-
exports.getLocalRepoName = getLocalRepoName;
|
|
42
|
-
exports.getGitHubBranchName = getGitHubBranchName;
|
|
43
|
-
exports.getVercelBranchName = getVercelBranchName;
|
|
44
|
-
exports.getLocalBranchName = getLocalBranchName;
|
|
45
|
-
exports.getGitLabRepoName = getGitLabRepoName;
|
|
46
|
-
exports.getGitLabBranchName = getGitLabBranchName;
|
|
47
|
-
exports.getDefaultBranchName = getDefaultBranchName;
|
|
48
|
-
const simple_git_1 = __importDefault(require("simple-git"));
|
|
49
|
-
const fs = __importStar(require("fs"));
|
|
50
|
-
const path = __importStar(require("path"));
|
|
51
|
-
/**
|
|
52
|
-
* GitHub Actions: Get repository name
|
|
53
|
-
*
|
|
54
|
-
* Uses GITHUB_REPOSITORY environment variable (format: "owner/repo").
|
|
55
|
-
* This is the ONLY method for GitHub - no fallbacks, no alternatives.
|
|
56
|
-
*/
|
|
57
|
-
async function getGitHubRepoName(_repoRoot) {
|
|
58
|
-
const githubRepo = process.env.GITHUB_REPOSITORY;
|
|
59
|
-
if (!githubRepo) {
|
|
60
|
-
throw new Error('GitHub Actions: GITHUB_REPOSITORY environment variable is not set. ' +
|
|
61
|
-
'This should be automatically provided by GitHub Actions.');
|
|
62
|
-
}
|
|
63
|
-
const serverUrl = process.env.GITHUB_SERVER_URL || 'https://github.com';
|
|
64
|
-
return `${serverUrl}/${githubRepo}.git`;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Vercel: Get repository name
|
|
68
|
-
*
|
|
69
|
-
* Uses VERCEL_GIT_REPO_OWNER and VERCEL_GIT_REPO_SLUG environment variables.
|
|
70
|
-
* This is the ONLY method for Vercel - no fallbacks, no alternatives.
|
|
71
|
-
*/
|
|
72
|
-
async function getVercelRepoName(_repoRoot) {
|
|
73
|
-
const owner = process.env.VERCEL_GIT_REPO_OWNER;
|
|
74
|
-
const slug = process.env.VERCEL_GIT_REPO_SLUG;
|
|
75
|
-
if (!owner || !slug) {
|
|
76
|
-
throw new Error('Vercel: VERCEL_GIT_REPO_OWNER or VERCEL_GIT_REPO_SLUG environment variable is not set. ' +
|
|
77
|
-
'This should be automatically provided by Vercel CI.');
|
|
78
|
-
}
|
|
79
|
-
return `https://github.com/${owner}/${slug}.git`;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Local: Get repository name
|
|
83
|
-
*
|
|
84
|
-
* Uses git command to get origin remote URL.
|
|
85
|
-
* This is the ONLY method for local - no fallbacks, no alternatives.
|
|
86
|
-
* Git should always be available in local development.
|
|
87
|
-
*/
|
|
88
|
-
async function getLocalRepoName(repoRoot) {
|
|
89
|
-
const git = (0, simple_git_1.default)(repoRoot);
|
|
90
|
-
// Check if we're in a git repo
|
|
91
|
-
const isRepo = await git.checkIsRepo();
|
|
92
|
-
if (!isRepo) {
|
|
93
|
-
throw new Error('Local: Not a git repository. Threadline requires a git repository.');
|
|
94
|
-
}
|
|
95
|
-
try {
|
|
96
|
-
const remotes = await git.getRemotes(true);
|
|
97
|
-
const origin = remotes.find(r => r.name === 'origin');
|
|
98
|
-
if (!origin || !origin.refs?.fetch) {
|
|
99
|
-
throw new Error('Local: No origin remote found. ' +
|
|
100
|
-
'Please configure an origin remote: git remote add origin <url>');
|
|
101
|
-
}
|
|
102
|
-
return origin.refs.fetch;
|
|
103
|
-
}
|
|
104
|
-
catch (error) {
|
|
105
|
-
// If it's already our error, re-throw it
|
|
106
|
-
if (error instanceof Error && error.message.includes('Local:')) {
|
|
107
|
-
throw error;
|
|
108
|
-
}
|
|
109
|
-
// Otherwise, wrap it
|
|
110
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
111
|
-
throw new Error(`Local: Failed to get repository name from git: ${errorMessage}`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* GitHub Actions: Get branch name
|
|
116
|
-
*
|
|
117
|
-
* Uses GITHUB_REF_NAME environment variable.
|
|
118
|
-
* This is the ONLY method for GitHub - no fallbacks, no alternatives.
|
|
119
|
-
*/
|
|
120
|
-
async function getGitHubBranchName(_repoRoot) {
|
|
121
|
-
const refName = process.env.GITHUB_REF_NAME;
|
|
122
|
-
if (!refName) {
|
|
123
|
-
throw new Error('GitHub Actions: GITHUB_REF_NAME environment variable is not set. ' +
|
|
124
|
-
'This should be automatically provided by GitHub Actions.');
|
|
125
|
-
}
|
|
126
|
-
return refName;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Vercel: Get branch name
|
|
130
|
-
*
|
|
131
|
-
* Uses VERCEL_GIT_COMMIT_REF environment variable.
|
|
132
|
-
* This is the ONLY method for Vercel - no fallbacks, no alternatives.
|
|
133
|
-
*/
|
|
134
|
-
async function getVercelBranchName(_repoRoot) {
|
|
135
|
-
const branchName = process.env.VERCEL_GIT_COMMIT_REF;
|
|
136
|
-
if (!branchName) {
|
|
137
|
-
throw new Error('Vercel: VERCEL_GIT_COMMIT_REF environment variable is not set. ' +
|
|
138
|
-
'This should be automatically provided by Vercel CI.');
|
|
139
|
-
}
|
|
140
|
-
return branchName;
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Local: Get branch name
|
|
144
|
-
*
|
|
145
|
-
* Uses git command to get current branch name.
|
|
146
|
-
* This is the ONLY method for local - no fallbacks, no alternatives.
|
|
147
|
-
* Git should always be available in local development.
|
|
148
|
-
*/
|
|
149
|
-
async function getLocalBranchName(repoRoot) {
|
|
150
|
-
const git = (0, simple_git_1.default)(repoRoot);
|
|
151
|
-
// Check if we're in a git repo
|
|
152
|
-
const isRepo = await git.checkIsRepo();
|
|
153
|
-
if (!isRepo) {
|
|
154
|
-
throw new Error('Local: Not a git repository. Threadline requires a git repository.');
|
|
155
|
-
}
|
|
156
|
-
try {
|
|
157
|
-
const branchName = await git.revparse(['--abbrev-ref', 'HEAD']);
|
|
158
|
-
if (!branchName || branchName.trim() === '') {
|
|
159
|
-
throw new Error('Local: Could not determine branch name. ' +
|
|
160
|
-
'This might be a brand new repository with no commits. ' +
|
|
161
|
-
'Make at least one commit before running threadlines check.');
|
|
162
|
-
}
|
|
163
|
-
// Handle detached HEAD state
|
|
164
|
-
if (branchName === 'HEAD') {
|
|
165
|
-
throw new Error('Local: Currently in detached HEAD state. ' +
|
|
166
|
-
'Please checkout a branch before running threadlines check.');
|
|
167
|
-
}
|
|
168
|
-
return branchName.trim();
|
|
169
|
-
}
|
|
170
|
-
catch (error) {
|
|
171
|
-
// If it's already our error, re-throw it
|
|
172
|
-
if (error instanceof Error && error.message.includes('Local:')) {
|
|
173
|
-
throw error;
|
|
174
|
-
}
|
|
175
|
-
// Otherwise, wrap it
|
|
176
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
177
|
-
throw new Error(`Local: Failed to get branch name from git: ${errorMessage}`);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* GitLab CI: Get repository name
|
|
182
|
-
*
|
|
183
|
-
* Uses CI_PROJECT_URL environment variable.
|
|
184
|
-
* This is the ONLY method for GitLab - no fallbacks, no alternatives.
|
|
185
|
-
*/
|
|
186
|
-
async function getGitLabRepoName(_repoRoot) {
|
|
187
|
-
const projectUrl = process.env.CI_PROJECT_URL;
|
|
188
|
-
if (!projectUrl) {
|
|
189
|
-
throw new Error('GitLab CI: CI_PROJECT_URL environment variable is not set. ' +
|
|
190
|
-
'This should be automatically provided by GitLab CI.');
|
|
191
|
-
}
|
|
192
|
-
// CI_PROJECT_URL is like "https://gitlab.com/owner/repo"
|
|
193
|
-
// Add .git suffix for consistency with other environments
|
|
194
|
-
return `${projectUrl}.git`;
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* GitLab CI: Get branch name
|
|
198
|
-
*
|
|
199
|
-
* Uses CI_COMMIT_REF_NAME environment variable.
|
|
200
|
-
* This is the ONLY method for GitLab - no fallbacks, no alternatives.
|
|
201
|
-
*/
|
|
202
|
-
async function getGitLabBranchName(_repoRoot) {
|
|
203
|
-
const refName = process.env.CI_COMMIT_REF_NAME;
|
|
204
|
-
if (!refName) {
|
|
205
|
-
throw new Error('GitLab CI: CI_COMMIT_REF_NAME environment variable is not set. ' +
|
|
206
|
-
'This should be automatically provided by GitLab CI.');
|
|
207
|
-
}
|
|
208
|
-
return refName;
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Detects the default branch name of the repository for GitHub Actions.
|
|
212
|
-
*
|
|
213
|
-
* Uses GITHUB_EVENT_PATH JSON (repository.default_branch) - the most authoritative source
|
|
214
|
-
* provided directly by GitHub Actions.
|
|
215
|
-
*
|
|
216
|
-
* This function is ONLY called from GitHub Actions context (github.ts),
|
|
217
|
-
* so GITHUB_EVENT_PATH should always be available. If it's not, we fail with a clear error.
|
|
218
|
-
*
|
|
219
|
-
* Returns the branch name (e.g., "main", "master") without the "origin/" prefix.
|
|
220
|
-
* Throws an error if the default branch cannot be detected.
|
|
221
|
-
*/
|
|
222
|
-
async function getDefaultBranchName(_repoRoot) {
|
|
223
|
-
// GitHub Actions provides GITHUB_EVENT_PATH which contains repository.default_branch
|
|
224
|
-
const githubEventPath = process.env.GITHUB_EVENT_PATH;
|
|
225
|
-
if (!githubEventPath) {
|
|
226
|
-
throw new Error('GITHUB_EVENT_PATH environment variable is not set. ' +
|
|
227
|
-
'This should be automatically provided by GitHub Actions. ' +
|
|
228
|
-
'This function should only be called in GitHub Actions context.');
|
|
229
|
-
}
|
|
230
|
-
try {
|
|
231
|
-
const eventPath = path.resolve(githubEventPath);
|
|
232
|
-
if (!fs.existsSync(eventPath)) {
|
|
233
|
-
throw new Error(`GITHUB_EVENT_PATH file does not exist: ${eventPath}`);
|
|
234
|
-
}
|
|
235
|
-
const eventJson = JSON.parse(fs.readFileSync(eventPath, 'utf8'));
|
|
236
|
-
const defaultBranch = eventJson.repository?.default_branch;
|
|
237
|
-
if (!defaultBranch || typeof defaultBranch !== 'string') {
|
|
238
|
-
throw new Error('Could not find repository.default_branch in GITHUB_EVENT_PATH JSON. ' +
|
|
239
|
-
'This should be automatically provided by GitHub Actions.');
|
|
240
|
-
}
|
|
241
|
-
return defaultBranch;
|
|
242
|
-
}
|
|
243
|
-
catch (error) {
|
|
244
|
-
// If it's already our error, re-throw it
|
|
245
|
-
if (error instanceof Error && (error.message.includes('GITHUB_EVENT_PATH') || error.message.includes('default_branch'))) {
|
|
246
|
-
throw error;
|
|
247
|
-
}
|
|
248
|
-
// Otherwise, wrap it
|
|
249
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
250
|
-
throw new Error(`Failed to read or parse GITHUB_EVENT_PATH: ${errorMessage}. ` +
|
|
251
|
-
'This should be automatically provided by GitHub Actions.');
|
|
252
|
-
}
|
|
253
|
-
}
|