Skip to content

Commit 01cd449

Browse files
authored
Merge branch 'main' into austinmerrick/fix-turbo-version-handling
2 parents 6539666 + 60d439d commit 01cd449

File tree

13 files changed

+342
-8
lines changed

13 files changed

+342
-8
lines changed

.changeset/heavy-pens-report.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"vercel": patch
3+
---
4+
5+
[cli] track invocation of `vercel alias *`

.changeset/tiny-ducks-camp.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"vercel": minor
3+
---
4+
5+
Enable direct access to marketplace integration dashboards via `vc integration open [integration]` command

.changeset/weak-dolphins-begin.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"vercel": minor
3+
---
4+
5+
[cli] remove deprecated `certs renew` command

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ const COMMAND_CONFIG = {
1717
add: ['add'],
1818
issue: ['issue'],
1919
ls: ['ls', 'list'],
20-
renew: ['renew'],
2120
rm: ['rm', 'remove'],
2221
};
2322

@@ -54,9 +53,6 @@ export default async function main(client: Client) {
5453
return rm(client, parsedArgs.flags, args);
5554
case 'add':
5655
return add(client, parsedArgs.flags, args);
57-
case 'renew':
58-
output.error('Renewing certificates is deprecated, issue a new one.');
59-
return 1;
6056
default:
6157
output.error('Please specify a valid subcommand: ls | issue | rm');
6258
client.output.print(

packages/cli/src/commands/integration/client.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import Client from '../../util/client';
1+
import type Client from '../../util/client';
22
import type {
33
Integration,
44
IntegrationInstallation,
55
IntegrationProduct,
66
Metadata,
77
BillingPlan,
8+
Configuration,
89
} from './types';
910

1011
export async function fetchIntegration(client: Client, slug: string) {
@@ -16,6 +17,22 @@ export async function fetchIntegration(client: Client, slug: string) {
1617
);
1718
}
1819

20+
export async function fetchMarketplaceIntegrations(
21+
client: Client,
22+
slug: string
23+
) {
24+
const searchParams = new URLSearchParams();
25+
searchParams.set('view', 'account');
26+
searchParams.set('installationType', 'marketplace');
27+
searchParams.set('integrationIdOrSlug', slug);
28+
return await client.fetch<Configuration[]>(
29+
`/v1/integrations/configurations?${searchParams}`,
30+
{
31+
json: true,
32+
}
33+
);
34+
}
35+
1936
export async function fetchInstallations(
2037
client: Client,
2138
integration: Integration

packages/cli/src/commands/integration/command.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { packageName } from '../../util/pkg-name';
2-
import { Command } from '../help';
2+
import type { Command } from '../help';
33

44
export const integrationCommand: Command = {
55
name: 'integration',
@@ -24,6 +24,18 @@ export const integrationCommand: Command = {
2424
options: [],
2525
examples: [],
2626
},
27+
{
28+
name: 'open',
29+
description: "Opens a marketplace integration's dashboard",
30+
arguments: [
31+
{
32+
name: 'name',
33+
required: true,
34+
},
35+
],
36+
options: [],
37+
examples: [],
38+
},
2739
],
2840
examples: [
2941
{
@@ -33,5 +45,12 @@ export const integrationCommand: Command = {
3345
`${packageName} integration add acme`,
3446
],
3547
},
48+
{
49+
name: "Open a marketplace integration's dashboard",
50+
value: [
51+
`${packageName} integration open <integration-name>`,
52+
`${packageName} integration open acme`,
53+
],
54+
},
3655
],
3756
};

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
import Client from '../../util/client';
1+
import type Client from '../../util/client';
22
import { parseArguments } from '../../util/get-args';
33
import getInvalidSubcommand from '../../util/get-invalid-subcommand';
44
import getSubcommand from '../../util/get-subcommand';
55
import { help } from '../help';
66
import { add } from './add';
77
import { integrationCommand } from './command';
8+
import { openIntegration } from './open-integration';
89

910
const COMMAND_CONFIG = {
1011
add: ['add'],
12+
open: ['open'],
1113
};
1214

1315
export default async function main(client: Client) {
@@ -28,6 +30,9 @@ export default async function main(client: Client) {
2830
case 'add': {
2931
return add(client, subArgs);
3032
}
33+
case 'open': {
34+
return openIntegration(client, subArgs);
35+
}
3136
default: {
3237
client.output.error(getInvalidSubcommand(COMMAND_CONFIG));
3338
return 2;
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import chalk from 'chalk';
2+
import open from 'open';
3+
import type Client from '../../util/client';
4+
import getScope from '../../util/get-scope';
5+
import type { Configuration } from './types';
6+
import { fetchMarketplaceIntegrations } from './client';
7+
8+
export async function openIntegration(client: Client, args: string[]) {
9+
if (args.length > 1) {
10+
client.output.error('Cannot open more than one dashboard at a time');
11+
return 1;
12+
}
13+
14+
const integrationSlug = args[0];
15+
16+
if (!integrationSlug) {
17+
client.output.error('You must pass an integration slug');
18+
return 1;
19+
}
20+
21+
const { team } = await getScope(client);
22+
23+
if (!team) {
24+
client.output.error('Team not found');
25+
return 1;
26+
}
27+
28+
let configuration: Configuration | undefined;
29+
30+
try {
31+
configuration = await getFirstConfiguration(client, integrationSlug);
32+
} catch (error) {
33+
client.output.error(
34+
`Failed to fetch configuration for ${chalk.bold(`"${integrationSlug}"`)}: ${(error as Error).message}`
35+
);
36+
return 1;
37+
}
38+
39+
if (!configuration) {
40+
client.output.error(
41+
`No configuration found for ${chalk.bold(`"${integrationSlug}"`)}.`
42+
);
43+
return 1;
44+
}
45+
46+
client.output.print(
47+
`Opening the ${chalk.bold(integrationSlug)} dashboard...`
48+
);
49+
50+
const url = new URL('/api/marketplace/sso', 'https://vercel.com');
51+
url.searchParams.set('teamId', team.id);
52+
url.searchParams.set('integrationConfigurationId', configuration.id);
53+
open(url.href);
54+
55+
return 0;
56+
}
57+
58+
async function getFirstConfiguration(client: Client, integrationSlug: string) {
59+
const configurations = await fetchMarketplaceIntegrations(
60+
client,
61+
integrationSlug
62+
);
63+
return configurations.length > 0 ? configurations[0] : undefined;
64+
}

packages/cli/src/commands/integration/types.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,21 @@ export interface IntegrationProduct {
3737
metadataSchema: MetadataSchema;
3838
}
3939

40+
export type InstallationType = 'marketplace' | 'external';
41+
42+
export interface Configuration {
43+
id: string;
44+
integrationId: string;
45+
ownerId: string;
46+
slug: string;
47+
teamId: string;
48+
userId: string;
49+
scopes: string[];
50+
source: string;
51+
installationType: InstallationType;
52+
projects: string[];
53+
}
54+
4055
export interface Integration {
4156
id: string;
4257
slug: string;
@@ -46,7 +61,7 @@ export interface Integration {
4661

4762
export interface IntegrationInstallation {
4863
id: string;
49-
installationType: 'marketplace' | 'external';
64+
installationType: InstallationType;
5065
ownerId: string;
5166
}
5267

packages/cli/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,7 @@ const main = async () => {
554554
let func: any;
555555
switch (targetCommand) {
556556
case 'alias':
557+
telemetry.trackCliCommandAlias(userSuppliedSubCommand);
557558
func = require('./commands/alias').default;
558559
break;
559560
case 'bisect':

0 commit comments

Comments
 (0)