Compare commits

..

1 Commits

Author SHA1 Message Date
Nathan Rajlich
0fc114ee16 [cli] Enable TS path alias 2023-04-14 00:46:58 -07:00
126 changed files with 1329 additions and 1363 deletions

View File

@@ -11,8 +11,6 @@ packages/cli/@types
packages/cli/download
packages/cli/dist
packages/cli/test/dev/fixtures
packages/cli/bin
packages/cli/link
packages/cli/src/util/dev/templates/*.ts
# client

55
.eslintrc.json Normal file
View File

@@ -0,0 +1,55 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"modules": true
},
"plugins": ["jest"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"env": {
"node": true,
"jest": true,
"es6": true
},
"rules": {
"no-restricted-syntax": [
"warn",
"WithStatement",
{
"message": "substr() is deprecated, use slice() or substring() instead",
"selector": "MemberExpression > Identifier[name='substr']"
}
],
"no-dupe-keys": 2,
"require-atomic-updates": 0,
"@typescript-eslint/ban-ts-comment": 0,
"@typescript-eslint/camelcase": 0,
"@typescript-eslint/explicit-module-boundary-types": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-non-null-assertion": 0,
"@typescript-eslint/no-unused-vars": 2,
"@typescript-eslint/no-use-before-define": 0,
"@typescript-eslint/no-var-requires": 0,
"jest/no-disabled-tests": 2,
"jest/no-focused-tests": 2
},
"overrides": [
{
"files": ["packages/client/**/*"],
"rules": {
"prefer-const": 0,
"require-atomic-updates": 0,
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/no-explicit-any": 0
}
}
]
}

View File

@@ -1,18 +0,0 @@
{
"private": true,
"name": "@vercel-internals/constants",
"types": "dist/index.d.ts",
"main": "dist/index.js",
"scripts": {
"build": "tsc -p tsconfig.json"
},
"dependencies": {
"@vercel/build-utils": "6.3.2",
"@vercel/routing-utils": "2.1.10"
},
"devDependencies": {
"@vercel-internals/tsconfig": "*",
"@vercel/style-guide": "4.0.2",
"typescript": "4.9.4"
}
}

View File

@@ -1,5 +0,0 @@
export const PROJECT_ENV_TARGET = [
'production',
'preview',
'development',
] as const;

View File

@@ -1,7 +0,0 @@
{
"extends": "@vercel-internals/tsconfig",
"compilerOptions": {
"outDir": "./dist"
},
"include": ["src/**/*.ts"]
}

View File

@@ -1,10 +1,6 @@
import type { BuilderFunctions } from '@vercel/build-utils';
import type { Readable, Writable } from 'stream';
import type { Route } from '@vercel/routing-utils';
import { PROJECT_ENV_TARGET } from '@vercel-internals/constants';
export type ProjectEnvTarget = typeof PROJECT_ENV_TARGET[number];
export type ProjectEnvType = 'plain' | 'secret' | 'encrypted' | 'system';
export type ProjectSettings = import('@vercel/build-utils').ProjectSettings;
@@ -304,6 +300,20 @@ export interface Secret {
createdAt: number;
}
// TODO (Ethan-Arrowood) - Replace enums
export enum ProjectEnvTarget {
Production = 'production',
Preview = 'preview',
Development = 'development',
}
export enum ProjectEnvType {
Plaintext = 'plain',
Secret = 'secret',
Encrypted = 'encrypted',
System = 'system',
}
export interface ProjectEnvVariable {
id: string;
key: string;

View File

@@ -1,11 +1,15 @@
{
"private": true,
"name": "@vercel-internals/types",
"types": "index.d.ts",
"main": "index.d.ts",
"types": "dist/index.d.ts",
"main": "dist/index.js",
"files": [
"dist"
],
"scripts": {
"build": "tsc -p tsconfig.json"
},
"dependencies": {
"@types/node": "14.14.31",
"@vercel-internals/constants": "*",
"@vercel/build-utils": "6.3.2",
"@vercel/routing-utils": "2.1.10"
},

View File

@@ -1,7 +1,7 @@
{
"extends": "@vercel-internals/tsconfig",
"compilerOptions": {
"noEmit": true
"outDir": "./dist"
},
"include": ["index.d.ts"]
"include": ["index.ts"]
}

View File

@@ -8,6 +8,7 @@
"lerna": "5.6.2"
},
"devDependencies": {
"@limegrass/eslint-plugin-import-alias": "1.0.6",
"@types/node": "14.18.33",
"@typescript-eslint/eslint-plugin": "5.21.0",
"@typescript-eslint/parser": "5.21.0",
@@ -32,13 +33,14 @@
"source-map-support": "0.5.12",
"ts-eager": "2.0.2",
"ts-jest": "29.1.0",
"turbo": "1.9.1"
"turbo": "1.8.5"
},
"scripts": {
"lerna": "lerna",
"version": "pnpm install && git add pnpm-lock.yaml",
"bootstrap": "lerna bootstrap",
"publish-stable": "echo 'Run `pnpm changelog` for instructions'",
"publish-canary": "git checkout main && git pull && lerna version prerelease --preid canary --message \"Publish Canary\" --exact",
"publish-from-github": "./utils/publish.sh",
"changelog": "node utils/changelog.js",
"build": "node utils/gen.js && turbo --no-update-notifier run build",
@@ -69,83 +71,5 @@
"trailingComma": "es5",
"singleQuote": true,
"arrowParens": "avoid"
},
"eslintConfig": {
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"modules": true
},
"plugins": [
"jest"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"env": {
"node": true,
"jest": true,
"es6": true
},
"rules": {
"no-restricted-syntax": [
"warn",
"WithStatement",
{
"message": "substr() is deprecated, use slice() or substring() instead",
"selector": "MemberExpression > Identifier[name='substr']"
}
],
"no-dupe-keys": 2,
"require-atomic-updates": 0,
"@typescript-eslint/ban-ts-comment": 0,
"@typescript-eslint/camelcase": 0,
"@typescript-eslint/explicit-module-boundary-types": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-non-null-assertion": 0,
"@typescript-eslint/no-unused-vars": 2,
"@typescript-eslint/no-use-before-define": 0,
"@typescript-eslint/no-var-requires": 0,
"jest/no-disabled-tests": 2,
"jest/no-focused-tests": 2
},
"overrides": [
{
"files": [
"packages/cli/**/*"
],
"rules": {
"lines-between-class-members": 0,
"no-async-promise-executor": 0,
"no-control-regex": 0,
"no-empty": 0,
"prefer-const": 0,
"prefer-destructuring": 0,
"@typescript-eslint/ban-types": 0,
"@typescript-eslint/consistent-type-assertions": 0,
"@typescript-eslint/member-delimiter-style": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-inferrable-types": 0
}
},
{
"files": [
"packages/client/**/*"
],
"rules": {
"prefer-const": 0,
"require-atomic-updates": 0,
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/no-explicit-any": 0
}
}
]
}
}

View File

