From a9ba3a5c71559272c730d16ad6828afc4a366a91 Mon Sep 17 00:00:00 2001 From: Adam McKee Date: Tue, 23 Jan 2024 19:17:11 -0600 Subject: [PATCH] initial commit --- backend/package.json | 1 + backend/src/Repositories.ts | 75 ------------ backend/src/Server.ts | 18 ++- backend/src/Template.ts | 13 ++ backend/src/req.d.ts | 1 + backend/tsconfig.json | 3 + cloud/aws.md | 24 ++++ cloud/backend.nomad | 30 +++++ cloud/postgres.nomad | 27 ++++ frontend/index.html | 5 +- frontend/src/app.ts | 136 +++++++-------------- frontend/src/browse.ts | 10 ++ frontend/src/components/RepoLink.ts | 45 +++++++ frontend/src/configure.ts | 32 +++++ frontend/src/{style.css => graphPaper.css} | 46 +++---- frontend/src/graphPaper.ts | 24 ++-- frontend/src/search.css | 33 +++++ frontend/src/search.ts | 36 ++++++ github/lib/GitHub.d.ts | 5 + github/lib/GitHub.js | 30 +++++ github/package.json | 25 ++++ github/src/GitHub.ts | 3 + github/src/Model.ts | 24 ++++ {backend => github}/src/Releases.ts | 32 +---- github/src/Repositories.ts | 32 +++++ github/tsconfig.json | 21 ++++ pnpm-lock.yaml | 16 +++ pnpm-workspace.yaml | 1 + template/package.json | 4 +- template/src/Distrubtions.ts | 2 +- template/src/Generate.test.ts | 8 +- template/src/Generate.ts | 18 ++- {backend => template}/src/Resolution.ts | 25 +--- template/src/Template.ts | 3 + 34 files changed, 522 insertions(+), 286 deletions(-) delete mode 100644 backend/src/Repositories.ts create mode 100644 backend/src/Template.ts create mode 100644 cloud/aws.md create mode 100644 cloud/backend.nomad create mode 100644 cloud/postgres.nomad create mode 100644 frontend/src/browse.ts create mode 100644 frontend/src/components/RepoLink.ts create mode 100644 frontend/src/configure.ts rename frontend/src/{style.css => graphPaper.css} (68%) create mode 100644 frontend/src/search.css create mode 100644 frontend/src/search.ts create mode 100644 github/lib/GitHub.d.ts create mode 100644 github/lib/GitHub.js create mode 100644 github/package.json create mode 100644 github/src/GitHub.ts create mode 100644 github/src/Model.ts rename {backend => github}/src/Releases.ts (68%) create mode 100644 github/src/Repositories.ts create mode 100644 github/tsconfig.json rename {backend => template}/src/Resolution.ts (59%) create mode 100644 template/src/Template.ts diff --git a/backend/package.json b/backend/package.json index 482d14c..d66ee74 100644 --- a/backend/package.json +++ b/backend/package.json @@ -14,6 +14,7 @@ "build": "tsc --build --clean && tsc --build" }, "dependencies": { + "@eighty4/install-github": "workspace:^0.0.1", "@eighty4/install-template": "workspace:^0.0.1", "cookie-parser": "^1.4.6", "express": "^5.0.0-beta.1", diff --git a/backend/src/Repositories.ts b/backend/src/Repositories.ts deleted file mode 100644 index c4b9b2d..0000000 --- a/backend/src/Repositories.ts +++ /dev/null @@ -1,75 +0,0 @@ -import type {Repository} from '@eighty4/install-template' - -export interface UserRepositoriesRequest { - accessToken: string -} - -export async function queryPinnedUserRepositories(accessToken: string): Promise> { - const query = ` -query { - viewer { - pinnedItems(first: 6, types: REPOSITORY) { - nodes { - ... on Repository { - name - owner { - login - } - } - } - } - } -}` - const response = await fetch('https://api.github.com/graphql', { - method: 'POST', - headers: { - 'Authorization': 'Bearer ' + accessToken, - }, - body: JSON.stringify({query}), - }) - if (response.status === 200) { - const json = await response.json() - if (json.errors && json.errors.length) { - throw new Error('queryPinnedUserRepositories POST https://api.github.com/graphql ' + json.errors[0].message) - } else { - const result = [] - for (const repo of json.data.viewer.pinnedItems.nodes) { - result.push({owner: repo.owner.login, name: repo.name}) - } - return result - } - } else { - throw new Error('queryPinnedUserRepositories POST https://api.github.com/graphql ' + response.status) - } -} - -export async function queryUserRepositories({accessToken}: UserRepositoriesRequest): Promise> { - const query = ` -query { - viewer { - repositories(first: 20, types: REPOSITORY, affiliations: [OWNER, COLLABORATOR, ORGANIZATION_MEMBER]) { - nodes { - ... on Repository { - name - owner { - login - } - } - } - } - } -}` - const response = await fetch('https://api.github.com/graphql', { - method: 'POST', - headers: { - 'Authorization': 'Bearer ' + accessToken, - }, - body: JSON.stringify({query}), - }) - const json = await response.json() - const result = [] - for (const repo of json.data.viewer.repositories.nodes) { - result.push({owner: repo.owner.login, name: repo.name}) - } - return result -} diff --git a/backend/src/Server.ts b/backend/src/Server.ts index da2cf9e..684c299 100644 --- a/backend/src/Server.ts +++ b/backend/src/Server.ts @@ -1,11 +1,11 @@ import net from 'node:net' import express, {RequestHandler} from 'express' import cookieParser from 'cookie-parser' +import {queryLatestRelease} from '@eighty4/install-github' import {generateScript} from '@eighty4/install-template' import {loadGeneratedScripts, saveGeneratedScript} from './Database.js' import {initiateLogin, resolveLogin} from './Login.js' -import {queryLatestRelease} from './Releases.js' -import {resolveTemplateRuntimeVersion} from './Resolution.js' +import {resolveTemplateRuntimeVersion} from './Template.js' import {verifyAccessToken} from './User.js' const parsePortEnvVariable = (key: string, def: number): number => { @@ -15,7 +15,7 @@ const parsePortEnvVariable = (key: string, def: number): number => { } else { try { return parseInt(val, 10) - } catch(e) { + } catch (e) { console.error(`env variable ${key} must be numeric`) process.exit(1) } @@ -48,7 +48,7 @@ app.use((req, res, next) => { }) const authorize: RequestHandler = (req, res, next) => { - const accessToken = req.cookies.gat + const accessToken = req.cookies.gh verifyAccessToken(accessToken) .then((user) => { if (user === false) { @@ -89,7 +89,7 @@ app.get('/login/notify', async (req, res) => { } else { try { const authData = await resolveLogin(loginId) - res.setHeader('Set-Cookie', `gat=${authData.accessToken}; Secure; HttpOnly; SameSite=Strict; Path=/api`) + res.setHeader('Set-Cookie', `gh=${authData.accessToken}; Secure; SameSite=Strict; Path=/api`) res.json({newUser: authData.newUser}) } catch (e: any) { console.log('auth resolve wtf', e.message) @@ -110,11 +110,9 @@ app.get('/api/projects', authorize, async (req, res) => { }) app.get('/api/release/:repoOwner/:repoName', authorize, async (req, res) => { - const release = await queryLatestRelease({ - accessToken: req.user!.accessToken, repository: { - owner: req.params['repoOwner'], - name: req.params['repoName'], - }, + const release = await queryLatestRelease(req.user!.accessToken, { + owner: req.params['repoOwner'], + name: req.params['repoName'], }) if (release) { res.json(release) diff --git a/backend/src/Template.ts b/backend/src/Template.ts new file mode 100644 index 0000000..5058dbb --- /dev/null +++ b/backend/src/Template.ts @@ -0,0 +1,13 @@ +import {readFileSync} from 'node:fs' + +export function resolveTemplateRuntimeVersion() { + try { + let packageJson = import.meta.resolve('../node_modules/@eighty4/install-template/package.json') + if (packageJson.startsWith('file:///')) { + packageJson = packageJson.substring(7) + } + return JSON.parse(readFileSync(packageJson).toString()).version + } catch (e) { + throw new Error('failed resolving version of @eighty4/install-template') + } +} diff --git a/backend/src/req.d.ts b/backend/src/req.d.ts index dc6180d..b65e734 100644 --- a/backend/src/req.d.ts +++ b/backend/src/req.d.ts @@ -1,5 +1,6 @@ declare namespace Express { export interface Request { user?: { accessToken: string, login: string, userId: number }, + cookies: { gh?: string }, } } diff --git a/backend/tsconfig.json b/backend/tsconfig.json index f8bef3d..2f9f8e3 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -17,6 +17,9 @@ "src/**/*.ts" ], "references": [ + { + "path": "../github" + }, { "path": "../template" } diff --git a/cloud/aws.md b/cloud/aws.md new file mode 100644 index 0000000..f19cc9f --- /dev/null +++ b/cloud/aws.md @@ -0,0 +1,24 @@ +t4g arm instance +t4g.medium +$12 per month +2 cpu 4 gb + +t3 intel instance +t3.medium +$15 per month +2 cpu 4 gb + +CICD on AWS would be with CodeBuild or CodePipeline + https://aws.amazon.com/blogs/devops/build-arm-based-applications-using-codebuild/ + +install docker +configure systemd postgres and install.sh services + https://blog.container-solutions.com/running-docker-containers-with-systemd + +cicd update install.sh with ssh restart + https://unix.stackexchange.com/a/395781 + +send to grafana cloud +- machine metrics +- container metrics +- container logs diff --git a/cloud/backend.nomad b/cloud/backend.nomad new file mode 100644 index 0000000..94574b4 --- /dev/null +++ b/cloud/backend.nomad @@ -0,0 +1,30 @@ +job "install.backend" { + type = "service" + + group "install.backend" { + count = 1 + + task "install.backend" { + driver = "docker" + + config { + image = "84tech/install.backend:latest" + + auth { + config = "/Users/adam/.docker/config.json" + } + } + + env { + } + } + } + + update { + max_parallel = 1 + min_healthy_time = "5s" + healthy_deadline = "3m" + auto_revert = false + canary = 0 + } +} diff --git a/cloud/postgres.nomad b/cloud/postgres.nomad new file mode 100644 index 0000000..1a375b5 --- /dev/null +++ b/cloud/postgres.nomad @@ -0,0 +1,27 @@ +job "postgres" { + type = "service" + + group "postgres" { + count = 1 + + task "postgres" { + driver = "docker" + + config { + image = "postgres:16" + } + + env { + POSTGRES_PASSWORD = eighty4 + } + } + } + + update { + max_parallel = 1 + min_healthy_time = "5s" + healthy_deadline = "3m" + auto_revert = false + canary = 0 + } +} diff --git a/frontend/index.html b/frontend/index.html index 07573fa..f18a39b 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -369,8 +369,9 @@