@diff-review-system/drs 1.1.2 → 2.1.0

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.
Files changed (229) hide show
  1. package/.opencode/agent/describe/pr-describer.md +221 -0
  2. package/.opencode/agent/review/documentation.md +56 -0
  3. package/.opencode/agent/review/performance.md +32 -139
  4. package/.opencode/agent/review/quality.md +36 -113
  5. package/.opencode/agent/review/security.md +32 -97
  6. package/.opencode/agent/review/style.md +4 -0
  7. package/.opencode/agent/review/unified-reviewer.md +74 -0
  8. package/.opencode/opencode.jsonc +4 -29
  9. package/.opencode/tool/write_json_output.ts +24 -0
  10. package/README.md +48 -21
  11. package/dist/ci/runner.d.ts.map +1 -1
  12. package/dist/ci/runner.js +2 -0
  13. package/dist/ci/runner.js.map +1 -1
  14. package/dist/cli/describe-mr.d.ts +11 -0
  15. package/dist/cli/describe-mr.d.ts.map +1 -0
  16. package/dist/cli/describe-mr.js +104 -0
  17. package/dist/cli/describe-mr.js.map +1 -0
  18. package/dist/cli/describe-pr.d.ts +12 -0
  19. package/dist/cli/describe-pr.d.ts.map +1 -0
  20. package/dist/cli/describe-pr.js +105 -0
  21. package/dist/cli/describe-pr.js.map +1 -0
  22. package/dist/cli/index.js +222 -16
  23. package/dist/cli/index.js.map +1 -1
  24. package/dist/cli/init.d.ts +1 -1
  25. package/dist/cli/init.d.ts.map +1 -1
  26. package/dist/cli/init.js +273 -145
  27. package/dist/cli/init.js.map +1 -1
  28. package/dist/cli/post-comments.d.ts +16 -0
  29. package/dist/cli/post-comments.d.ts.map +1 -0
  30. package/dist/cli/post-comments.js +222 -0
  31. package/dist/cli/post-comments.js.map +1 -0
  32. package/dist/cli/review-local.d.ts +3 -0
  33. package/dist/cli/review-local.d.ts.map +1 -1
  34. package/dist/cli/review-local.js +44 -18
  35. package/dist/cli/review-local.js.map +1 -1
  36. package/dist/cli/review-mr.d.ts +6 -0
  37. package/dist/cli/review-mr.d.ts.map +1 -1
  38. package/dist/cli/review-mr.js +63 -7
  39. package/dist/cli/review-mr.js.map +1 -1
  40. package/dist/cli/review-pr.d.ts +6 -0
  41. package/dist/cli/review-pr.d.ts.map +1 -1
  42. package/dist/cli/review-pr.js +8 -1
  43. package/dist/cli/review-pr.js.map +1 -1
  44. package/dist/cli/show-changes.d.ts +15 -0
  45. package/dist/cli/show-changes.d.ts.map +1 -0
  46. package/dist/cli/show-changes.js +184 -0
  47. package/dist/cli/show-changes.js.map +1 -0
  48. package/dist/github/platform-adapter.d.ts.map +1 -1
  49. package/dist/github/platform-adapter.js +4 -2
  50. package/dist/github/platform-adapter.js.map +1 -1
  51. package/dist/gitlab/client.d.ts.map +1 -1
  52. package/dist/gitlab/client.js +1 -1
  53. package/dist/gitlab/client.js.map +1 -1
  54. package/dist/gitlab/platform-adapter.d.ts.map +1 -1
  55. package/dist/gitlab/platform-adapter.js +6 -5
  56. package/dist/gitlab/platform-adapter.js.map +1 -1
  57. package/dist/lib/change-summary.d.ts +8 -0
  58. package/dist/lib/change-summary.d.ts.map +1 -0
  59. package/dist/lib/change-summary.js +2 -0
  60. package/dist/lib/change-summary.js.map +1 -0
  61. package/dist/lib/comment-formatter.d.ts +3 -2
  62. package/dist/lib/comment-formatter.d.ts.map +1 -1
  63. package/dist/lib/comment-formatter.js +16 -2
  64. package/dist/lib/comment-formatter.js.map +1 -1
  65. package/dist/lib/comment-formatter.test.d.ts +2 -0
  66. package/dist/lib/comment-formatter.test.d.ts.map +1 -0
  67. package/dist/lib/comment-formatter.test.js +607 -0
  68. package/dist/lib/comment-formatter.test.js.map +1 -0
  69. package/dist/lib/comment-manager.test.d.ts +2 -0
  70. package/dist/lib/comment-manager.test.d.ts.map +1 -0
  71. package/dist/lib/comment-manager.test.js +618 -0
  72. package/dist/lib/comment-manager.test.js.map +1 -0
  73. package/dist/lib/comment-poster.d.ts +21 -0
  74. package/dist/lib/comment-poster.d.ts.map +1 -0
  75. package/dist/lib/comment-poster.js +96 -0
  76. package/dist/lib/comment-poster.js.map +1 -0
  77. package/dist/lib/comment-poster.test.d.ts +5 -0
  78. package/dist/lib/comment-poster.test.d.ts.map +1 -0
  79. package/dist/lib/comment-poster.test.js +215 -0
  80. package/dist/lib/comment-poster.test.js.map +1 -0
  81. package/dist/lib/config-model-overrides.test.js +71 -41
  82. package/dist/lib/config-model-overrides.test.js.map +1 -1
  83. package/dist/lib/config.d.ts +65 -7
  84. package/dist/lib/config.d.ts.map +1 -1
  85. package/dist/lib/config.js +122 -22
  86. package/dist/lib/config.js.map +1 -1
  87. package/dist/lib/config.test.js +31 -2
  88. package/dist/lib/config.test.js.map +1 -1
  89. package/dist/lib/context-compression.d.ts +19 -0
  90. package/dist/lib/context-compression.d.ts.map +1 -0
  91. package/dist/lib/context-compression.js +170 -0
  92. package/dist/lib/context-compression.js.map +1 -0
  93. package/dist/lib/context-compression.test.d.ts +2 -0
  94. package/dist/lib/context-compression.test.d.ts.map +1 -0
  95. package/dist/lib/context-compression.test.js +33 -0
  96. package/dist/lib/context-compression.test.js.map +1 -0
  97. package/dist/lib/context-loader.d.ts.map +1 -1
  98. package/dist/lib/context-loader.js +8 -1
  99. package/dist/lib/context-loader.js.map +1 -1
  100. package/dist/lib/context-loader.test.d.ts +2 -0
  101. package/dist/lib/context-loader.test.d.ts.map +1 -0
  102. package/dist/lib/context-loader.test.js +207 -0
  103. package/dist/lib/context-loader.test.js.map +1 -0
  104. package/dist/lib/describe-core.d.ts +9 -0
  105. package/dist/lib/describe-core.d.ts.map +1 -0
  106. package/dist/lib/describe-core.js +71 -0
  107. package/dist/lib/describe-core.js.map +1 -0
  108. package/dist/lib/describe-core.test.d.ts +2 -0
  109. package/dist/lib/describe-core.test.d.ts.map +1 -0
  110. package/dist/lib/describe-core.test.js +208 -0
  111. package/dist/lib/describe-core.test.js.map +1 -0
  112. package/dist/lib/describe-output-path.test.d.ts +2 -0
  113. package/dist/lib/describe-output-path.test.d.ts.map +1 -0
  114. package/dist/lib/describe-output-path.test.js +51 -0
  115. package/dist/lib/describe-output-path.test.js.map +1 -0
  116. package/dist/lib/describe-parser.d.ts +3 -0
  117. package/dist/lib/describe-parser.d.ts.map +1 -0
  118. package/dist/lib/describe-parser.js +163 -0
  119. package/dist/lib/describe-parser.js.map +1 -0
  120. package/dist/lib/describe-parser.test.d.ts +2 -0
  121. package/dist/lib/describe-parser.test.d.ts.map +1 -0
  122. package/dist/lib/describe-parser.test.js +282 -0
  123. package/dist/lib/describe-parser.test.js.map +1 -0
  124. package/dist/lib/description-executor.d.ts +22 -0
  125. package/dist/lib/description-executor.d.ts.map +1 -0
  126. package/dist/lib/description-executor.js +72 -0
  127. package/dist/lib/description-executor.js.map +1 -0
  128. package/dist/lib/description-formatter.d.ts +37 -0
  129. package/dist/lib/description-formatter.d.ts.map +1 -0
  130. package/dist/lib/description-formatter.js +219 -0
  131. package/dist/lib/description-formatter.js.map +1 -0
  132. package/dist/lib/diff-parser.d.ts +11 -0
  133. package/dist/lib/diff-parser.d.ts.map +1 -1
  134. package/dist/lib/diff-parser.js +37 -0
  135. package/dist/lib/diff-parser.js.map +1 -1
  136. package/dist/lib/issue-parser.d.ts +1 -1
  137. package/dist/lib/issue-parser.d.ts.map +1 -1
  138. package/dist/lib/issue-parser.js +16 -14
  139. package/dist/lib/issue-parser.js.map +1 -1
  140. package/dist/lib/json-output-schema.d.ts +207 -0
  141. package/dist/lib/json-output-schema.d.ts.map +1 -0
  142. package/dist/lib/json-output-schema.js +124 -0
  143. package/dist/lib/json-output-schema.js.map +1 -0
  144. package/dist/lib/json-output-schema.test.d.ts +2 -0
  145. package/dist/lib/json-output-schema.test.d.ts.map +1 -0
  146. package/dist/lib/json-output-schema.test.js +92 -0
  147. package/dist/lib/json-output-schema.test.js.map +1 -0
  148. package/dist/lib/json-output.d.ts +43 -0
  149. package/dist/lib/json-output.d.ts.map +1 -0
  150. package/dist/lib/json-output.js +34 -0
  151. package/dist/lib/json-output.js.map +1 -0
  152. package/dist/lib/output-paths.d.ts +6 -0
  153. package/dist/lib/output-paths.d.ts.map +1 -0
  154. package/dist/lib/output-paths.js +5 -0
  155. package/dist/lib/output-paths.js.map +1 -0
  156. package/dist/lib/platform-client.d.ts +1 -1
  157. package/dist/lib/platform-client.d.ts.map +1 -1
  158. package/dist/lib/repository-validator.d.ts +57 -0
  159. package/dist/lib/repository-validator.d.ts.map +1 -0
  160. package/dist/lib/repository-validator.js +225 -0
  161. package/dist/lib/repository-validator.js.map +1 -0
  162. package/dist/lib/repository-validator.test.d.ts +5 -0
  163. package/dist/lib/repository-validator.test.d.ts.map +1 -0
  164. package/dist/lib/repository-validator.test.js +341 -0
  165. package/dist/lib/repository-validator.test.js.map +1 -0
  166. package/dist/lib/review-core.d.ts +66 -0
  167. package/dist/lib/review-core.d.ts.map +1 -0
  168. package/dist/lib/review-core.js +449 -0
  169. package/dist/lib/review-core.js.map +1 -0
  170. package/dist/lib/review-core.test.d.ts +2 -0
  171. package/dist/lib/review-core.test.d.ts.map +1 -0
  172. package/dist/lib/review-core.test.js +552 -0
  173. package/dist/lib/review-core.test.js.map +1 -0
  174. package/dist/lib/review-orchestrator.d.ts +27 -10
  175. package/dist/lib/review-orchestrator.d.ts.map +1 -1
  176. package/dist/lib/review-orchestrator.js +51 -110
  177. package/dist/lib/review-orchestrator.js.map +1 -1
  178. package/dist/lib/review-orchestrator.test.d.ts +2 -0
  179. package/dist/lib/review-orchestrator.test.d.ts.map +1 -0
  180. package/dist/lib/review-orchestrator.test.js +413 -0
  181. package/dist/lib/review-orchestrator.test.js.map +1 -0
  182. package/dist/lib/review-output-path.test.d.ts +2 -0
  183. package/dist/lib/review-output-path.test.d.ts.map +1 -0
  184. package/dist/lib/review-output-path.test.js +83 -0
  185. package/dist/lib/review-output-path.test.js.map +1 -0
  186. package/dist/lib/review-parser.d.ts +2 -0
  187. package/dist/lib/review-parser.d.ts.map +1 -0
  188. package/dist/lib/review-parser.js +100 -0
  189. package/dist/lib/review-parser.js.map +1 -0
  190. package/dist/lib/unified-review-executor.d.ts +21 -4
  191. package/dist/lib/unified-review-executor.d.ts.map +1 -1
  192. package/dist/lib/unified-review-executor.js +84 -151
  193. package/dist/lib/unified-review-executor.js.map +1 -1
  194. package/dist/lib/unified-review-executor.test.d.ts +5 -0
  195. package/dist/lib/unified-review-executor.test.d.ts.map +1 -0
  196. package/dist/lib/unified-review-executor.test.js +350 -0
  197. package/dist/lib/unified-review-executor.test.js.map +1 -0
  198. package/dist/lib/write-json-output.d.ts +13 -0
  199. package/dist/lib/write-json-output.d.ts.map +1 -0
  200. package/dist/lib/write-json-output.js +37 -0
  201. package/dist/lib/write-json-output.js.map +1 -0
  202. package/dist/opencode/agent-loader.d.ts +3 -4
  203. package/dist/opencode/agent-loader.d.ts.map +1 -1
  204. package/dist/opencode/agent-loader.js +48 -34
  205. package/dist/opencode/agent-loader.js.map +1 -1
  206. package/dist/opencode/agent-skill-overlay.d.ts +11 -0
  207. package/dist/opencode/agent-skill-overlay.d.ts.map +1 -0
  208. package/dist/opencode/agent-skill-overlay.js +164 -0
  209. package/dist/opencode/agent-skill-overlay.js.map +1 -0
  210. package/dist/opencode/client.d.ts +11 -3
  211. package/dist/opencode/client.d.ts.map +1 -1
  212. package/dist/opencode/client.js +237 -71
  213. package/dist/opencode/client.js.map +1 -1
  214. package/dist/opencode/client.test.d.ts +2 -0
  215. package/dist/opencode/client.test.d.ts.map +1 -0
  216. package/dist/opencode/client.test.js +317 -0
  217. package/dist/opencode/client.test.js.map +1 -0
  218. package/dist/opencode/opencode-paths.d.ts +2 -0
  219. package/dist/opencode/opencode-paths.d.ts.map +1 -0
  220. package/dist/opencode/opencode-paths.js +7 -0
  221. package/dist/opencode/opencode-paths.js.map +1 -0
  222. package/dist/opencode/skill-loader.d.ts +6 -0
  223. package/dist/opencode/skill-loader.d.ts.map +1 -0
  224. package/dist/opencode/skill-loader.js +36 -0
  225. package/dist/opencode/skill-loader.js.map +1 -0
  226. package/package.json +7 -7
  227. package/.opencode/agent/github-reviewer.md +0 -77
  228. package/.opencode/agent/gitlab-reviewer.md +0 -77
  229. package/.opencode/agent/local-reviewer.md +0 -63
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Repository validation utilities for PR/MR reviews
3
+ *
4
+ * This module handles repository and branch validation to ensure
5
+ * that reviews are run from the correct repository and branch.
6
+ */
7
+ import simpleGit from 'simple-git';
8
+ /**
9
+ * Normalize a repository path by removing leading slashes and .git suffix
10
+ */
11
+ export function normalizeRepoPath(path) {
12
+ return path
13
+ .replace(/^\/+/, '')
14
+ .replace(/\.git$/i, '')
15
+ .toLowerCase();
16
+ }
17
+ /**
18
+ * Parse a git remote URL to extract host and repository path
19
+ */
20
+ export function parseRemoteUrl(remoteUrl) {
21
+ if (!remoteUrl)
22
+ return null;
23
+ const trimmed = remoteUrl.trim();
24
+ // SSH format: git@github.com:owner/repo.git
25
+ const sshMatch = trimmed.match(/^[^@]+@([^:]+):(.+)$/);
26
+ if (sshMatch) {
27
+ return { host: sshMatch[1], repoPath: sshMatch[2], remoteUrl: trimmed };
28
+ }
29
+ // HTTP/HTTPS format
30
+ if (trimmed.startsWith('ssh://') ||
31
+ trimmed.startsWith('http://') ||
32
+ trimmed.startsWith('https://')) {
33
+ try {
34
+ const url = new URL(trimmed);
35
+ return {
36
+ host: url.hostname,
37
+ repoPath: url.pathname.replace(/^\/+/, ''),
38
+ remoteUrl: trimmed,
39
+ };
40
+ }
41
+ catch {
42
+ return null;
43
+ }
44
+ }
45
+ return null;
46
+ }
47
+ /**
48
+ * Extract expected repository info from PR/MR platform data
49
+ */
50
+ export function getExpectedRepoInfo(pr, projectId) {
51
+ const data = pr?.platformData;
52
+ // GitHub format
53
+ if (data?.base?.repo?.full_name) {
54
+ const hostUrl = data.base.repo.html_url ?? data.base.repo.clone_url ?? data.base.repo.ssh_url;
55
+ const hostInfo = hostUrl ? parseRemoteUrl(hostUrl) : null;
56
+ return {
57
+ host: hostInfo?.host ?? 'github.com',
58
+ repoPath: data.base.repo.full_name,
59
+ };
60
+ }
61
+ // GitLab numeric project ID with slash format
62
+ if (typeof projectId === 'string' && projectId.includes('/')) {
63
+ return { repoPath: projectId };
64
+ }
65
+ // GitLab web_url format
66
+ if (typeof data?.web_url === 'string') {
67
+ const info = parseRemoteUrl(data.web_url);
68
+ if (info?.repoPath) {
69
+ const pathWithoutSuffix = info.repoPath.replace(/\/-\/.*$/, '');
70
+ return { host: info.host, repoPath: pathWithoutSuffix };
71
+ }
72
+ }
73
+ return null;
74
+ }
75
+ /**
76
+ * Normalize a base branch name by adding origin/ prefix if needed
77
+ */
78
+ export function normalizeBaseBranch(baseBranch) {
79
+ if (!baseBranch)
80
+ return undefined;
81
+ return baseBranch.startsWith('origin/') ? baseBranch : `origin/${baseBranch}`;
82
+ }
83
+ /**
84
+ * Resolve the base branch from CLI, environment variables, or PR/MR data
85
+ */
86
+ export function resolveBaseBranch(cliBaseBranch, targetBranch) {
87
+ // CLI argument takes highest priority
88
+ if (cliBaseBranch) {
89
+ const resolved = normalizeBaseBranch(cliBaseBranch);
90
+ return {
91
+ baseBranch: cliBaseBranch,
92
+ resolvedBaseBranch: resolved,
93
+ source: 'cli',
94
+ };
95
+ }
96
+ // DRS-specific environment variable
97
+ if (process.env.DRS_BASE_BRANCH) {
98
+ const resolved = normalizeBaseBranch(process.env.DRS_BASE_BRANCH);
99
+ return {
100
+ baseBranch: process.env.DRS_BASE_BRANCH,
101
+ resolvedBaseBranch: resolved,
102
+ source: 'env:DRS_BASE_BRANCH',
103
+ };
104
+ }
105
+ // GitHub Actions environment variable
106
+ if (process.env.GITHUB_BASE_REF) {
107
+ const resolved = normalizeBaseBranch(process.env.GITHUB_BASE_REF);
108
+ return {
109
+ baseBranch: process.env.GITHUB_BASE_REF,
110
+ resolvedBaseBranch: resolved,
111
+ source: 'env:GITHUB_BASE_REF',
112
+ };
113
+ }
114
+ // GitLab CI environment variable
115
+ if (process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME) {
116
+ const resolved = normalizeBaseBranch(process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME);
117
+ return {
118
+ baseBranch: process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME,
119
+ resolvedBaseBranch: resolved,
120
+ source: 'env:CI_MERGE_REQUEST_TARGET_BRANCH_NAME',
121
+ };
122
+ }
123
+ // Fall back to PR/MR target branch
124
+ if (targetBranch) {
125
+ const resolved = normalizeBaseBranch(targetBranch);
126
+ return {
127
+ baseBranch: targetBranch,
128
+ resolvedBaseBranch: resolved,
129
+ source: 'pr:targetBranch',
130
+ };
131
+ }
132
+ return {};
133
+ }
134
+ /**
135
+ * Generate a canonical git diff command for documentation purposes
136
+ */
137
+ export function getCanonicalDiffCommand(pr, baseBranchResolution) {
138
+ // GitHub Actions environment
139
+ const githubBase = process.env.GITHUB_BASE_REF;
140
+ const githubHead = process.env.GITHUB_HEAD_REF;
141
+ if (githubBase && githubHead) {
142
+ return `git diff origin/${githubBase} origin/${githubHead} -- <file>`;
143
+ }
144
+ // GitLab CI environment
145
+ const gitlabBase = process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME;
146
+ const gitlabHead = process.env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME;
147
+ if (gitlabBase && gitlabHead) {
148
+ return `git diff origin/${gitlabBase} origin/${gitlabHead} -- <file>`;
149
+ }
150
+ // PR/MR data
151
+ if (pr.targetBranch && pr.sourceBranch) {
152
+ return `git diff origin/${pr.targetBranch} origin/${pr.sourceBranch} -- <file>`;
153
+ }
154
+ // Resolved base branch
155
+ if (baseBranchResolution.resolvedBaseBranch) {
156
+ return `git diff ${baseBranchResolution.resolvedBaseBranch}...HEAD -- <file>`;
157
+ }
158
+ return 'git diff -- <file>';
159
+ }
160
+ /**
161
+ * Enforce that the current working directory matches the PR/MR repository and branch
162
+ *
163
+ * This prevents accidentally reviewing the wrong repository or branch.
164
+ *
165
+ * @param skipRepoCheck - If true, skip repository validation (default: false)
166
+ * @param skipBranchCheck - If true, skip branch validation (default: false)
167
+ * @throws Error if repository or branch doesn't match
168
+ */
169
+ export async function enforceRepoBranchMatch(workingDir, projectId, pr, options) {
170
+ const git = simpleGit({ baseDir: workingDir });
171
+ // Check if this is a git repository
172
+ const isRepo = await git.checkIsRepo();
173
+ if (!isRepo) {
174
+ throw new Error('Not a git repository. Run review from the PR/MR repository checkout.');
175
+ }
176
+ // Get current branch and commit
177
+ const branchSummary = await git.branch();
178
+ const currentBranch = branchSummary.current;
179
+ const headSha = (await git.revparse(['HEAD'])).trim();
180
+ // Get remote URL
181
+ const remotes = await git.getRemotes(true);
182
+ const origin = remotes.find((r) => r.name === 'origin') ?? remotes[0];
183
+ const remoteUrl = origin?.refs?.fetch ?? origin?.refs?.push;
184
+ if (!remoteUrl) {
185
+ throw new Error('No git remotes found. Cannot validate repository match for PR/MR.');
186
+ }
187
+ // Parse local repository info
188
+ const localRepo = parseRemoteUrl(remoteUrl);
189
+ if (!localRepo?.repoPath) {
190
+ throw new Error(`Unable to parse git remote URL: ${remoteUrl}`);
191
+ }
192
+ // Get expected repository info from PR/MR
193
+ const expectedRepo = getExpectedRepoInfo(pr, projectId);
194
+ if (!expectedRepo?.repoPath) {
195
+ throw new Error('Unable to determine expected repository from PR/MR data.');
196
+ }
197
+ // Validate repository match (unless skipRepoCheck is enabled)
198
+ if (!options?.skipRepoCheck) {
199
+ const localRepoPath = normalizeRepoPath(localRepo.repoPath);
200
+ const expectedRepoPath = normalizeRepoPath(expectedRepo.repoPath);
201
+ const hostMismatch = expectedRepo.host &&
202
+ localRepo.host &&
203
+ expectedRepo.host.toLowerCase() !== localRepo.host.toLowerCase();
204
+ const repoMismatch = localRepoPath !== expectedRepoPath;
205
+ if (hostMismatch || repoMismatch) {
206
+ throw new Error(`Repository mismatch for PR/MR review.\n` +
207
+ `Local repo: ${localRepo.host ? `${localRepo.host}/` : ''}${localRepoPath}\n` +
208
+ `Expected: ${expectedRepo.host ? `${expectedRepo.host}/` : ''}${expectedRepoPath}\n` +
209
+ `Run the review from the PR/MR repository checkout.`);
210
+ }
211
+ }
212
+ // Validate branch match (unless skipBranchCheck is enabled)
213
+ if (!options?.skipBranchCheck) {
214
+ const expectedBranch = pr.sourceBranch;
215
+ const branchMatches = currentBranch === expectedBranch;
216
+ const shaMatches = pr.headSha ? headSha === pr.headSha : false;
217
+ if (!branchMatches && !shaMatches) {
218
+ throw new Error(`Branch mismatch for PR/MR review.\n` +
219
+ `Local branch: ${currentBranch ?? '(unknown)'}\n` +
220
+ `Expected branch: ${expectedBranch}\n` +
221
+ `Check out the PR/MR source branch before running the review.`);
222
+ }
223
+ }
224
+ }
225
+ //# sourceMappingURL=repository-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository-validator.js","sourceRoot":"","sources":["../../src/lib/repository-validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for repository-validator.ts
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=repository-validator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository-validator.test.d.ts","sourceRoot":"","sources":["../../src/lib/repository-validator.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Tests for repository-validator.ts
3
+ */
4
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
5
+ import { normalizeRepoPath, parseRemoteUrl, getExpectedRepoInfo, normalizeBaseBranch, resolveBaseBranch, getCanonicalDiffCommand, enforceRepoBranchMatch, } from './repository-validator.js';
6
+ describe('repository-validator', () => {
7
+ describe('normalizeRepoPath', () => {
8
+ it('should remove leading slashes', () => {
9
+ expect(normalizeRepoPath('/owner/repo')).toBe('owner/repo');
10
+ expect(normalizeRepoPath('///owner/repo')).toBe('owner/repo');
11
+ });
12
+ it('should remove .git suffix', () => {
13
+ expect(normalizeRepoPath('owner/repo.git')).toBe('owner/repo');
14
+ expect(normalizeRepoPath('owner/repo.GIT')).toBe('owner/repo');
15
+ });
16
+ it('should convert to lowercase', () => {
17
+ expect(normalizeRepoPath('Owner/Repo')).toBe('owner/repo');
18
+ expect(normalizeRepoPath('OWNER/REPO')).toBe('owner/repo');
19
+ });
20
+ it('should handle combined transformations', () => {
21
+ expect(normalizeRepoPath('/Owner/Repo.git')).toBe('owner/repo');
22
+ });
23
+ });
24
+ describe('parseRemoteUrl', () => {
25
+ it('should parse SSH format', () => {
26
+ const result = parseRemoteUrl('git@github.com:owner/repo.git');
27
+ expect(result).toEqual({
28
+ host: 'github.com',
29
+ repoPath: 'owner/repo.git',
30
+ remoteUrl: 'git@github.com:owner/repo.git',
31
+ });
32
+ });
33
+ it('should parse HTTPS format', () => {
34
+ const result = parseRemoteUrl('https://github.com/owner/repo.git');
35
+ expect(result).toEqual({
36
+ host: 'github.com',
37
+ repoPath: 'owner/repo.git',
38
+ remoteUrl: 'https://github.com/owner/repo.git',
39
+ });
40
+ });
41
+ it('should parse HTTP format', () => {
42
+ const result = parseRemoteUrl('http://gitlab.com/owner/repo.git');
43
+ expect(result).toEqual({
44
+ host: 'gitlab.com',
45
+ repoPath: 'owner/repo.git',
46
+ remoteUrl: 'http://gitlab.com/owner/repo.git',
47
+ });
48
+ });
49
+ it('should parse ssh:// format', () => {
50
+ const result = parseRemoteUrl('ssh://git@github.com/owner/repo.git');
51
+ expect(result).toEqual({
52
+ host: 'github.com',
53
+ repoPath: 'owner/repo.git',
54
+ remoteUrl: 'ssh://git@github.com/owner/repo.git',
55
+ });
56
+ });
57
+ it('should return null for empty string', () => {
58
+ expect(parseRemoteUrl('')).toBeNull();
59
+ });
60
+ it('should return null for invalid URL', () => {
61
+ expect(parseRemoteUrl('not-a-url')).toBeNull();
62
+ });
63
+ it('should handle URLs with trailing slashes', () => {
64
+ const result = parseRemoteUrl('https://github.com/owner/repo.git/');
65
+ expect(result?.repoPath).toBe('owner/repo.git/');
66
+ });
67
+ });
68
+ describe('getExpectedRepoInfo', () => {
69
+ it('should extract GitHub repository info from full_name', () => {
70
+ const pr = {
71
+ platformData: {
72
+ base: {
73
+ repo: {
74
+ full_name: 'owner/repo',
75
+ html_url: 'https://github.com/owner/repo',
76
+ },
77
+ },
78
+ },
79
+ };
80
+ const result = getExpectedRepoInfo(pr, 'ignored');
81
+ expect(result).toEqual({
82
+ host: 'github.com',
83
+ repoPath: 'owner/repo',
84
+ });
85
+ });
86
+ it('should use clone_url if html_url is missing', () => {
87
+ const pr = {
88
+ platformData: {
89
+ base: {
90
+ repo: {
91
+ full_name: 'owner/repo',
92
+ clone_url: 'https://github.com/owner/repo.git',
93
+ },
94
+ },
95
+ },
96
+ };
97
+ const result = getExpectedRepoInfo(pr, 'ignored');
98
+ expect(result).toEqual({
99
+ host: 'github.com',
100
+ repoPath: 'owner/repo',
101
+ });
102
+ });
103
+ it('should use ssh_url if html_url and clone_url are missing', () => {
104
+ const pr = {
105
+ platformData: {
106
+ base: {
107
+ repo: {
108
+ full_name: 'owner/repo',
109
+ ssh_url: 'git@github.com:owner/repo.git',
110
+ },
111
+ },
112
+ },
113
+ };
114
+ const result = getExpectedRepoInfo(pr, 'ignored');
115
+ expect(result).toEqual({
116
+ host: 'github.com',
117
+ repoPath: 'owner/repo',
118
+ });
119
+ });
120
+ it('should use default github.com if no URL is provided', () => {
121
+ const pr = {
122
+ platformData: {
123
+ base: {
124
+ repo: {
125
+ full_name: 'owner/repo',
126
+ },
127
+ },
128
+ },
129
+ };
130
+ const result = getExpectedRepoInfo(pr, 'ignored');
131
+ expect(result).toEqual({
132
+ host: 'github.com',
133
+ repoPath: 'owner/repo',
134
+ });
135
+ });
136
+ it('should handle GitLab project ID with slash format', () => {
137
+ const pr = {};
138
+ const result = getExpectedRepoInfo(pr, 'owner/repo');
139
+ expect(result).toEqual({
140
+ repoPath: 'owner/repo',
141
+ });
142
+ });
143
+ it('should parse GitLab web_url', () => {
144
+ const pr = {
145
+ platformData: {
146
+ web_url: 'https://gitlab.com/owner/repo/-/merge_requests/123',
147
+ },
148
+ };
149
+ const result = getExpectedRepoInfo(pr, '12345');
150
+ expect(result).toEqual({
151
+ host: 'gitlab.com',
152
+ repoPath: 'owner/repo',
153
+ });
154
+ });
155
+ it('should return null for empty platform data', () => {
156
+ const pr = {};
157
+ const result = getExpectedRepoInfo(pr, '12345');
158
+ expect(result).toBeNull();
159
+ });
160
+ });
161
+ describe('normalizeBaseBranch', () => {
162
+ it('should add origin/ prefix if not present', () => {
163
+ expect(normalizeBaseBranch('main')).toBe('origin/main');
164
+ expect(normalizeBaseBranch('develop')).toBe('origin/develop');
165
+ });
166
+ it('should not duplicate origin/ prefix', () => {
167
+ expect(normalizeBaseBranch('origin/main')).toBe('origin/main');
168
+ expect(normalizeBaseBranch('origin/develop')).toBe('origin/develop');
169
+ });
170
+ it('should return undefined for undefined input', () => {
171
+ expect(normalizeBaseBranch(undefined)).toBeUndefined();
172
+ });
173
+ it('should return undefined for empty string', () => {
174
+ expect(normalizeBaseBranch('')).toBeUndefined();
175
+ });
176
+ });
177
+ describe('resolveBaseBranch', () => {
178
+ const originalEnv = process.env;
179
+ beforeEach(() => {
180
+ process.env = { ...originalEnv };
181
+ // Clear all branch-related env vars for test isolation
182
+ delete process.env.DRS_BASE_BRANCH;
183
+ delete process.env.GITHUB_BASE_REF;
184
+ delete process.env.GITHUB_HEAD_REF;
185
+ delete process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME;
186
+ delete process.env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME;
187
+ });
188
+ afterEach(() => {
189
+ process.env = originalEnv;
190
+ });
191
+ it('should prioritize CLI argument', () => {
192
+ process.env.DRS_BASE_BRANCH = 'env-branch';
193
+ const result = resolveBaseBranch('cli-branch', 'pr-branch');
194
+ expect(result).toEqual({
195
+ baseBranch: 'cli-branch',
196
+ resolvedBaseBranch: 'origin/cli-branch',
197
+ source: 'cli',
198
+ });
199
+ });
200
+ it('should use DRS_BASE_BRANCH env var if CLI not provided', () => {
201
+ process.env.DRS_BASE_BRANCH = 'env-branch';
202
+ const result = resolveBaseBranch(undefined, 'pr-branch');
203
+ expect(result).toEqual({
204
+ baseBranch: 'env-branch',
205
+ resolvedBaseBranch: 'origin/env-branch',
206
+ source: 'env:DRS_BASE_BRANCH',
207
+ });
208
+ });
209
+ it('should use GITHUB_BASE_REF env var', () => {
210
+ process.env.GITHUB_BASE_REF = 'github-branch';
211
+ const result = resolveBaseBranch(undefined, 'pr-branch');
212
+ expect(result).toEqual({
213
+ baseBranch: 'github-branch',
214
+ resolvedBaseBranch: 'origin/github-branch',
215
+ source: 'env:GITHUB_BASE_REF',
216
+ });
217
+ });
218
+ it('should use CI_MERGE_REQUEST_TARGET_BRANCH_NAME env var', () => {
219
+ process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME = 'gitlab-branch';
220
+ const result = resolveBaseBranch(undefined, 'pr-branch');
221
+ expect(result).toEqual({
222
+ baseBranch: 'gitlab-branch',
223
+ resolvedBaseBranch: 'origin/gitlab-branch',
224
+ source: 'env:CI_MERGE_REQUEST_TARGET_BRANCH_NAME',
225
+ });
226
+ });
227
+ it('should fall back to PR target branch', () => {
228
+ const result = resolveBaseBranch(undefined, 'pr-branch');
229
+ expect(result).toEqual({
230
+ baseBranch: 'pr-branch',
231
+ resolvedBaseBranch: 'origin/pr-branch',
232
+ source: 'pr:targetBranch',
233
+ });
234
+ });
235
+ it('should return empty object if no sources available', () => {
236
+ const result = resolveBaseBranch(undefined, undefined);
237
+ expect(result).toEqual({});
238
+ });
239
+ it('should respect environment variable precedence', () => {
240
+ process.env.DRS_BASE_BRANCH = 'drs-branch';
241
+ process.env.GITHUB_BASE_REF = 'github-branch';
242
+ process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME = 'gitlab-branch';
243
+ const result = resolveBaseBranch(undefined, 'pr-branch');
244
+ expect(result.source).toBe('env:DRS_BASE_BRANCH');
245
+ });
246
+ });
247
+ describe('getCanonicalDiffCommand', () => {
248
+ const originalEnv = process.env;
249
+ beforeEach(() => {
250
+ process.env = { ...originalEnv };
251
+ // Clear all branch-related env vars for test isolation
252
+ delete process.env.DRS_BASE_BRANCH;
253
+ delete process.env.GITHUB_BASE_REF;
254
+ delete process.env.GITHUB_HEAD_REF;
255
+ delete process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME;
256
+ delete process.env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME;
257
+ });
258
+ afterEach(() => {
259
+ process.env = originalEnv;
260
+ });
261
+ it('should use GitHub Actions environment variables', () => {
262
+ process.env.GITHUB_BASE_REF = 'main';
263
+ process.env.GITHUB_HEAD_REF = 'feature';
264
+ const pr = {
265
+ number: 123,
266
+ title: 'Test PR',
267
+ author: 'test-user',
268
+ sourceBranch: 'feature',
269
+ targetBranch: 'main',
270
+ headSha: 'abc123',
271
+ };
272
+ const result = getCanonicalDiffCommand(pr, {});
273
+ expect(result).toBe('git diff origin/main origin/feature -- <file>');
274
+ });
275
+ it('should use GitLab CI environment variables', () => {
276
+ process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME = 'main';
277
+ process.env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME = 'feature';
278
+ const pr = {
279
+ number: 123,
280
+ title: 'Test MR',
281
+ author: 'test-user',
282
+ sourceBranch: 'feature',
283
+ targetBranch: 'main',
284
+ headSha: 'abc123',
285
+ };
286
+ const result = getCanonicalDiffCommand(pr, {});
287
+ expect(result).toBe('git diff origin/main origin/feature -- <file>');
288
+ });
289
+ it('should use PR/MR branch data if no env vars', () => {
290
+ const pr = {
291
+ number: 123,
292
+ title: 'Test PR',
293
+ author: 'test-user',
294
+ sourceBranch: 'feature',
295
+ targetBranch: 'main',
296
+ headSha: 'abc123',
297
+ };
298
+ const result = getCanonicalDiffCommand(pr, {});
299
+ expect(result).toBe('git diff origin/main origin/feature -- <file>');
300
+ });
301
+ it('should use resolved base branch', () => {
302
+ const pr = {
303
+ number: 123,
304
+ title: 'Test PR',
305
+ author: 'test-user',
306
+ sourceBranch: '',
307
+ targetBranch: '',
308
+ headSha: 'abc123',
309
+ };
310
+ const baseBranchResolution = {
311
+ baseBranch: 'develop',
312
+ resolvedBaseBranch: 'origin/develop',
313
+ source: 'cli',
314
+ };
315
+ const result = getCanonicalDiffCommand(pr, baseBranchResolution);
316
+ expect(result).toBe('git diff origin/develop...HEAD -- <file>');
317
+ });
318
+ it('should return generic diff command as fallback', () => {
319
+ const pr = {
320
+ number: 123,
321
+ title: 'Test PR',
322
+ author: 'test-user',
323
+ sourceBranch: '',
324
+ targetBranch: '',
325
+ headSha: 'abc123',
326
+ };
327
+ const result = getCanonicalDiffCommand(pr, {});
328
+ expect(result).toBe('git diff -- <file>');
329
+ });
330
+ });
331
+ describe('enforceRepoBranchMatch', () => {
332
+ it('should be defined and exported', () => {
333
+ expect(enforceRepoBranchMatch).toBeDefined();
334
+ expect(typeof enforceRepoBranchMatch).toBe('function');
335
+ });
336
+ // Note: Full integration tests for enforceRepoBranchMatch require complex
337
+ // mocking of simple-git operations and are better tested as integration tests
338
+ // with actual git repositories or comprehensive mocks in CLI tests.
339
+ });
340
+ });
341
+ //# sourceMappingURL=repository-validator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository-validator.test.js","sourceRoot":"","sources":["../../src/lib/repository-validator.test.ts"],"names":[],"mappings":"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"}