@@ -0,0 +1,5 @@
@types
download
dist
test/dev/fixtures
src/util/dev/templates/*.ts

View File

@@ -0,0 +1,24 @@
{
"extends": ["../../.eslintrc.json"],
"plugins": ["@limegrass/import-alias"],
"rules": {
"@limegrass/import-alias/import-alias": [
"warn",
{
"aliasConfigPath": "./packages/cli/tsconfig.json"
}
],
"lines-between-class-members": 0,
"no-async-promise-executor": 0,
"no-control-regex": 0,
"no-empty": 0,
"prefer-const": 0,
"prefer-destructuring": 0,
"@typescript-eslint/ban-types": 0,
"@typescript-eslint/consistent-type-assertions": 0,
"@typescript-eslint/member-delimiter-style": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-inferrable-types": 0
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "28.19.0",
"version": "28.18.5",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Vercel",
@@ -33,15 +33,15 @@
},
"dependencies": {
"@vercel/build-utils": "6.7.1",
"@vercel/go": "2.5.0",
"@vercel/hydrogen": "0.0.63",
"@vercel/next": "3.7.5",
"@vercel/node": "2.11.0",
"@vercel/python": "3.1.59",
"@vercel/go": "2.4.4",
"@vercel/hydrogen": "0.0.62",
"@vercel/next": "3.7.4",
"@vercel/node": "2.10.3",
"@vercel/python": "3.1.58",
"@vercel/redwood": "1.1.14",
"@vercel/remix-builder": "1.8.5",
"@vercel/remix-builder": "1.8.4",
"@vercel/ruby": "1.3.75",
"@vercel/static-build": "1.3.24"
"@vercel/static-build": "1.3.23"
},
"devDependencies": {
"@alex_neo/jest-expect-message": "1.0.5",
@@ -84,13 +84,12 @@
"@types/which": "1.3.2",
"@types/write-json-file": "2.2.1",
"@types/yauzl-promise": "2.1.0",
"@vercel-internals/constants": "*",
"@vercel-internals/get-package-json": "*",
"@vercel-internals/types": "*",
"@vercel/client": "12.4.10",
"@vercel/error-utils": "1.0.10",
"@vercel/client": "12.4.9",
"@vercel/error-utils": "1.0.9",
"@vercel/frameworks": "1.3.4",
"@vercel/fs-detectors": "3.8.11",
"@vercel/fs-detectors": "3.8.10",
"@vercel/fun": "1.0.4",
"@vercel/ncc": "0.24.0",
"@vercel/routing-utils": "2.2.0",

View File

@@ -12,7 +12,7 @@ import stamp from '../../util/output/stamp';
import strlen from '../../util/strlen';
import getCommandFlags from '../../util/get-command-flags';
import { getCommandName } from '../../util/pkg-name';
import type { Alias } from '@vercel-internals/types';
import { Alias } from '@vercel-internals/types';
export default async function ls(
client: Client,

View File

@@ -9,7 +9,7 @@ import strlen from '../../util/strlen';
import confirm from '../../util/input/confirm';
import findAliasByAliasOrId from '../../util/alias/find-alias-by-alias-or-id';
import type { Alias } from '@vercel-internals/types';
import { Alias } from '@vercel-internals/types';
import { isValidName } from '../../util/is-valid-name';
import { getCommandName } from '../../util/pkg-name';

View File

@@ -1,7 +1,7 @@
import chalk from 'chalk';
import { SetDifference } from 'utility-types';
import { AliasRecord } from '../../util/alias/create-alias';
import type { Domain } from '@vercel-internals/types';
import { Domain } from '@vercel-internals/types';
import { Output } from '../../util/output';
import * as ERRORS from '../../util/errors-ts';
import assignAlias from '../../util/alias/assign-alias';

View File

@@ -5,7 +5,7 @@ import stamp from '../../util/output/stamp';
import createCertFromFile from '../../util/certs/create-cert-from-file';
import createCertForCns from '../../util/certs/create-cert-for-cns';
import { getCommandName } from '../../util/pkg-name';
import type { Cert } from '@vercel-internals/types';
import { Cert } from '@vercel-internals/types';
interface Options {
'--overwrite'?: boolean;

View File

@@ -10,7 +10,7 @@ import {
import stamp from '../../util/output/stamp';
import getCerts from '../../util/certs/get-certs';
import strlen from '../../util/strlen';
import type { Cert } from '@vercel-internals/types';
import { Cert } from '@vercel-internals/types';
import getCommandFlags from '../../util/get-command-flags';
import { getCommandName } from '../../util/pkg-name';

View File

@@ -2,7 +2,7 @@ import chalk from 'chalk';
import ms from 'ms';
import plural from 'pluralize';
import table from 'text-table';
import type { Cert } from '@vercel-internals/types';
import { Cert } from '@vercel-internals/types';
import * as ERRORS from '../../util/errors-ts';
import { Output } from '../../util/output';
import deleteCertById from '../../util/certs/delete-cert-by-id';

View File

@@ -71,7 +71,6 @@ export const help = () => `
-m, --meta Add metadata for the deployment (e.g.: ${chalk.dim(
'`-m KEY=value`'
)}). Can appear many times.
--no-wait Don't wait for the deployment to finish
-S, --scope Set a custom scope
--regions Set default regions to enable the deployment on
--prod Create a production deployment

View File

@@ -16,7 +16,7 @@ import { handleError } from '../../util/error';
import Client from '../../util/client';
import { getPrettyError } from '@vercel/build-utils';
import toHumanPath from '../../util/humanize-path';
import Now, { CreateOptions } from '../../util';
import Now from '../../util';
import stamp from '../../util/output/stamp';
import createDeploy from '../../util/deploy/create-deploy';
import getDeployment from '../../util/get-deployment';
@@ -70,8 +70,6 @@ import { isValidArchive } from '../../util/deploy/validate-archive-format';
import { parseEnv } from '../../util/parse-env';
import { errorToString, isErrnoException, isError } from '@vercel/error-utils';
import { pickOverrides } from '../../util/projects/project-settings';
import { isDeploying } from '../../util/deploy/is-deploying';
import type { Deployment } from '@vercel-internals/types';
export default async (client: Client): Promise<number> => {
const { output } = client;
@@ -92,7 +90,6 @@ export default async (client: Client): Promise<number> => {
'--prebuilt': Boolean,
'--prod': Boolean,
'--archive': String,
'--no-wait': Boolean,
'--yes': Boolean,
'-f': '--force',
'-p': '--public',
@@ -508,20 +505,12 @@ export default async (client: Client): Promise<number> => {
});
let deployStamp = stamp();
let deployment = null;
const noWait = !!argv['--no-wait'];
const localConfigurationOverrides = pickOverrides(localConfig);
const name = project ? project.name : newProjectName;
if (!name) {
throw new Error(
'`name` not found on project or provided by existing project'
);
}
try {
const createArgs: CreateOptions = {
name,
const createArgs: any = {
name: project ? project.name : newProjectName,
env: deploymentEnv,
build: { env: deploymentBuildEnv },
forceNew: argv['--force'],
@@ -529,7 +518,8 @@ export default async (client: Client): Promise<number> => {
prebuilt: argv['--prebuilt'],
rootDirectory,
quiet,
wantsPublic: Boolean(argv['--public'] || localConfig.public),
wantsPublic: argv['--public'] || localConfig.public,
type: null,
nowConfig: {
...localConfig,
// `images` is allowed in "vercel.json" and processed
@@ -542,7 +532,6 @@ export default async (client: Client): Promise<number> => {
deployStamp,
target,
skipAutoDetectionConfirmation: autoConfirm,
noWait,
};
if (!localConfig.builds || localConfig.builds.length === 0) {
@@ -638,10 +627,8 @@ export default async (client: Client): Promise<number> => {
return 1;
}
if (!noWait) {
// get the deployment just to double check that it actually deployed
await getDeployment(client, contextName, deployment.id);
}
// get the deployment just to double check that it actually deployed
await getDeployment(client, contextName, deployment.id);
if (deployment === null) {
error('Uploading failed. Please try again.');
@@ -728,7 +715,7 @@ export default async (client: Client): Promise<number> => {
return 1;
}
return printDeploymentStatus(output, client, deployment, deployStamp, noWait);
return printDeploymentStatus(output, client, deployment, deployStamp);
};
function handleCreateDeployError(
@@ -848,7 +835,7 @@ const printDeploymentStatus = async (
url: deploymentUrl,
aliasWarning,
}: {
readyState: Deployment['readyState'];
readyState: string;
alias: string[];
aliasError: Error;
target: string;
@@ -861,26 +848,12 @@ const printDeploymentStatus = async (
action?: string;
};
},
deployStamp: () => string,
noWait: boolean
deployStamp: () => string
) => {
indications = indications || [];
const isProdDeployment = target === 'production';
let isStillBuilding = false;
if (noWait) {
if (isDeploying(readyState)) {
isStillBuilding = true;
output.print(
prependEmoji(
'Note: Deployment is still processing...',
emoji('notice')
) + '\n'
);
}
}
if (!isStillBuilding && readyState !== 'READY') {
if (readyState !== 'READY') {
output.error(
`Your deployment failed. Please retry later. More: https://err.sh/vercel/deployment-error`
);
@@ -896,8 +869,7 @@ const printDeploymentStatus = async (
} else {
// print preview/production url
let previewUrl: string;
// if `noWait` is true, then use the deployment url, not an alias
if (!noWait && Array.isArray(aliasList) && aliasList.length > 0) {
if (Array.isArray(aliasList) && aliasList.length > 0) {
const previewUrlInfo = await getPreferredPreviewURL(client, aliasList);
if (previewUrlInfo) {
previewUrl = previewUrlInfo.previewUrl;

View File

@@ -5,7 +5,7 @@ import DevServer from '../../util/dev/server';
import { parseListen } from '../../util/dev/parse-listen';
import Client from '../../util/client';
import { getLinkedProject } from '../../util/projects/link';
import type { ProjectSettings } from '@vercel-internals/types';
import { ProjectSettings } from '@vercel-internals/types';
import setupAndLink from '../../util/link/setup-and-link';
import { getCommandName } from '../../util/pkg-name';
import param from '../../util/output/param';

View File

@@ -1,7 +1,7 @@
import chalk from 'chalk';
import ms from 'ms';
import { DomainNotFound } from '../../util/errors-ts';
import type { DNSRecord } from '@vercel-internals/types';
import { DNSRecord } from '@vercel-internals/types';
import Client from '../../util/client';
import formatTable from '../../util/format-table';
import getDNSRecords, {

View File

@@ -1,7 +1,7 @@
import chalk from 'chalk';
import ms from 'ms';
import table from 'text-table';
import type { DNSRecord } from '@vercel-internals/types';
import { DNSRecord } from '@vercel-internals/types';
import { Output } from '../../util/output';
import Client from '../../util/client';
import deleteDNSRecordById from '../../util/dns/delete-dns-record-by-id';

View File

@@ -8,7 +8,7 @@ import getScope from '../../util/get-scope';
import stamp from '../../util/output/stamp';
import formatTable from '../../util/format-table';
import { formatDateWithoutTime } from '../../util/format-date';
import type { Domain } from '@vercel-internals/types';
import { Domain } from '@vercel-internals/types';
import getCommandFlags from '../../util/get-command-flags';
import {
PaginationOptions,

View File

@@ -2,7 +2,7 @@ import chalk from 'chalk';
import plural from 'pluralize';
import { DomainNotFound, DomainPermissionDenied } from '../../util/errors-ts';
import type { Domain } from '@vercel-internals/types';
import { Domain } from '@vercel-internals/types';
import { Output } from '../../util/output';
import Client from '../../util/client';
import deleteCertById from '../../util/certs/delete-cert-by-id';

View File

@@ -1,5 +1,9 @@
import chalk from 'chalk';
import type { Project, ProjectEnvTarget } from '@vercel-internals/types';
import {
ProjectEnvTarget,
Project,
ProjectEnvType,
} from '@vercel-internals/types';
import { Output } from '../../util/output';
import Client from '../../util/client';
import stamp from '../../util/output/stamp';
@@ -8,7 +12,7 @@ import getEnvRecords from '../../util/env/get-env-records';
import {
isValidEnvTarget,
getEnvTargetPlaceholder,
envTargetChoices,
getEnvTargetChoices,
} from '../../util/env/env-target';
import readStandardInput from '../../util/input/read-standard-input';
import param from '../../util/output/param';
@@ -88,7 +92,7 @@ export default async function add(
const existing = new Set(
envs.filter(r => r.key === envName).map(r => r.target)
);
const choices = envTargetChoices.filter(c => !existing.has(c.value));
const choices = getEnvTargetChoices().filter(c => !existing.has(c.value));
if (choices.length === 0) {
output.error(
@@ -134,7 +138,7 @@ export default async function add(
!stdInput &&
!envGitBranch &&
envTargets.length === 1 &&
envTargets[0] === 'preview'
envTargets[0] === ProjectEnvTarget.Preview
) {
const { inputValue } = await client.prompt({
type: 'input',
@@ -151,7 +155,7 @@ export default async function add(
output,
client,
project.id,
'encrypted',
ProjectEnvType.Encrypted,
envName,
envValue,
envTargets,

View File

@@ -1,7 +1,11 @@
import chalk from 'chalk';
import ms from 'ms';
import { Output } from '../../util/output';
import type { Project, ProjectEnvVariable } from '@vercel-internals/types';
import {
Project,
ProjectEnvVariable,
ProjectEnvType,
} from '@vercel-internals/types';
import Client from '../../util/client';
import formatTable from '../../util/format-table';
import getEnvRecords from '../../util/env/get-env-records';
@@ -95,13 +99,13 @@ function getTable(records: ProjectEnvVariable[]) {
function getRow(env: ProjectEnvVariable) {
let value: string;
if (env.type === 'plain') {
if (env.type === ProjectEnvType.Plaintext) {
// replace space characters (line-break, etc.) with simple spaces
// to make sure the displayed value is a single line
const singleLineValue = env.value.replace(/\s/g, ' ');
value = chalk.gray(ellipsis(singleLineValue, 19));
} else if (env.type === 'system') {
} else if (env.type === ProjectEnvType.System) {
value = chalk.gray.italic(env.value);
} else {
value = chalk.gray.italic('Encrypted');

View File

@@ -2,7 +2,7 @@ import chalk from 'chalk';
import { outputFile } from 'fs-extra';
import { closeSync, openSync, readSync } from 'fs';
import { resolve } from 'path';
import type { Project, ProjectEnvTarget } from '@vercel-internals/types';
import { Project, ProjectEnvTarget } from '@vercel-internals/types';
import Client from '../../util/client';
import { emoji, prependEmoji } from '../../util/emoji';
import confirm from '../../util/input/confirm';
@@ -101,7 +101,7 @@ export default async function pull(
const records = (
await pullEnvRecords(output, client, project.id, source, {
target: environment || 'development',
target: environment || ProjectEnvTarget.Development,
gitBranch,
})
).env;

View File

@@ -1,5 +1,5 @@
import chalk from 'chalk';
import type { Project } from '@vercel-internals/types';
import { Project } from '@vercel-internals/types';
import { Output } from '../../util/output';
import confirm from '../../util/input/confirm';
import removeEnvRecord from '../../util/env/remove-env-record';

View File

@@ -10,14 +10,10 @@ import getScope from '../util/get-scope';
import { getPkgName, getCommandName } from '../util/pkg-name';
import Client from '../util/client';
import getDeployment from '../util/get-deployment';
import type { Build, Deployment } from '@vercel-internals/types';
import { Build, Deployment } from '@vercel-internals/types';
import title from 'title';
import { isErrnoException } from '@vercel/error-utils';
import { URL } from 'url';
import readStandardInput from '../util/input/read-standard-input';
import sleep from '../util/sleep';
import ms from 'ms';
import { isDeploying } from '../util/deploy/is-deploying';
const help = () => {
console.log(`
@@ -38,10 +34,6 @@ const help = () => {
-d, --debug Debug mode [off]
--no-color No color mode [off]
-S, --scope Set a custom scope
--timeout=${chalk.bold.underline(
'TIME'
)} Time to wait for deployment completion [3m]
--wait Blocks until deployment completes
${chalk.dim('Examples:')}
@@ -52,16 +44,6 @@ const help = () => {
${chalk.gray('-')} Get information about the deployment an alias points to
${chalk.cyan(`$ ${getPkgName()} inspect my-deployment.vercel.app`)}
${chalk.gray('-')} Get information about a deployment by piping in the URL
${chalk.cyan(`$ echo my-deployment.vercel.app | ${getPkgName()} inspect`)}
${chalk.gray('-')} Wait up to 90 seconds for deployment to complete
${chalk.cyan(
`$ ${getPkgName()} inspect my-deployment.vercel.app --wait --timeout 90s`
)}
`);
};
@@ -69,10 +51,7 @@ export default async function main(client: Client) {
let argv;
try {
argv = getArgs(client.argv.slice(2), {
'--timeout': String,
'--wait': Boolean,
});
argv = getArgs(client.argv.slice(2));
} catch (err) {
handleError(err);
return 1;
@@ -88,28 +67,12 @@ export default async function main(client: Client) {
// extract the first parameter
let [, deploymentIdOrHost] = argv._;
if (!deploymentIdOrHost) {
// if the URL is not passed in, check stdin
// allows cool stuff like `echo my-deployment.vercel.app | vc inspect --wait`
const stdInput = await readStandardInput(client.stdin);
if (stdInput) {
deploymentIdOrHost = stdInput;
}
}
if (!deploymentIdOrHost) {
if (argv._.length !== 2) {
error(`${getCommandName('inspect <url>')} expects exactly one argument`);
help();
return 1;
}
// validate the timeout
const timeout = ms(argv['--timeout'] ?? '3m');
if (timeout === undefined) {
error(`Invalid timeout "${argv['--timeout']}"`);
return 1;
}
let contextName: string | null = null;
try {
@@ -135,22 +98,12 @@ export default async function main(client: Client) {
`Fetching deployment "${deploymentIdOrHost}" in ${chalk.bold(contextName)}`
);
const until = Date.now() + timeout;
const wait = argv['--wait'];
// resolve the deployment, since we might have been given an alias
let deployment = await getDeployment(client, contextName, deploymentIdOrHost);
while (Date.now() < until) {
if (!wait || !isDeploying(deployment.readyState)) {
break;
}
await sleep(250);
// check the deployment state again
deployment = await getDeployment(client, contextName, deploymentIdOrHost);
}
const deployment = await getDeployment(
client,
contextName,
deploymentIdOrHost
);
const {
id,

View File

@@ -1,7 +1,7 @@
import chalk from 'chalk';
import ms from 'ms';
import table from 'text-table';
import type { Project } from '@vercel-internals/types';
import { Project } from '@vercel-internals/types';
import Client from '../../util/client';
import getCommandFlags from '../../util/get-command-flags';
import { getCommandName } from '../../util/pkg-name';

View File

@@ -18,41 +18,43 @@ import sourceMap from '@zeit/source-map-support';
import { mkdirp } from 'fs-extra';
import chalk from 'chalk';
import epipebomb from 'epipebomb';
import getLatestVersion from './util/get-latest-version';
import getLatestVersion from '~/util/get-latest-version';
import { URL } from 'url';
import * as Sentry from '@sentry/node';
import hp from './util/humanize-path';
import commands from './commands';
import pkg from './util/pkg';
import { Output } from './util/output';
import cmd from './util/output/cmd';
import info from './util/output/info';
import error from './util/output/error';
import param from './util/output/param';
import highlight from './util/output/highlight';
import getArgs from './util/get-args';
import getUser from './util/get-user';
import getTeams from './util/teams/get-teams';
import Client from './util/client';
import { handleError } from './util/error';
import reportError from './util/report-error';
import getConfig from './util/get-config';
import * as configFiles from './util/config/files';
import getGlobalPathConfig from './util/config/global-path';
import hp from '~/util/humanize-path';
import commands from '~/commands';
import pkg from '~/util/pkg';
import { Output } from '~/util/output';
import cmd from '~/util/output/cmd';
import info from '~/util/output/info';
import error from '~/util/output/error';
import param from '~/util/output/param';
import highlight from '~/util/output/highlight';
import getArgs from '~/util/get-args';
import getUser from '~/util/get-user';
import getTeams from '~/util/teams/get-teams';
import Client from '~/util/client';
import { handleError } from '~/util/error';
import reportError from '~/util/report-error';
import getConfig from '~/util/get-config';
import * as configFiles from '~/util/config/files';
import getGlobalPathConfig from '~/util/config/global-path';
import {
defaultAuthConfig,
defaultGlobalConfig,
} from './util/config/get-default';
import * as ERRORS from './util/errors-ts';
import { APIError } from './util/errors-ts';
import { SENTRY_DSN } from './util/constants';
import getUpdateCommand from './util/get-update-command';
import { metrics, shouldCollectMetrics } from './util/metrics';
import { getCommandName, getTitleName } from './util/pkg-name';
import doLoginPrompt from './util/login/prompt';
import type { AuthConfig, GlobalConfig } from '@vercel-internals/types';
} from '~/util/config/get-default';
import * as ERRORS from '~/util/errors-ts';
import { APIError } from '~/util/errors-ts';
import { SENTRY_DSN } from '~/util/constants';
import getUpdateCommand from '~/util/get-update-command';
import { metrics, shouldCollectMetrics } from '~/util/metrics';
import { getCommandName, getTitleName } from '~/util/pkg-name';
import doLoginPrompt from '~/util/login/prompt';
import { AuthConfig, GlobalConfig } from '@vercel-internals/types';
import { VercelConfig } from '@vercel/client';
import box from './util/output/box';
import box from '~/util/output/box';
const isCanary = pkg.version.includes('canary');
const VERCEL_DIR = getGlobalPathConfig();
const VERCEL_CONFIG_PATH = configFiles.getConfigFilePath();
@@ -68,7 +70,7 @@ sourceMap.install();
Sentry.init({
dsn: SENTRY_DSN,
release: `vercel-cli@${pkg.version}`,
environment: 'stable',
environment: isCanary ? 'canary' : 'stable',
});
let client: Client;
@@ -163,7 +165,13 @@ const main = async () => {
)}`
);
} else {
output.print(`${chalk.grey(`${getTitleName()} CLI ${pkg.version}`)}\n`);
output.print(
`${chalk.grey(
`${getTitleName()} CLI ${pkg.version}${
isCanary ? ' — https://vercel.com/feedback' : ''
}`
)}\n`
);
}
// Handle `--version` directly
@@ -475,76 +483,76 @@ const main = async () => {
let func: any;
switch (targetCommand) {
case 'alias':
func = require('./commands/alias').default;
func = require('~/commands/alias').default;
break;
case 'bisect':
func = require('./commands/bisect').default;
func = require('~/commands/bisect').default;
break;
case 'build':
func = require('./commands/build').default;
func = require('~/commands/build').default;
break;
case 'certs':
func = require('./commands/certs').default;
func = require('~/commands/certs').default;
break;
case 'deploy':
func = require('./commands/deploy').default;
func = require('~/commands/deploy').default;
break;
case 'dev':
func = require('./commands/dev').default;
func = require('~/commands/dev').default;
break;
case 'dns':
func = require('./commands/dns').default;
func = require('~/commands/dns').default;
break;
case 'domains':
func = require('./commands/domains').default;
func = require('~/commands/domains').default;
break;
case 'env':
func = require('./commands/env').default;
func = require('~/commands/env').default;
break;
case 'git':
func = require('./commands/git').default;
func = require('~/commands/git').default;
break;
case 'init':
func = require('./commands/init').default;
func = require('~/commands/init').default;
break;
case 'inspect':
func = require('./commands/inspect').default;
func = require('~/commands/inspect').default;
break;
case 'link':
func = require('./commands/link').default;
func = require('~/commands/link').default;
break;
case 'list':
func = require('./commands/list').default;
func = require('~/commands/list').default;
break;
case 'logs':
func = require('./commands/logs').default;
func = require('~/commands/logs').default;
break;
case 'login':
func = require('./commands/login').default;
func = require('~/commands/login').default;
break;
case 'logout':
func = require('./commands/logout').default;
func = require('~/commands/logout').default;
break;
case 'project':
func = require('./commands/project').default;
func = require('~/commands/project').default;
break;
case 'pull':
func = require('./commands/pull').default;
func = require('~/commands/pull').default;
break;
case 'remove':
func = require('./commands/remove').default;
func = require('~/commands/remove').default;
break;
case 'rollback':
func = require('./commands/rollback').default;
func = require('~/commands/rollback').default;
break;
case 'secrets':
func = require('./commands/secrets').default;
func = require('~/commands/secrets').default;
break;
case 'teams':
func = require('./commands/teams').default;
func = require('~/commands/teams').default;
break;
case 'whoami':
func = require('./commands/whoami').default;
func = require('~/commands/whoami').default;
break;
default:
func = null;
@@ -699,6 +707,7 @@ main()
// Check if an update is available. If so, `latest` will contain a string
// of the latest version, otherwise `undefined`.
const latest = getLatestVersion({
distTag: isCanary ? 'canary' : 'latest',
output,
pkg,
});

View File

@@ -1,5 +1,5 @@
import { Output } from '../output';
import type { Alias } from '@vercel-internals/types';
import { Alias } from '@vercel-internals/types';
import Client from '../client';

View File

@@ -2,7 +2,7 @@ import path from 'path';
import chalk from 'chalk';
import Client from '../client';
import { Output } from '../output';
import type { User } from '@vercel-internals/types';
import { User } from '@vercel-internals/types';
import { VercelConfig } from '../dev/types';
import getDeploymentsByAppName from '../deploy/get-deployments-by-appname';
import getDeployment from '../get-deployment';

View File

@@ -1,6 +1,6 @@
import Client from '../client';
import getAliases from './get-aliases';
import type { Alias } from '@vercel-internals/types';
import { Alias } from '@vercel-internals/types';
export default async function getDomainAliases(client: Client, domain: string) {
const { aliases } = await getAliases(client);

View File

@@ -1,4 +1,4 @@
import type { Build } from '@vercel-internals/types';
import { Build } from '@vercel-internals/types';
export const isReady = ({ readyState }: Pick<Build, 'readyState'>) =>
readyState === 'READY';

View File

@@ -1,7 +1,7 @@
import { readFileSync } from 'fs';
import { resolve } from 'path';
import Client from '../client';
import type { Cert } from '@vercel-internals/types';
import { Cert } from '@vercel-internals/types';
import { isErrnoException } from '@vercel/error-utils';
import { isAPIError } from '../errors-ts';

View File

@@ -1,6 +1,6 @@
import chalk from 'chalk';
import type { Cert } from '@vercel-internals/types';
import { Cert } from '@vercel-internals/types';
import * as ERRORS from '../errors-ts';
import Client from '../client';
import mapCertError from './map-cert-error';

View File

@@ -1,4 +1,4 @@
import type { Cert } from '@vercel-internals/types';
import { Cert } from '@vercel-internals/types';
import Client from '../client';
import * as ERRORS from '../errors-ts';

View File

@@ -1,5 +1,5 @@
import { stringify } from 'querystring';
import type { Cert } from '@vercel-internals/types';
import { Cert } from '@vercel-internals/types';
import Client from '../client';
/**

View File

@@ -1,5 +1,5 @@
import { stringify } from 'querystring';
import type { Cert } from '@vercel-internals/types';
import { Cert } from '@vercel-internals/types';
import * as ERRORS from '../errors-ts';
import Client from '../client';

View File

@@ -1,5 +1,5 @@
import retry from 'async-retry';
import type { Cert } from '@vercel-internals/types';
import { Cert } from '@vercel-internals/types';
import Client from '../client';
import { isAPIError } from '../errors-ts';
import { isError } from '@vercel/error-utils';

View File

@@ -5,13 +5,13 @@ import { URL } from 'url';
import { VercelConfig } from '@vercel/client';
import retry, { RetryFunction, Options as RetryOptions } from 'async-retry';
import fetch, { BodyInit, Headers, RequestInit, Response } from 'node-fetch';
import ua from './ua';
import { Output } from './output/create-output';
import responseError from './response-error';
import printIndications from './print-indications';
import reauthenticate from './login/reauthenticate';
import { SAMLError } from './login/types';
import { writeToAuthConfigFile } from './config/files';
import ua from '~/util/ua';
import { Output } from '~/util/output/create-output';
import responseError from '~/util/response-error';
import printIndications from '~/util/print-indications';
import reauthenticate from '~/util/login/reauthenticate';
import { SAMLError } from '~/util/login/types';
import { writeToAuthConfigFile } from '~/util/config/files';
import type {
AuthConfig,
GlobalConfig,
@@ -20,8 +20,8 @@ import type {
ReadableTTY,
WritableTTY,
} from '@vercel-internals/types';
import { sharedPromise } from './promise';
import { APIError } from './errors-ts';
import { sharedPromise } from '~/util/promise';
import { APIError } from '~/util/errors-ts';
import { normalizeError } from '@vercel/error-utils';
const isSAMLError = (v: any): v is SAMLError => {

View File

@@ -3,7 +3,7 @@ import * as ERRORS_TS from '../errors-ts';
import * as ERRORS from '../errors';
import { NowError } from '../now-error';
import mapCertError from '../certs/map-cert-error';
import type { Org } from '@vercel-internals/types';
import { Org } from '@vercel-internals/types';
import Now, { CreateOptions } from '..';
import Client from '../client';
import { ArchiveFormat, DeploymentError } from '@vercel/client';

View File

@@ -1,5 +1,5 @@
import { URLSearchParams } from 'url';
import type { Deployment } from '@vercel-internals/types';
import { Deployment } from '@vercel-internals/types';
import Client from '../client';
type LegacyDeployment = {

View File

@@ -1,23 +0,0 @@
import { Deployment } from '@vercel-internals/types';
export const deploymentInProgressStates: Deployment['readyState'][] = [
'QUEUED',
'BUILDING',
'INITIALIZING',
];
export const deploymentCompletedStates: Deployment['readyState'][] = [
'READY',
'CANCELED',
'ERROR',
];
/**
* Checks if the deployments readyState is considered to be in progress.
* @param readyState The deployment's readyState
* @returns `true` if in a pending deployment state, otherwise `false` if it's
* ready/canceled/errored
*/
export function isDeploying(readyState: Deployment['readyState']): Boolean {
return deploymentInProgressStates.includes(readyState);
}

