Skip to content

Commit

Permalink
View projects and options
Browse files Browse the repository at this point in the history
  • Loading branch information
natesawant committed Jun 19, 2024
1 parent f6ae778 commit 27641cd
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 218 deletions.
25 changes: 25 additions & 0 deletions cli/src/endpoints/authAxios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import axios from "axios";

export const axiosInstance = axios.create({
withCredentials: true, // Ensure credentials are sent with every request
});

export const config = {
baseUrl: "https://routes-orcin.vercel.app",
};

export function SetCookie(credentials: string) {
// Add a request interceptor to include the cookie in the headers
axiosInstance.interceptors.request.use(
(config) => {
// Set the cookie in the header
config.headers.Cookie = credentials;

return config;
},
(error) => {
// Do something with request error
return Promise.reject(error);
},
);
}
14 changes: 14 additions & 0 deletions cli/src/endpoints/getProjects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Project } from "../types";
import { axiosInstance, config } from "./authAxios";

export default async function GetProjects() {
const fullUrl = `${config.baseUrl}/api/trpc/database.get?input=${encodeURIComponent(JSON.stringify({ json: { searchTerms: "" } }))}`;

const response = await axiosInstance.get(fullUrl);

const { result } = response.data as { result: { data: { json: Project[] } } };

const projects = result.data.json;

return projects;
}
164 changes: 39 additions & 125 deletions cli/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,140 +1,54 @@
#!/usr/bin/env node

import inquirer from "inquirer";
import parse, { type Config } from "parse-git-config";
import type { CLIAnswers, EndpointResponse } from "./types";
import parseGithubUrl from "parse-github-url";
import axios from "axios";
import updateExistingEnvVariable from "./utils/updateEnv";
import SetupCLI from "./menu/setup";
import { exit } from "process";

export const baseUrl = "https://routes-orcin.vercel.app/";
export const apiPath = "api/trpc/";
const createDatabasePath = "database.create";
const endpointPath = "database.endpoint";
import ViewProjects from "./menu/projects";
import inquirer from "inquirer";

// Create an Axios instance
const axiosInstance = axios.create({
withCredentials: true, // Ensure credentials are sent with every request
});
type MainAnswers = {
selectedMenu: "setup" | "projects" | "exit";
};

