UNPKG

sindri

Version:

The Sindri Labs JavaScript SDK and CLI tool.

175 lines (161 loc) 5.64 kB
import { existsSync, readFileSync } from "node:fs"; import path from "node:path"; import { Command } from "@commander-js/extra-typings"; import { confirm } from "@inquirer/prompts"; import { findFileUpwards } from "cli/utils"; import sindri from "lib"; import { ApiError } from "lib/api"; async function deleteProject(projectIdentifier: string): Promise<void> { try { await sindri._client.internal.projectDelete(projectIdentifier); sindri.logger.debug(`Deleted project "${projectIdentifier}".`); } catch (error) { if (error instanceof ApiError && error.status === 401) { sindri.logger.error( "Your credentials are invalid. Please log in again with `sindri login`.", ); } else if (error instanceof ApiError && error.status === 404) { sindri.logger.error(`The project "${projectIdentifier}" does not exist.`); } else { sindri.logger.fatal("An unknown error occurred."); sindri.logger.error(error); } return process.exit(1); } } function findProjectName(directory: string): string { // Find `sindri.json` and move into the root of the project directory. const directoryPath = path.resolve(directory); if (!existsSync(directoryPath)) { sindri.logger.error( `The "${directoryPath}" directory does not exist. Aborting.`, ); return process.exit(1); } const sindriJsonPath = findFileUpwards(/^sindri.json$/i, directoryPath); if (!sindriJsonPath) { sindri.logger.error( `No "sindri.json" file was found in or above "${directoryPath}". Aborting.`, ); return process.exit(1); } sindri.logger.debug(`Found "sindri.json" at "${sindriJsonPath}".`); const rootDirectory = path.dirname(sindriJsonPath); sindri.logger.debug(`Changing current directory to "${rootDirectory}".`); process.chdir(rootDirectory); // Load `sindri.json`. let sindriJson: object = {}; try { const sindriJsonContent = readFileSync(sindriJsonPath, { encoding: "utf-8", }); sindriJson = JSON.parse(sindriJsonContent); sindri.logger.debug( `Successfully loaded "sindri.json" from "${sindriJsonPath}":`, ); sindri.logger.debug(sindriJson); } catch (error) { sindri.logger.fatal( `Error loading "${sindriJsonPath}", perhaps it is not valid JSON?`, ); sindri.logger.error(error); return process.exit(1); } if (!("name" in sindriJson) || typeof sindriJson.name !== "string") { sindri.logger.error('No "name" field found in "sindri.json". Aborting.'); return process.exit(1); } return sindriJson.name; } async function getSomeProjectNames(teamName: string): Promise<string[]> { // Used as an efficient iterator for `projectDeleteCommand`. try { const projects = await sindri._client.internal.projectListPaginated({ team_name: teamName, }); return projects.items.map(({ name }) => name); } catch (error) { if (error instanceof ApiError && error.status === 401) { sindri.logger.error( "Your credentials are invalid. Please log in again with `sindri login`.", ); } else { sindri.logger.fatal("An unknown error occurred."); sindri.logger.error(error); } return process.exit(1); } } async function getTeamName(): Promise<string> { try { const response = await sindri._client.internal.teamMe(); return response.team.slug; } catch (error) { if (error instanceof ApiError && error.status === 401) { sindri.logger.error( "Your credentials are invalid. Please log in again with `sindri login`.", ); } else { sindri.logger.fatal("An unknown error occurred."); sindri.logger.error(error); } return process.exit(1); } } const projectDeleteCommand = new Command() .name("delete") .description("Delete a project and all associated builds and proofs.") .option( "-a, --all", "Delete *all* projects. Overrides the `--name` and directory options.", ) .option("-f, --force", "Skip the confirmation prompt.") .option( "-n, --name <name>", "The name of the project to delete. Overrides the directory option.", ) .argument("[directory]", "The location of the Sindri project to delete.", ".") .action(async (directory, { all, force, name }) => { // Check that the API client is authorized. if (!sindri.apiKey || !sindri.baseUrl) { sindri.logger.warn("You must login first with `sindri login`."); return process.exit(1); } // Ask the user for confirmation. if (!force) { const userConfirmed = await confirm({ message: "This will permanently delete the project(s) and any associated proofs. Proceed?", default: true, }); if (!userConfirmed) { sindri.logger.warn("Aborting. No projects were deleted."); return; } } // Perform the deletion. let deletedCount = 0; if (!all) { name = name || findProjectName(directory); await deleteProject(name); deletedCount++; } else { const teamName = await getTeamName(); while (true) { const projectNames = await getSomeProjectNames(teamName); if (projectNames.length === 0) { break; } // Iterate through project names. for (const projectName of projectNames) { await deleteProject(projectName); deletedCount++; } } } sindri.logger.info(`Successfully deleted ${deletedCount} projects.`); }); export const projectCommand = new Command() .name("project") .description("Commands related to managing projects.") .addCommand(projectDeleteCommand);