UNPKG

@ordino.ai/cli

Version:
441 lines (394 loc) 11.4 kB
import inquirer from "inquirer"; import { systemApiKeyService } from "../service/ordino.systemApiKey.service"; import { userApiKeyService } from "../service/ordino.userApiKey.service"; import { printMessage } from "../utils/printMessage.util"; import { userService } from "../service/ordino.user.service"; import { teamService } from "../service/ordino.team.service"; import { projectService } from "../service/ordino.project.service"; import { User, Team, Project, projectTypes, ApplicationType, } from "../models/models"; import { serviceFactory } from "../config/service-factory"; import { getApiEndpoints } from "../config/api-endpoints"; // Types for the prompts type SystemLoginAnswers = { username: string; password: string; }; type ProjectAnswer = { project: Project }; type InitialPromptAnswers = { isCompanyIDAvailable: boolean; }; export type ProjectTypeAnswers = { authToken: string; projectType: projectTypes; }; type MicroFrontendAnswers = { clientTestProjectURL: string; testProjectURL: string; }; type TestPromptAnswers = { includeSampleTest: boolean; }; type GitUrlAndYmlAnswers = { gitUrl: string | null; needGitActionSetup: boolean; }; // Functions // Initial prompt to ask if the company ID is available async function getInitialPrompts(): Promise<InitialPromptAnswers> { return inquirer.prompt([ { type: "confirm", name: "isCompanyIDAvailable", message: "Do you have a company ID?", default: true, }, ]); } // Validate the provided API key async function validateApiKey(apiKey: string): Promise<true | string> { const frameworkVersion = "1.0.0"; if (apiKey.trim() === "") { return "API key is required!!!"; } try { // Get the current environment and corresponding endpoints const currentEnvironment = serviceFactory.getEnvironment(); const endpoints = getApiEndpoints(currentEnvironment); const response = await fetch(endpoints.authentication, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ apiKey, frameworkVersion }), }); if (!response.ok) { return "Use a valid key."; } const data = await response.json(); switch (data.status) { case "INVALID": return "Use a valid key."; case "FRAMEWORK_OUT_DATED": return "Update your CLI."; case "VALID": return true; default: return "Unexpected response. Please try again."; } } catch (error) { return `Use a valid key. ${error}`; } } // Prompt for project type and company ID async function projectType(): Promise<ProjectTypeAnswers> { return inquirer.prompt([ { type: "input", name: "authToken", message: "Provide the Company ID:", validate: validateApiKey, }, { type: "list", name: "projectType", message: "What is the type of your project? (Choose one: UI / API):", choices: mapEnumToChoices(), }, ]); } // Get prompts for Micro Frontend project URLs async function getMicroFrontendPrompts(): Promise<MicroFrontendAnswers> { return inquirer.prompt([ { type: "input", name: "clientTestProjectURL", message: "Please add the Client Test Project URL:", }, { type: "input", name: "testProjectURL", message: "Please add the Test Project URL:", }, ]); } // Get prompts for project name and company async function getStandardPrompts( projectName: string, companyName: string ): Promise<string> { const suggestedName = `${companyName}-${projectName}-test`; const nameConfirmation = await inquirer.prompt<{ useSuggestedName: boolean }>( [ { type: "confirm", name: "useSuggestedName", message: `Would you like the tool to suggest a project name (${suggestedName})?`, default: true, }, ] ); if (!nameConfirmation.useSuggestedName) { const customName = await inquirer.prompt<{ customProjectName: string }>([ { type: "input", name: "customProjectName", message: "Please enter a project name:", validate: (input: string) => input.trim() !== "" || "Project name cannot be empty.", }, ]); return customName.customProjectName; } return suggestedName; } // Get project details based on API key and project type async function getProjectName( apiKey: string, projectType: projectTypes ): Promise<Project | null> { const partnerId = await getPartnerId(apiKey); if (!partnerId) { return null; } const users: User[] = await userService.getAllUsers(partnerId); const teams: Team[] = await teamService.getAllTeams(partnerId); const projects: Project[] = await projectService.getAllProjects(); if (projects.length > 0) { const { projectId } = await inquirer.prompt({ type: "list", name: "projectId", message: "Select a project:", choices: projects.map((project) => ({ name: project.name, value: project.id, })), }); return projects.find(({ id }) => id === projectId) ?? null; } else if (teams.length > 0) { const { teamId } = await inquirer.prompt({ type: "list", name: "teamId", message: "Select a team:", choices: teams.map((team) => ({ name: team.name, value: team.id })), }); const { projectName } = await inquirer.prompt([ { type: "input", name: "projectName", message: "Enter the project name:", }, ]); const { userId } = await inquirer.prompt({ type: "list", name: "userId", message: "Select a user:", choices: users.map((user) => ({ name: user.information.email, value: user.id, })), }); const project = await projectService.cerateProject({ partnerId: partnerId, teamId: teamId, name: projectName, applicationTypes: getApplicationType(projectType), qaLeadId: userId, isRegressionSuite: false, isCloudEnabled: false, }); return project ?? null; } else { const { teamName, projectName } = await inquirer.prompt([ { type: "input", name: "teamName", message: "Enter the team name:", }, { type: "input", name: "projectName", message: "Enter the project name:", }, ]); const team = await teamService.createTeam({ partnerId: partnerId, name: teamName, description: "", applicationTypes: getApplicationType(projectType), integrationDefinitionIds: ["TEST_INTEGRATION"], }); const { userId } = await inquirer.prompt({ type: "list", name: "userId", message: "Select a user:", choices: users.map((user) => ({ name: user.information.email, value: user.id, })), }); const project = await projectService.cerateProject({ partnerId: partnerId, teamId: team.id, name: projectName, applicationTypes: getApplicationType(projectType), qaLeadId: userId, isRegressionSuite: false, isCloudEnabled: false, }); return project ?? null; } } // Prompt for whether to include a sample test async function getTestPrompt(): Promise<TestPromptAnswers> { return inquirer.prompt([ { type: "confirm", name: "includeSampleTest", message: "Do you want to add a sample test? (yes/no):", default: true, }, ]); } // Map project types to choices for user selection function mapEnumToChoices(): { name: string; value: projectTypes }[] { return Object.keys(projectTypes) .filter((key) => isNaN(Number(key))) .map((key) => ({ name: key, value: projectTypes[key as keyof typeof projectTypes], })); } // Get application types based on project type function getApplicationType(projectType: projectTypes) { switch (projectType) { case projectTypes.UI: return [ApplicationType.WEB_UI]; case projectTypes.API: return [ApplicationType.API]; case projectTypes.UI_AND_API: return [ApplicationType.WEB_UI, ApplicationType.API]; default: throw new Error("Invalid project type"); } } // Get the partner ID based on the API key async function getPartnerId(apiKey: string): Promise<string | null> { const partnerId: string | null = null; try { if (apiKey.startsWith("SYS:")) { const res = await systemApiKeyService.getBySystemApiKey(apiKey); return res.partnerId; } if (apiKey.startsWith("USR:")) { const res = await userApiKeyService.getByUserApiKey(apiKey); return res.partnerId; } } catch (error) { printMessage( `Please check you api key is valid. If it's valid please contact support team https://www.ordino.ai/support`, "35", true, true ); return partnerId; } return partnerId; } // Convert project name to a valid package name export function convertToValidPackageName(projectName: string) { const validName = projectName .toLowerCase() .replace(/\s+/g, "-") .replace(/[^a-z0-9-]/g, "") .replace(/^-+/, "") .replace(/-+$/, ""); return validName; } async function handleGitAndYml(): Promise<GitUrlAndYmlAnswers> { const gitUrlResponse = await inquirer.prompt([ { type: "confirm", name: "gitUrl", message: "Do you want to set up a Git repository?", default: true, }, ]); let gitUrl = null; let needGitActionSetup = false; if (gitUrlResponse.gitUrl) { const gitUrlInput = await inquirer.prompt([ { type: "input", name: "gitUrl", message: "Please provide the Git repository URL:", validate: (input: string) => input.trim() !== "" ? true : "Git URL cannot be empty.", }, { type: "confirm", name: "needGitActionSetup", message: "Do you want to use GitHub Actions for CI/CD?", default: true, }, ]); gitUrl = gitUrlInput.gitUrl; needGitActionSetup = gitUrlInput.needGitActionSetup; } return { gitUrl, needGitActionSetup }; } //Initial prompt to ask login credentials async function getLoginPrompts(): Promise<SystemLoginAnswers> { return inquirer.prompt<SystemLoginAnswers>([ { type: "input", name: "username", message: "Ordino portal login username?", validate: (input: string) => input.trim() !== "" ? true : "Username cannot be empty.", }, { type: "password", name: "password", message: "Ordino portal login password?", validate: (input: string) => input.trim() !== "" ? true : "password cannot be empty.", }, ]); } //Get projects list async function getProjectsList(projectsList: Project[]): Promise<ProjectAnswer> { return inquirer.prompt([ { type: "list", name: "project", message: "Please select the project?", choices: mapProjectsList(projectsList), } ]); } //Map projects list. function mapProjectsList(projectsList: Project[]): { name: string, value: Project }[] { return projectsList.map((project) => ({ name: project.name, value: project })); } export { getLoginPrompts, getProjectsList, getInitialPrompts, getMicroFrontendPrompts, getStandardPrompts, getTestPrompt, projectType, getProjectName, handleGitAndYml, };