Skip to content

Commit

Permalink
feat: initial repo creation
Browse files Browse the repository at this point in the history
  • Loading branch information
xynydev committed Apr 15, 2024
1 parent 65d7122 commit 8b88c75
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 15 deletions.
13 changes: 13 additions & 0 deletions src/lib/ts/github/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@ export async function ghApiPost(
return { data: await res.json(), ok: res.ok };
}

export async function ghApiPut(
token: string,
path: string,
data: object
): Promise<{ ok: boolean; data: object }> {
const res = await fetch(`https://api.github.com${path}`, {
method: "put",
headers: { Authorization: `Bearer ${token}`, "X-GitHub-Api-Version": "2022-11-28" },
body: JSON.stringify(data)
});
return { data: await res.json(), ok: res.ok };
}

export async function ghApiGet(
token: string,
path: string
Expand Down
119 changes: 105 additions & 14 deletions src/routes/api/github/createRepo/+server.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,115 @@
import { createLogStream } from "$lib/ts/misc/logStream.js";
import { ghApiGet, ghApiPost, ghApiPut } from "$lib/ts/github/api";
import { createLogStream } from "$lib/ts/misc/logStream";
import type { Endpoints } from "@octokit/types";

export async function POST({ request, cookies }): Promise<Response> {
return await createLogStream(async (logStream) => {
return await createLogStream(async (log) => {
const token = cookies.get("github_oauth_token");
if (token === undefined) throw new Error("Not logged in");
const { login, name } = await request.json();

logStream.enqueue("Creating repo: " + login + "/" + name);
const res = await fetch(`https://api.github.com/repos/blue-build/template/generate`, {
method: "post",
headers: { Authorization: `Bearer ${token}` },
body: JSON.stringify({
owner: login,
name: name
})
// Create repository
log("Creating repo: " + login + "/" + name);
const repo = await ghApiPost(token, "/repos/blue-build/template/generate", {
owner: login,
name: name
});
const repo = await res.json();
if (!res.ok) {
logStream.enqueue("Repo creation failed: " + JSON.stringify(repo));
if (!repo.ok) {
log("Repo creation failed: " + JSON.stringify(repo));
} else {
logStream.enqueue("Repo created successfully!");
log("Repo created successfully!");
}
const repoData =
repo.data as Endpoints["POST /repos/{template_owner}/{template_repo}/generate"]["response"]["data"];

// hacky fix for issues caused by repository being empty right after generation
log("Taking a short break to make sure the repo gets fully generated...");
await new Promise((r) => setTimeout(r, 2000));

// Edit README.md
log("Fetching template README.md...");
const readme = await ghApiGet(token, `/repos/${repoData.full_name}/contents/README.md`);
if (!readme.ok) {
log("Fetching README failed: " + JSON.stringify(readme));
} else {
log("Fetched README successfully!");
}
const readmeData =
readme.data as Endpoints["GET /repos/{owner}/{repo}/contents/{path}"]["response"]["data"];
let readmeStr = String(atob(readmeData.content));
readmeStr = readmeStr.replaceAll("blue-build/template", repoData.full_name?.toLowerCase());
readmeStr = readmeStr.replaceAll("# BlueBuild Template", "# " + name);
const readmeUpdate = await ghApiPut(
token,
`/repos/${repoData.full_name}/contents/README.md`,
{
message: "chore(automatic): replace all reference to template in README",
content: btoa(readmeStr),
sha: readmeData.sha
}
);
if (!readmeUpdate.ok) {
log("Updating README failed: " + JSON.stringify(readme));
} else {
log("Updated README successfully!");
}

// Edit recipe.yml
log("Fetching template recipe.yml...");
const recipe = await ghApiGet(
token,
`/repos/${repoData.full_name}/contents/config/recipe.yml`
);
if (!recipe.ok) {
log("Fetching recipe failed: " + JSON.stringify(recipe));
} else {
log("Fetched recipe successfully!");
}
const recipeData =
recipe.data as Endpoints["GET /repos/{owner}/{repo}/contents/{path}"]["response"]["data"];
let recipeStr = String(atob(recipeData.content));
recipeStr = recipeStr.replaceAll("name: template", `name: ${name}`);
// update
const recipeUpdate = await ghApiPut(
token,
`/repos/${repoData.full_name}/contents/config/recipe.yml`,
{
message: "chore(automatic): change image name in recipe",
content: btoa(recipeStr),
sha: recipeData.sha
}
);
if (!recipeUpdate.ok) {
log("Updating recipe failed: " + JSON.stringify(recipe));
} else {
log("Updated recipe successfully!");
}

// This code just hangs. I think the actions are enabled by default.
// log("Enabling GitHub Actions...");
// const enableActions = await ghApiPut(
// token,
// `/repos/${repoData.full_name}/actions/permissions`,
// {
// enabled: true
// }
// );
// if (!enableActions.ok) {
// log("Enabling GitHub Actions failed: " + JSON.stringify(enableActions));
// } else {
// log("Enabled GitHub Actions successfully!");
// }
// const enableBuildYml = await ghApiPut(
// token,
// `/repos/${repoData.full_name}/actions/workflows/build.yml/enable`,
// {}
// );
// if (!enableBuildYml.ok) {
// log("Enabling build.yml workflow failed: " + JSON.stringify(enableBuildYml));
// } else {
// log("Enabled build.yml workflow successfully!");
// }

log("Initial repository setup DONE!");
});
}
6 changes: 5 additions & 1 deletion src/routes/new/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
});
readLogStream(res, (value) => {
log = [...log, value];
if (value.includes("DONE!")) {
setupStep = "cosign";
}
});
}
Expand Down Expand Up @@ -85,10 +88,11 @@
Create repository
</Button>
{:else if setupStep === "inprogress"}
<Progress value={log.length} class="mb-6" />
<Progress value={log.length} max={10} class="mb-6" />
<Log {log} />
{:else if setupStep === "cosign"}
Set up container signing
<Log {log} />
{:else}
Done!
{/if}
Expand Down

0 comments on commit 8b88c75

Please sign in to comment.