g1t/apps/web/app/lib/add-ci.server.ts
| 1 | /** |
| 2 | * "Add CI": a starter workflow for a repository that has no checks, worked |
| 3 | * out from what is at its root (lib/starter-workflow.ts), committed on a |
| 4 | * new branch as the person asking and opened as their pull request. Its |
| 5 | * runs then become the repository's checks, and it can be required. |
| 6 | */ |
| 7 | import type { RepoPath, User } from "@g1t/contracts"; |
| 8 | |
| 9 | import { repos, work } from "./services.server"; |
| 10 | import { STARTER_PATH, freeBranch, starterDescription, starterWorkflow } from "./starter-workflow"; |
| 11 | |
| 12 | export type AddedCi = { number: number }; |
| 13 | |
| 14 | export async function addCi(user: User, path: RepoPath): Promise<{ ok: true; value: AddedCi } | { ok: false; message: string }> { |
| 15 | const repo = await repos.get(path, user); |
| 16 | if (!repo.ok) return { ok: false, message: repo.error.message }; |
| 17 | const defaultBranch = repo.value.defaultBranch; |
| 18 | const [root, branches] = await Promise.all([repos.tree(path, user, null, ""), repos.branches(path, user)]); |
| 19 | if (!root.ok) return { ok: false, message: root.error.message }; |
| 20 | if (!root.value.head) return { ok: false, message: `${defaultBranch} has no commits yet. Push a first commit, then add CI.` }; |
| 21 | const names = root.value.entries.map((entry) => entry.name); |
| 22 | const packageJson = names.includes("package.json") |
| 23 | ? await repos.blob(path, user, defaultBranch, "package.json").then((found) => (found.ok ? found.value.text : null)) |
| 24 | : null; |
| 25 | const { yaml, stacks } = starterWorkflow({ names, packageJson }, defaultBranch); |
| 26 | const branch = freeBranch(branches.ok ? branches.value.map((known) => known.name) : []); |
| 27 | const committed = await repos.commitFile(path, user, { |
| 28 | branch, |
| 29 | path: STARTER_PATH, |
| 30 | content: yaml, |
| 31 | message: "Add CI workflow", |
| 32 | }); |
| 33 | if (!committed.ok) return { ok: false, message: committed.error.message }; |
| 34 | const opened = await work.openPull(user, path, { |
| 35 | branch, |
| 36 | title: "Add CI", |
| 37 | body: starterDescription(stacks, defaultBranch), |
| 38 | agent: user.username, |
| 39 | runtime: "external", |
| 40 | }); |
| 41 | if (!opened.ok) return { ok: false, message: opened.error.message }; |
| 42 | return { ok: true, value: { number: opened.value.number } }; |
| 43 | } |