Skip to content

Commit 5ec7587

Browse files
Merge branch 'main' into update/project-commands-spec
2 parents 8753520 + 969bbf4 commit 5ec7587

File tree

12 files changed

+338
-190
lines changed

12 files changed

+338
-190
lines changed

.changeset/wet-baboons-hear.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'vercel': major
3+
---
4+
5+
Migrate `vercel teams` subcommands to their own command specifications

packages/cli/src/commands/teams/add.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import chalk from 'chalk';
22
import stamp from '../../util/output/stamp';
33
import eraseLines from '../../util/output/erase-lines';
44
import chars from '../../util/output/chars';
5-
65
import invite from './invite';
76
import { writeToConfigFile } from '../../util/config/files';
87
import { getCommandName } from '../../util/pkg-name';
@@ -13,7 +12,6 @@ import { errorToString, isError } from '@vercel/error-utils';
1312
import output from '../../output-manager';
1413

1514
const validateSlug = (value: string) => /^[a-z]+[a-z0-9_-]*$/.test(value);
16-
1715
const validateName = (value: string) => /^[ a-zA-Z0-9_-]+$/.test(value);
1816

1917
const teamUrlPrefix = 'Team URL'.padEnd(14) + chalk.gray('vercel.com/');
@@ -90,17 +88,6 @@ export default async function add(client: Client): Promise<number> {
9088
output.stopSpinner();
9189
process.stdout.write(eraseLines(2));
9290

93-
/*
94-
if (res.error) {
95-
output.error(res.error.message);
96-
output.log(`${chalk.red(`✖ ${teamNamePrefix}`)}${name}`);
97-
98-
return 1;
99-
// TODO: maybe we want to ask the user to retry? not sure if
100-
// there's a scenario where that would be wanted
101-
}
102-
*/
103-
10491
team = Object.assign(team, res);
10592

10693
output.success(`Team name saved ${elapsed()}`);
Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,66 @@
11
import { packageName } from '../../util/pkg-name';
22
import { nextOption } from '../../util/arg-common';
33

4+
export const addSubcommand = {
5+
name: 'add',
6+
aliases: ['create'],
7+
description: 'Create a new team',
8+
arguments: [],
9+
options: [],
10+
examples: [],
11+
} as const;
12+
413
export const listSubcommand = {
514
name: 'list',
615
aliases: ['ls'],
7-
description: "Show all teams you're a part of",
16+
description: "Show all teams that you're a member of",
817
arguments: [],
918
options: [
1019
nextOption,
1120
{ name: 'since', shorthand: null, type: String, deprecated: true },
1221
{ name: 'until', shorthand: null, type: String, deprecated: true },
1322
{ name: 'count', shorthand: 'C', type: Number, deprecated: true },
1423
],
15-
examples: [],
24+
examples: [
25+
{
26+
name: 'Paginate results, where `1584722256178` is the time in milliseconds since the UNIX epoch',
27+
value: `${packageName} teams ls --next 1584722256178`,
28+
},
29+
],
1630
} as const;
1731

18-
export const teamsCommand = {
19-
name: 'teams',
20-
aliases: ['switch', 'team'],
21-
description: 'Manage teams under your Vercel account',
22-
arguments: [],
23-
subcommands: [
32+
export const switchSubcommand = {
33+
name: 'switch',
34+
aliases: ['change'],
35+
description: 'Switch to a different team',
36+
arguments: [
2437
{
25-
name: 'add',
26-
aliases: ['create'],
27-
description: 'Create a new team',
28-
arguments: [],
29-
options: [],
30-
examples: [],
38+
name: 'name',
39+
required: false,
3140
},
32-
listSubcommand,
41+
],
42+
options: [],
43+
examples: [
3344
{
34-
name: 'switch',
35-
aliases: ['change'],
36-
description: 'Switch to a different team',
37-
arguments: [
38-
{
39-
name: 'name',
40-
required: false,
41-
},
42-
],
43-
options: [],
44-
examples: [],
45+
name: "Switch to a team. If your team's url is 'vercel.com/name', then 'name' is the slug. If the slug is omitted, you can choose interactively",
46+
value: `${packageName} teams switch <slug>`,
4547
},
48+
],
49+
} as const;
50+
51+
export const inviteSubcommand = {
52+
name: 'invite',
53+
aliases: [],
54+
description: 'Invite a new member to a team',
55+
arguments: [
4656
{
47-
name: 'invite',
48-
aliases: [],
49-
description: 'Invite a new member to a team',
50-
arguments: [
51-
{
52-
name: 'emails',
53-
required: true,
54-
},
55-
],
56-
options: [],
57-
examples: [],
57+
name: 'email',
58+
required: true,
59+
multiple: true,
5860
},
5961
],
60-
options: [
61-
// {
62-
// name: 'next',
63-
// shorthand: 'N',
64-
// type: String,
65-
// argument: 'MS',
66-
// deprecated: false,
67-
// description: 'Show next page of results',
68-
// },
69-
],
62+
options: [],
7063
examples: [
71-
{
72-
name: "Switch to a team. If your team's url is 'vercel.com/name', then 'name' is the slug. If the slug is omitted, you can choose interactively.",
73-
value: `${packageName} teams switch <slug>`,
74-
},
7564
{
7665
name: 'Invite new members (interactively)',
7766
value: `${packageName} teams invite`,
@@ -80,9 +69,20 @@ export const teamsCommand = {
8069
name: 'Invite multiple members simultaneously',
8170
value: `${packageName} teams invite [email protected] [email protected]`,
8271
},
83-
{
84-
name: 'Paginate results, where `1584722256178` is the time in milliseconds since the UNIX epoch.',
85-
value: `${packageName} teams ls --next 1584722256178`,
86-
},
8772
],
8873
} as const;
74+
75+
export const teamsCommand = {
76+
name: 'teams',
77+
aliases: ['switch', 'team'],
78+
description: 'Manage Teams under your Vercel account',
79+
arguments: [],
80+
subcommands: [
81+
addSubcommand,
82+
inviteSubcommand,
83+
listSubcommand,
84+
switchSubcommand,
85+
],
86+
options: [],
87+
examples: [],
88+
} as const;

packages/cli/src/commands/teams/index.ts

Lines changed: 62 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@ import add from './add';
33
import change from './switch';
44
import invite from './invite';
55
import { parseArguments } from '../../util/get-args';
6-
import Client from '../../util/client';
7-
import { teamsCommand } from './command';
8-
import { help } from '../help';
6+
import {
7+
addSubcommand,
8+
inviteSubcommand,
9+
listSubcommand,
10+
switchSubcommand,
11+
teamsCommand,
12+
} from './command';
13+
import { Command, help } from '../help';
914
import { getFlagsSpecification } from '../../util/get-flags-specification';
1015
import handleError from '../../util/handle-error';
1116
import { TeamsTelemetryClient } from '../../util/telemetry/commands/teams';
1217
import output from '../../output-manager';
1318
import getSubcommand from '../../util/get-subcommand';
19+
import type Client from '../../util/client';
1420

1521
const COMMAND_CONFIG = {
1622
list: ['ls', 'list'],
@@ -19,18 +25,15 @@ const COMMAND_CONFIG = {
1925
invite: ['invite'],
2026
};
2127

22-
export default async (client: Client) => {
23-
const telemetryClient = new TeamsTelemetryClient({
28+
export default async function teams(client: Client) {
29+
const telemetry = new TeamsTelemetryClient({
2430
opts: {
2531
store: client.telemetryEventStore,
2632
},
2733
});
2834

29-
let parsedArgs = null;
30-
35+
let parsedArgs;
3136
const flagsSpecification = getFlagsSpecification(teamsCommand.options);
32-
33-
// Parse CLI args
3437
try {
3538
parsedArgs = parseArguments(client.argv.slice(2), flagsSpecification, {
3639
permissive: true,
@@ -40,57 +43,72 @@ export default async (client: Client) => {
4043
return 1;
4144
}
4245

43-
const isSwitch = parsedArgs.args[0] === 'switch';
44-
parsedArgs.args = parsedArgs.args.slice(1);
45-
let subcommand: string | string[] | undefined;
46-
let subcommandOriginal: string | undefined;
47-
48-
if (isSwitch) {
49-
subcommand = 'switch';
50-
} else {
51-
const getSubcommandResult = getSubcommand(parsedArgs.args, COMMAND_CONFIG);
52-
subcommand = getSubcommandResult.subcommand;
53-
subcommandOriginal = getSubcommandResult.subcommandOriginal;
54-
parsedArgs.args.shift();
46+
if (parsedArgs.args[0] === 'switch') {
47+
parsedArgs.args.unshift('teams');
5548
}
5649

57-
if (parsedArgs.flags['--help']) {
58-
telemetryClient.trackCliFlagHelp('teams', subcommand);
50+
const { subcommand, args, subcommandOriginal } = getSubcommand(
51+
parsedArgs.args.slice(1),
52+
COMMAND_CONFIG
53+
);
54+
55+
const needHelp = parsedArgs.flags['--help'];
56+
57+
if (!subcommand && needHelp) {
58+
telemetry.trackCliFlagHelp('teams', subcommand);
5959
output.print(help(teamsCommand, { columns: client.stderr.columns }));
6060
return 2;
6161
}
6262

63-
let exitCode = 0;
63+
function printHelp(command: Command) {
64+
output.print(
65+
help(command, { parent: teamsCommand, columns: client.stderr.columns })
66+
);
67+
}
68+
6469
switch (subcommand) {
6570
case 'list': {
66-
telemetryClient.trackCliSubcommandList(subcommandOriginal);
67-
exitCode = await list(client);
68-
break;
71+
if (needHelp) {
72+
telemetry.trackCliFlagHelp('teams', 'list');
73+
printHelp(listSubcommand);
74+
return 2;
75+
}
76+
telemetry.trackCliSubcommandList(subcommandOriginal);
77+
return list(client, args);
6978
}
7079
case 'switch': {
71-
telemetryClient.trackCliSubcommandSwitch(subcommandOriginal);
72-
exitCode = await change(client, parsedArgs.args[0]);
73-
break;
80+
if (needHelp) {
81+
telemetry.trackCliFlagHelp('teams', 'switch');
82+
printHelp(switchSubcommand);
83+
return 2;
84+
}
85+
telemetry.trackCliSubcommandSwitch(subcommandOriginal);
86+
return change(client, args);
7487
}
7588
case 'add': {
76-
telemetryClient.trackCliSubcommandAdd(subcommandOriginal);
77-
exitCode = await add(client);
78-
break;
89+
if (needHelp) {
90+
telemetry.trackCliFlagHelp('teams', 'add');
91+
printHelp(addSubcommand);
92+
return 2;
93+
}
94+
telemetry.trackCliSubcommandAdd(subcommandOriginal);
95+
return add(client);
7996
}
8097
case 'invite': {
81-
telemetryClient.trackCliSubcommandInvite(subcommandOriginal);
82-
exitCode = await invite(client, parsedArgs.args);
83-
break;
98+
if (needHelp) {
99+
telemetry.trackCliFlagHelp('teams', 'invite');
100+
printHelp(inviteSubcommand);
101+
return 2;
102+
}
103+
telemetry.trackCliSubcommandInvite(subcommandOriginal);
104+
return invite(client, args);
84105
}
85106
default: {
86-
if (subcommand !== 'help') {
87-
output.error(
88-
'Please specify a valid subcommand: add | ls | switch | invite'
89-
);
90-
}
91-
exitCode = 2;
107+
output.error(
108+
'Please specify a valid subcommand: add | ls | switch | invite'
109+
);
92110
output.print(help(teamsCommand, { columns: client.stderr.columns }));
111+
return 2;
93112
}
94113
}
95-
return exitCode;
96-
};
114+
}

packages/cli/src/commands/teams/invite.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ import { isAPIError } from '../../util/errors-ts';
1414
import { errorToString, isError } from '@vercel/error-utils';
1515
import { TeamsInviteTelemetryClient } from '../../util/telemetry/commands/teams/invite';
1616
import output from '../../output-manager';
17+
import { parseArguments } from '../../util/get-args';
18+
import { getFlagsSpecification } from '../../util/get-flags-specification';
19+
import handleError from '../../util/handle-error';
20+
import { inviteSubcommand } from './command';
1721

1822
const validateEmail = (data: string) =>
1923
regexEmail.test(data.trim()) || data.length === 0;
@@ -37,7 +41,7 @@ const domains = Array.from(
3741

3842
export default async function invite(
3943
client: Client,
40-
emails: string[] = [],
44+
argv: string[],
4145
{ introMsg = '', noopMsg = 'No changes made' } = {}
4246
): Promise<number> {
4347
const { config, telemetryEventStore } = client;
@@ -48,6 +52,16 @@ export default async function invite(
4852
},
4953
});
5054

55+
let parsedArgs;
56+
const flagsSpecification = getFlagsSpecification(inviteSubcommand.options);
57+
try {
58+
parsedArgs = parseArguments(argv, flagsSpecification);
59+
} catch (error) {
60+
handleError(error);
61+
return 1;
62+
}
63+
const { args: emails } = parsedArgs;
64+
5165
output.spinner('Fetching teams');
5266
const teams = await getTeams(client);
5367
const currentTeam = teams.find(team => team.id === currentTeamId);
@@ -72,7 +86,7 @@ export default async function invite(
7286
introMsg || `Inviting team members to ${chalk.bold(currentTeam.name)}`
7387
);
7488

75-
telemetry.trackCliArgumentEmail(emails.length);
89+
telemetry.trackCliArgumentEmail(emails);
7690

7791
if (emails.length > 0) {
7892
for (const email of emails) {

0 commit comments

Comments
 (0)