View File

@@ -9,7 +9,7 @@ import {
import { Output } from '../output';
import { progress } from '../output/progress';
import Now from '../../util';
import type { Org } from '@vercel-internals/types';
import { Org } from '@vercel-internals/types';
import ua from '../ua';
import { linkFolderToProject } from '../projects/link';
import { prependEmoji, emoji } from '../emoji';
@@ -34,7 +34,6 @@ export default async function processDeployment({
isSettingUpProject,
archive,
skipAutoDetectionConfirmation,
noWait,
...args
}: {
now: Now;
@@ -53,8 +52,7 @@ export default async function processDeployment({
archive?: ArchiveFormat;
skipAutoDetectionConfirmation?: boolean;
cwd?: string;
rootDirectory?: string | null;
noWait?: boolean;
rootDirectory?: string;
}) {
let {
now,
@@ -182,10 +180,6 @@ export default async function processDeployment({
process.stdout.write(`https://${event.payload.url}`);
}
if (noWait) {
return event.payload;
}
output.spinner(
event.payload.readyState === 'QUEUED' ? 'Queued' : 'Building',
0

View File

@@ -51,8 +51,10 @@ import link from '../output/link';
import sleep from '../sleep';
import { Output } from '../output';
import { relative } from '../path-helpers';
import { getDistTag } from '../get-dist-tag';
import getVercelConfigPath from '../config/local-path';
import { MissingDotenvVarsError } from '../errors-ts';
import cliPkg from '../pkg';
import { getVercelDirectory } from '../projects/link';
import { staticFiles as getFiles } from '../get-files';
import { validateConfig } from '../validate-config';
@@ -83,7 +85,7 @@ import {
HttpHeadersConfig,
EnvConfigs,
} from './types';
import type { ProjectSettings } from '@vercel-internals/types';
import { ProjectSettings } from '@vercel-internals/types';
import { treeKill } from '../tree-kill';
import { applyOverriddenHeaders, nodeHeadersToFetchHeaders } from './headers';
import { formatQueryString, parseQueryString } from './parse-query-string';
@@ -591,7 +593,7 @@ export default class DevServer {
rewriteRoutes,
errorRoutes,
} = await detectBuilders(files, pkg, {
tag: 'latest',
tag: getDistTag(cliPkg.version) === 'canary' ? 'canary' : 'latest',
functions: vercelConfig.functions,
projectSettings: projectSettings || this.projectSettings,
featHandleMiss,

View File

@@ -16,7 +16,7 @@ import {
import { VercelConfig } from '@vercel/client';
import { HandleValue, Route } from '@vercel/routing-utils';
import { Output } from '../output';
import type { ProjectSettings } from '@vercel-internals/types';
import { ProjectSettings } from '@vercel-internals/types';
import { BuilderWithPkg } from '../build/import-builders';
export { VercelConfig };

View File

@@ -7,7 +7,7 @@ import {
DNSConflictingRecord,
isAPIError,
} from '../errors-ts';
import type { DNSRecordData } from '@vercel-internals/types';
import { DNSRecordData } from '@vercel-internals/types';
type Response = {
uid: string;

View File

@@ -1,5 +1,5 @@
import chalk from 'chalk';
import type { DNSRecordData } from '@vercel-internals/types';
import { DNSRecordData } from '@vercel-internals/types';
import textInput from '../input/text';
import promptBool from '../input/prompt-bool';
import Client from '../client';

View File

@@ -1,4 +1,4 @@
import type { DNSRecord } from '@vercel-internals/types';
import { DNSRecord } from '@vercel-internals/types';
import Client from '../client';
export default async function getDNSRecordById(

View File

@@ -1,4 +1,4 @@
import type { DNSRecord } from '@vercel-internals/types';
import { DNSRecord } from '@vercel-internals/types';
import { DomainNotFound } from '../errors-ts';
import { Output } from '../output';
import Client from '../client';

View File

@@ -1,4 +1,4 @@
import type { DNSRecordData } from '@vercel-internals/types';
import { DNSRecordData } from '@vercel-internals/types';
export default function parseAddArgs(
args: string[]

View File

@@ -1,7 +1,7 @@
import chalk from 'chalk';
import retry from 'async-retry';
import { DomainAlreadyExists, InvalidDomain, isAPIError } from '../errors-ts';
import type { Domain } from '@vercel-internals/types';
import { Domain } from '@vercel-internals/types';
import Client from '../client';
type Response = {

View File

@@ -1,6 +1,6 @@
import chalk from 'chalk';
import Client from '../client';
import type { Domain } from '@vercel-internals/types';
import { Domain } from '@vercel-internals/types';
import {
DomainPermissionDenied,
DomainNotFound,

View File

@@ -1,5 +1,5 @@
import Client from '../client';
import type { DomainConfig } from '@vercel-internals/types';
import { DomainConfig } from '@vercel-internals/types';
import { isAPIError } from '../errors-ts';
export async function getDomainConfig(client: Client, domainName: string) {

View File

@@ -1,4 +1,4 @@
import type { Domain } from '@vercel-internals/types';
import { Domain } from '@vercel-internals/types';
export type DomainRegistrar = 'Vercel' | 'Purchase in Process' | 'Third Party';

View File

@@ -1,6 +1,6 @@
import chalk from 'chalk';
import Client from '../client';
import type { Domain } from '@vercel-internals/types';
import { Domain } from '@vercel-internals/types';
import { isAPIError } from '../errors-ts';
type Response = {

View File

@@ -1,4 +1,4 @@
import type { Domain } from '@vercel-internals/types';
import { Domain } from '@vercel-internals/types';
export default function isDomainExternal(domain: Domain) {
return domain.serviceType !== 'zeit.world';

View File

@@ -1,6 +1,6 @@
import psl from 'psl';
import { NowError } from '../now-error';
import type { Domain } from '@vercel-internals/types';
import { Domain } from '@vercel-internals/types';
import { Output } from '../output';
import * as ERRORS from '../errors-ts';
import addDomain from './add-domain';

View File

@@ -1,6 +1,6 @@
import * as ERRORS from '../errors-ts';
import Client from '../client';
import type { Domain } from '@vercel-internals/types';
import { Domain } from '@vercel-internals/types';
type Response = {
domain: Domain;

View File

@@ -1,6 +1,6 @@
import { Output } from '../output';
import Client from '../client';
import type {
import {
ProjectEnvTarget,
ProjectEnvVariable,
ProjectEnvType,

View File

@@ -1,22 +1,22 @@
import type { ProjectEnvTarget } from '@vercel-internals/types';
import { PROJECT_ENV_TARGET } from '@vercel-internals/constants';
import title from 'title';
import { ProjectEnvTarget } from '@vercel-internals/types';
export const envTargetChoices = PROJECT_ENV_TARGET.map(t => ({
name: title(t),
value: t,
}));
function envTargets(): string[] {
return Object.values(ProjectEnvTarget);
}
export function getEnvTargetChoices() {
return Object.entries(ProjectEnvTarget).map(([key, value]) => ({
name: key,
value: value,
}));
}
export function isValidEnvTarget(
target?: string
): target is ProjectEnvTarget | undefined {
// Specify `map` returns strings, instead of string constants so `.includes` works
return (
typeof target === 'undefined' ||
envTargetChoices.map<string>(c => c.value).includes(target)
);
return typeof target === 'undefined' || envTargets().includes(target);
}
export function getEnvTargetPlaceholder() {
return `<${envTargetChoices.map(c => c.value).join(' | ')}>`;
return `<${envTargets().join(' | ')}>`;
}

View File

@@ -1,5 +1,5 @@
import title from 'title';
import type { ProjectEnvVariable } from '@vercel-internals/types';
import { ProjectEnvVariable } from '@vercel-internals/types';
export default function formatEnvTarget(env: ProjectEnvVariable): string {
const target = (Array.isArray(env.target) ? env.target : [env.target || ''])

View File

@@ -1,9 +1,6 @@
import { Output } from '../output';
import Client from '../client';
import type {
ProjectEnvVariable,
ProjectEnvTarget,
} from '@vercel-internals/types';
import { ProjectEnvVariable, ProjectEnvTarget } from '@vercel-internals/types';
import { URLSearchParams } from 'url';
/** The CLI command that was used that needs the environment variables. */

View File

@@ -1,6 +1,6 @@
import { Output } from '../output';
import Client from '../client';
import type { ProjectEnvVariable } from '@vercel-internals/types';
import { ProjectEnvVariable } from '@vercel-internals/types';
export default async function removeEnvRecord(
output: Output,

View File

@@ -0,0 +1,9 @@
import semver from 'semver';
export function getDistTag(version: string): string {
const parsed = semver.parse(version);
if (parsed && typeof parsed.prerelease[0] === 'string') {
return parsed.prerelease[0] as string;
}
return 'latest';
}

View File

@@ -2,7 +2,7 @@ import Client from './client';
import getUser from './get-user';
import getTeamById from './teams/get-team-by-id';
import { TeamDeleted } from './errors-ts';
import type { Team } from '@vercel-internals/types';
import { Team } from '@vercel-internals/types';
interface GetScopeOptions {
getTeam?: boolean;

View File

@@ -1,8 +1,31 @@
import { readFile, realpath } from 'fs-extra';
import { Stats } from 'fs';
import { sep, dirname, join, resolve } from 'path';
import { scanParentDirs } from '@vercel/build-utils';
import { lstat, readlink, readFile, realpath } from 'fs-extra';
import { isCanary } from './is-canary';
import { getPkgName } from './pkg-name';
async function isYarn(): Promise<boolean> {
let s: Stats;
let binPath = process.argv[1];
// eslint-disable-next-line no-constant-condition
while (true) {
s = await lstat(binPath);
if (s.isSymbolicLink()) {
binPath = resolve(dirname(binPath), await readlink(binPath));
} else {
break;
}
}
const pkgPath = join(dirname(binPath), '..', 'package.json');
/*
* Generally, pkgPath looks like:
* "/Users/username/.config/yarn/global/node_modules/vercel/package.json"
* "/usr/local/share/.config/yarn/global/node_modules/vercel/package.json"
*/
return pkgPath.includes(join('yarn', 'global'));
}
async function getConfigPrefix() {
const paths = [
process.env.npm_config_userconfig || process.env.NPM_CONFIG_USERCONFIG,
@@ -53,10 +76,6 @@ async function isGlobal() {
return true;
}
if (installPath.includes(['', 'pnpm', 'global', ''].join(sep))) {
return true;
}
if (installPath.includes(['', 'fnm', 'node-versions', ''].join(sep))) {
return true;
}
@@ -80,26 +99,16 @@ async function isGlobal() {
}
export default async function getUpdateCommand(): Promise<string> {
const pkgAndVersion = `${getPkgName()}@latest`;
const tag = isCanary() ? 'canary' : 'latest';
const pkgAndVersion = `${getPkgName()}@${tag}`;
const entrypoint = await realpath(process.argv[1]);
let { cliType, lockfilePath } = await scanParentDirs(
dirname(dirname(entrypoint))
);
if (!lockfilePath) {
// Global installs for npm do not have a lockfile
cliType = 'npm';
}
const yarn = cliType === 'yarn';
let install = yarn ? 'add' : 'i';
if (await isGlobal()) {
if (yarn) {
install = 'global add';
} else {
install = 'i -g';
}
return (await isYarn())
? `yarn global add ${pkgAndVersion}`
: `npm i -g ${pkgAndVersion}`;
}
return `${cliType} ${install} ${pkgAndVersion}`;
return (await isYarn())
? `yarn add ${pkgAndVersion}`
: `npm i ${pkgAndVersion}`;
}

View File

@@ -1,5 +1,5 @@
import Client from './client';
import type { User } from '@vercel-internals/types';
import { User } from '@vercel-internals/types';
import { APIError, InvalidToken, MissingUser } from './errors-ts';
export default async function getUser(client: Client) {

View File

@@ -36,7 +36,7 @@ export interface CreateOptions {
project?: string;
wantsPublic: boolean;
prebuilt?: boolean;
rootDirectory?: string | null;
rootDirectory?: string;
meta: Dictionary<string>;
gitMetadata?: GitMetadata;
regions?: string[];
@@ -49,7 +49,6 @@ export interface CreateOptions {
deployStamp: () => string;
projectSettings?: any;
skipAutoDetectionConfirmation?: boolean;
noWait?: boolean;
}
export interface RemoveOptions {
@@ -129,7 +128,6 @@ export default class Now extends EventEmitter {
deployStamp,
projectSettings,
skipAutoDetectionConfirmation,
noWait,
}: CreateOptions,
org: Org,
isSettingUpProject: boolean,
@@ -176,7 +174,6 @@ export default class Now extends EventEmitter {
cwd,
prebuilt,
rootDirectory,
noWait,
});
if (deployment && deployment.warnings) {

View File

@@ -4,7 +4,7 @@ import chalk from 'chalk';
import frameworkList, { Framework } from '@vercel/frameworks';
import Client from '../client';
import { isSettingValue } from '../is-setting-value';
import type { ProjectSettings } from '@vercel-internals/types';
import { ProjectSettings } from '@vercel-internals/types';
const settingMap = {
buildCommand: 'Build Command',

View File

@@ -0,0 +1,5 @@
import pkg from '../../package.json';
export function isCanary() {
return pkg.version.includes('canary');
}

View File

@@ -12,10 +12,9 @@ export const parseEnv = (env?: string | string[] | Dictionary<string>) => {
}
if (Array.isArray(env)) {
const startingDict: Dictionary<string> = {};
return env.reduce((o, e) => {
let key: string | undefined;
let value: string | undefined;
let key;
let value;
const equalsSign = e.indexOf('=');
if (equalsSign === -1) {
@@ -25,12 +24,9 @@ export const parseEnv = (env?: string | string[] | Dictionary<string>) => {
value = e.slice(equalsSign + 1);
}
if (typeof value !== 'undefined') {
o[key] = value;
}
o[key] = value;
return o;
}, startingDict);
}, {} as Dictionary<string | undefined>);
}
// assume it's already an Object

View File

@@ -1,6 +1,6 @@
import chalk from 'chalk';
import Client from '../client';
import type { ProjectAliasTarget } from '@vercel-internals/types';
import { ProjectAliasTarget } from '@vercel-internals/types';
import { isAPIError } from '../errors-ts';
export async function addDomainToProject(

View File

@@ -1,5 +1,5 @@
import Client from '../client';
import type { Project } from '@vercel-internals/types';
import { Project } from '@vercel-internals/types';
export default async function createProject(
client: Client,

View File

@@ -1,5 +1,5 @@
import Client from '../client';
import type { Project } from '@vercel-internals/types';
import { Project } from '@vercel-internals/types';
import { URLSearchParams } from 'url';
import { isAPIError } from '../errors-ts';

View File

@@ -1,5 +1,5 @@
import Client from '../client';
import type { Project } from '@vercel-internals/types';
import { Project } from '@vercel-internals/types';
import { isAPIError, ProjectNotFound } from '../errors-ts';
export default async function getProjectByNameOrId(

View File

@@ -12,7 +12,7 @@ import { InvalidToken, isAPIError, ProjectNotFound } from '../errors-ts';
import getUser from '../get-user';
import getTeamById from '../teams/get-team-by-id';
import { Output } from '../output';
import type {
import {
Project,
ProjectLinkResult,
Org,

View File

@@ -1,6 +1,6 @@
import chalk from 'chalk';
import Client from '../client';
import type { ProjectAliasTarget } from '@vercel-internals/types';
import { ProjectAliasTarget } from '@vercel-internals/types';
import { isAPIError } from '../errors-ts';
export async function removeDomainFromProject(

View File

@@ -1,4 +1,4 @@
import type { Team } from '@vercel-internals/types';
import { Team } from '@vercel-internals/types';
import Client from '../client';
export default async function createTeam(

View File

@@ -1,5 +1,5 @@
import Client from '../client';
import type { Team } from '@vercel-internals/types';
import { Team } from '@vercel-internals/types';
const teamCache = new Map<string, Team>();

View File

@@ -1,6 +1,6 @@
import { URLSearchParams } from 'url';
import Client from '../client';
import type { Team } from '@vercel-internals/types';
import { Team } from '@vercel-internals/types';
import { APIError, InvalidToken } from '../errors-ts';
export interface GetTeamsV1Options {

View File

@@ -1,4 +1,4 @@
import type { Team } from '@vercel-internals/types';
import { Team } from '@vercel-internals/types';
import Client from '../client';
export default async function patchTeam(

View File

@@ -1,7 +1,7 @@
{
"version": 2,
"builds": [
{ "src": "entrypoint**", "use": "@vercel/node" },
{ "src": "type-module-package-json/**/*.js", "use": "@vercel/node" }
{ "src": "entrypoint**", "use": "@vercel/node@canary" },
{ "src": "type-module-package-json/**/*.js", "use": "@vercel/node@canary" }
]
}

View File

@@ -1 +1 @@
{"builds":[{"src":"index.js","use":"@vercel/node"}]}
{"builds":[{"src":"index.js","use":"@vercel/node@canary"}]}

View File

@@ -3,7 +3,7 @@
"builds": [
{
"src": "package.json",
"use": "@vercel/static-build",
"use": "@vercel/static-build@canary",
"config": {
"distDir": "public"
}

View File

@@ -4,6 +4,7 @@ const {
fetch,
sleep,
fixture,
isCanary,
shouldSkip,
testFixture,
fetchWithRetry,
@@ -45,7 +46,11 @@ test('[vercel dev] 02-angular-node', async () => {
await sleep(5000);
stderr.includes('@now/build-utils@latest');
if (isCanary()) {
stderr.includes('@now/build-utils@canary');
} else {
stderr.includes('@now/build-utils@latest');
}
});
test(

View File

@@ -5,6 +5,8 @@ const fetch = require('node-fetch');
const retry = require('async-retry');
const { satisfies } = require('semver');
const stripAnsi = require('strip-ansi');
const { getDistTag } = require('../../src/util/get-dist-tag');
const { version: cliVersion } = require('../../package.json');
const {
fetchCachedToken,
} = require('../../../../test/lib/deployment/now-deploy');
@@ -14,6 +16,7 @@ jest.setTimeout(10 * 60 * 1000);
const isCI = !!process.env.CI;
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const isCanary = () => getDistTag(cliVersion) === 'canary';
let port = 3000;
@@ -604,6 +607,7 @@ afterEach(async () => {
module.exports = {
sleep,
isCanary,
testPath,
testFixture,
testFixtureStdio,

View File

@@ -1 +0,0 @@
export default (req, res) => res.end('Vercel');

View File

@@ -1 +0,0 @@
module.exports = (req, res) => res.end('Vercel');

View File

@@ -1 +0,0 @@
export default (req, res) => res.end('Vercel');

View File

@@ -1,3 +0,0 @@
import { IncomingMessage, ServerResponse } from 'http';
export default (req: IncomingMessage, res: ServerResponse) => res.end('Vercel');

View File

@@ -449,26 +449,6 @@ test('should allow deploying a directory that was prebuilt, but has no builds.js
expect(body).toEqual('readme contents for build-output-api-raw');
});
test('should deploy and not wait for completion', async () => {
const projectDir = await setupE2EFixture('static-deployment');
await vcLink(projectDir);
const { exitCode, stdout, stderr } = await execCli(
binaryPath,
[
// omit the default "deploy" command
'--no-wait',
],
{
cwd: projectDir,
}
);
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
expect(stderr).toMatch(/Note: Deployment is still processing/);
});
test('[vc link] with vercel.json configuration overrides should create a valid deployment', async () => {
const directory = await setupE2EFixture(
'vercel-json-configuration-overrides-link'

View File

@@ -32,6 +32,7 @@ const binaryPath = path.resolve(__dirname, `../scripts/start.js`);
const deployHelpMessage = `${logo} vercel [options] <command | path>`;
let session = 'temp-session';
let secretName: string | undefined;
const isCanary = pkg.version.includes('canary');
const createFile = (dest: fs.PathLike) => fs.closeSync(fs.openSync(dest, 'w'));
@@ -1218,6 +1219,8 @@ test('create zero-config deployment', async () => {
'--yes',
]);
console.log('isCanary', isCanary);
expect(output.exitCode, formatOutput(output)).toBe(0);
const { host } = new URL(output.stdout);
@@ -1230,11 +1233,13 @@ test('create zero-config deployment', async () => {
expect(data.error).toBe(undefined);
const validBuilders = data.builds.every(
build => !build.use.endsWith('@canary')
const validBuilders = data.builds.every(build =>
isCanary ? build.use.endsWith('@canary') : !build.use.endsWith('@canary')
);
expect(validBuilders).toBe(true);
const buildList = JSON.stringify(data.builds.map(b => b.use));
const message = `builders match canary (${isCanary}): ${buildList}`;
expect(validBuilders, message).toBe(true);
});
test('next unsupported functions config shows warning link', async () => {

View File

@@ -80,12 +80,12 @@ export class MockClient extends Client {
this.stdout = new MockStream();
this.stdout.setEncoding('utf8');
this.stdout.end = () => this.stdout;
this.stdout.end = () => {};
this.stdout.pause();
this.stderr = new MockStream();
this.stderr.setEncoding('utf8');
this.stderr.end = () => this.stderr;
this.stderr.end = () => {};
this.stderr.pause();
this.stderr.isTTY = true;

View File

@@ -1,7 +1,8 @@
import { client } from './client';
import type {
ProjectEnvTarget,
import {
Project,
ProjectEnvTarget,
ProjectEnvType,
ProjectEnvVariable,
} from '@vercel-internals/types';
import { formatProvider } from '../../src/util/git/connect-git-provider';
@@ -10,44 +11,44 @@ import type { Env } from '@vercel/build-utils';
const envs: ProjectEnvVariable[] = [
{
type: 'encrypted',
type: ProjectEnvType.Encrypted,
id: '781dt89g8r2h789g',
key: 'REDIS_CONNECTION_STRING',
value: 'redis://abc123@redis.example.com:6379',
target: ['production', 'preview'],
target: [ProjectEnvTarget.Production, ProjectEnvTarget.Preview],
gitBranch: undefined,
configurationId: null,
updatedAt: 1557241361455,
createdAt: 1557241361455,
},
{
type: 'encrypted',
type: ProjectEnvType.Encrypted,
id: '781dt89g8r2h789g',
key: 'BRANCH_ENV_VAR',
value: 'env var for a specific branch',
target: ['preview'],
target: [ProjectEnvTarget.Preview],
gitBranch: 'feat/awesome-thing',
configurationId: null,
updatedAt: 1557241361455,
createdAt: 1557241361455,
},
{
type: 'encrypted',
type: ProjectEnvType.Encrypted,
id: 'r124t6frtu25df16',
key: 'SQL_CONNECTION_STRING',
value: 'Server=sql.example.com;Database=app;Uid=root;Pwd=P455W0RD;',
target: ['production'],
target: [ProjectEnvTarget.Production],
gitBranch: undefined,
configurationId: null,
updatedAt: 1557241361445,
createdAt: 1557241361445,
},
{
type: 'encrypted',
type: ProjectEnvType.Encrypted,
id: 'a235l6frtu25df32',
key: 'SPECIAL_FLAG',
value: '1',
target: ['development'],
target: [ProjectEnvTarget.Development],
gitBranch: undefined,
configurationId: null,
updatedAt: 1557241361445,
@@ -126,6 +127,7 @@ export const defaultProject = {
buildingAt: 1571239348998,
createdAt: 1571239348998,
createdIn: 'sfo1',
deploymentHostname: 'a-project-name-rjtr4pz3f',
forced: false,
id: 'dpl_89qyp1cskzkLrVicDaZoDbjyHuDJ',
meta: {},
@@ -410,7 +412,7 @@ function exposeSystemEnvs(
}
for (let env of projectEnvs) {
if (env.type === 'system') {
if (env.type === ProjectEnvType.System) {
envs[env.key] = getSystemEnvValue(env.value, { vercelUrl });
} else {
envs[env.key] = env.value;

View File

@@ -3,6 +3,7 @@ import path from 'path';
import env from '../../../src/commands/env';
import { setupUnitFixture } from '../../helpers/setup-unit-fixture';
import { client } from '../../mocks/client';
import { ProjectEnvTarget, ProjectEnvType } from '@vercel-internals/types';
import { defaultProject, useProject } from '../../mocks/project';
import { useTeams } from '../../mocks/team';
import { useUser } from '../../mocks/user';
@@ -301,11 +302,11 @@ describe('env', () => {
useUser();
useTeams('team_dummy');
defaultProject.env.push({
type: 'encrypted',
type: ProjectEnvType.Encrypted,
id: '781dt89g8r2h789g',
key: 'NEW_VAR',
value: '"testvalue"',
target: ['development'],
target: [ProjectEnvTarget.Development],
configurationId: null,
updatedAt: 1557241361455,
createdAt: 1557241361455,
@@ -338,11 +339,11 @@ describe('env', () => {
useUser();
useTeams('team_dummy');
defaultProject.env.push({
type: 'encrypted',
type: ProjectEnvType.Encrypted,
id: '781dt89g8r2h789g',
key: 'NEW_VAR',
value: 'testvalue',
target: ['development'],
target: [ProjectEnvTarget.Development],
configurationId: null,
updatedAt: 1557241361455,
createdAt: 1557241361455,

View File

@@ -5,7 +5,7 @@ import { useTeams } from '../../mocks/team';
import { defaultProject, useProject } from '../../mocks/project';
import { client } from '../../mocks/client';
import git from '../../../src/commands/git';
import type { Project } from '@vercel-internals/types';
import { Project } from '@vercel-internals/types';
describe('git', () => {
describe('connect', () => {

Some files were not shown because too many files have changed in this diff Show More