Canvas: Generate Github nodes out of the dodo-app config

Change-Id: Ifc5b09deb39352a3025f7ea66ce39b421daac94d
diff --git a/apps/canvas/back/src/github.ts b/apps/canvas/back/src/github.ts
index 7657043..df8eacf 100644
--- a/apps/canvas/back/src/github.ts
+++ b/apps/canvas/back/src/github.ts
@@ -1,34 +1,11 @@
 import axios from "axios";
-import { z } from "zod";
-
-export const GithubRepositorySchema = z.object({
-	id: z.number(),
-	name: z.string(),
-	full_name: z.string(),
-	html_url: z.string(),
-	ssh_url: z.string(),
-});
-
-const DeployKeysSchema = z.array(
-	z.object({
-		id: z.number(),
-		key: z.string(),
-	}),
-);
-
-const WebhookSchema = z.object({
-	id: z.number(),
-	config: z.object({
-		url: z.string().optional(), // url might not always be present
-		content_type: z.string().optional(),
-	}),
-	events: z.array(z.string()),
-	active: z.boolean(),
-});
-
-const ListWebhooksResponseSchema = z.array(WebhookSchema);
-
-export type GithubRepository = z.infer<typeof GithubRepositorySchema>;
+import {
+	GithubRepository,
+	GithubRepositoriesSchema,
+	DeployKeysSchema,
+	ListWebhooksResponseSchema,
+	DeployKeys,
+} from "config";
 
 export class GithubClient {
 	private token: string;
@@ -49,13 +26,13 @@
 		const response = await axios.get("https://api.github.com/user/repos", {
 			headers: this.getHeaders(),
 		});
-		return z.array(GithubRepositorySchema).parse(response.data);
+		return GithubRepositoriesSchema.parse(response.data);
 	}
 
 	async addDeployKey(repoPath: string, key: string) {
 		const sshUrl = repoPath;
 		const repoOwnerAndName = sshUrl.replace("git@github.com:", "").replace(".git", "");
-		let existingKeys: z.infer<typeof DeployKeysSchema> = [];
+		let existingKeys: DeployKeys = [];
 		const response = await axios.get(`https://api.github.com/repos/${repoOwnerAndName}/keys`, {
 			headers: this.getHeaders(),
 		});
diff --git a/apps/canvas/back/src/index.ts b/apps/canvas/back/src/index.ts
index 0ba25b0..82e55fe 100644
--- a/apps/canvas/back/src/index.ts
+++ b/apps/canvas/back/src/index.ts
@@ -12,7 +12,16 @@
 import shell from "shelljs";
 import { RealFileSystem } from "./lib/fs.js";
 import path from "node:path";
-import { Env, generateDodoConfig, ConfigSchema, AppNode, ConfigWithInput, configToGraph, Network } from "config";
+import {
+	Env,
+	generateDodoConfig,
+	ConfigSchema,
+	AppNode,
+	ConfigWithInput,
+	configToGraph,
+	Network,
+	GithubRepository,
+} from "config";
 
 async function generateKey(root: string): Promise<[string, string]> {
 	const privKeyPath = path.join(root, "key");
@@ -325,12 +334,18 @@
 			resp.write(JSON.stringify({ error: "Invalid configuration", issues: config.error.format() }));
 			return;
 		}
+		let repos: GithubRepository[] = [];
+		if (p.githubToken) {
+			const github = new GithubClient(p.githubToken);
+			repos = await github.getRepositories();
+		}
 		const state = req.body.state
 			? JSON.stringify(req.body.state)
 			: JSON.stringify(
 					configToGraph(
 						config.data,
 						getNetworks(resp.locals.username),
+						repos,
 						p.state ? JSON.parse(Buffer.from(p.state).toString("utf8")) : null,
 					),
 				);
diff --git a/apps/canvas/back/src/lib/nodejs.test.ts b/apps/canvas/back/src/lib/nodejs.test.ts
index 5de8423..579cad5 100644
--- a/apps/canvas/back/src/lib/nodejs.test.ts
+++ b/apps/canvas/back/src/lib/nodejs.test.ts
@@ -1,9 +1,7 @@
 import { NodeJSAnalyzer } from "./nodejs.js";
-import { FileSystem, RealFileSystem } from "./fs.js";
+import { FileSystem } from "./fs.js";
 import { Volume, IFs, createFsFromVolume } from "memfs";
 import { test, expect } from "@jest/globals";
-import { expandValue } from "./env.js";
-import shell from "shelljs";
 
 class InMemoryFileSystem implements FileSystem {
 	constructor(private readonly fs: IFs) {}
@@ -19,14 +17,6 @@
 	}
 }
 
-test("canvas", async () => {
-	const fs: FileSystem = new RealFileSystem("/home/gio/code/apps/canvas/back");
-	const analyzer = new NodeJSAnalyzer();
-	expect(analyzer.detect(fs, "/")).toBe(true);
-	const info = await analyzer.analyze(fs, "/");
-	console.log(info);
-});
-
 test("nodejs", async () => {
 	return;
 	const root = "/";
@@ -55,29 +45,3 @@
 	const info = await analyzer.analyze(fs, root);
 	console.log(info);
 });
-
-test("env", () => {
-	console.log(expandValue("${PORT} ${DODO_VOLUME_DB}"));
-	console.log(expandValue("$PORT $DODO_VOLUME_DB"));
-	console.log(expandValue("${UNDEFINED:-${MACHINE}${UNDEFINED:-default}}"));
-});
-
-test("clone", async () => {
-	expect(shell.which("ssh-agent")).toBeTruthy();
-	expect(shell.which("ssh-add")).toBeTruthy();
-	expect(shell.which("git")).toBeTruthy();
-	expect(
-		shell.exec(
-			"GIT_SSH_COMMAND='ssh -i /home/gio/.ssh/key -o IdentitiesOnly=yes' git clone git@github.com:giolekva/dodo-blog.git /tmp/dodo-blog",
-		).code,
-	).toBe(0);
-	const fs: FileSystem = new RealFileSystem("/tmp/dodo-blog");
-	const analyzer = new NodeJSAnalyzer();
-	expect(analyzer.detect(fs, "/")).toBe(true);
-	const info = await analyzer.analyze(fs, "/");
-	console.log(info);
-});
-
-test("keygen", () => {
-	expect(shell.exec(`ssh-keygen -y -t ed25519 -f /tmp/key`).code).toBe(0);
-});