threadlines 0.1.20 → 0.1.22
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/commands/check.js +19 -11
- package/dist/git/diff.js +0 -38
- package/dist/git/github-diff.js +109 -0
- package/dist/git/gitlab-diff.js +63 -0
- package/dist/git/local-diff.js +53 -0
- package/dist/git/repo.js +79 -0
- package/dist/utils/git-diff-executor.js +23 -12
- package/package.json +1 -1
package/dist/commands/check.js
CHANGED
|
@@ -127,26 +127,34 @@ async function checkCommand(options) {
|
|
|
127
127
|
}
|
|
128
128
|
else {
|
|
129
129
|
// Auto-detect: Use environment-specific implementation
|
|
130
|
+
const envNames = {
|
|
131
|
+
vercel: 'Vercel',
|
|
132
|
+
github: 'GitHub',
|
|
133
|
+
gitlab: 'GitLab',
|
|
134
|
+
local: 'Local'
|
|
135
|
+
};
|
|
136
|
+
console.log(chalk_1.default.gray(`📝 Collecting git changes for ${envNames[environment]}...`));
|
|
137
|
+
gitDiff = await (0, git_diff_executor_1.getDiffForEnvironment)(environment, repoRoot);
|
|
138
|
+
// Create context for metadata collection
|
|
130
139
|
if (environment === 'vercel') {
|
|
131
|
-
// Vercel: Direct environment-based routing (single implementation)
|
|
132
|
-
console.log(chalk_1.default.gray(`📝 Collecting git changes for Vercel commit...`));
|
|
133
|
-
gitDiff = await (0, git_diff_executor_1.getDiffForEnvironment)(environment, repoRoot);
|
|
134
|
-
// Vercel uses commit context, but we don't need to create it explicitly
|
|
135
140
|
context = { type: 'commit', commitSha: process.env.VERCEL_GIT_COMMIT_SHA };
|
|
136
141
|
}
|
|
137
|
-
else {
|
|
138
|
-
//
|
|
142
|
+
else if (environment === 'github' || environment === 'gitlab') {
|
|
143
|
+
// GitHub/GitLab: Detect context for metadata (but diff already obtained)
|
|
139
144
|
context = (0, context_1.detectContext)(environment);
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
// Local: Use local context
|
|
148
|
+
context = { type: 'local' };
|
|
143
149
|
}
|
|
144
150
|
}
|
|
145
151
|
// 3. Collect metadata (commit SHA, commit message, PR title)
|
|
146
152
|
const metadata = await (0, metadata_1.collectMetadata)(context, environment, repoRoot);
|
|
147
153
|
if (gitDiff.changedFiles.length === 0) {
|
|
148
|
-
console.
|
|
149
|
-
|
|
154
|
+
console.error(chalk_1.default.red('❌ Error: No changes detected.'));
|
|
155
|
+
console.error(chalk_1.default.red(' Threadline check requires code changes to analyze.'));
|
|
156
|
+
console.error(chalk_1.default.red(' This may indicate a problem with git diff detection.'));
|
|
157
|
+
process.exit(1);
|
|
150
158
|
}
|
|
151
159
|
// Check for zero diff (files changed but no actual code changes)
|
|
152
160
|
if (!gitDiff.diff || gitDiff.diff.trim() === '') {
|
package/dist/git/diff.js
CHANGED
|
@@ -3,49 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getGitDiff = getGitDiff;
|
|
7
6
|
exports.getBranchDiff = getBranchDiff;
|
|
8
7
|
exports.getCommitMessage = getCommitMessage;
|
|
9
8
|
exports.getCommitDiff = getCommitDiff;
|
|
10
9
|
exports.getPRMRDiff = getPRMRDiff;
|
|
11
10
|
const simple_git_1 = __importDefault(require("simple-git"));
|
|
12
|
-
/**
|
|
13
|
-
* Get diff for staged/unstaged changes (current behavior)
|
|
14
|
-
*/
|
|
15
|
-
async function getGitDiff(repoRoot) {
|
|
16
|
-
const git = (0, simple_git_1.default)(repoRoot);
|
|
17
|
-
// Check if we're in a git repo
|
|
18
|
-
const isRepo = await git.checkIsRepo();
|
|
19
|
-
if (!isRepo) {
|
|
20
|
-
throw new Error('Not a git repository. Threadline requires a git repository.');
|
|
21
|
-
}
|
|
22
|
-
// Get diff (staged changes, or unstaged if no staged)
|
|
23
|
-
const status = await git.status();
|
|
24
|
-
let diff;
|
|
25
|
-
if (status.staged.length > 0) {
|
|
26
|
-
// Use staged changes
|
|
27
|
-
diff = await git.diff(['--cached', '-U200']);
|
|
28
|
-
}
|
|
29
|
-
else if (status.files.length > 0) {
|
|
30
|
-
// Use unstaged changes
|
|
31
|
-
diff = await git.diff(['-U200']);
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
// No changes
|
|
35
|
-
return {
|
|
36
|
-
diff: '',
|
|
37
|
-
changedFiles: []
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
// Get list of changed files
|
|
41
|
-
const changedFiles = status.files
|
|
42
|
-
.filter(f => f.working_dir !== ' ' || f.index !== ' ')
|
|
43
|
-
.map(f => f.path);
|
|
44
|
-
return {
|
|
45
|
-
diff: diff || '',
|
|
46
|
-
changedFiles
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
11
|
/**
|
|
50
12
|
* Get diff for a specific branch (all commits vs base branch)
|
|
51
13
|
* Uses git merge-base to find common ancestor, then diffs from there
|
|
@@ -0,0 +1,109 @@
|
|
|
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.getGitHubDiff = getGitHubDiff;
|
|
7
|
+
const simple_git_1 = __importDefault(require("simple-git"));
|
|
8
|
+
const repo_1 = require("./repo");
|
|
9
|
+
/**
|
|
10
|
+
* Get diff for GitHub Actions CI environment
|
|
11
|
+
*
|
|
12
|
+
* Handles four scenarios:
|
|
13
|
+
*
|
|
14
|
+
* 1. PR Context (pull_request event):
|
|
15
|
+
* Uses GITHUB_BASE_REF vs GITHUB_HEAD_REF
|
|
16
|
+
* Shows: All changes in the PR
|
|
17
|
+
*
|
|
18
|
+
* 2. Merge Commit to Default Branch (push event, default branch):
|
|
19
|
+
* Compare: origin/default~1 vs origin/default
|
|
20
|
+
* Shows: All changes that were merged in
|
|
21
|
+
*
|
|
22
|
+
* 3. Feature Branch Push (push event, feature branch):
|
|
23
|
+
* Compare: origin/default vs origin/feature-branch
|
|
24
|
+
* Shows: Cumulative changes in feature branch vs default
|
|
25
|
+
*
|
|
26
|
+
* 4. Direct Commit to Default Branch (push event, default branch, non-merge):
|
|
27
|
+
* Compare: origin/default~1 vs origin/default
|
|
28
|
+
* Shows: Changes in the direct commit
|
|
29
|
+
*
|
|
30
|
+
*/
|
|
31
|
+
async function getGitHubDiff(repoRoot) {
|
|
32
|
+
const git = (0, simple_git_1.default)(repoRoot);
|
|
33
|
+
// Check if we're in a git repo
|
|
34
|
+
const isRepo = await git.checkIsRepo();
|
|
35
|
+
if (!isRepo) {
|
|
36
|
+
throw new Error('Not a git repository. Threadline requires a git repository.');
|
|
37
|
+
}
|
|
38
|
+
// Detect the default branch name (e.g., "main", "master")
|
|
39
|
+
// This is used for scenarios 2, 3, and 4
|
|
40
|
+
const defaultBranch = await (0, repo_1.getDefaultBranchName)(repoRoot);
|
|
41
|
+
// Determine context from GitHub environment variables
|
|
42
|
+
const eventName = process.env.GITHUB_EVENT_NAME;
|
|
43
|
+
const baseRef = process.env.GITHUB_BASE_REF;
|
|
44
|
+
const headRef = process.env.GITHUB_HEAD_REF;
|
|
45
|
+
const refName = process.env.GITHUB_REF_NAME;
|
|
46
|
+
const commitSha = process.env.GITHUB_SHA;
|
|
47
|
+
// Scenario 1: PR Context
|
|
48
|
+
// When a PR is created or updated, GitHub provides both base and head branches
|
|
49
|
+
// This is the simplest case - we use what GitHub gives us directly
|
|
50
|
+
if (eventName === 'pull_request') {
|
|
51
|
+
if (!baseRef || !headRef) {
|
|
52
|
+
throw new Error('GitHub PR context detected but GITHUB_BASE_REF or GITHUB_HEAD_REF is missing. ' +
|
|
53
|
+
'This should be automatically provided by GitHub Actions.');
|
|
54
|
+
}
|
|
55
|
+
// Compare target branch (base) vs source branch (head)
|
|
56
|
+
// This shows all changes in the PR
|
|
57
|
+
const diff = await git.diff([`origin/${baseRef}...origin/${headRef}`, '-U200']);
|
|
58
|
+
const diffSummary = await git.diffSummary([`origin/${baseRef}...origin/${headRef}`]);
|
|
59
|
+
const changedFiles = diffSummary.files.map(f => f.file);
|
|
60
|
+
return {
|
|
61
|
+
diff: diff || '',
|
|
62
|
+
changedFiles
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// Scenario 2 & 4: Default Branch Push (merge commit or direct commit)
|
|
66
|
+
// When code is pushed to the default branch, we compare default~1 vs default
|
|
67
|
+
// This works for both merge commits and direct commits:
|
|
68
|
+
// - Merge commits: Shows all changes that were merged in
|
|
69
|
+
// - Direct commits: Shows the changes in the direct commit
|
|
70
|
+
if (refName === defaultBranch && commitSha) {
|
|
71
|
+
// Compare default branch before the push (default~1) vs default branch after the push (default)
|
|
72
|
+
// This shows all changes introduced by the push, whether merged or direct
|
|
73
|
+
try {
|
|
74
|
+
const diff = await git.diff([`origin/${defaultBranch}~1...origin/${defaultBranch}`, '-U200']);
|
|
75
|
+
const diffSummary = await git.diffSummary([`origin/${defaultBranch}~1...origin/${defaultBranch}`]);
|
|
76
|
+
const changedFiles = diffSummary.files.map(f => f.file);
|
|
77
|
+
return {
|
|
78
|
+
diff: diff || '',
|
|
79
|
+
changedFiles
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
// If we can't get the diff (e.g., first commit on branch), throw a clear error
|
|
84
|
+
throw new Error(`Could not get diff for default branch '${defaultBranch}'. ` +
|
|
85
|
+
`This might be the first commit on the branch. Error: ${error.message}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Scenario 3: Feature Branch Push
|
|
89
|
+
// When code is pushed to a feature branch, we want to see all changes vs the default branch
|
|
90
|
+
// Compare: origin/default vs origin/feature-branch
|
|
91
|
+
// This shows cumulative changes in the feature branch (all commits vs default branch)
|
|
92
|
+
// Note: We don't use HEAD~1 vs HEAD because that only shows the last commit,
|
|
93
|
+
// not the cumulative changes in the branch
|
|
94
|
+
if (refName) {
|
|
95
|
+
// For branch pushes, compare against origin/default (detected default branch)
|
|
96
|
+
// GitHub Actions with fetch-depth: 0 should have origin/default available
|
|
97
|
+
const diff = await git.diff([`origin/${defaultBranch}...origin/${refName}`, '-U200']);
|
|
98
|
+
const diffSummary = await git.diffSummary([`origin/${defaultBranch}...origin/${refName}`]);
|
|
99
|
+
const changedFiles = diffSummary.files.map(f => f.file);
|
|
100
|
+
return {
|
|
101
|
+
diff: diff || '',
|
|
102
|
+
changedFiles
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// Neither PR nor branch context available
|
|
106
|
+
throw new Error('GitHub Actions environment detected but no valid context found. ' +
|
|
107
|
+
'Expected GITHUB_EVENT_NAME="pull_request" (with GITHUB_BASE_REF/GITHUB_HEAD_REF) ' +
|
|
108
|
+
'or GITHUB_REF_NAME for branch context.');
|
|
109
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
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.getGitLabDiff = getGitLabDiff;
|
|
7
|
+
const simple_git_1 = __importDefault(require("simple-git"));
|
|
8
|
+
/**
|
|
9
|
+
* Get diff for GitLab CI environment
|
|
10
|
+
*
|
|
11
|
+
* GitLab CI provides environment variables that tell us exactly what to compare:
|
|
12
|
+
* - MR context: CI_MERGE_REQUEST_TARGET_BRANCH_NAME (target branch) and CI_MERGE_REQUEST_SOURCE_BRANCH_NAME (source branch)
|
|
13
|
+
* - Branch context: CI_COMMIT_REF_NAME (current branch), compare against origin/main
|
|
14
|
+
*
|
|
15
|
+
* This implementation follows the same pattern as GitHub Actions, using GitLab's equivalent
|
|
16
|
+
* environment variables. This is the ONLY implementation for GitLab - no fallbacks, no alternatives.
|
|
17
|
+
* If this doesn't work, we fail with a clear error.
|
|
18
|
+
*/
|
|
19
|
+
async function getGitLabDiff(repoRoot) {
|
|
20
|
+
const git = (0, simple_git_1.default)(repoRoot);
|
|
21
|
+
// Check if we're in a git repo
|
|
22
|
+
const isRepo = await git.checkIsRepo();
|
|
23
|
+
if (!isRepo) {
|
|
24
|
+
throw new Error('Not a git repository. Threadline requires a git repository.');
|
|
25
|
+
}
|
|
26
|
+
// Determine context from GitLab CI environment variables
|
|
27
|
+
const mrIid = process.env.CI_MERGE_REQUEST_IID;
|
|
28
|
+
const targetBranch = process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME;
|
|
29
|
+
const sourceBranch = process.env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME;
|
|
30
|
+
const refName = process.env.CI_COMMIT_REF_NAME;
|
|
31
|
+
// MR context: GitLab provides both target and source branches
|
|
32
|
+
if (mrIid) {
|
|
33
|
+
if (!targetBranch || !sourceBranch) {
|
|
34
|
+
throw new Error('GitLab MR context detected but CI_MERGE_REQUEST_TARGET_BRANCH_NAME or ' +
|
|
35
|
+
'CI_MERGE_REQUEST_SOURCE_BRANCH_NAME is missing. ' +
|
|
36
|
+
'This should be automatically provided by GitLab CI.');
|
|
37
|
+
}
|
|
38
|
+
// Use the branches GitLab provides directly - no detection needed
|
|
39
|
+
const diff = await git.diff([`origin/${targetBranch}...origin/${sourceBranch}`, '-U200']);
|
|
40
|
+
const diffSummary = await git.diffSummary([`origin/${targetBranch}...origin/${sourceBranch}`]);
|
|
41
|
+
const changedFiles = diffSummary.files.map(f => f.file);
|
|
42
|
+
return {
|
|
43
|
+
diff: diff || '',
|
|
44
|
+
changedFiles
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// Branch context: GitLab provides branch name, compare against origin/main
|
|
48
|
+
if (refName) {
|
|
49
|
+
// For branch pushes, compare against origin/main (standard base branch)
|
|
50
|
+
// GitLab CI with fetch-depth: 0 should have origin/main available
|
|
51
|
+
const diff = await git.diff([`origin/main...origin/${refName}`, '-U200']);
|
|
52
|
+
const diffSummary = await git.diffSummary([`origin/main...origin/${refName}`]);
|
|
53
|
+
const changedFiles = diffSummary.files.map(f => f.file);
|
|
54
|
+
return {
|
|
55
|
+
diff: diff || '',
|
|
56
|
+
changedFiles
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// Neither MR nor branch context available
|
|
60
|
+
throw new Error('GitLab CI environment detected but no valid context found. ' +
|
|
61
|
+
'Expected CI_MERGE_REQUEST_IID (with CI_MERGE_REQUEST_TARGET_BRANCH_NAME/CI_MERGE_REQUEST_SOURCE_BRANCH_NAME) ' +
|
|
62
|
+
'or CI_COMMIT_REF_NAME for branch context.');
|
|
63
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
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.getLocalDiff = getLocalDiff;
|
|
7
|
+
const simple_git_1 = __importDefault(require("simple-git"));
|
|
8
|
+
/**
|
|
9
|
+
* Get diff for local development environment
|
|
10
|
+
*
|
|
11
|
+
* For local development, we check staged changes first, then unstaged changes.
|
|
12
|
+
* This allows developers to review what they've staged before committing,
|
|
13
|
+
* or review unstaged changes if nothing is staged.
|
|
14
|
+
*
|
|
15
|
+
* This is the ONLY implementation for local - no fallbacks, no alternatives.
|
|
16
|
+
* If this doesn't work, we fail with a clear error.
|
|
17
|
+
*/
|
|
18
|
+
async function getLocalDiff(repoRoot) {
|
|
19
|
+
const git = (0, simple_git_1.default)(repoRoot);
|
|
20
|
+
// Check if we're in a git repo
|
|
21
|
+
const isRepo = await git.checkIsRepo();
|
|
22
|
+
if (!isRepo) {
|
|
23
|
+
throw new Error('Not a git repository. Threadline requires a git repository.');
|
|
24
|
+
}
|
|
25
|
+
// Get git status to determine what changes exist
|
|
26
|
+
const status = await git.status();
|
|
27
|
+
let diff;
|
|
28
|
+
let changedFiles;
|
|
29
|
+
// Priority 1: Use staged changes if available
|
|
30
|
+
if (status.staged.length > 0) {
|
|
31
|
+
diff = await git.diff(['--cached', '-U200']);
|
|
32
|
+
// status.staged is an array of strings (file paths)
|
|
33
|
+
changedFiles = status.staged;
|
|
34
|
+
}
|
|
35
|
+
// Priority 2: Use unstaged changes if no staged changes
|
|
36
|
+
else if (status.files.length > 0) {
|
|
37
|
+
diff = await git.diff(['-U200']);
|
|
38
|
+
changedFiles = status.files
|
|
39
|
+
.filter(f => f.working_dir !== ' ' || f.index !== ' ')
|
|
40
|
+
.map(f => f.path);
|
|
41
|
+
}
|
|
42
|
+
// No changes at all
|
|
43
|
+
else {
|
|
44
|
+
return {
|
|
45
|
+
diff: '',
|
|
46
|
+
changedFiles: []
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
diff: diff || '',
|
|
51
|
+
changedFiles
|
|
52
|
+
};
|
|
53
|
+
}
|
package/dist/git/repo.js
CHANGED
|
@@ -1,11 +1,47 @@
|
|
|
1
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
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
5
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
39
|
exports.getRepoName = getRepoName;
|
|
7
40
|
exports.getBranchName = getBranchName;
|
|
41
|
+
exports.getDefaultBranchName = getDefaultBranchName;
|
|
8
42
|
const simple_git_1 = __importDefault(require("simple-git"));
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
9
45
|
/**
|
|
10
46
|
* Gets repository URL. Prefers CI environment variables over git commands.
|
|
11
47
|
*
|
|
@@ -61,3 +97,46 @@ async function getBranchName(repoRoot) {
|
|
|
61
97
|
return null;
|
|
62
98
|
}
|
|
63
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Detects the default branch name of the repository for GitHub Actions.
|
|
102
|
+
*
|
|
103
|
+
* Uses GITHUB_EVENT_PATH JSON (repository.default_branch) - the most authoritative source
|
|
104
|
+
* provided directly by GitHub Actions.
|
|
105
|
+
*
|
|
106
|
+
* This function is ONLY called from GitHub Actions context (getGitHubDiff),
|
|
107
|
+
* so GITHUB_EVENT_PATH should always be available. If it's not, we fail with a clear error.
|
|
108
|
+
*
|
|
109
|
+
* Returns the branch name (e.g., "main", "master") without the "origin/" prefix.
|
|
110
|
+
* Throws an error if the default branch cannot be detected.
|
|
111
|
+
*/
|
|
112
|
+
async function getDefaultBranchName(repoRoot) {
|
|
113
|
+
// GitHub Actions provides GITHUB_EVENT_PATH which contains repository.default_branch
|
|
114
|
+
const githubEventPath = process.env.GITHUB_EVENT_PATH;
|
|
115
|
+
if (!githubEventPath) {
|
|
116
|
+
throw new Error('GITHUB_EVENT_PATH environment variable is not set. ' +
|
|
117
|
+
'This should be automatically provided by GitHub Actions. ' +
|
|
118
|
+
'This function should only be called in GitHub Actions context.');
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const eventPath = path.resolve(githubEventPath);
|
|
122
|
+
if (!fs.existsSync(eventPath)) {
|
|
123
|
+
throw new Error(`GITHUB_EVENT_PATH file does not exist: ${eventPath}`);
|
|
124
|
+
}
|
|
125
|
+
const eventJson = JSON.parse(fs.readFileSync(eventPath, 'utf8'));
|
|
126
|
+
const defaultBranch = eventJson.repository?.default_branch;
|
|
127
|
+
if (!defaultBranch || typeof defaultBranch !== 'string') {
|
|
128
|
+
throw new Error('Could not find repository.default_branch in GITHUB_EVENT_PATH JSON. ' +
|
|
129
|
+
'This should be automatically provided by GitHub Actions.');
|
|
130
|
+
}
|
|
131
|
+
return defaultBranch;
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
// If it's already our error, re-throw it
|
|
135
|
+
if (error.message.includes('GITHUB_EVENT_PATH') || error.message.includes('default_branch')) {
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
// Otherwise, wrap it
|
|
139
|
+
throw new Error(`Failed to read or parse GITHUB_EVENT_PATH: ${error.message}. ` +
|
|
140
|
+
'This should be automatically provided by GitHub Actions.');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -11,16 +11,20 @@ exports.getDiffForContext = getDiffForContext;
|
|
|
11
11
|
exports.getContextDescription = getContextDescription;
|
|
12
12
|
const diff_1 = require("../git/diff");
|
|
13
13
|
const vercel_diff_1 = require("../git/vercel-diff");
|
|
14
|
+
const github_diff_1 = require("../git/github-diff");
|
|
15
|
+
const local_diff_1 = require("../git/local-diff");
|
|
16
|
+
const gitlab_diff_1 = require("../git/gitlab-diff");
|
|
14
17
|
/**
|
|
15
18
|
* Executes the appropriate git diff function based on environment.
|
|
16
19
|
*
|
|
17
20
|
* Each environment has a single, specific implementation:
|
|
18
21
|
* - Vercel: Uses VERCEL_GIT_COMMIT_SHA, gets commit diff via git show
|
|
19
|
-
* - GitHub: Uses
|
|
20
|
-
* - GitLab: Uses
|
|
21
|
-
* - Local: Uses staged
|
|
22
|
+
* - GitHub: Uses GITHUB_BASE_REF/GITHUB_HEAD_REF for PRs, GITHUB_REF_NAME for branches
|
|
23
|
+
* - GitLab: Uses CI_MERGE_REQUEST_TARGET_BRANCH_NAME/CI_MERGE_REQUEST_SOURCE_BRANCH_NAME for MRs, CI_COMMIT_REF_NAME for branches
|
|
24
|
+
* - Local: Uses staged changes first, then unstaged changes
|
|
22
25
|
*
|
|
23
26
|
* No fallbacks - if the environment-specific implementation fails, we fail clearly.
|
|
27
|
+
* Each environment is completely isolated - changes to one don't affect others.
|
|
24
28
|
*/
|
|
25
29
|
async function getDiffForEnvironment(environment, repoRoot, context) {
|
|
26
30
|
switch (environment) {
|
|
@@ -28,25 +32,32 @@ async function getDiffForEnvironment(environment, repoRoot, context) {
|
|
|
28
32
|
// Vercel: Single implementation using commit SHA
|
|
29
33
|
return await (0, vercel_diff_1.getVercelDiff)(repoRoot);
|
|
30
34
|
case 'github':
|
|
35
|
+
// GitHub: Single implementation using GitHub-provided environment variables
|
|
36
|
+
return await (0, github_diff_1.getGitHubDiff)(repoRoot);
|
|
31
37
|
case 'gitlab':
|
|
38
|
+
// GitLab: Single implementation using GitLab-provided environment variables
|
|
39
|
+
return await (0, gitlab_diff_1.getGitLabDiff)(repoRoot);
|
|
32
40
|
case 'local':
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
throw new Error(`Context required for ${environment} environment`);
|
|
36
|
-
}
|
|
37
|
-
return await getDiffForContext(context, repoRoot, environment);
|
|
41
|
+
// Local: Single implementation using staged/unstaged changes
|
|
42
|
+
return await (0, local_diff_1.getLocalDiff)(repoRoot);
|
|
38
43
|
default:
|
|
39
44
|
const _exhaustive = environment;
|
|
40
45
|
throw new Error(`Unknown environment: ${_exhaustive}`);
|
|
41
46
|
}
|
|
42
47
|
}
|
|
43
48
|
/**
|
|
44
|
-
*
|
|
49
|
+
* Legacy GitLab-specific diff function (deprecated).
|
|
45
50
|
*
|
|
46
|
-
* This is
|
|
47
|
-
*
|
|
51
|
+
* This function is kept for backward compatibility but should not be used.
|
|
52
|
+
* GitLab now uses getDiffForEnvironment() which routes to getGitLabDiff().
|
|
53
|
+
*
|
|
54
|
+
* @deprecated Use getDiffForEnvironment('gitlab', repoRoot) instead
|
|
48
55
|
*/
|
|
49
56
|
async function getDiffForContext(context, repoRoot, environment) {
|
|
57
|
+
// This should only be called for GitLab legacy code paths
|
|
58
|
+
if (environment !== 'gitlab') {
|
|
59
|
+
throw new Error(`getDiffForContext() is deprecated. Use getDiffForEnvironment('${environment}', repoRoot) instead.`);
|
|
60
|
+
}
|
|
50
61
|
switch (context.type) {
|
|
51
62
|
case 'pr':
|
|
52
63
|
return await (0, diff_1.getPRMRDiff)(repoRoot, context.sourceBranch, context.targetBranch);
|
|
@@ -57,7 +68,7 @@ async function getDiffForContext(context, repoRoot, environment) {
|
|
|
57
68
|
case 'commit':
|
|
58
69
|
return await (0, diff_1.getCommitDiff)(repoRoot, context.commitSha);
|
|
59
70
|
case 'local':
|
|
60
|
-
|
|
71
|
+
throw new Error('Local context should use getDiffForEnvironment(), not getDiffForContext()');
|
|
61
72
|
default:
|
|
62
73
|
// TypeScript exhaustiveness check - should never reach here
|
|
63
74
|
const _exhaustive = context;
|