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

const makeCreateRepository: ServiceMethodFactory<
  RepositoryServiceDeps,
  [CreateRepositoryDTO],
  Promise<Repository>
> = ({ request }) => {
  return async ({ parentOrgSlug, repoSlug, repoData, repoInitFlags }) => {
    const {
      orgRepositoriesDir,
      withBaseReadmeFile: _,
      withLicense: __,
      withLicenseKind: ___,
    } = repoInitFlags;

    const parentOrg = await request.prisma.organization.findUnique({
      where: {
        slug: parentOrgSlug,
      },
    });

    if (parentOrg == null) {
      throw new Error(
        `Could not find the parent organization to create new repository in.`
      );
    }

    console.log(
      `[..] creating repository "${parentOrg.slug}/${repoSlug}" in database`
    );

    const newRepo = await request.prisma.repository.create({
      data: {
        ...repoData,
        organizationId: parentOrg.id,
        slug: repoSlug,
      },
    });

    console.log(
      `[ok] created repository in database with id "${newRepo.id}" and slug "${parentOrg.slug}/${newRepo.slug}"!`
    );

    if (existsSync(orgRepositoriesDir.toString()) === false) {
      console.log(`[..] creating organization directory...`);
      await mkdir(orgRepositoriesDir.toString(), { recursive: true });
      console.log(
        `[ok] created organization directory in:`,
        orgRepositoriesDir
      );
    }

    console.log(
      `[..] creating repository folder with "git init --bare --shared=group" in org directory:`,
      orgRepositoriesDir
    );

    const gitInitBareRepoProcess = spawn(
      "git",
      [
        "init",
        "--bare",
        `--initial-branch=${Const.PRIMARY_BRANCH_REF}`,
        "--shared=group",
        `${newRepo.slug}.git`,
      ],
      {
        cwd: orgRepositoriesDir.toString(),
        env: {
          LANG: "C",
        },
      }
    );

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

    console.log(
      `[ok] finished execution of "git init --bare --shared=group" with result:\n\t`,
      gitInitBareRepoResult
    );

    return newRepo;
  };
};

export default makeCreateRepository;