-
Notifications
You must be signed in to change notification settings - Fork 0
[showcase] Add flags unarchive command #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: showcase/base-17332
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| --- | ||
| 'vercel': patch | ||
| --- | ||
|
|
||
| Add a `vercel flags unarchive` command for unarchiving feature flags. | ||
|
|
||
| Examples: | ||
|
|
||
| - `vercel flags unarchive my-feature-flag` | ||
| - `vercel flags unarchive my-feature-flag --yes` | ||
| - `vercel flags unarchive my-feature-flag --project my-project --yes` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| import chalk from 'chalk'; | ||
| import type Client from '../../util/client'; | ||
| import { parseArguments } from '../../util/get-args'; | ||
| import { getFlagsSpecification } from '../../util/get-flags-specification'; | ||
| import { printError } from '../../util/error'; | ||
| import { getCommandName } from '../../util/pkg-name'; | ||
| import { getFlag } from '../../util/flags/get-flags'; | ||
| import { updateFlag } from '../../util/flags/update-flag'; | ||
| import output from '../../output-manager'; | ||
| import { FlagsUnarchiveTelemetryClient } from '../../util/telemetry/commands/flags/unarchive'; | ||
| import { unarchiveSubcommand } from './command'; | ||
| import { getLinkedFlagsProject, getProjectNameFromFlags } from './project'; | ||
|
|
||
| export default async function unarchive( | ||
| client: Client, | ||
| argv: string[] | ||
| ): Promise<number> { | ||
| const telemetryClient = new FlagsUnarchiveTelemetryClient({ | ||
| opts: { | ||
| store: client.telemetryEventStore, | ||
| }, | ||
| }); | ||
|
|
||
| let parsedArgs; | ||
| const flagsSpecification = getFlagsSpecification(unarchiveSubcommand.options); | ||
| try { | ||
| parsedArgs = parseArguments(argv, flagsSpecification); | ||
| } catch (err) { | ||
| printError(err); | ||
| return 1; | ||
| } | ||
|
|
||
| const { args, flags } = parsedArgs; | ||
| const [flagArg] = args; | ||
| const skipConfirmation = flags['--yes'] as boolean | undefined; | ||
| const projectName = getProjectNameFromFlags(flags); | ||
|
|
||
| if (!flagArg) { | ||
| output.error('Please provide a flag slug or ID to unarchive'); | ||
| output.log(`Example: ${getCommandName('flags unarchive my-feature')}`); | ||
| return 1; | ||
| } | ||
|
|
||
| telemetryClient.trackCliArgumentFlag(flagArg); | ||
| telemetryClient.trackCliOptionProject(projectName); | ||
| telemetryClient.trackCliFlagYes(skipConfirmation); | ||
|
|
||
| const link = await getLinkedFlagsProject(client, projectName); | ||
| if (link.status === 'error') { | ||
| return link.exitCode; | ||
| } else if (link.status === 'not_linked') { | ||
| output.error( | ||
| `Your codebase isn't linked to a project on Vercel. Pass --project <name>, or run ${getCommandName('link')} to link it.` | ||
| ); | ||
| return 1; | ||
| } | ||
|
|
||
| client.config.currentTeam = | ||
| link.org.type === 'team' ? link.org.id : undefined; | ||
|
|
||
| const { project } = link; | ||
|
|
||
| try { | ||
| output.spinner('Fetching flag...'); | ||
| const flag = await getFlag(client, project.id, flagArg); | ||
| output.stopSpinner(); | ||
|
|
||
| if (flag.state === 'active') { | ||
| output.warn(`Flag ${chalk.bold(flag.slug)} is already active`); | ||
| return 0; | ||
| } | ||
|
|
||
| if (!skipConfirmation) { | ||
| if (!client.stdin.isTTY) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When AGENTS.md reference: packages/cli/AGENTS.md:L98-L98 Useful? React with 👍 / 👎. |
||
| output.error( | ||
| 'Missing required flag --yes. Use --yes to skip the confirmation prompt in non-interactive mode.' | ||
| ); | ||
| return 1; | ||
| } | ||
|
|
||
| const confirmed = await client.input.confirm( | ||
| `Are you sure you want to unarchive ${chalk.bold(flag.slug)}?`, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When no AGENTS.md reference: packages/cli/AGENTS.md:L15-L18 Useful? React with 👍 / 👎. |
||
| false | ||
| ); | ||
|
|
||
| if (!confirmed) { | ||
| output.log('Aborted'); | ||
| return 0; | ||
| } | ||
| } | ||
|
|
||
| output.spinner('Unarchiving flag...'); | ||
| await updateFlag(client, project.id, flagArg, { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When the API applies this PATCH but its response is lost, or it returns a retryable 5xx after committing, AGENTS.md reference: packages/cli/AGENTS.md:L102-L102 Useful? React with 👍 / 👎. |
||
| state: 'active', | ||
| message: 'Unarchive', | ||
| }); | ||
| output.stopSpinner(); | ||
|
|
||
| output.success(`Feature flag ${chalk.bold(flag.slug)} has been unarchived`); | ||
| } catch (err) { | ||
| output.stopSpinner(); | ||
| printError(err); | ||
| return 1; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import { TelemetryClient } from '../..'; | ||
|
|
||
| export class FlagsUnarchiveTelemetryClient extends TelemetryClient { | ||
| trackCliArgumentFlag(flag: string | undefined) { | ||
| if (flag) { | ||
| this.trackCliArgument({ | ||
| arg: 'flag', | ||
| value: this.redactedValue, | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| trackCliFlagYes(yes: boolean | undefined) { | ||
| if (yes) { | ||
| this.trackCliFlag('yes'); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
flags archive ... --project Bis run from a directory linked to project A—or from an unlinked directory—the new next-step command drops--project B. Copying it therefore targets a same-named flag in A or fails as unlinked instead of undoing the archive in B; construct the suggestion with the explicit/resolved project and relevant global targeting flags.AGENTS.md reference: packages/cli/AGENTS.md:L15-L18
Useful? React with 👍 / 👎.