async function askRetry(): Promise<boolean> {
const answers = (await inquirer.prompt([
async function GetMainAnswers(): Promise<MainAnswers> {
return (await inquirer.prompt([
{
type: "confirm",
name: "retry",
message: "Do you want to try updating the environment variable again?",
default: false,
type: "list",
name: "selectedMenu",
message: "Select a menu option",
choices: ["setup", "projects", "exit"],
},
])) as { retry: boolean };
return answers.retry;
])) as MainAnswers;
}

//this is where the cli code is generated to ensure we are able to get the user info
/**
* 1. Setup CLI (Auto setup if env vars are missing)
* 2. Databases
* a. Add Project
* b. Project 1
* i. Pause/Start
* ii. Delete
* iii. main (active db)
* 1. Set connection url to env
* 2. Generate sample data
* iv. test-branch (no db)
* 1. Push database
* ...
* c. Project 3
*/
async function main() {
await SetupCLI();

process.exit(1);
/*
const config: Config = parse.expandKeys(parse.sync());
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
const repoUrl = config?.remote?.origin?.url;
const answers: CLIAnswers = (await inquirer.prompt([
{
type: "list",
name: "backendLanguage",
message:
"What backend language are you using? (Other clients will be added later)",
choices: ["TypeScript"],
},
{
type: "list",
name: "dbProvider",
message: "What database provider are you using?",
choices: ["mysql", "postgres"],
},
{
type: "confirm",
name: "deployDatabase",
message: "Do you want to deploy a database to the cloud?",
},
{
type: "confirm",
name: "correctRepo",
message: `Is ${repoUrl} your correct repo?`,
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
when: (answers) => answers.deployDatabase === true,
},
])) as CLIAnswers;
if (answers.deployDatabase) {
const parsedUrl = parseGithubUrl(repoUrl as string);
console.log("Name:", parsedUrl?.name); // repositoryName
if (!repoUrl) {
console.error("No repo found in git config");
const { selectedMenu } = await GetMainAnswers();

switch (selectedMenu) {
case "setup":
await SetupCLI();
break;
case "projects":
await ViewProjects();
break;
default:
process.exit(1);
}
console.log("Deploying database...");
// Send request to backend to create database
try {
await axiosInstance.post(`${baseUrl}${apiPath}${createDatabasePath}`, {
json: {
repoUrl: repoUrl as string,
provider: answers.dbProvider,
},
});
} catch (error) {
console.warn("Database on this branch has already been deployed");
}
console.log("Deploying, this may take up to 10 minutes");
// Send request to backend to create database
for (let i = 0; i < 120; i++) {
try {
const endpointResponse = await axiosInstance.post(
`${baseUrl}${apiPath}${endpointPath}`,
{
json: {
repoUrl: repoUrl as string,
},
},
);
if (endpointResponse) {
const endpointData = endpointResponse.data as EndpointResponse;
console.log("Connection information:\n");
console.log("\t" + endpointData.result.data.json.connection);
console.log();
}

// Automatically set connection as environment URL
let retrySetEnv = true;
while (retrySetEnv) {
const success = await updateExistingEnvVariable(
"DATABASE_URL",
endpointData.result.data.json.connection,
);
if (success) {
console.log("Environment variable updated successfully.");
break;
} else {
console.error("Failed to update environment variable.");
retrySetEnv = await askRetry();
}
}
break;
}
} catch (error) {
await new Promise((resolve) => setTimeout(resolve, 10000));
console.warn("Retrying...");
}
}
} */
await main();
}

await main();
87 changes: 87 additions & 0 deletions cli/src/menu/projects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import inquirer from "inquirer";
import GetProjects from "../endpoints/getProjects";
import type { Project } from "../types";

type ProjectAnswers = {
selectedProject: string;
};

const addProjectLabel = "Add a new project";

async function SelectProject(projectNames: string[]): Promise<ProjectAnswers> {
return (await inquirer.prompt([
{
type: "list",
name: "selectedProject",
message: "Select a project",
choices: [addProjectLabel].concat(projectNames).concat(["back"]),
},
])) as ProjectAnswers;
}

type ProjectOptionsAnswers = {
selectedOption: string;
};

async function SelectProjectOption(
validOptions: string[],
): Promise<ProjectOptionsAnswers> {
return (await inquirer.prompt([
{
type: "list",
name: "selectedProject",
message: "Select a project",
choices: validOptions,
},
])) as ProjectOptionsAnswers;
}

export default async function ViewProjects() {
const projects = await GetProjects();

const { selectedProject: selectedProjectName } = await SelectProject(
projects.map((proj) => proj.repository),
);

if (selectedProjectName === addProjectLabel) {
} else if (selectedProjectName === "back") {
// Do nothing
} else {
const selectedProject =
projects[
projects.findIndex((proj) => proj.repository === selectedProjectName)
];

await ViewProjectOptions(selectedProject);
}
}

async function ViewProjectOptions(project: Project) {
console.log(project);
const { status } = project;

const validOptions =
status === "available"
? ["stop", "delete", "back"]
: ["start", "delete", "back"];

const { selectedOption } = await SelectProjectOption(validOptions);

switch (selectedOption) {
case "start":
break;
case "stop":
break;
case "create":
break;
case "delete":
break;
case "endpoint":
break;
case "back":
// Do nothing
break;
}

await ViewProjects();
}
39 changes: 12 additions & 27 deletions cli/src/menu/setup.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import inquirer from "inquirer";
import axios from "axios";
import { GetCredentials } from "../utils/getCredentials";
import updateExistingEnvVariable from "../utils/updateEnv";
import { axiosInstance, SetCookie, config } from "../endpoints/authAxios";

type SetupAnswers = {
useGenerateBackend: boolean;
Expand Down Expand Up @@ -36,57 +36,42 @@ export default async function SetupCLI() {

const backendUrl = alternateBackendUrl ?? "https://routes-orcin.vercel.app";

// Create an Axios instance
const axiosInstance = axios.create({
withCredentials: true, // Ensure credentials are sent with every request
});

// Verify you can connect to backend
try {
console.log(`Attempting to reach ${backendUrl}`);
const { status } = await axiosInstance.get(`${backendUrl}/api/health`);
if (status !== 200) {
console.error("DevDB backend url not healthy, exiting...");
console.error("DevDB backend url not healthy, exiting...");
process.exit(1);
} else {
await updateExistingEnvVariable("DEVDB_URL", backendUrl);
console.log("Successfully reached the backend");
config.baseUrl = backendUrl;
console.log("✅ Successfully reached the backend");
}
} catch (error) {
console.error("DevDB backend url not healthy, exiting...");
console.error("DevDB backend url not healthy, exiting...");
process.exit(1);
} finally {
}

// Verify session token is valid
try {
console.log(`Attempting to authenticated token`);
const credentials = await GetCredentials(backendUrl, sessionToken);
// Add a request interceptor to include the cookie in the headers
axiosInstance.interceptors.request.use(
(config) => {
// Set the cookie in the header
config.headers.Cookie = credentials;
const credentials = await GetCredentials(config.baseUrl, sessionToken);
SetCookie(credentials);

return config;
},
(error) => {
// Do something with request error
return Promise.reject(error);
},
const { status } = await axiosInstance.get(
`${config.baseUrl}/api/trpc/health`,
);

const { status } = await axiosInstance.get(`${backendUrl}/api/trpc/health`);
if (status !== 200) {
console.error("Token not authenticated, exiting...");
console.error("Token not authenticated, exiting...");
process.exit(1);
} else {
await updateExistingEnvVariable("DEVDB_TOKEN", sessionToken);
console.log("Successfully authenticated the token");
console.log("Successfully authenticated the token");
}
} catch (error) {
console.log(error);
console.error("Token not authenticated, exiting...");
console.error("Token not authenticated, exiting...");
process.exit(1);
}
}
Loading

0 comments on commit 27641cd

Please sign in to comment.