({ path: filePath, repo: repoName, ref }: FileBlameRequest, { source }: { source?: string } = {})
| 157 | }; |
| 158 | |
| 159 | export const getFileBlame = async ({ path: filePath, repo: repoName, ref }: FileBlameRequest, { source }: { source?: string } = {}): Promise<FileBlameResponse | ServiceError> => |
| 160 | sew(() => |
| 161 | withOptionalAuth(async ({ org, prisma, user }) => { |
| 162 | if (user) { |
| 163 | const resolvedSource = source ?? (await headers()).get('X-Sourcebot-Client-Source') ?? undefined; |
| 164 | await createAudit({ |
| 165 | action: 'user.fetched_file_blame', |
| 166 | actor: { id: user.id, type: 'user' }, |
| 167 | target: { id: org.id.toString(), type: 'org' }, |
| 168 | orgId: org.id, |
| 169 | metadata: { source: resolvedSource }, |
| 170 | }); |
| 171 | } |
| 172 | |
| 173 | const repo = await prisma.repo.findFirst({ |
| 174 | where: { name: repoName, orgId: org.id }, |
| 175 | }); |
| 176 | if (!repo) { |
| 177 | return notFound(`Repository "${repoName}" not found.`); |
| 178 | } |
| 179 | |
| 180 | if (!isPathValid(filePath)) { |
| 181 | return fileNotFound(filePath, repoName); |
| 182 | } |
| 183 | |
| 184 | if (ref !== undefined && !isGitRefValid(ref)) { |
| 185 | return invalidGitRef(ref); |
| 186 | } |
| 187 | |
| 188 | const { path: repoPath } = getRepoPath(repo); |
| 189 | const git = simpleGit().cwd(repoPath); |
| 190 | |
| 191 | const gitRef = ref ?? repo.defaultBranch ?? 'HEAD'; |
| 192 | |
| 193 | let porcelain: string; |
| 194 | try { |
| 195 | porcelain = await git.raw(['blame', '--porcelain', gitRef, '--', filePath]); |
| 196 | } catch (error: unknown) { |
| 197 | const errorMessage = error instanceof Error ? error.message : String(error); |
| 198 | if (errorMessage.includes('no such path') || errorMessage.includes('does not exist') || errorMessage.includes('fatal: path') || errorMessage.includes('no such file')) { |
| 199 | return fileNotFound(filePath, repoName); |
| 200 | } |
| 201 | if (errorMessage.includes('unknown revision') || errorMessage.includes('bad revision') || errorMessage.includes('invalid object name')) { |
| 202 | return unresolvedGitRef(gitRef); |
| 203 | } |
| 204 | return unexpectedError(errorMessage); |
| 205 | } |
| 206 | |
| 207 | try { |
| 208 | return parsePorcelainBlame(porcelain) satisfies FileBlameResponse; |
| 209 | } catch (error: unknown) { |
| 210 | const errorMessage = error instanceof Error ? error.message : String(error); |
| 211 | return unexpectedError(`Failed to parse git blame output: ${errorMessage}`); |
| 212 | } |
| 213 | }) |
| 214 | ); |
no test coverage detected