threadlines 0.2.14 → 0.2.16
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/git/bitbucket.js +8 -47
- package/dist/git/diff.js +85 -36
- package/dist/git/github.js +7 -38
- package/dist/git/gitlab.js +10 -41
- package/dist/git/local.js +3 -28
- package/dist/git/vercel.js +8 -54
- package/package.json +1 -1
package/dist/git/bitbucket.js
CHANGED
|
@@ -23,7 +23,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
24
|
exports.getBitbucketContext = getBitbucketContext;
|
|
25
25
|
const simple_git_1 = __importDefault(require("simple-git"));
|
|
26
|
-
const child_process_1 = require("child_process");
|
|
27
26
|
const diff_1 = require("./diff");
|
|
28
27
|
const logger_1 = require("../utils/logger");
|
|
29
28
|
/**
|
|
@@ -43,8 +42,9 @@ async function getBitbucketContext(repoRoot) {
|
|
|
43
42
|
const context = detectContext();
|
|
44
43
|
const reviewContext = detectReviewContext();
|
|
45
44
|
const commitSha = getCommitSha();
|
|
46
|
-
// Get commit author (
|
|
47
|
-
|
|
45
|
+
// Get commit author using shared function (git log)
|
|
46
|
+
// getCommitAuthor throws on failure with descriptive error
|
|
47
|
+
const commitAuthor = await (0, diff_1.getCommitAuthor)(repoRoot);
|
|
48
48
|
// Get commit message if we have a SHA
|
|
49
49
|
let commitMessage;
|
|
50
50
|
if (commitSha) {
|
|
@@ -69,36 +69,26 @@ async function getBitbucketContext(repoRoot) {
|
|
|
69
69
|
* Get diff for Bitbucket Pipelines environment
|
|
70
70
|
*
|
|
71
71
|
* Strategy:
|
|
72
|
-
* - PR context:
|
|
72
|
+
* - PR context: Uses shared getPRDiff() - fetches destination branch, compares against HEAD
|
|
73
73
|
* - Any push (main or feature branch): Compare last commit only (HEAD~1...HEAD)
|
|
74
74
|
*
|
|
75
75
|
* Note: We fetch the destination branch on-demand so this works with shallow clones.
|
|
76
76
|
* Users don't need `depth: full` in their bitbucket-pipelines.yml.
|
|
77
77
|
*/
|
|
78
78
|
async function getDiff(repoRoot) {
|
|
79
|
-
const git = (0, simple_git_1.default)(repoRoot);
|
|
80
79
|
const prId = process.env.BITBUCKET_PR_ID;
|
|
81
80
|
const prDestinationBranch = process.env.BITBUCKET_PR_DESTINATION_BRANCH;
|
|
82
|
-
// PR Context:
|
|
81
|
+
// PR Context: Use shared getPRDiff() implementation
|
|
83
82
|
if (prId) {
|
|
84
83
|
if (!prDestinationBranch) {
|
|
85
84
|
throw new Error('Bitbucket PR context detected but BITBUCKET_PR_DESTINATION_BRANCH is not set. ' +
|
|
86
85
|
'This should be automatically provided by Bitbucket Pipelines.');
|
|
87
86
|
}
|
|
88
|
-
|
|
89
|
-
logger_1.logger.debug(`Fetching destination branch: origin/${prDestinationBranch}`);
|
|
90
|
-
await git.fetch(['origin', `${prDestinationBranch}:refs/remotes/origin/${prDestinationBranch}`, '--depth=1']);
|
|
91
|
-
logger_1.logger.debug(`PR #${prId}, using origin/${prDestinationBranch}...HEAD`);
|
|
92
|
-
const diff = await git.diff([`origin/${prDestinationBranch}...HEAD`, '-U200']);
|
|
93
|
-
const diffSummary = await git.diffSummary([`origin/${prDestinationBranch}...HEAD`]);
|
|
94
|
-
const changedFiles = diffSummary.files.map(f => f.file);
|
|
95
|
-
return { diff: diff || '', changedFiles };
|
|
87
|
+
return (0, diff_1.getPRDiff)(repoRoot, prDestinationBranch, logger_1.logger);
|
|
96
88
|
}
|
|
97
89
|
// Any push (main or feature branch): Review last commit only
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const changedFiles = diffSummary.files.map(f => f.file);
|
|
101
|
-
return { diff: diff || '', changedFiles };
|
|
90
|
+
// Use shared getCommitDiff (defaults to HEAD)
|
|
91
|
+
return (0, diff_1.getCommitDiff)(repoRoot);
|
|
102
92
|
}
|
|
103
93
|
/**
|
|
104
94
|
* Gets repository name for Bitbucket Pipelines
|
|
@@ -172,32 +162,3 @@ function detectReviewContext() {
|
|
|
172
162
|
function getCommitSha() {
|
|
173
163
|
return process.env.BITBUCKET_COMMIT;
|
|
174
164
|
}
|
|
175
|
-
/**
|
|
176
|
-
* Gets commit author for Bitbucket Pipelines
|
|
177
|
-
*
|
|
178
|
-
* Bitbucket doesn't provide commit author as an environment variable,
|
|
179
|
-
* so we use git log to get it.
|
|
180
|
-
*
|
|
181
|
-
* This approach is verified by our test script (test-bitbucket-context.ts)
|
|
182
|
-
* which successfully retrieves commit author in all scenarios:
|
|
183
|
-
* - Direct commit to main
|
|
184
|
-
* - Feature branch push
|
|
185
|
-
* - PR pipeline
|
|
186
|
-
* - Merge commit
|
|
187
|
-
*/
|
|
188
|
-
async function getCommitAuthor(repoRoot) {
|
|
189
|
-
// Use raw git commands - this is exactly what the test script uses and we know it works
|
|
190
|
-
try {
|
|
191
|
-
const name = (0, child_process_1.execSync)('git log -1 --format=%an', { encoding: 'utf-8', cwd: repoRoot }).trim();
|
|
192
|
-
const email = (0, child_process_1.execSync)('git log -1 --format=%ae', { encoding: 'utf-8', cwd: repoRoot }).trim();
|
|
193
|
-
if (!name || !email) {
|
|
194
|
-
throw new Error('git log returned empty name or email');
|
|
195
|
-
}
|
|
196
|
-
return { name, email };
|
|
197
|
-
}
|
|
198
|
-
catch (error) {
|
|
199
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
200
|
-
throw new Error(`Bitbucket Pipelines: Failed to get commit author from git log. ` +
|
|
201
|
-
`Error: ${errorMessage}`);
|
|
202
|
-
}
|
|
203
|
-
}
|
package/dist/git/diff.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getCommitMessage = getCommitMessage;
|
|
7
7
|
exports.getCommitAuthor = getCommitAuthor;
|
|
8
|
+
exports.getPRDiff = getPRDiff;
|
|
8
9
|
exports.getCommitDiff = getCommitDiff;
|
|
9
10
|
const simple_git_1 = __importDefault(require("simple-git"));
|
|
10
11
|
const child_process_1 = require("child_process");
|
|
@@ -29,48 +30,106 @@ async function getCommitMessage(repoRoot, sha) {
|
|
|
29
30
|
*
|
|
30
31
|
* Uses raw git log command to extract author information.
|
|
31
32
|
* Works in all environments where git is available.
|
|
33
|
+
*
|
|
34
|
+
* Throws on error - git commits always have authors, so failure indicates
|
|
35
|
+
* an invalid SHA or repository issue that should surface immediately.
|
|
36
|
+
*
|
|
37
|
+
* Used by: GitHub, GitLab, Bitbucket, Vercel, Local (all CI environments)
|
|
32
38
|
*/
|
|
33
39
|
async function getCommitAuthor(repoRoot, sha) {
|
|
40
|
+
const commitRef = sha || 'HEAD';
|
|
41
|
+
let output;
|
|
34
42
|
try {
|
|
35
43
|
// Use raw git command (same as test scripts) - more reliable than simple-git API
|
|
36
|
-
const commitRef = sha || 'HEAD';
|
|
37
44
|
const command = `git log -1 --format="%an <%ae>" ${commitRef}`;
|
|
38
|
-
|
|
45
|
+
output = (0, child_process_1.execSync)(command, {
|
|
39
46
|
encoding: 'utf-8',
|
|
40
47
|
cwd: repoRoot
|
|
41
48
|
}).trim();
|
|
42
|
-
// Parse output: "Name <email>"
|
|
43
|
-
const match = output.match(/^(.+?)\s*<(.+?)>$/);
|
|
44
|
-
if (!match) {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
const name = match[1].trim();
|
|
48
|
-
const email = match[2].trim();
|
|
49
|
-
if (!name || !email) {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
return { name, email };
|
|
53
49
|
}
|
|
54
|
-
catch {
|
|
55
|
-
|
|
50
|
+
catch (error) {
|
|
51
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
52
|
+
throw new Error(`Failed to get commit author for ${commitRef}: ${message}`);
|
|
53
|
+
}
|
|
54
|
+
// Parse output: "Name <email>"
|
|
55
|
+
const match = output.match(/^(.+?)\s*<(.+?)>$/);
|
|
56
|
+
if (!match) {
|
|
57
|
+
throw new Error(`Failed to parse commit author for ${commitRef}. ` +
|
|
58
|
+
`Expected format "Name <email>", got: "${output}"`);
|
|
59
|
+
}
|
|
60
|
+
const name = match[1].trim();
|
|
61
|
+
const email = match[2].trim();
|
|
62
|
+
if (!name || !email) {
|
|
63
|
+
throw new Error(`Commit author for ${commitRef} has empty name or email. ` +
|
|
64
|
+
`Got name="${name}", email="${email}"`);
|
|
56
65
|
}
|
|
66
|
+
return { name, email };
|
|
57
67
|
}
|
|
58
68
|
/**
|
|
59
|
-
* Get diff for a
|
|
69
|
+
* Get diff for a PR/MR context in CI environments.
|
|
70
|
+
*
|
|
71
|
+
* This is a shared implementation for CI environments that do shallow clones.
|
|
72
|
+
* It fetches the target branch on-demand and compares it against HEAD.
|
|
73
|
+
*
|
|
74
|
+
* Strategy:
|
|
75
|
+
* 1. Fetch target branch: origin/${targetBranch}:refs/remotes/origin/${targetBranch}
|
|
76
|
+
* 2. Diff: origin/${targetBranch}..HEAD (two dots = direct comparison)
|
|
77
|
+
*
|
|
78
|
+
* Why HEAD instead of origin/${sourceBranch}?
|
|
79
|
+
* - CI shallow clones only have HEAD available by default
|
|
80
|
+
* - origin/${sourceBranch} doesn't exist until explicitly fetched
|
|
81
|
+
* - HEAD IS the source branch in PR/MR pipelines
|
|
82
|
+
*
|
|
83
|
+
* Used by: GitHub, GitLab, Bitbucket (all PR/MR contexts)
|
|
84
|
+
* Future: Azure DevOps will use this when added
|
|
85
|
+
*
|
|
86
|
+
* @param repoRoot - Path to the repository root
|
|
87
|
+
* @param targetBranch - The branch being merged INTO (e.g., "main", "develop")
|
|
88
|
+
* @param logger - Optional logger for debug output
|
|
60
89
|
*/
|
|
61
|
-
async function
|
|
90
|
+
async function getPRDiff(repoRoot, targetBranch, logger) {
|
|
62
91
|
const git = (0, simple_git_1.default)(repoRoot);
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
92
|
+
// Fetch target branch on-demand (works with shallow clones)
|
|
93
|
+
logger?.debug(`Fetching target branch: origin/${targetBranch}`);
|
|
94
|
+
try {
|
|
95
|
+
await git.fetch(['origin', `${targetBranch}:refs/remotes/origin/${targetBranch}`, '--depth=1']);
|
|
67
96
|
}
|
|
68
|
-
|
|
69
|
-
|
|
97
|
+
catch (fetchError) {
|
|
98
|
+
throw new Error(`Failed to fetch target branch origin/${targetBranch}. ` +
|
|
99
|
+
`This is required for PR/MR diff comparison. ` +
|
|
100
|
+
`Error: ${fetchError instanceof Error ? fetchError.message : 'Unknown error'}`);
|
|
101
|
+
}
|
|
102
|
+
// Use two dots (..) for direct comparison (same as GitHub)
|
|
103
|
+
// Two dots: shows all changes in HEAD that aren't in origin/${targetBranch}
|
|
104
|
+
// Three dots: requires finding merge base which can fail with shallow clones
|
|
105
|
+
logger?.debug(`Comparing origin/${targetBranch}..HEAD`);
|
|
106
|
+
const diff = await git.diff([`origin/${targetBranch}..HEAD`, '-U200']);
|
|
107
|
+
const diffSummary = await git.diffSummary([`origin/${targetBranch}..HEAD`]);
|
|
108
|
+
const changedFiles = diffSummary.files.map(f => f.file);
|
|
109
|
+
return {
|
|
110
|
+
diff: diff || '',
|
|
111
|
+
changedFiles
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get diff for a specific commit (or HEAD if no SHA provided).
|
|
116
|
+
*
|
|
117
|
+
* Uses `git show` which works reliably with shallow clones (depth=1).
|
|
118
|
+
* This is safer than `HEAD~1...HEAD` which requires depth >= 2.
|
|
119
|
+
*
|
|
120
|
+
* Used by:
|
|
121
|
+
* - All CI environments for push/commit context (GitHub, GitLab, Bitbucket, Vercel)
|
|
122
|
+
* - Local environment for --commit flag
|
|
123
|
+
*
|
|
124
|
+
* @param repoRoot - Path to the repository root
|
|
125
|
+
* @param sha - Commit SHA to get diff for (defaults to HEAD)
|
|
126
|
+
*/
|
|
127
|
+
async function getCommitDiff(repoRoot, sha = 'HEAD') {
|
|
128
|
+
const git = (0, simple_git_1.default)(repoRoot);
|
|
129
|
+
// Get diff using git show
|
|
70
130
|
let diff;
|
|
71
131
|
let changedFiles;
|
|
72
132
|
try {
|
|
73
|
-
// Get diff using git show
|
|
74
133
|
diff = await git.show([sha, '--format=', '--no-color', '-U200']);
|
|
75
134
|
// Get changed files using git show --name-only
|
|
76
135
|
const commitFiles = await git.show([sha, '--name-only', '--format=', '--pretty=format:']);
|
|
@@ -80,18 +139,8 @@ async function getCommitDiff(repoRoot, sha) {
|
|
|
80
139
|
.map(line => line.trim());
|
|
81
140
|
}
|
|
82
141
|
catch (error) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
diff = await git.diff([`${sha}^..${sha}`, '-U200']);
|
|
86
|
-
// Get files from diff summary
|
|
87
|
-
const diffSummary = await git.diffSummary([`${sha}^..${sha}`]);
|
|
88
|
-
changedFiles = diffSummary.files.map(f => f.file);
|
|
89
|
-
}
|
|
90
|
-
catch (diffError) {
|
|
91
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
92
|
-
const diffErrorMessage = diffError instanceof Error ? diffError.message : 'Unknown error';
|
|
93
|
-
throw new Error(`Commit ${sha} not found or invalid: ${errorMessage || diffErrorMessage}`);
|
|
94
|
-
}
|
|
142
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
143
|
+
throw new Error(`Failed to get diff for commit ${sha}: ${errorMessage}`);
|
|
95
144
|
}
|
|
96
145
|
return {
|
|
97
146
|
diff: diff || '',
|
package/dist/git/github.js
CHANGED
|
@@ -43,6 +43,7 @@ async function getGitHubContext(repoRoot) {
|
|
|
43
43
|
'This should be automatically provided by GitHub Actions.');
|
|
44
44
|
}
|
|
45
45
|
// Get commit author using git commands (same approach as Bitbucket/Local)
|
|
46
|
+
// getCommitAuthor throws on failure with descriptive error
|
|
46
47
|
const commitAuthor = await (0, diff_1.getCommitAuthor)(repoRoot, commitSha);
|
|
47
48
|
// Get commit message if we have a SHA
|
|
48
49
|
let commitMessage;
|
|
@@ -54,11 +55,6 @@ async function getGitHubContext(repoRoot) {
|
|
|
54
55
|
}
|
|
55
56
|
// Get PR title if in PR context
|
|
56
57
|
const prTitle = getPRTitle(context);
|
|
57
|
-
// Validate commit author was found
|
|
58
|
-
if (!commitAuthor) {
|
|
59
|
-
throw new Error(`GitHub Actions: Failed to get commit author from git log for commit ${commitSha || 'HEAD'}. ` +
|
|
60
|
-
'This should be automatically available in the git repository.');
|
|
61
|
-
}
|
|
62
58
|
return {
|
|
63
59
|
diff,
|
|
64
60
|
repoName,
|
|
@@ -75,53 +71,26 @@ async function getGitHubContext(repoRoot) {
|
|
|
75
71
|
* Gets diff for GitHub Actions CI environment
|
|
76
72
|
*
|
|
77
73
|
* Strategy:
|
|
78
|
-
* - PR context:
|
|
79
|
-
* - Any push (main or feature branch): Compare last commit only
|
|
74
|
+
* - PR context: Uses shared getPRDiff() - fetches base branch, compares against HEAD
|
|
75
|
+
* - Any push (main or feature branch): Compare last commit only using git show HEAD
|
|
80
76
|
*
|
|
81
77
|
* Note: GitHub Actions does shallow clones by default (fetch-depth: 1), so we fetch
|
|
82
78
|
* the base branch on-demand. HEAD points to the merge commit which contains all PR changes.
|
|
83
79
|
*/
|
|
84
80
|
async function getDiff(repoRoot) {
|
|
85
|
-
const git = (0, simple_git_1.default)(repoRoot);
|
|
86
81
|
const eventName = process.env.GITHUB_EVENT_NAME;
|
|
87
82
|
const baseRef = process.env.GITHUB_BASE_REF;
|
|
88
|
-
// PR Context:
|
|
83
|
+
// PR Context: Use shared getPRDiff() implementation
|
|
89
84
|
if (eventName === 'pull_request') {
|
|
90
85
|
if (!baseRef) {
|
|
91
86
|
throw new Error('GitHub PR context detected but GITHUB_BASE_REF is missing. ' +
|
|
92
87
|
'This should be automatically provided by GitHub Actions.');
|
|
93
88
|
}
|
|
94
|
-
|
|
95
|
-
logger_1.logger.debug(`Fetching base branch: origin/${baseRef}`);
|
|
96
|
-
try {
|
|
97
|
-
await git.fetch(['origin', `${baseRef}:refs/remotes/origin/${baseRef}`, '--depth=1']);
|
|
98
|
-
}
|
|
99
|
-
catch (fetchError) {
|
|
100
|
-
throw new Error(`Failed to fetch base branch origin/${baseRef}. ` +
|
|
101
|
-
`This is required for PR diff comparison. Error: ${fetchError instanceof Error ? fetchError.message : 'Unknown error'}`);
|
|
102
|
-
}
|
|
103
|
-
logger_1.logger.debug(`PR context, using origin/${baseRef}..HEAD (two dots for direct comparison)`);
|
|
104
|
-
// Use two dots (..) instead of three dots (...) for direct comparison
|
|
105
|
-
// Three dots requires finding merge base which can fail with shallow clones
|
|
106
|
-
// Two dots shows all changes in HEAD that aren't in origin/${baseRef}
|
|
107
|
-
const diff = await git.diff([`origin/${baseRef}..HEAD`, '-U200']);
|
|
108
|
-
const diffSummary = await git.diffSummary([`origin/${baseRef}..HEAD`]);
|
|
109
|
-
const changedFiles = diffSummary.files.map(f => f.file);
|
|
110
|
-
return {
|
|
111
|
-
diff: diff || '',
|
|
112
|
-
changedFiles
|
|
113
|
-
};
|
|
89
|
+
return (0, diff_1.getPRDiff)(repoRoot, baseRef, logger_1.logger);
|
|
114
90
|
}
|
|
115
91
|
// Any push (main or feature branch): Review last commit only
|
|
116
|
-
// Use
|
|
117
|
-
|
|
118
|
-
// Extract changed files from git show
|
|
119
|
-
const showNameOnly = await git.show(['HEAD', '--name-only', '--format=', '--pretty=format:']);
|
|
120
|
-
const changedFiles = showNameOnly
|
|
121
|
-
.split('\n')
|
|
122
|
-
.filter(line => line.trim().length > 0)
|
|
123
|
-
.map(line => line.trim());
|
|
124
|
-
return { diff: diff || '', changedFiles };
|
|
92
|
+
// Use shared getCommitDiff (defaults to HEAD)
|
|
93
|
+
return (0, diff_1.getCommitDiff)(repoRoot);
|
|
125
94
|
}
|
|
126
95
|
/**
|
|
127
96
|
* Gets repository name for GitHub Actions
|
package/dist/git/gitlab.js
CHANGED
|
@@ -37,8 +37,9 @@ async function getGitLabContext(repoRoot) {
|
|
|
37
37
|
const context = detectContext();
|
|
38
38
|
const reviewContext = detectReviewContext();
|
|
39
39
|
const commitSha = getCommitSha(context);
|
|
40
|
-
// Get commit author
|
|
41
|
-
|
|
40
|
+
// Get commit author using shared function (git log)
|
|
41
|
+
// getCommitAuthor throws on failure with descriptive error
|
|
42
|
+
const commitAuthor = await (0, diff_1.getCommitAuthor)(repoRoot);
|
|
42
43
|
// Get commit message if we have a SHA
|
|
43
44
|
let commitMessage;
|
|
44
45
|
if (commitSha) {
|
|
@@ -65,36 +66,26 @@ async function getGitLabContext(repoRoot) {
|
|
|
65
66
|
* Get diff for GitLab CI environment
|
|
66
67
|
*
|
|
67
68
|
* Strategy:
|
|
68
|
-
* - MR context:
|
|
69
|
+
* - MR context: Uses shared getPRDiff() - fetches target branch, compares against HEAD
|
|
69
70
|
* - Any push (main or feature branch): Compare last commit only (HEAD~1...HEAD)
|
|
70
71
|
*
|
|
71
72
|
* Note: GitLab CI does a shallow clone, so we fetch the target branch for MR context.
|
|
72
73
|
* For regular pushes, HEAD~1...HEAD works without additional fetching.
|
|
73
74
|
*/
|
|
74
75
|
async function getDiff(repoRoot) {
|
|
75
|
-
const git = (0, simple_git_1.default)(repoRoot);
|
|
76
76
|
const mrIid = process.env.CI_MERGE_REQUEST_IID;
|
|
77
77
|
const targetBranch = process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME;
|
|
78
|
-
|
|
79
|
-
// MR Context: Fetch target branch and compare
|
|
78
|
+
// MR Context: Use shared getPRDiff() implementation
|
|
80
79
|
if (mrIid) {
|
|
81
|
-
if (!targetBranch
|
|
82
|
-
throw new Error('GitLab MR context detected but CI_MERGE_REQUEST_TARGET_BRANCH_NAME
|
|
83
|
-
'CI_MERGE_REQUEST_SOURCE_BRANCH_NAME is missing. ' +
|
|
80
|
+
if (!targetBranch) {
|
|
81
|
+
throw new Error('GitLab MR context detected but CI_MERGE_REQUEST_TARGET_BRANCH_NAME is missing. ' +
|
|
84
82
|
'This should be automatically provided by GitLab CI.');
|
|
85
83
|
}
|
|
86
|
-
|
|
87
|
-
await git.fetch(['origin', `${targetBranch}:refs/remotes/origin/${targetBranch}`, '--depth=1']);
|
|
88
|
-
const diff = await git.diff([`origin/${targetBranch}...origin/${sourceBranch}`, '-U200']);
|
|
89
|
-
const diffSummary = await git.diffSummary([`origin/${targetBranch}...origin/${sourceBranch}`]);
|
|
90
|
-
const changedFiles = diffSummary.files.map(f => f.file);
|
|
91
|
-
return { diff: diff || '', changedFiles };
|
|
84
|
+
return (0, diff_1.getPRDiff)(repoRoot, targetBranch, logger_1.logger);
|
|
92
85
|
}
|
|
93
86
|
// Any push (main or feature branch): Review last commit only
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const changedFiles = diffSummary.files.map(f => f.file);
|
|
97
|
-
return { diff: diff || '', changedFiles };
|
|
87
|
+
// Use shared getCommitDiff (defaults to HEAD)
|
|
88
|
+
return (0, diff_1.getCommitDiff)(repoRoot);
|
|
98
89
|
}
|
|
99
90
|
/**
|
|
100
91
|
* Gets repository name for GitLab CI
|
|
@@ -173,28 +164,6 @@ function getCommitSha(context) {
|
|
|
173
164
|
}
|
|
174
165
|
return undefined;
|
|
175
166
|
}
|
|
176
|
-
/**
|
|
177
|
-
* Gets commit author for GitLab CI
|
|
178
|
-
* Uses CI_COMMIT_AUTHOR environment variable (most reliable)
|
|
179
|
-
*/
|
|
180
|
-
async function getCommitAuthor() {
|
|
181
|
-
const commitAuthor = process.env.CI_COMMIT_AUTHOR;
|
|
182
|
-
if (!commitAuthor) {
|
|
183
|
-
throw new Error('GitLab CI: CI_COMMIT_AUTHOR environment variable is not set. ' +
|
|
184
|
-
'This should be automatically provided by GitLab CI.');
|
|
185
|
-
}
|
|
186
|
-
// Parse "name <email>" format
|
|
187
|
-
const match = commitAuthor.match(/^(.+?)\s*<(.+?)>$/);
|
|
188
|
-
if (!match) {
|
|
189
|
-
throw new Error(`GitLab CI: CI_COMMIT_AUTHOR format is invalid. ` +
|
|
190
|
-
`Expected format: "name <email>", got: "${commitAuthor}". ` +
|
|
191
|
-
`This should be automatically provided by GitLab CI in the correct format.`);
|
|
192
|
-
}
|
|
193
|
-
return {
|
|
194
|
-
name: match[1].trim(),
|
|
195
|
-
email: match[2].trim()
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
167
|
/**
|
|
199
168
|
* Gets MR title for GitLab CI
|
|
200
169
|
*/
|
package/dist/git/local.js
CHANGED
|
@@ -29,7 +29,7 @@ async function getLocalContext(repoRoot, commitSha) {
|
|
|
29
29
|
throw new Error('Not a git repository. Threadline requires a git repository.');
|
|
30
30
|
}
|
|
31
31
|
// Get all Local context
|
|
32
|
-
const diff = commitSha ? await getCommitDiff(repoRoot, commitSha) : await getDiff(repoRoot);
|
|
32
|
+
const diff = commitSha ? await (0, diff_1.getCommitDiff)(repoRoot, commitSha) : await getDiff(repoRoot);
|
|
33
33
|
const repoName = await getRepoName(repoRoot);
|
|
34
34
|
const branchName = await getBranchName(repoRoot);
|
|
35
35
|
const context = commitSha ? { type: 'commit', commitSha } : { type: 'local' };
|
|
@@ -96,24 +96,6 @@ async function getDiff(repoRoot) {
|
|
|
96
96
|
changedFiles
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
|
-
/**
|
|
100
|
-
* Get diff for a specific commit (when --commit flag is used)
|
|
101
|
-
*/
|
|
102
|
-
async function getCommitDiff(repoRoot, commitSha) {
|
|
103
|
-
const git = (0, simple_git_1.default)(repoRoot);
|
|
104
|
-
// Get diff using git show
|
|
105
|
-
const diff = await git.show([commitSha, '--format=', '--no-color', '-U200']);
|
|
106
|
-
// Get changed files using git show --name-only
|
|
107
|
-
const commitFiles = await git.show([commitSha, '--name-only', '--format=', '--pretty=format:']);
|
|
108
|
-
const changedFiles = commitFiles
|
|
109
|
-
.split('\n')
|
|
110
|
-
.filter(line => line.trim().length > 0)
|
|
111
|
-
.map(line => line.trim());
|
|
112
|
-
return {
|
|
113
|
-
diff: diff || '',
|
|
114
|
-
changedFiles
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
99
|
/**
|
|
118
100
|
* Gets repository name for local environment
|
|
119
101
|
*/
|
|
@@ -177,15 +159,8 @@ async function getCommitAuthorFromConfig(repoRoot) {
|
|
|
177
159
|
}
|
|
178
160
|
/**
|
|
179
161
|
* Gets commit author from git log (for specific commits)
|
|
162
|
+
* getCommitAuthor throws on failure with descriptive error
|
|
180
163
|
*/
|
|
181
164
|
async function getCommitAuthorFromGit(repoRoot, commitSha) {
|
|
182
|
-
|
|
183
|
-
if (!gitAuthor || !gitAuthor.email) {
|
|
184
|
-
throw new Error(`Local: Failed to get commit author from git log for commit ${commitSha}. ` +
|
|
185
|
-
'This should be available in your local git repository.');
|
|
186
|
-
}
|
|
187
|
-
return {
|
|
188
|
-
name: gitAuthor.name,
|
|
189
|
-
email: gitAuthor.email
|
|
190
|
-
};
|
|
165
|
+
return (0, diff_1.getCommitAuthor)(repoRoot, commitSha);
|
|
191
166
|
}
|
package/dist/git/vercel.js
CHANGED
|
@@ -17,7 +17,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.getVercelContext = getVercelContext;
|
|
19
19
|
const simple_git_1 = __importDefault(require("simple-git"));
|
|
20
|
-
const child_process_1 = require("child_process");
|
|
21
20
|
const diff_1 = require("./diff");
|
|
22
21
|
/**
|
|
23
22
|
* Gets all Vercel context
|
|
@@ -36,8 +35,9 @@ async function getVercelContext(repoRoot) {
|
|
|
36
35
|
const commitSha = getCommitSha();
|
|
37
36
|
const context = { type: 'commit', commitSha };
|
|
38
37
|
const reviewContext = 'commit';
|
|
39
|
-
// Get commit author
|
|
40
|
-
|
|
38
|
+
// Get commit author using shared function (git log)
|
|
39
|
+
// getCommitAuthor throws on failure with descriptive error
|
|
40
|
+
const commitAuthor = await (0, diff_1.getCommitAuthor)(repoRoot, commitSha);
|
|
41
41
|
// Get commit message
|
|
42
42
|
let commitMessage;
|
|
43
43
|
const message = await (0, diff_1.getCommitMessage)(repoRoot, commitSha);
|
|
@@ -58,29 +58,13 @@ async function getVercelContext(repoRoot) {
|
|
|
58
58
|
/**
|
|
59
59
|
* Get diff for Vercel CI environment
|
|
60
60
|
*
|
|
61
|
-
* Vercel
|
|
62
|
-
*
|
|
61
|
+
* Vercel only supports commit context (no PRs).
|
|
62
|
+
* Uses shared getCommitDiff with HEAD (which equals VERCEL_GIT_COMMIT_SHA).
|
|
63
63
|
*/
|
|
64
64
|
async function getDiff(repoRoot) {
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
if (!commitSha) {
|
|
69
|
-
throw new Error('VERCEL_GIT_COMMIT_SHA environment variable is not set. ' +
|
|
70
|
-
'This should be automatically provided by Vercel CI.');
|
|
71
|
-
}
|
|
72
|
-
// Get diff using git show - this is the ONLY way we get diff in Vercel
|
|
73
|
-
const diff = await git.show([commitSha, '--format=', '--no-color', '-U200']);
|
|
74
|
-
// Get changed files using git show --name-only
|
|
75
|
-
const commitFiles = await git.show([commitSha, '--name-only', '--format=', '--pretty=format:']);
|
|
76
|
-
const changedFiles = commitFiles
|
|
77
|
-
.split('\n')
|
|
78
|
-
.filter(line => line.trim().length > 0)
|
|
79
|
-
.map(line => line.trim());
|
|
80
|
-
return {
|
|
81
|
-
diff: diff || '', // Empty diff is legitimate (e.g., metadata-only commits, merge commits)
|
|
82
|
-
changedFiles
|
|
83
|
-
};
|
|
65
|
+
// Use shared getCommitDiff (defaults to HEAD)
|
|
66
|
+
// In Vercel, HEAD is the commit being deployed
|
|
67
|
+
return (0, diff_1.getCommitDiff)(repoRoot);
|
|
84
68
|
}
|
|
85
69
|
/**
|
|
86
70
|
* Gets repository name for Vercel
|
|
@@ -116,33 +100,3 @@ function getCommitSha() {
|
|
|
116
100
|
}
|
|
117
101
|
return commitSha;
|
|
118
102
|
}
|
|
119
|
-
/**
|
|
120
|
-
* Gets commit author for Vercel
|
|
121
|
-
* Uses VERCEL_GIT_COMMIT_AUTHOR_NAME for name, raw git log command for email
|
|
122
|
-
*
|
|
123
|
-
* Uses raw `git log` command (same as test script) instead of simple-git library
|
|
124
|
-
* because simple-git's log method may not work correctly in Vercel's shallow clone.
|
|
125
|
-
*/
|
|
126
|
-
async function getCommitAuthorForVercel(repoRoot, commitSha) {
|
|
127
|
-
const authorName = process.env.VERCEL_GIT_COMMIT_AUTHOR_NAME;
|
|
128
|
-
if (!authorName) {
|
|
129
|
-
throw new Error('Vercel: VERCEL_GIT_COMMIT_AUTHOR_NAME environment variable is not set. ' +
|
|
130
|
-
'This should be automatically provided by Vercel.');
|
|
131
|
-
}
|
|
132
|
-
// Use raw git log command (same approach as test script) - more reliable than simple-git
|
|
133
|
-
try {
|
|
134
|
-
const email = (0, child_process_1.execSync)(`git log ${commitSha} -1 --format=%ae`, { encoding: 'utf-8', cwd: repoRoot }).trim();
|
|
135
|
-
if (!email) {
|
|
136
|
-
throw new Error('Email is empty');
|
|
137
|
-
}
|
|
138
|
-
return {
|
|
139
|
-
name: authorName.trim(),
|
|
140
|
-
email: email.trim()
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
catch (error) {
|
|
144
|
-
throw new Error(`Vercel: Failed to get commit author email from git log for commit ${commitSha}. ` +
|
|
145
|
-
`This should be available in Vercel's build environment. ` +
|
|
146
|
-
`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
147
|
-
}
|
|
148
|
-
}
|