diff --git a/apps/cli/src/commands/variable.command.ts b/apps/cli/src/commands/variable.command.ts new file mode 100644 index 00000000..d5f1ac8f --- /dev/null +++ b/apps/cli/src/commands/variable.command.ts @@ -0,0 +1,28 @@ +import BaseCommand from '@/commands/base.command' +import CreateVariable from '@/commands/variable/create.variable' +import DeleteVariable from '@/commands/variable/delete.variable' +import ListVariable from '@/commands/variable/list.variable' +import FetchVariableRevisions from '@/commands/variable/revisions.variable' +import UpdateVariable from '@/commands/variable/update.variable' +import RollbackVariable from '@/commands/variable/rollback.variable' + +export default class VariableCommand extends BaseCommand { + getName(): string { + return 'variable' + } + + getDescription(): string { + return 'Manages the variable on keyshade' + } + + getSubCommands(): BaseCommand[] { + return [ + new CreateVariable(), + new DeleteVariable(), + new ListVariable(), + new FetchVariableRevisions(), + new UpdateVariable(), + new RollbackVariable() + ] + } +} diff --git a/apps/cli/src/commands/variable/create.variable.ts b/apps/cli/src/commands/variable/create.variable.ts new file mode 100644 index 00000000..35ef146c --- /dev/null +++ b/apps/cli/src/commands/variable/create.variable.ts @@ -0,0 +1,115 @@ +import BaseCommand from '@/commands/base.command' +import { text } from '@clack/prompts' +import ControllerInstance from '@/util/controller-instance' +import { Logger } from '@/util/logger' +import { + type CommandActionData, + type CommandArgument, + type CommandOption +} from '@/types/command/command.types' + +export default class CreateVariable extends BaseCommand { + getName(): string { + return 'create' + } + getDescription(): string { + return 'Create a variable' + } + getArguments(): CommandArgument[] { + return [ + { + name: '', + description: + 'Slug of the project under which you want to create variable' + } + ] + } + + getOptions(): CommandOption[] { + return [ + { + short: '-n', + long: '--name ', + description: 'Name of the variable. Must be unique across the project' + }, + { + short: '-d', + long: '--note ', + description: 'A note describing the usage of the variable.' + }, + { + short: '-e', + long: '--entries [entries...]', + description: + 'An array of key-value pair (value and environmentSlug) for the variable.' + } + ] + } + + async action({ args, options }: CommandActionData): Promise { + const { name, note, entries } = await this.parseInput(options) + const [projectSlug] = args + + if (!projectSlug) { + Logger.error('Project slug is required') + return + } + + const { data, error, success } = + await ControllerInstance.getInstance().variableController.createVariable( + { + name, + note, + entries, + projectSlug + }, + this.headers + ) + + if (success) { + Logger.info(`Variable ${data.name} (${data.slug}) created successfully!`) + Logger.info(`Created at ${data.createdAt}`) + Logger.info(`Updated at ${data.updatedAt}`) + } else { + Logger.error(`Failed to create variable: ${error.message}`) + } + } + + private async parseInput(options: CommandActionData['options']): Promise<{ + name: string + note?: string + entries: Array<{ value: string; environmentSlug: string }> + }> { + let { name, note } = options + const { entries } = options + + if (!name) { + name = await text({ + message: 'Enter the name of variable', + placeholder: 'My Variable' + }) + } + + if (!entries) { + throw new Error('Entries is required') + } + + if (!note) { + note = name + } + + const parsedEntries = entries.map((entry) => { + const [environmentSlug, value] = entry.split('=').map(s => s.trim()) + if (!environmentSlug || !value) { + throw new Error(`Invalid entry format: ${entry}. Expected format: "environmentSlug=value"`) + } + return { environmentSlug, value } + }) + + return { + name, + note, + entries: parsedEntries + } + } +} diff --git a/apps/cli/src/commands/variable/delete.variable.ts b/apps/cli/src/commands/variable/delete.variable.ts new file mode 100644 index 00000000..1ac432d6 --- /dev/null +++ b/apps/cli/src/commands/variable/delete.variable.ts @@ -0,0 +1,44 @@ +import type { + CommandActionData, + CommandArgument +} from '@/types/command/command.types' +import BaseCommand from '@/commands/base.command' +import { Logger } from '@/util/logger' +import ControllerInstance from '@/util/controller-instance' + +export default class DeleteVariable extends BaseCommand { + getName(): string { + return 'delete' + } + + getDescription(): string { + return 'Deletes a variable' + } + + getArguments(): CommandArgument[] { + return [ + { + name: '', + description: 'Slug of the variable that you want to delete.' + } + ] + } + + async action({ args }: CommandActionData): Promise { + const [variableSlug] = args + + const { error, success } = + await ControllerInstance.getInstance().variableController.deleteVariable( + { + variableSlug + }, + this.headers + ) + + if (success) { + Logger.info(`Variable ${variableSlug} deleted successfully!`) + } else { + Logger.error(`Failed to delete variable: ${error.message}`) + } + } +} diff --git a/apps/cli/src/commands/variable/list.variable.ts b/apps/cli/src/commands/variable/list.variable.ts new file mode 100644 index 00000000..fcea68b4 --- /dev/null +++ b/apps/cli/src/commands/variable/list.variable.ts @@ -0,0 +1,50 @@ +import type { + CommandActionData, + CommandArgument +} from '@/types/command/command.types' +import BaseCommand from '@/commands/base.command' +import ControllerInstance from '@/util/controller-instance' +import { Logger } from '@/util/logger' + +export default class ListVariable extends BaseCommand { + getName(): string { + return 'list' + } + + getDescription(): string { + return 'List all variable under a project' + } + + getArguments(): CommandArgument[] { + return [ + { + name: '', + description: 'Slug of the project whose variable you want.' + } + ] + } + + async action({ args }: CommandActionData): Promise { + const [projectSlug] = args + const { data, error, success } = + await ControllerInstance.getInstance().variableController.getAllVariablesOfProject( + { + projectSlug + }, + this.headers + ) + + if (success) { + const variables = data + if (variables.length > 0) { + data.forEach((variable: any) => { + Logger.info(`- ${variable.name} (${variable.value})`) + }) + } else { + Logger.info('No variables found') + } + } else { + Logger.error(`Failed fetching variables: ${error.message}`) + } + } +} diff --git a/apps/cli/src/commands/variable/revisions.variable.ts b/apps/cli/src/commands/variable/revisions.variable.ts new file mode 100644 index 00000000..18c9f0d5 --- /dev/null +++ b/apps/cli/src/commands/variable/revisions.variable.ts @@ -0,0 +1,63 @@ +import type { + CommandActionData, + CommandArgument +} from '@/types/command/command.types' +import BaseCommand from '@/commands/base.command' +import ControllerInstance from '@/util/controller-instance' +import { Logger } from '@/util/logger' + +export default class FetchVariableRevisions extends BaseCommand { + getName(): string { + return 'revisions' + } + + getDescription(): string { + return 'Fetch all revisions of a variable' + } + + getArguments(): CommandArgument[] { + return [ + { + name: '', + description: 'Slug of the variable whose revisions you want.' + }, + { + name: '', + description: + 'Environment slug of the variable whose revisions you want.' + } + ] + } + + async action({ args }: CommandActionData): Promise { + const [variableSlug, environmentSlug] = args + + const { data, error, success } = + await ControllerInstance.getInstance().variableController.getRevisionsOfVariable( + { + variableSlug, + environmentSlug + }, + this.headers + ) + + if (success) { + const revisions = data.items + if (revisions.length > 0) { + data.items.forEach((revision: any) => { + Logger.info(`Id ${revision.id}`) + Logger.info(`value ${revision.value}`) + Logger.info(`version ${revision.version}`) + Logger.info(`variableID ${revision.variableId}`) + Logger.info(`Created On ${revision.createdOn}`) + Logger.info(`Created By Id ${revision.createdById}`) + Logger.info(`environmentId ${revision.environmentId}`) + }) + } else { + Logger.info('No revisions found') + } + } else { + Logger.error(`Failed fetching revisions: ${error.message}`) + } + } +} diff --git a/apps/cli/src/commands/variable/rollback.variable.ts b/apps/cli/src/commands/variable/rollback.variable.ts new file mode 100644 index 00000000..a5a56d3d --- /dev/null +++ b/apps/cli/src/commands/variable/rollback.variable.ts @@ -0,0 +1,78 @@ +import type { + CommandActionData, + CommandArgument, + CommandOption +} from '@/types/command/command.types' +import BaseCommand from '@/commands/base.command' +import { Logger } from '@/util/logger' +import ControllerInstance from '@/util/controller-instance' + +export default class RollbackVariable extends BaseCommand { + getName(): string { + return 'rollback' + } + + getDescription(): string { + return 'Rollbacks a variable' + } + + getArguments(): CommandArgument[] { + return [ + { + name: '', + description: 'Slug of the variable that you want to rollback' + } + ] + } + + getOptions(): CommandOption[] { + return [ + { + short: '-v', + long: '--version ', + description: 'Version of the variable to which you want to rollback' + }, + { + short: '-e', + long: '--environmentSlug ', + description: + 'Slug of the environment of the variable to which you want to rollback' + } + ] + } + + async action({ args, options }: CommandActionData): Promise { + const [variableSlug] = args + const { environmentSlug, version } = await this.parseInput(options) + const { data, error, success } = + await ControllerInstance.getInstance().variableController.rollbackVariable( + { + environmentSlug, + version, + variableSlug + }, + this.headers + ) + + if (success) { + Logger.info(`Variable ${data.name} (${data.slug}) updated successfully!`) + Logger.info(`Created at ${data.createdAt}`) + Logger.info(`Updated at ${data.updatedAt}`) + Logger.info(`Note: ${data.note}`) + } else { + Logger.error(`Failed to update variable: ${error.message}`) + } + } + + private async parseInput(options: CommandActionData['options']): Promise<{ + environmentSlug: string + version: string + }> { + const { environmentSlug, version } = options + + return { + environmentSlug, + version + } + } +} diff --git a/apps/cli/src/commands/variable/update.variable.ts b/apps/cli/src/commands/variable/update.variable.ts new file mode 100644 index 00000000..15bdd872 --- /dev/null +++ b/apps/cli/src/commands/variable/update.variable.ts @@ -0,0 +1,69 @@ +import type { + CommandActionData, + CommandArgument, + CommandOption +} from '@/types/command/command.types' +import BaseCommand from '@/commands/base.command' +import { Logger } from '@/util/logger' +import ControllerInstance from '@/util/controller-instance' + +export default class UpdateVariable extends BaseCommand { + getName(): string { + return 'update' + } + + getDescription(): string { + return 'Updates a variable' + } + + getArguments(): CommandArgument[] { + return [ + { + name: '', + description: 'Slug of the variable that you want to update' + } + ] + } + + getOptions(): CommandOption[] { + return [ + { + short: '-n', + long: '--name ', + description: 'Name of the Variable' + }, + { + short: '-d', + long: '--note ', + description: ' An optional note describing the usage of the variable.' + }, + { + short: '-e', + long: '--entries [entries...]', + description: 'An array of values for the variable.' + } + ] + } + + async action({ args, options }: CommandActionData): Promise { + const [variableSlug] = args + + const { data, error, success } = + await ControllerInstance.getInstance().variableController.updateVariable( + { + variableSlug, + ...options + }, + this.headers + ) + + if (success) { + Logger.info(`Variable ${data.name} (${data.slug}) updated successfully!`) + Logger.info(`Created at ${data.createdAt}`) + Logger.info(`Updated at ${data.updatedAt}`) + Logger.info(`Note: ${data.note}`) + } else { + Logger.error(`Failed to update variable: ${error.message}`) + } + } +} diff --git a/apps/cli/src/index.ts b/apps/cli/src/index.ts index 3f908dd0..3bc7cb02 100644 --- a/apps/cli/src/index.ts +++ b/apps/cli/src/index.ts @@ -8,6 +8,7 @@ import WorkspaceCommand from '@/commands/workspace.command' import ScanCommand from '@/commands/scan.command' import ProjectCommand from './commands/project.command' import SecretCommand from './commands/secret.command' +import VariableCommand from './commands/variable.command' const program = new Command() @@ -23,7 +24,8 @@ const COMMANDS: BaseCommand[] = [ new ProjectCommand(), new EnvironmentCommand(), new SecretCommand(), - new ScanCommand() + new ScanCommand(), + new VariableCommand() ] COMMANDS.forEach((command) => {