chore: update src/lib/pr-dependencies.ts
swadhinbiswas committed 8 months ago
93b5e3c
1 parent 556e308
commit 93b5e3c
1 file changed
+88 -5
Showing 1 changed file+88-5
▼src/lib/pr-dependencies.ts
+88-5
| @@ -6,6 +6,7 @@ | ||
6 | 6 | import { getDatabase, schema } from "@/db"; |
7 | 7 | import { eq, and, inArray } from "drizzle-orm"; |
8 | 8 | import { logger } from "./logger"; |
9 | +import { getChangedFiles } from "./git"; | |
9 | 10 | |
10 | 11 | export interface PRDependency { |
11 | 12 | prId: string; |
| @@ -88,17 +89,99 @@ export async function detectBranchDependencies( | ||
88 | 89 | export async function detectFileDependencies( |
89 | 90 | repositoryId: string |
90 | 91 | ): Promise<{ conflicting: { pr1: string; pr2: string; files: string[] }[] }> { |
91 | - // Note: This would require accessing git diff data | |
92 | - // For now, return empty - implementation would need git integration | |
93 | - logger.info({ repositoryId }, "File dependency detection not yet implemented"); | |
94 | - return { conflicting: [] }; | |
92 | + const db = getDatabase(); | |
93 | + | |
94 | + const repo = await db.query.repositories.findFirst({ | |
95 | + where: eq(schema.repositories.id, repositoryId), | |
96 | + }); | |
97 | + | |
98 | + if (!repo?.diskPath) { | |
99 | + logger.warn({ repositoryId }, "Skipping file dependency detection: repository disk path not available"); | |
100 | + return { conflicting: [] }; | |
101 | + } | |
102 | + | |
103 | + const prs = await db.query.pullRequests.findMany({ | |
104 | + where: and( | |
105 | + eq(schema.pullRequests.repositoryId, repositoryId), | |
106 | + eq(schema.pullRequests.state, "open") | |
107 | + ), | |
108 | + }); | |
109 | + | |
110 | + if (prs.length < 2) { | |
111 | + return { conflicting: [] }; | |
112 | + } | |
113 | + | |
114 | + const filesByPrId = new Map<string, Set<string>>(); | |
115 | + for (const pr of prs) { | |
116 | + try { | |
117 | + const files = await getChangedFiles(repo.diskPath, pr.baseBranch, pr.headBranch); | |
118 | + filesByPrId.set(pr.id, new Set(files)); | |
119 | + } catch (error) { | |
120 | + logger.warn({ repositoryId, prId: pr.id, error }, "Failed to load PR changed files for dependency detection"); | |
121 | + filesByPrId.set(pr.id, new Set<string>()); | |
122 | + } | |
123 | + } | |
124 | + | |
125 | + const conflicting: { pr1: string; pr2: string; files: string[] }[] = []; | |
126 | + | |
127 | + for (let i = 0; i < prs.length; i++) { | |
128 | + for (let j = i + 1; j < prs.length; j++) { | |
129 | + const left = prs[i]; | |
130 | + const right = prs[j]; | |
131 | + const leftFiles = filesByPrId.get(left.id) || new Set<string>(); | |
132 | + const rightFiles = filesByPrId.get(right.id) || new Set<string>(); | |
133 | + | |
134 | + const overlap: string[] = []; | |
135 | + for (const file of leftFiles) { | |
136 | + if (rightFiles.has(file)) overlap.push(file); | |
137 | + } | |
138 | + | |
139 | + if (overlap.length > 0) { | |
140 | + conflicting.push({ | |
141 | + pr1: left.id, | |
142 | + pr2: right.id, | |
143 | + files: overlap.sort(), | |
144 | + }); | |
145 | + } | |
146 | + } | |
147 | + } | |
148 | + | |
149 | + return { conflicting }; | |
95 | 150 | } |
96 | 151 | |
97 | 152 | /** |
98 | 153 | * Get dependency graph for visualization |
99 | 154 | */ |
100 | 155 | export async function getDependencyGraph(repositoryId: string): Promise<DependencyGraph> { |
101 | - return detectBranchDependencies(repositoryId); | |
156 | + const [branchGraph, fileDeps] = await Promise.all([ | |
157 | + detectBranchDependencies(repositoryId), | |
158 | + detectFileDependencies(repositoryId), | |
159 | + ]); | |
160 | + | |
161 | + const edges = [...branchGraph.edges]; | |
162 | + for (const conflict of fileDeps.conflicting) { | |
163 | + edges.push({ | |
164 | + from: conflict.pr1, | |
165 | + to: conflict.pr2, | |
166 | + type: "files", | |
167 | + }); | |
168 | + } | |
169 | + | |
170 | + const conflictByPr = new Map<string, Set<string>>(); | |
171 | + for (const conflict of fileDeps.conflicting) { | |
172 | + if (!conflictByPr.has(conflict.pr1)) conflictByPr.set(conflict.pr1, new Set<string>()); | |
173 | + if (!conflictByPr.has(conflict.pr2)) conflictByPr.set(conflict.pr2, new Set<string>()); | |
174 | + conflictByPr.get(conflict.pr1)!.add(conflict.pr2); | |
175 | + conflictByPr.get(conflict.pr2)!.add(conflict.pr1); | |
176 | + } | |
177 | + | |
178 | + const nodes = branchGraph.nodes.map((node) => ({ | |
179 | + ...node, | |
180 | + blockedBy: Array.from(new Set([...node.blockedBy, ...(conflictByPr.get(node.prId) || [])])), | |
181 | + dependencyType: (conflictByPr.get(node.prId)?.size ? "files" : node.dependencyType) as PRDependency["dependencyType"], | |
182 | + })); | |
183 | + | |
184 | + return { nodes, edges }; | |
102 | 185 | } |
103 | 186 | |
104 | 187 | /** |
105 | 188 | |