mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 04:22:13 +00:00
Compare commits
13 Commits
@vercel/bu
...
@vercel/py
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a8504fc45 | ||
|
|
576217b344 | ||
|
|
f03129ac7a | ||
|
|
3eaad1fd52 | ||
|
|
4e471491d8 | ||
|
|
99395fd9fe | ||
|
|
4980fe6513 | ||
|
|
24676ae020 | ||
|
|
72ada9abd8 | ||
|
|
da893e7c57 | ||
|
|
e40eecafc9 | ||
|
|
d9e5342eba | ||
|
|
b0ab13778d |
2
.github/workflows/test-integration-cli.yml
vendored
2
.github/workflows/test-integration-cli.yml
vendored
@@ -11,7 +11,7 @@ on:
|
||||
jobs:
|
||||
test:
|
||||
name: CLI
|
||||
timeout-minutes: 30
|
||||
timeout-minutes: 40
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -10,7 +10,7 @@ Deploy your own Angular project with Vercel.
|
||||
|
||||
[](https://vercel.com/new/clone?repository-url=https://github.com/vercel/vercel/tree/main/examples/angular&template=angular)
|
||||
|
||||
_Live Example: https://angular-now-examples.vercel.app_
|
||||
_Live Example: https://angular-template.vercel.app_
|
||||
|
||||
## Development server
|
||||
|
||||
|
||||
4882
examples/nextjs/package-lock.json
generated
Normal file
4882
examples/nextjs/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,12 +7,12 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "12.1.0",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2"
|
||||
"next": "12.1.4",
|
||||
"react": "18.0.0",
|
||||
"react-dom": "18.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "8.9.0",
|
||||
"eslint-config-next": "12.1.0"
|
||||
"eslint": "8.12.0",
|
||||
"eslint-config-next": "12.1.4"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "2.15.1-canary.0",
|
||||
"version": "2.15.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
@@ -30,7 +30,7 @@
|
||||
"@types/node-fetch": "^2.1.6",
|
||||
"@types/semver": "6.0.0",
|
||||
"@types/yazl": "^2.4.1",
|
||||
"@vercel/frameworks": "0.7.1-canary.0",
|
||||
"@vercel/frameworks": "0.7.1",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"aggregate-error": "3.0.1",
|
||||
"async-retry": "1.2.3",
|
||||
|
||||
@@ -119,10 +119,11 @@ export interface PrepareCacheOptions {
|
||||
workPath: string;
|
||||
|
||||
/**
|
||||
* A writable temporary directory where you can build a cache to use for
|
||||
* the next run.
|
||||
* The "Root Directory" is assigned to the `workPath` so the `repoRootPath`
|
||||
* is the Git Repository Root. This is only relevant for Monorepos.
|
||||
* See https://vercel.com/blog/monorepos
|
||||
*/
|
||||
cachePath: string;
|
||||
repoRootPath?: string;
|
||||
|
||||
/**
|
||||
* An arbitrary object passed by the user in the build definition defined
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "24.0.2-canary.0",
|
||||
"version": "24.1.0",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Vercel",
|
||||
@@ -43,11 +43,11 @@
|
||||
"node": ">= 12"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.15.1-canary.0",
|
||||
"@vercel/go": "1.3.2-canary.0",
|
||||
"@vercel/node": "1.14.1-canary.0",
|
||||
"@vercel/python": "2.2.2-canary.0",
|
||||
"@vercel/ruby": "1.3.2-canary.0",
|
||||
"@vercel/build-utils": "2.15.1",
|
||||
"@vercel/go": "1.3.2",
|
||||
"@vercel/node": "1.14.1",
|
||||
"@vercel/python": "2.2.2",
|
||||
"@vercel/ruby": "1.3.2",
|
||||
"update-notifier": "4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -88,9 +88,9 @@
|
||||
"@types/update-notifier": "5.1.0",
|
||||
"@types/which": "1.3.2",
|
||||
"@types/write-json-file": "2.2.1",
|
||||
"@vercel/client": "10.4.1-canary.0",
|
||||
"@vercel/client": "10.4.1",
|
||||
"@vercel/fetch-retry": "5.0.3",
|
||||
"@vercel/frameworks": "0.7.1-canary.0",
|
||||
"@vercel/frameworks": "0.7.1",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@vercel/nft": "0.17.5",
|
||||
"@zeit/fun": "0.11.2",
|
||||
|
||||
@@ -42,6 +42,7 @@ export const help = () => `
|
||||
|
||||
-h, --help Output usage information
|
||||
-v, --version Output the version number
|
||||
--cwd Current working directory
|
||||
-V, --platform-version Set the platform version to deploy to
|
||||
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
|
||||
'FILE'
|
||||
|
||||
15
packages/cli/src/commands/env/index.ts
vendored
15
packages/cli/src/commands/env/index.ts
vendored
@@ -1,4 +1,5 @@
|
||||
import chalk from 'chalk';
|
||||
import { ProjectEnvTarget } from '../../types';
|
||||
import Client from '../../util/client';
|
||||
import { getEnvTargetPlaceholder } from '../../util/env/env-target';
|
||||
import getArgs from '../../util/get-args';
|
||||
@@ -137,14 +138,14 @@ export default async function main(client: Client) {
|
||||
case 'rm':
|
||||
return rm(client, project, argv, args, output);
|
||||
case 'pull':
|
||||
output.warn(
|
||||
`${getCommandName(
|
||||
'env pull'
|
||||
)} is deprecated and will be removed in future releases. Run ${getCommandName(
|
||||
'pull'
|
||||
)} instead.`
|
||||
return pull(
|
||||
client,
|
||||
project,
|
||||
ProjectEnvTarget.Development,
|
||||
argv,
|
||||
args,
|
||||
output
|
||||
);
|
||||
return pull(client, project, argv, args, output);
|
||||
default:
|
||||
output.error(getInvalidSubcommand(COMMAND_CONFIG));
|
||||
help();
|
||||
|
||||
10
packages/cli/src/commands/env/pull.ts
vendored
10
packages/cli/src/commands/env/pull.ts
vendored
@@ -1,7 +1,7 @@
|
||||
import chalk from 'chalk';
|
||||
import { closeSync, openSync, promises, readSync } from 'fs';
|
||||
import { resolve } from 'path';
|
||||
import { Project } from '../../types';
|
||||
import { Project, ProjectEnvTarget } from '../../types';
|
||||
import Client from '../../util/client';
|
||||
import exposeSystemEnvs from '../../util/dev/expose-system-envs';
|
||||
import { emoji, prependEmoji } from '../../util/emoji';
|
||||
@@ -45,9 +45,11 @@ function tryReadHeadSync(path: string, length: number) {
|
||||
export default async function pull(
|
||||
client: Client,
|
||||
project: Project,
|
||||
environment: ProjectEnvTarget,
|
||||
opts: Partial<Options>,
|
||||
args: string[],
|
||||
output: Output
|
||||
output: Output,
|
||||
cwd: string = process.cwd()
|
||||
) {
|
||||
if (args.length > 1) {
|
||||
output.error(
|
||||
@@ -58,7 +60,7 @@ export default async function pull(
|
||||
|
||||
// handle relative or absolute filename
|
||||
const [filename = '.env'] = args;
|
||||
const fullPath = resolve(filename);
|
||||
const fullPath = resolve(cwd, filename);
|
||||
const skipConfirmation = opts['--yes'];
|
||||
|
||||
const head = tryReadHeadSync(fullPath, Buffer.byteLength(CONTENTS_PREFIX));
|
||||
@@ -88,7 +90,7 @@ export default async function pull(
|
||||
output.spinner('Downloading');
|
||||
|
||||
const [{ envs: projectEnvs }, { systemEnvValues }] = await Promise.all([
|
||||
getDecryptedEnvRecords(output, client, project.id),
|
||||
getDecryptedEnvRecords(output, client, project.id, environment),
|
||||
project.autoExposeSystemEnvs
|
||||
? getSystemEnvValues(output, client, project.id)
|
||||
: { systemEnvValues: [] },
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import chalk from 'chalk';
|
||||
import { join } from 'path';
|
||||
import Client from '../util/client';
|
||||
import { ProjectEnvTarget } from '../types';
|
||||
import { emoji, prependEmoji } from '../util/emoji';
|
||||
import getArgs from '../util/get-args';
|
||||
import handleError from '../util/handle-error';
|
||||
@@ -14,7 +15,13 @@ import {
|
||||
VERCEL_DIR_PROJECT,
|
||||
} from '../util/projects/link';
|
||||
import { writeProjectSettings } from '../util/projects/project-settings';
|
||||
import pull from './env/pull';
|
||||
import envPull from './env/pull';
|
||||
|
||||
import type { Project, Org } from '../types';
|
||||
import {
|
||||
isValidEnvTarget,
|
||||
getEnvTargetPlaceholder,
|
||||
} from '../util/env/env-target';
|
||||
|
||||
const help = () => {
|
||||
return console.log(`
|
||||
@@ -30,7 +37,7 @@ const help = () => {
|
||||
'DIR'
|
||||
)} Path to the global ${'`.vercel`'} directory
|
||||
-d, --debug Debug mode [off]
|
||||
--env [filename] The file to write Development Environment Variables to [.env]
|
||||
--environment [environment] Deployment environment [development]
|
||||
-y, --yes Skip the confirmation prompt
|
||||
|
||||
${chalk.dim('Examples:')}
|
||||
@@ -41,32 +48,51 @@ const help = () => {
|
||||
${chalk.cyan(`$ ${getPkgName()} pull ./path-to-project`)}
|
||||
${chalk.cyan(`$ ${getPkgName()} pull --env .env.local`)}
|
||||
${chalk.cyan(`$ ${getPkgName()} pull ./path-to-project --env .env.local`)}
|
||||
|
||||
${chalk.gray('–')} Pull specific environment's Project Settings from the cloud
|
||||
|
||||
${chalk.cyan(
|
||||
`$ ${getPkgName()} pull --environment=${getEnvTargetPlaceholder()}`
|
||||
)}
|
||||
`);
|
||||
};
|
||||
export default async function main(client: Client) {
|
||||
let argv;
|
||||
|
||||
function processArgs(client: Client) {
|
||||
return getArgs(client.argv.slice(2), {
|
||||
'--yes': Boolean,
|
||||
'--env': String, // deprecated
|
||||
'--environment': String,
|
||||
'--debug': Boolean,
|
||||
'-d': '--debug',
|
||||
'-y': '--yes',
|
||||
});
|
||||
}
|
||||
|
||||
function parseArgs(client: Client) {
|
||||
try {
|
||||
argv = getArgs(client.argv.slice(2), {
|
||||
'--yes': Boolean,
|
||||
'--env': String,
|
||||
'--debug': Boolean,
|
||||
'-d': '--debug',
|
||||
'-y': '--yes',
|
||||
});
|
||||
const argv = processArgs(client);
|
||||
|
||||
if (argv['--help']) {
|
||||
help();
|
||||
return 2;
|
||||
}
|
||||
|
||||
return argv;
|
||||
} catch (err) {
|
||||
handleError(err);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (argv['--help']) {
|
||||
help();
|
||||
return 2;
|
||||
}
|
||||
|
||||
const cwd = argv._[1] || process.cwd();
|
||||
const yes = argv['--yes'];
|
||||
const env = argv['--env'] ?? '.env';
|
||||
const settingsStamp = stamp();
|
||||
type LinkResult = {
|
||||
org: Org;
|
||||
project: Project;
|
||||
};
|
||||
async function ensureLink(
|
||||
client: Client,
|
||||
cwd: string,
|
||||
yes: boolean
|
||||
): Promise<LinkResult | number> {
|
||||
let link = await getLinkedProject(client, cwd);
|
||||
if (link.status === 'not_linked') {
|
||||
link = await setupAndLink(client, cwd, {
|
||||
@@ -85,24 +111,70 @@ export default async function main(client: Client) {
|
||||
return link.exitCode;
|
||||
}
|
||||
|
||||
return { org: link.org, project: link.project };
|
||||
}
|
||||
|
||||
async function pullAllEnvFiles(
|
||||
environment: ProjectEnvTarget,
|
||||
client: Client,
|
||||
project: Project,
|
||||
argv: ReturnType<typeof processArgs>,
|
||||
cwd: string
|
||||
): Promise<number> {
|
||||
const environmentFile = `.env.${environment}.local`;
|
||||
return envPull(
|
||||
client,
|
||||
project,
|
||||
environment,
|
||||
argv,
|
||||
[join('.vercel', environmentFile)],
|
||||
client.output,
|
||||
cwd
|
||||
);
|
||||
}
|
||||
|
||||
function parseEnvironment(environment = 'development'): ProjectEnvTarget {
|
||||
if (!isValidEnvTarget(environment)) {
|
||||
throw new Error(
|
||||
`environment "${environment}" not supported; must be one of ${getEnvTargetPlaceholder()}`
|
||||
);
|
||||
}
|
||||
return environment;
|
||||
}
|
||||
|
||||
export default async function main(client: Client) {
|
||||
const argv = parseArgs(client);
|
||||
if (typeof argv === 'number') {
|
||||
return argv;
|
||||
}
|
||||
|
||||
const cwd = argv._[1] || process.cwd();
|
||||
const yes = Boolean(argv['--yes']);
|
||||
const environment = parseEnvironment(argv['--environment'] || undefined);
|
||||
|
||||
const link = await ensureLink(client, cwd, yes);
|
||||
if (typeof link === 'number') {
|
||||
return link;
|
||||
}
|
||||
|
||||
const { project, org } = link;
|
||||
|
||||
client.config.currentTeam = org.type === 'team' ? org.id : undefined;
|
||||
|
||||
const result = await pull(
|
||||
const pullResultCode = await pullAllEnvFiles(
|
||||
environment,
|
||||
client,
|
||||
project,
|
||||
argv,
|
||||
[join(cwd, env)],
|
||||
client.output
|
||||
cwd
|
||||
);
|
||||
if (result !== 0) {
|
||||
// an error happened
|
||||
return result;
|
||||
if (pullResultCode !== 0) {
|
||||
return pullResultCode;
|
||||
}
|
||||
|
||||
await writeProjectSettings(cwd, project, org);
|
||||
|
||||
const settingsStamp = stamp();
|
||||
client.output.print(
|
||||
`${prependEmoji(
|
||||
`Downloaded project settings to ${chalk.bold(
|
||||
|
||||
@@ -12,7 +12,7 @@ try {
|
||||
}
|
||||
|
||||
import { join } from 'path';
|
||||
import { existsSync, lstatSync } from 'fs';
|
||||
import { existsSync } from 'fs';
|
||||
import sourceMap from '@zeit/source-map-support';
|
||||
import { mkdirp } from 'fs-extra';
|
||||
import chalk from 'chalk';
|
||||
@@ -136,6 +136,11 @@ const main = async () => {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const cwd = argv['--cwd'];
|
||||
if (cwd) {
|
||||
process.chdir(cwd);
|
||||
}
|
||||
|
||||
// Print update information, if available
|
||||
if (notifier.update && notifier.update.latest !== pkg.version && isTTY) {
|
||||
const { latest } = notifier.update;
|
||||
@@ -386,34 +391,11 @@ const main = async () => {
|
||||
GLOBAL_COMMANDS.has(targetOrSubcommand) ||
|
||||
commands.has(targetOrSubcommand);
|
||||
|
||||
if (targetPathExists && subcommandExists) {
|
||||
const fileType = lstatSync(targetPath).isDirectory()
|
||||
? 'subdirectory'
|
||||
: 'file';
|
||||
const plural = targetOrSubcommand + 's';
|
||||
const singular = targetOrSubcommand.endsWith('s')
|
||||
? targetOrSubcommand.slice(0, -1)
|
||||
: '';
|
||||
let alternative = '';
|
||||
if (commands.has(plural)) {
|
||||
alternative = plural;
|
||||
} else if (commands.has(singular)) {
|
||||
alternative = singular;
|
||||
}
|
||||
console.error(
|
||||
error(
|
||||
`The supplied argument ${param(targetOrSubcommand)} is ambiguous.` +
|
||||
`\nIf you wish to deploy the ${fileType} ${param(
|
||||
targetOrSubcommand
|
||||
)}, first run "cd ${targetOrSubcommand}". ` +
|
||||
(alternative
|
||||
? `\nIf you wish to use the subcommand ${param(
|
||||
targetOrSubcommand
|
||||
)}, use ${param(alternative)} instead.`
|
||||
: '')
|
||||
)
|
||||
if (targetPathExists && subcommandExists && !argv['--cwd']) {
|
||||
output.warn(
|
||||
`Did you mean to deploy the subdirectory "${targetOrSubcommand}"? ` +
|
||||
`Use \`vc --cwd ${targetOrSubcommand}\` instead.`
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (subcommandExists) {
|
||||
|
||||
@@ -25,7 +25,9 @@ const ARG_COMMON = {
|
||||
|
||||
'--api': String,
|
||||
|
||||
'--target': String
|
||||
'--target': String,
|
||||
|
||||
'--cwd': String,
|
||||
};
|
||||
|
||||
export default () => ARG_COMMON;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { ProjectEnvType, ProjectEnvVariable } from '../../types';
|
||||
import {
|
||||
ProjectEnvType,
|
||||
ProjectEnvVariable,
|
||||
ProjectEnvTarget,
|
||||
} from '../../types';
|
||||
import { Env } from '@vercel/build-utils';
|
||||
|
||||
function getSystemEnvValue(
|
||||
@@ -16,13 +20,14 @@ export default function exposeSystemEnvs(
|
||||
projectEnvs: ProjectEnvVariable[],
|
||||
systemEnvValues: string[],
|
||||
autoExposeSystemEnvs: boolean | undefined,
|
||||
vercelUrl?: string
|
||||
vercelUrl?: string,
|
||||
target?: ProjectEnvTarget
|
||||
) {
|
||||
const envs: Env = {};
|
||||
|
||||
if (autoExposeSystemEnvs) {
|
||||
envs['VERCEL'] = '1';
|
||||
envs['VERCEL_ENV'] = 'development';
|
||||
envs['VERCEL_ENV'] = target || 'development';
|
||||
|
||||
for (const key of systemEnvValues) {
|
||||
envs[key] = getSystemEnvValue(key, { vercelUrl });
|
||||
|
||||
2
packages/cli/src/util/env/add-env-record.ts
vendored
2
packages/cli/src/util/env/add-env-record.ts
vendored
@@ -26,7 +26,7 @@ export default async function addEnvRecord(
|
||||
target: targets,
|
||||
gitBranch: gitBranch || undefined,
|
||||
};
|
||||
const url = `/v7/projects/${projectId}/env`;
|
||||
const url = `/v8/projects/${projectId}/env`;
|
||||
await client.fetch(url, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(body),
|
||||
|
||||
2
packages/cli/src/util/env/get-env-records.ts
vendored
2
packages/cli/src/util/env/get-env-records.ts
vendored
@@ -32,7 +32,7 @@ export default async function getEnvRecords(
|
||||
query.set('decrypt', decrypt.toString());
|
||||
}
|
||||
|
||||
const url = `/v7/projects/${projectId}/env?${query}`;
|
||||
const url = `/v8/projects/${projectId}/env?${query}`;
|
||||
|
||||
return client.fetch<{ envs: ProjectEnvVariable[] }>(url);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export default async function removeEnvRecord(
|
||||
): Promise<void> {
|
||||
output.debug(`Removing Environment Variable ${env.key}`);
|
||||
|
||||
const urlProject = `/v7/projects/${projectId}/env/${env.id}`;
|
||||
const urlProject = `/v8/projects/${projectId}/env/${env.id}`;
|
||||
|
||||
await client.fetch<ProjectEnvVariable>(urlProject, {
|
||||
method: 'DELETE',
|
||||
|
||||
@@ -11,10 +11,11 @@ import getEnvRecords from './env/get-env-records';
|
||||
export default async function getDecryptedEnvRecords(
|
||||
output: Output,
|
||||
client: Client,
|
||||
projectId: string
|
||||
projectId: string,
|
||||
target?: ProjectEnvTarget
|
||||
): Promise<{ envs: ProjectEnvVariable[] }> {
|
||||
const { envs } = await getEnvRecords(output, client, projectId, {
|
||||
target: ProjectEnvTarget.Development,
|
||||
target: target || ProjectEnvTarget.Development,
|
||||
decrypt: true,
|
||||
});
|
||||
|
||||
|
||||
@@ -19,19 +19,24 @@ export default async function inputProject(
|
||||
// attempt to auto-detect a project to link
|
||||
let detectedProject = null;
|
||||
output.spinner('Searching for existing projects…', 1000);
|
||||
try {
|
||||
const [project, slugifiedProject] = await Promise.all([
|
||||
getProjectByIdOrName(client, detectedProjectName, org.id),
|
||||
slugifiedName !== detectedProjectName
|
||||
? getProjectByIdOrName(client, slugifiedName, org.id)
|
||||
: null,
|
||||
]);
|
||||
detectedProject = !(project instanceof ProjectNotFound)
|
||||
? project
|
||||
: !(slugifiedProject instanceof ProjectNotFound)
|
||||
? slugifiedProject
|
||||
: null;
|
||||
} catch (error) {}
|
||||
|
||||
const [project, slugifiedProject] = await Promise.all([
|
||||
getProjectByIdOrName(client, detectedProjectName, org.id),
|
||||
slugifiedName !== detectedProjectName
|
||||
? getProjectByIdOrName(client, slugifiedName, org.id)
|
||||
: null,
|
||||
]);
|
||||
|
||||
detectedProject = !(project instanceof ProjectNotFound)
|
||||
? project
|
||||
: !(slugifiedProject instanceof ProjectNotFound)
|
||||
? slugifiedProject
|
||||
: null;
|
||||
|
||||
if (detectedProject && !detectedProject.id) {
|
||||
throw new Error(`Detected linked project does not have "id".`);
|
||||
}
|
||||
|
||||
output.stopSpinner();
|
||||
|
||||
if (autoConfirm) {
|
||||
|
||||
@@ -9,7 +9,7 @@ export default async function getProjectByNameOrId(
|
||||
) {
|
||||
try {
|
||||
const project = await client.fetch<Project>(
|
||||
`/projects/${encodeURIComponent(projectNameOrId)}`,
|
||||
`/v8/projects/${encodeURIComponent(projectNameOrId)}`,
|
||||
{ accountId }
|
||||
);
|
||||
return project;
|
||||
|
||||
@@ -20,9 +20,15 @@ describe('pull', () => {
|
||||
client.setArgv('pull', '--yes', cwd);
|
||||
const exitCode = await pull(client);
|
||||
expect(exitCode).toEqual(0);
|
||||
|
||||
const rawDevEnv = await fs.readFile(
|
||||
path.join(cwd, '.vercel', '.env.development.local')
|
||||
);
|
||||
const devFileHasDevEnv = rawDevEnv.toString().includes('SPECIAL_FLAG');
|
||||
expect(devFileHasDevEnv).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should handle custom --env flag', async () => {
|
||||
it('should handle --environment=preview flag', async () => {
|
||||
const cwd = setupFixture('vercel-pull-next');
|
||||
useUser();
|
||||
useTeams();
|
||||
@@ -31,15 +37,42 @@ describe('pull', () => {
|
||||
id: 'vercel-pull-next',
|
||||
name: 'vercel-pull-next',
|
||||
});
|
||||
const expectedEnvFilename = '.env.vercel';
|
||||
client.setArgv('pull', '--yes', `--env=${expectedEnvFilename}`, cwd);
|
||||
|
||||
client.setArgv('pull', '--yes', '--environment=preview', cwd);
|
||||
const exitCode = await pull(client);
|
||||
const actualEnv = await fs.pathExists(path.join(cwd, expectedEnvFilename));
|
||||
const raw = await fs.readFile(path.join(cwd, expectedEnvFilename));
|
||||
|
||||
expect(exitCode).toEqual(0);
|
||||
expect(actualEnv).toBeTruthy();
|
||||
expect(raw.includes('# Created by Vercel CLI')).toBeTruthy();
|
||||
|
||||
const rawPreviewEnv = await fs.readFile(
|
||||
path.join(cwd, '.vercel', '.env.preview.local')
|
||||
);
|
||||
const previewFileHasPreviewEnv = rawPreviewEnv
|
||||
.toString()
|
||||
.includes('REDIS_CONNECTION_STRING');
|
||||
expect(previewFileHasPreviewEnv).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should handle --environment=production flag', async () => {
|
||||
const cwd = setupFixture('vercel-pull-next');
|
||||
useUser();
|
||||
useTeams();
|
||||
useProject({
|
||||
...defaultProject,
|
||||
id: 'vercel-pull-next',
|
||||
name: 'vercel-pull-next',
|
||||
});
|
||||
client.setArgv('pull', '--yes', '--environment=production', cwd);
|
||||
const exitCode = await pull(client);
|
||||
expect(exitCode).toEqual(0);
|
||||
|
||||
const rawProdEnv = await fs.readFile(
|
||||
path.join(cwd, '.vercel', '.env.production.local')
|
||||
);
|
||||
const previewFileHasPreviewEnv1 = rawProdEnv
|
||||
.toString()
|
||||
.includes('REDIS_CONNECTION_STRING');
|
||||
expect(previewFileHasPreviewEnv1).toBeTruthy();
|
||||
const previewFileHasPreviewEnv2 = rawProdEnv
|
||||
.toString()
|
||||
.includes('SQL_CONNECTION_STRING');
|
||||
expect(previewFileHasPreviewEnv2).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -168,6 +168,17 @@ module.exports = async function prepare(session, binaryPath) {
|
||||
'vercel.json': JSON.stringify({ version: 2 }),
|
||||
'README.md': 'readme contents',
|
||||
},
|
||||
'deploy-default-with-sub-directory': {
|
||||
'vercel.json': JSON.stringify({ version: 2 }),
|
||||
'output/README.md':
|
||||
'readme contents for deploy-default-with-sub-directory',
|
||||
},
|
||||
'deploy-default-with-conflicting-sub-directory': {
|
||||
'list/vercel.json': JSON.stringify({ version: 2 }),
|
||||
'list/list/README.md': 'nested nested readme contents',
|
||||
'list/README.md':
|
||||
'readme contents for deploy-default-with-conflicting-sub-directory',
|
||||
},
|
||||
'local-config-v2': {
|
||||
[`main-${session}.html`]: '<h1>hello main</h1>',
|
||||
[`test-${session}.html`]: '<h1>hello test</h1>',
|
||||
@@ -192,10 +203,6 @@ module.exports = async function prepare(session, binaryPath) {
|
||||
name: 'nested-level',
|
||||
}),
|
||||
},
|
||||
'subdirectory-secret': {
|
||||
'index.html': 'Home page',
|
||||
'secret/file.txt': 'my secret',
|
||||
},
|
||||
'build-secret': {
|
||||
'package.json': JSON.stringify({
|
||||
private: true,
|
||||
|
||||
143
packages/cli/test/integration.js
vendored
143
packages/cli/test/integration.js
vendored
@@ -125,6 +125,19 @@ ${stdout}
|
||||
`;
|
||||
}
|
||||
|
||||
async function vcLink(t, projectPath) {
|
||||
const { exitCode, stderr, stdout } = await execa(
|
||||
binaryPath,
|
||||
['link', '--confirm', ...defaultArgs],
|
||||
{
|
||||
reject: false,
|
||||
cwd: projectPath,
|
||||
}
|
||||
);
|
||||
|
||||
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
|
||||
}
|
||||
|
||||
// AVA's `t.context` can only be set before the tests,
|
||||
// but we want to set it within as well
|
||||
const context = {};
|
||||
@@ -355,6 +368,8 @@ test('default command should prompt login with empty auth.json', async t => {
|
||||
}
|
||||
});
|
||||
|
||||
// NOTE: Test order is important here.
|
||||
// This test MUST run before the tests below for them to work.
|
||||
test('login', async t => {
|
||||
t.timeout(ms('1m'));
|
||||
|
||||
@@ -378,6 +393,110 @@ test('login', async t => {
|
||||
t.is(auth.token, token);
|
||||
});
|
||||
|
||||
test('default command should deploy directory', async t => {
|
||||
const projectDir = fixture('deploy-default-with-sub-directory');
|
||||
const target = 'output';
|
||||
|
||||
await vcLink(t, path.join(projectDir, target));
|
||||
|
||||
const { exitCode, stderr, stdout } = await execa(
|
||||
binaryPath,
|
||||
[
|
||||
// omit the default "deploy" command
|
||||
target,
|
||||
...defaultArgs,
|
||||
],
|
||||
{
|
||||
cwd: projectDir,
|
||||
}
|
||||
);
|
||||
|
||||
t.is(exitCode, 0, formatOutput({ stdout, stderr }));
|
||||
t.regex(stdout, /https:\/\/output-.+\.vercel\.app/);
|
||||
});
|
||||
|
||||
test('default command should warn when deploying with conflicting subdirectory', async t => {
|
||||
const projectDir = fixture('deploy-default-with-conflicting-sub-directory');
|
||||
const target = 'list'; // command that conflicts with a sub directory
|
||||
|
||||
await vcLink(t, projectDir);
|
||||
|
||||
const { exitCode, stderr, stdout } = await execa(
|
||||
binaryPath,
|
||||
[
|
||||
// omit the default "deploy" command
|
||||
target,
|
||||
...defaultArgs,
|
||||
],
|
||||
{
|
||||
cwd: projectDir,
|
||||
}
|
||||
);
|
||||
|
||||
t.is(exitCode, 0, formatOutput({ stdout, stderr }));
|
||||
t.regex(
|
||||
stderr || '',
|
||||
/Did you mean to deploy the subdirectory "list"\? Use `vc --cwd list` instead./
|
||||
);
|
||||
|
||||
const listHeader = /project +latest deployment +state +age +username/;
|
||||
t.regex(stdout || '', listHeader); // ensure `list` command still ran
|
||||
});
|
||||
|
||||
test('deploy command should not warn when deploying with conflicting subdirectory and using --cwd', async t => {
|
||||
const projectDir = fixture('deploy-default-with-conflicting-sub-directory');
|
||||
const target = 'list'; // command that conflicts with a sub directory
|
||||
|
||||
await vcLink(t, path.join(projectDir, target));
|
||||
|
||||
const { exitCode, stderr, stdout } = await execa(
|
||||
binaryPath,
|
||||
['list', '--cwd', target, ...defaultArgs],
|
||||
{
|
||||
cwd: projectDir,
|
||||
}
|
||||
);
|
||||
|
||||
t.is(exitCode, 0, formatOutput({ stdout, stderr }));
|
||||
t.notRegex(
|
||||
stderr || '',
|
||||
/Did you mean to deploy the subdirectory "list"\? Use `vc --cwd list` instead./
|
||||
);
|
||||
|
||||
const listHeader = /project +latest deployment +state +age +username/;
|
||||
t.regex(stdout || '', listHeader); // ensure `list` command still ran
|
||||
});
|
||||
|
||||
test('default command should work with --cwd option', async t => {
|
||||
const projectDir = fixture('deploy-default-with-conflicting-sub-directory');
|
||||
const target = 'list'; // command that conflicts with a sub directory
|
||||
|
||||
await vcLink(t, path.join(projectDir, 'list'));
|
||||
|
||||
const { exitCode, stderr, stdout } = await execa(
|
||||
binaryPath,
|
||||
[
|
||||
// omit the default "deploy" command
|
||||
'--cwd',
|
||||
target,
|
||||
...defaultArgs,
|
||||
],
|
||||
{
|
||||
cwd: projectDir,
|
||||
}
|
||||
);
|
||||
|
||||
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
|
||||
|
||||
const url = stdout;
|
||||
const deploymentResult = await fetch(`${url}/README.md`);
|
||||
const body = await deploymentResult.text();
|
||||
t.deepEqual(
|
||||
body,
|
||||
'readme contents for deploy-default-with-conflicting-sub-directory'
|
||||
);
|
||||
});
|
||||
|
||||
test('deploy using only now.json with `redirects` defined', async t => {
|
||||
const target = fixture('redirects-v2');
|
||||
|
||||
@@ -1088,30 +1207,6 @@ test('output the version', async t => {
|
||||
t.is(version, pkg.version);
|
||||
});
|
||||
|
||||
test('should error with suggestion for secrets subcommand', async t => {
|
||||
const target = fixture('subdirectory-secret');
|
||||
|
||||
const { exitCode, stderr, stdout } = await execa(
|
||||
binaryPath,
|
||||
['secret', 'add', 'key', 'value', ...defaultArgs],
|
||||
{
|
||||
cwd: target,
|
||||
reject: false,
|
||||
}
|
||||
);
|
||||
|
||||
console.log(stderr);
|
||||
console.log(stdout);
|
||||
console.log(exitCode);
|
||||
|
||||
t.is(exitCode, 1);
|
||||
t.regex(
|
||||
stderr,
|
||||
/secrets/gm,
|
||||
`Expected "secrets" suggestion but received "${stderr}"`
|
||||
);
|
||||
});
|
||||
|
||||
test('should add secret with hyphen prefix', async t => {
|
||||
const target = fixture('build-secret');
|
||||
const key = 'mysecret';
|
||||
|
||||
@@ -23,6 +23,17 @@ const envs = [
|
||||
updatedAt: 1557241361445,
|
||||
createdAt: 1557241361445,
|
||||
},
|
||||
{
|
||||
type: 'encrypted',
|
||||
id: 'a235l6frtu25df32',
|
||||
key: 'SPECIAL_FLAG',
|
||||
value: '1',
|
||||
target: ['development'],
|
||||
gitBranch: null,
|
||||
configurationId: null,
|
||||
updatedAt: 1557241361445,
|
||||
createdAt: 1557241361445,
|
||||
},
|
||||
];
|
||||
|
||||
export const defaultProject = {
|
||||
@@ -77,13 +88,19 @@ export const defaultProject = {
|
||||
};
|
||||
|
||||
export function useProject(project = defaultProject) {
|
||||
client.scenario.get(`/projects/${project.name}`, (_req, res) => {
|
||||
client.scenario.get(`/v8/projects/${project.name}`, (_req, res) => {
|
||||
res.json(project);
|
||||
});
|
||||
client.scenario.get(`/projects/${project.id}`, (_req, res) => {
|
||||
client.scenario.get(`/v8/projects/${project.id}`, (_req, res) => {
|
||||
res.json(project);
|
||||
});
|
||||
client.scenario.get(`/v7/projects/${project.id}/env`, (_req, res) => {
|
||||
client.scenario.get(`/v8/projects/${project.id}/env`, (_req, res) => {
|
||||
const target = _req.query.target;
|
||||
if (typeof target === 'string') {
|
||||
const targetEnvs = envs.filter(env => env.target.includes(target));
|
||||
res.json({ envs: targetEnvs });
|
||||
}
|
||||
|
||||
res.json({ envs });
|
||||
});
|
||||
|
||||
|
||||
@@ -11,7 +11,10 @@ import DevServer from '../../../src/util/dev/server';
|
||||
|
||||
async function runNpmInstall(fixturePath: string) {
|
||||
if (await fs.pathExists(path.join(fixturePath, 'package.json'))) {
|
||||
return execa('yarn', ['install'], { cwd: fixturePath, shell: true });
|
||||
return execa('yarn', ['install', '--network-timeout', '1000000'], {
|
||||
cwd: fixturePath,
|
||||
shell: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/client",
|
||||
"version": "10.4.1-canary.0",
|
||||
"version": "10.4.1",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"homepage": "https://vercel.com",
|
||||
@@ -41,7 +41,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.15.1-canary.0",
|
||||
"@vercel/build-utils": "2.15.1",
|
||||
"@zeit/fetch": "5.2.0",
|
||||
"async-retry": "1.2.3",
|
||||
"async-sema": "3.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/frameworks",
|
||||
"version": "0.7.1-canary.0",
|
||||
"version": "0.7.1",
|
||||
"main": "./dist/frameworks.js",
|
||||
"types": "./dist/frameworks.d.ts",
|
||||
"files": [
|
||||
@@ -20,7 +20,7 @@
|
||||
"@types/js-yaml": "3.12.1",
|
||||
"@types/node": "12.0.4",
|
||||
"@types/node-fetch": "2.5.8",
|
||||
"@vercel/routing-utils": "1.13.1-canary.0",
|
||||
"@vercel/routing-utils": "1.13.1",
|
||||
"ajv": "6.12.2",
|
||||
"typescript": "4.3.4"
|
||||
}
|
||||
|
||||
@@ -61,13 +61,13 @@ export interface Framework {
|
||||
*/
|
||||
logo: string;
|
||||
/**
|
||||
* A URL to the logo of a screenshot of the framework
|
||||
* @example "https://assets.vercel.com/image/upload/v1647366075/front/import/nuxtjs.png"
|
||||
* A URL to a screenshot of the demo
|
||||
* @example "https://assets.vercel.com/image/upload/v1647366075/front/import/nextjs.png"
|
||||
*/
|
||||
screenshot?: string;
|
||||
/**
|
||||
* A URL to a deployed example of the framework
|
||||
* @example "https://nextjs.now-examples.vercel.app"
|
||||
* @example "https://nextjs-template.vercel.app"
|
||||
*/
|
||||
demo?: string;
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/go",
|
||||
"version": "1.3.2-canary.0",
|
||||
"version": "1.3.2",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
||||
@@ -24,7 +24,7 @@
|
||||
"@types/fs-extra": "^5.0.5",
|
||||
"@types/node-fetch": "^2.3.0",
|
||||
"@types/tar": "^4.0.0",
|
||||
"@vercel/build-utils": "2.15.1-canary.0",
|
||||
"@vercel/build-utils": "2.15.1",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"async-retry": "1.3.1",
|
||||
"execa": "^1.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/node",
|
||||
"version": "1.14.1-canary.0",
|
||||
"version": "1.14.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
|
||||
@@ -32,7 +32,7 @@
|
||||
"@types/cookie": "0.3.3",
|
||||
"@types/etag": "1.8.0",
|
||||
"@types/test-listen": "1.1.0",
|
||||
"@vercel/build-utils": "2.15.1-canary.0",
|
||||
"@vercel/build-utils": "2.15.1",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@vercel/nft": "0.17.5",
|
||||
"content-type": "1.0.4",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/python",
|
||||
"version": "2.2.2-canary.0",
|
||||
"version": "2.2.2",
|
||||
"main": "./dist/index.js",
|
||||
"license": "MIT",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
||||
@@ -20,7 +20,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/execa": "^0.9.0",
|
||||
"@vercel/build-utils": "2.15.1-canary.0",
|
||||
"@vercel/build-utils": "2.15.1",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"execa": "^1.0.0",
|
||||
"typescript": "4.3.4"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/redwood",
|
||||
"version": "0.6.1-canary.0",
|
||||
"version": "0.7.0",
|
||||
"main": "./dist/index.js",
|
||||
"license": "MIT",
|
||||
"homepage": "https://vercel.com/docs",
|
||||
@@ -19,13 +19,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/nft": "0.17.5",
|
||||
"@vercel/routing-utils": "1.13.1-canary.0",
|
||||
"@vercel/routing-utils": "1.13.1",
|
||||
"semver": "6.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/aws-lambda": "8.10.19",
|
||||
"@types/node": "*",
|
||||
"@types/semver": "6.0.0",
|
||||
"@vercel/build-utils": "2.15.1-canary.0"
|
||||
"@vercel/build-utils": "2.15.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/routing-utils",
|
||||
"version": "1.13.1-canary.0",
|
||||
"version": "1.13.1",
|
||||
"description": "Vercel routing utilities",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@vercel/ruby",
|
||||
"author": "Nathan Cahill <nathan@nathancahill.com>",
|
||||
"version": "1.3.2-canary.0",
|
||||
"version": "1.3.2",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",
|
||||
@@ -22,7 +22,7 @@
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "8.0.0",
|
||||
"@types/semver": "6.0.0",
|
||||
"@vercel/build-utils": "2.15.1-canary.0",
|
||||
"@vercel/build-utils": "2.15.1",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"execa": "2.0.4",
|
||||
"fs-extra": "^7.0.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/static-build",
|
||||
"version": "0.23.1-canary.0",
|
||||
"version": "0.23.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/build-step",
|
||||
@@ -24,10 +24,10 @@
|
||||
"@types/ms": "0.7.31",
|
||||
"@types/node-fetch": "2.5.4",
|
||||
"@types/promise-timeout": "1.3.0",
|
||||
"@vercel/build-utils": "2.15.1-canary.0",
|
||||
"@vercel/frameworks": "0.7.1-canary.0",
|
||||
"@vercel/build-utils": "2.15.1",
|
||||
"@vercel/frameworks": "0.7.1",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@vercel/routing-utils": "1.13.1-canary.0",
|
||||
"@vercel/routing-utils": "1.13.1",
|
||||
"get-port": "5.0.0",
|
||||
"is-port-reachable": "2.0.1",
|
||||
"ms": "2.1.2",
|
||||
|
||||
@@ -10,7 +10,6 @@ import { cpus } from 'os';
|
||||
import {
|
||||
BuildV2,
|
||||
Files,
|
||||
FileFsRef,
|
||||
Config,
|
||||
PackageJson,
|
||||
PrepareCache,
|
||||
@@ -211,9 +210,15 @@ function getPkg(entrypoint: string, workPath: string) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const pkgPath = path.join(workPath, entrypoint);
|
||||
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as PackageJson;
|
||||
return pkg;
|
||||
try {
|
||||
const pkgPath = path.join(workPath, entrypoint);
|
||||
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as PackageJson;
|
||||
return pkg;
|
||||
} catch (err: any) {
|
||||
if (err.code !== 'ENOENT') throw err;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getFramework(
|
||||
@@ -742,31 +747,32 @@ export const prepareCache: PrepareCache = async ({
|
||||
workPath,
|
||||
config,
|
||||
}) => {
|
||||
const cacheFiles: Files = {};
|
||||
|
||||
// File System API v1 cache files
|
||||
const buildConfig = await readBuildOutputConfig<BuildConfig>({
|
||||
workPath,
|
||||
configFileName: 'build.json',
|
||||
});
|
||||
|
||||
if (buildConfig?.cache && Array.isArray(buildConfig.cache)) {
|
||||
const cacheFiles = {};
|
||||
for (const cacheGlob of buildConfig.cache) {
|
||||
Object.assign(cacheFiles, await glob(cacheGlob, workPath));
|
||||
}
|
||||
return cacheFiles;
|
||||
}
|
||||
|
||||
const defaultCacheFiles = await glob(
|
||||
'{.shadow-cljs,node_modules}/**',
|
||||
workPath
|
||||
// Default cache files
|
||||
Object.assign(
|
||||
cacheFiles,
|
||||
await glob('{.shadow-cljs,node_modules}/**', workPath)
|
||||
);
|
||||
|
||||
let frameworkCacheFiles: { [path: string]: FileFsRef } = {};
|
||||
// Framework cache files
|
||||
const pkg = getPkg(entrypoint, workPath);
|
||||
const framework = getFramework(config, pkg);
|
||||
|
||||
if (framework?.cachePattern) {
|
||||
frameworkCacheFiles = await glob(framework.cachePattern, workPath);
|
||||
Object.assign(cacheFiles, await glob(framework.cachePattern, workPath));
|
||||
}
|
||||
|
||||
return { ...defaultCacheFiles, ...frameworkCacheFiles };
|
||||
return cacheFiles;
|
||||
};
|
||||
|
||||
@@ -1 +1 @@
|
||||
pelican==4.1.1
|
||||
pelican==4.7.2
|
||||
|
||||
@@ -1 +1 @@
|
||||
mkdocs==1.0.4
|
||||
mkdocs==1.2.4
|
||||
|
||||
Reference in New Issue
Block a user