feat(repository): add support for retrieving git diff between 2 refs@@ -30,10 +30,18 @@ const getRepositoryDetailsView: ReqHandler = async (request, reply) => {
const path = "/";
const ref = "HEAD";
const repo = await repoService.getRepository(orgSlug, repoSlug);
+
if (repo == null) {
return reply.status(404).callNotFound();
}
+ const lastDiff = await repoService.getRepositoryRefDiff(
+ repo,
+ "HEAD",
+ "HEAD^^"
+ );
+ console.log("lastDiff:", lastDiff);
+
const readmeFiles = await repoService.isFileInRepositoryPath(
repo,
"",
@@ -9,6 +9,7 @@ import RepositoryExploreView, {
const getRepositoryExploreView: ReqHandler = async (request, reply) => {
const repoService = makeRepositoryService({ request });
+
const reqHandler = reply.makeRequestHandler(request, reply);
return reqHandler<RepositoryExploreViewProps>(RepositoryExploreView.name, {
repositories: await repoService.getRepositoryExploreCollection(),
@@ -0,0 +1,68 @@
+// std
+import { existsSync } from "node:fs";
+import { spawn } from "node:child_process";
+// 1st-party
+import { ServiceMethodFactory } from "@ethicdevs/react-monolith";
+// 3rd-party
+import parseDiff from "diffparser";
+// generated via script[generate:prisma]
+import type { Repository } from "@prisma/client";
+// app
+import type { RepositoryFileDiff } from "../../types";
+import { Env } from "../../env";
+// service
+import { RepositoryServiceDeps } from "./types";
+
+const makeGetRepositoryRefDiff: ServiceMethodFactory<
+ RepositoryServiceDeps,
+ [Repository, string, string | undefined],
+ Promise<RepositoryFileDiff[]>
+> = ({ request }) => {
+ return async (repo, refA, refB = undefined) => {
+ const parentOrg = await request.prisma.organization.findUnique({
+ where: {
+ id: repo.organizationId,
+ },
+ });
+
+ if (parentOrg == null) {
+ throw new Error(
+ `Could not find the parent organization for project "${repo.slug}".`
+ );
+ }
+
+ try {
+ const repoPath = `${Env.GIT_REPOSITORIES_ROOT}/${parentOrg.slug}/${repo.slug}.git`;
+ if (existsSync(repoPath) === false) {
+ throw new Error(
+ `Could not find a valid git repository at: ${repoPath}`
+ );
+ }
+
+ const gitDiffRefsProcess = spawn(
+ "git",
+ ["diff", `${refA}${refB != null ? `..${refB}` : ""}`],
+ {
+ cwd: repoPath,
+ }
+ );
+
+ const gitDiffRefsResult = await new Promise<string>((resolve, reject) => {
+ let buffer = [] as string[];
+ gitDiffRefsProcess.stdout.on("data", (data) => buffer.push(data));
+ gitDiffRefsProcess.stderr.on("data", (data) => {
+ reject(new Error(Buffer.from(data).toString("utf-8")));
+ });
+ gitDiffRefsProcess.stdout.on("close", () => {
+ resolve(buffer.join(""));
+ });
+ });
+
+ return parseDiff(gitDiffRefsResult);
+ } catch (_) {
+ return [];
+ }
+ };
+};
+
+export default makeGetRepositoryRefDiff;
@@ -13,6 +13,7 @@ import { default as makeGetRepositoryFiles } from "./getRepositoryFiles";
import { default as makeGetRepositoryHead } from "./getRepositoryHead";
import { default as makeGetRepositoryHTTPCloneUrl } from "./getRepositoryHTTPCloneUrl";
import { default as makeGetRepositorySSHCloneUrl } from "./getRepositorySSHCloneUrl";
+import { default as makeGetRepositoryRefDiff } from "./getRepositoryRefDiff";
import { default as makeIsFileInRepositoryPath } from "./isFileInRepositoryPath";
export const makeRepositoryService = makeService<
@@ -29,5 +30,6 @@ export const makeRepositoryService = makeService<
getRepositoryHead: makeGetRepositoryHead,
getRepositoryHTTPCloneUrl: makeGetRepositoryHTTPCloneUrl,
getRepositorySSHCloneUrl: makeGetRepositorySSHCloneUrl,
+ getRepositoryRefDiff: makeGetRepositoryRefDiff,
isFileInRepositoryPath: makeIsFileInRepositoryPath,
});
@@ -10,6 +10,7 @@ import type { Organization, Repository } from "@prisma/client";
import type {
RepositoryFile,
RepositoryFileContent,
+ RepositoryFileDiff,
RepositoryHead,
RepositoryLog,
} from "../../types";
@@ -62,6 +63,11 @@ export interface RepositoryServiceAPI extends ServiceApiContract {
): Promise<RepositoryHead>;
getRepositoryHTTPCloneUrl(repository: Repository): Promise<string>;
getRepositorySSHCloneUrl(repository: Repository): Promise<string>;
+ getRepositoryRefDiff(
+ repository: Repository,
+ refA: string,
+ refB?: string
+ ): Promise<RepositoryFileDiff[]>;
isFileInRepositoryPath(
repository: Repository,
path: string,
@@ -88,6 +88,33 @@ export interface RepositoryFileContent {
mimeType: string;
}
+export interface RepositoryFileDiffChunkChange {
+ type: string;
+ del: boolean;
+ oldLine?: number;
+ newLine?: number;
+ position: number;
+ content: string;
+}
+
+export interface RepositoryFileDiffChunk {
+ content: string;
+ changes: RepositoryFileDiffChunkChange[];
+ oldStart: number;
+ oldLines: number;
+ newStart: number;
+ newLines: number;
+}
+
+export interface RepositoryFileDiff {
+ additions: number;
+ deletions: number;
+ index: string[];
+ from: string;
+ to: string;
+ chunks: RepositoryFileDiffChunk[];
+}
+
export interface RepositoryLog {
commit: string;
abbreviated_commit: string;
@@ -35,6 +35,7 @@
"@prisma/client": "3.15.2",
"cross-fetch": "^3.1.5",
"cuid": "^2.1.8",
+ "diffparser": "^2.0.1",
"dotenv-flow": "^3.2.0",
"fastify": "^3.27.4",
"fastify-static": "^4.6.1",
@@ -1,5 +1,5 @@
diff --git a/node_modules/language-detect/vendor/extensions.json b/node_modules/language-detect/vendor/extensions.json
-index 903ba4e..283f806 100644
+index 903ba4e..ac2dd82 100644
--- a/node_modules/language-detect/vendor/extensions.json
+++ b/node_modules/language-detect/vendor/extensions.json
@@ -696,7 +696,8 @@
@@ -13,7 +13,7 @@ index 903ba4e..283f806 100644
".anim": "Unity3D Asset",
".asset": "Unity3D Asset",
diff --git a/node_modules/language-detect/vendor/filenames.json b/node_modules/language-detect/vendor/filenames.json
-index 18b7307..66fa064 100644
+index 18b7307..8000059 100644
--- a/node_modules/language-detect/vendor/filenames.json
+++ b/node_modules/language-detect/vendor/filenames.json
@@ -1,4 +1,5 @@
@@ -22,3 +22,12 @@ index 18b7307..66fa064 100644
"ant.xml": "Ant Build System",
"build.xml": "Ant Build System",
"CMakeLists.txt": "CMake",
+@@ -16,6 +17,8 @@
+ "Fakefile": "Fancy",
+ "ROOT": "Isabelle ROOT",
+ ".jshintrc": "JSON",
++ ".eslintrc": "JSON",
++ ".prettierrc": "JSON",
+ "composer.lock": "JSON",
+ "Jakefile": "JavaScript",
+ "ld.script": "Linker Script",
@@ -0,0 +1,7 @@
+import type { RepositoryFileDiff } from "../app/types";
+
+declare module "diffparser";
+
+export declare const parse: (diff: string) => RepositoryFileDiff[];
+
+export default parse;
@@ -1723,6 +1723,10 @@ diff@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
+diffparser@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/diffparser/-/diffparser-2.0.1.tgz#4228d5688ab2f05832c320231deda048fcfce8e7"
+
domexception@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304"