( repoPath: string, base: string, compare: string, )
| 142 | } |
| 143 | |
| 144 | async function discoverChangedFiles( |
| 145 | repoPath: string, |
| 146 | base: string, |
| 147 | compare: string, |
| 148 | ): Promise<FileRecord[]> { |
| 149 | // Run git diff --raw and --numstat in parallel |
| 150 | const [rawResult, numstatResult] = await Promise.all([ |
| 151 | execa( |
| 152 | 'git', |
| 153 | ['diff', '--raw', '-z', '--no-color', '--no-ext-diff', '--no-abbrev', `${base}...${compare}`], |
| 154 | { |
| 155 | cwd: repoPath, |
| 156 | }, |
| 157 | ), |
| 158 | execa('git', ['diff', '--numstat', `${base}...${compare}`], { |
| 159 | cwd: repoPath, |
| 160 | }), |
| 161 | ]); |
| 162 | |
| 163 | const rawFiles = parseRawDiff(rawResult.stdout); |
| 164 | const numstatMap = parseNumstat(numstatResult.stdout); |
| 165 | |
| 166 | // Merge the data |
| 167 | return rawFiles.map((file) => { |
| 168 | const stats = numstatMap.get(file.path); |
| 169 | return { |
| 170 | path: file.path, |
| 171 | status: file.status, |
| 172 | shaA: file.shaA, |
| 173 | shaB: file.shaB, |
| 174 | linesAdded: stats?.linesAdded, |
| 175 | linesRemoved: stats?.linesRemoved, |
| 176 | }; |
| 177 | }); |
| 178 | } |
| 179 | |
| 180 | function filterDenylist(files: FileRecord[]): FileRecord[] { |
| 181 | return files.map((file) => { |
no test coverage detected
searching dependent graphs…