GitFOSS
.ts
TypeScript
(application/typescript)
// std
import { existsSync } from "node:fs";
import { spawn } from "node:child_process";
// 1st-party
import { ServiceMethodFactory } from "@ethicdevs/react-monolith";
// generated via script[generate:prisma]
import type { Repository } from "@prisma/client";
// app
import { Env } from "../../env";
// service
import { RepositoryServiceDeps } from "./types";

const makeGetRepositoryBranches: ServiceMethodFactory<
  RepositoryServiceDeps,
  [Repository, undefined | boolean],
  Promise<string[]>
> = ({ request }) => {
  return async (repo, onlyLocalBranches = true) => {
    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}".`
      );
    }

    const repoPath = `${Env.GIT_REPOSITORIES_ROOT}/${parentOrg.slug}/${repo.slug}.git`;

    if (existsSync(repoPath) === false) {
      return [];
    }

    try {
      const gitBranchProcess = spawn("git", ["branch", "-a"], {
        cwd: repoPath,
        env: {
          LANG: "C",
        },
      });

      const gitBranchResult = await new Promise<string>((resolve, reject) => {
        let buffer = [] as string[];
        gitBranchProcess.stdout.on("data", (data) => buffer.push(data));
        gitBranchProcess.stderr.on("data", (data) => {
          reject(new Error(Buffer.from(data).toString("utf-8")));
        });
        gitBranchProcess.stdout.on("close", () => {
          resolve(buffer.join(""));
        });
      });

      const branches = gitBranchResult
        .split("\n")
        .map((b) => b.trim().replace(/^\* /i, ""))
        .filter((b) => b != null && b.trim() !== "")
        .filter((b) => onlyLocalBranches && b.startsWith("remotes/") === false);

      return branches;
    } catch (_) {
      return [];
    }
  };
};

export default makeGetRepositoryBranches;