mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 12:57:46 +00:00
Compare commits
27 Commits
@vercel/ru
...
@vercel/py
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6700630feb | ||
|
|
34cd8b4144 | ||
|
|
ad0ed6d852 | ||
|
|
0bad09b47a | ||
|
|
5120689bf2 | ||
|
|
5a39fd9242 | ||
|
|
352cd00ef0 | ||
|
|
abfe817f86 | ||
|
|
ebb5e2b208 | ||
|
|
e34858d082 | ||
|
|
f03c947f91 | ||
|
|
0d13fe7e34 | ||
|
|
4afec9d373 | ||
|
|
09c85f63d2 | ||
|
|
9963965e9a | ||
|
|
f3ed279007 | ||
|
|
4fe489edad | ||
|
|
e2911aac0b | ||
|
|
f3cbc5d746 | ||
|
|
40df88b483 | ||
|
|
75c4f45b73 | ||
|
|
05a236f944 | ||
|
|
4b7383f521 | ||
|
|
c263c31e48 | ||
|
|
c80530f9b1 | ||
|
|
16fd4396ef | ||
|
|
4e7138f400 |
25
.github/workflows/cron-update-next.yml
vendored
Normal file
25
.github/workflows/cron-update-next.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Cron Update Next
|
||||
|
||||
on:
|
||||
# Run every 4 hours https://crontab.guru/every-4-hours
|
||||
schedule:
|
||||
- cron: '0 */4 * * *'
|
||||
|
||||
jobs:
|
||||
create-pull-request:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
# 0 means fetch all commits so we can commit and push in the script below
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Create Pull Request
|
||||
uses: actions/github-script@v6
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
# See https://github.com/actions/github-script#run-a-separate-file-with-an-async-function
|
||||
with:
|
||||
script: |
|
||||
const script = require('./utils/update-next.js')
|
||||
await script({ github, context })
|
||||
@@ -63,9 +63,6 @@ export async function build(options: BuildOptions) {
|
||||
const lambda = createLambda(/* … */);
|
||||
return {
|
||||
output: lambda,
|
||||
watch: [
|
||||
// Dependent files to trigger a rebuild in `vercel dev` go here…
|
||||
],
|
||||
routes: [
|
||||
// If your Runtime needs to define additional routing, define it here…
|
||||
],
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
"selector": "MemberExpression > Identifier[name='substr']"
|
||||
}
|
||||
],
|
||||
"no-dupe-keys": 2,
|
||||
"require-atomic-updates": 0,
|
||||
"@typescript-eslint/ban-ts-comment": 0,
|
||||
"@typescript-eslint/camelcase": 0,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "5.3.1",
|
||||
"version": "5.3.2",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
|
||||
@@ -335,7 +335,6 @@ export interface ProjectSettings {
|
||||
directoryListing?: boolean;
|
||||
gitForkProtection?: boolean;
|
||||
commandForIgnoringBuildStep?: string | null;
|
||||
skipGitConnectDuringLink?: boolean;
|
||||
}
|
||||
|
||||
export interface BuilderV2 {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "28.0.1",
|
||||
"version": "28.1.4",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Vercel",
|
||||
@@ -41,16 +41,16 @@
|
||||
"node": ">= 14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "5.3.1",
|
||||
"@vercel/go": "2.1.1",
|
||||
"@vercel/hydrogen": "0.0.14",
|
||||
"@vercel/next": "3.1.18",
|
||||
"@vercel/node": "2.5.8",
|
||||
"@vercel/python": "3.1.9",
|
||||
"@vercel/redwood": "1.0.18",
|
||||
"@vercel/remix": "1.0.19",
|
||||
"@vercel/ruby": "1.3.26",
|
||||
"@vercel/static-build": "1.0.18",
|
||||
"@vercel/build-utils": "5.3.2",
|
||||
"@vercel/go": "2.2.2",
|
||||
"@vercel/hydrogen": "0.0.15",
|
||||
"@vercel/next": "3.1.21",
|
||||
"@vercel/node": "2.5.10",
|
||||
"@vercel/python": "3.1.11",
|
||||
"@vercel/redwood": "1.0.19",
|
||||
"@vercel/remix": "1.0.20",
|
||||
"@vercel/ruby": "1.3.28",
|
||||
"@vercel/static-build": "1.0.19",
|
||||
"update-notifier": "5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -96,7 +96,7 @@
|
||||
"@types/which": "1.3.2",
|
||||
"@types/write-json-file": "2.2.1",
|
||||
"@types/yauzl-promise": "2.1.0",
|
||||
"@vercel/client": "12.2.0",
|
||||
"@vercel/client": "12.2.1",
|
||||
"@vercel/frameworks": "1.1.3",
|
||||
"@vercel/fs-detectors": "2.0.5",
|
||||
"@vercel/fun": "1.0.4",
|
||||
|
||||
@@ -59,7 +59,7 @@ export default async function rm(
|
||||
|
||||
const removeStamp = stamp();
|
||||
if (!opts['--yes'] && !(await confirmAliasRemove(client, alias))) {
|
||||
output.log('Aborted');
|
||||
output.log('Canceled');
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -220,7 +220,7 @@ function handleSetupDomainError<T>(
|
||||
}
|
||||
|
||||
if (error instanceof ERRORS.UserAborted) {
|
||||
output.error(`User aborted`);
|
||||
output.error(`User canceled.`);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,8 +116,6 @@ export default async function main(client: Client): Promise<number> {
|
||||
}
|
||||
}
|
||||
|
||||
const badDeploymentPromise = getDeployment(client, bad).catch(err => err);
|
||||
|
||||
good = normalizeURL(good);
|
||||
parsed = parse(good);
|
||||
if (!parsed.hostname) {
|
||||
@@ -138,8 +136,6 @@ export default async function main(client: Client): Promise<number> {
|
||||
);
|
||||
}
|
||||
|
||||
const goodDeploymentPromise = getDeployment(client, good).catch(err => err);
|
||||
|
||||
if (!subpath) {
|
||||
subpath = await prompt(
|
||||
client,
|
||||
@@ -148,10 +144,9 @@ export default async function main(client: Client): Promise<number> {
|
||||
}
|
||||
|
||||
output.spinner('Retrieving deployments…');
|
||||
const [badDeployment, goodDeployment] = await Promise.all([
|
||||
badDeploymentPromise,
|
||||
goodDeploymentPromise,
|
||||
]);
|
||||
|
||||
// `getDeployment` cannot be parallelized because it might prompt for login
|
||||
const badDeployment = await getDeployment(client, bad).catch(err => err);
|
||||
|
||||
if (badDeployment) {
|
||||
if (badDeployment instanceof Error) {
|
||||
@@ -165,7 +160,8 @@ export default async function main(client: Client): Promise<number> {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const { projectId } = badDeployment;
|
||||
// `getDeployment` cannot be parallelized because it might prompt for login
|
||||
const goodDeployment = await getDeployment(client, good).catch(err => err);
|
||||
|
||||
if (goodDeployment) {
|
||||
if (goodDeployment instanceof Error) {
|
||||
@@ -181,6 +177,8 @@ export default async function main(client: Client): Promise<number> {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const { projectId } = badDeployment;
|
||||
|
||||
if (projectId !== goodDeployment.projectId) {
|
||||
output.error(`Good and Bad deployments must be from the same Project`);
|
||||
return 1;
|
||||
|
||||
@@ -171,7 +171,7 @@ export default async function main(client: Client): Promise<number> {
|
||||
);
|
||||
}
|
||||
if (!confirmed) {
|
||||
client.output.print(`Aborted. No Project Settings retrieved.\n`);
|
||||
client.output.print(`Canceled. No Project Settings retrieved.\n`);
|
||||
return 0;
|
||||
}
|
||||
const { argv: originalArgv } = client;
|
||||
|
||||
@@ -296,7 +296,7 @@ export default async (client: Client): Promise<number> => {
|
||||
));
|
||||
|
||||
if (!shouldStartSetup) {
|
||||
output.print(`Aborted. Project not set up.\n`);
|
||||
output.print(`Canceled. Project not set up.\n`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export default async function add(
|
||||
const { domain, data: argData } = parsedParams;
|
||||
const data = await getDNSData(client, argData);
|
||||
if (!data) {
|
||||
output.log(`Aborted`);
|
||||
output.log(`Canceled`);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ export default async function rm(
|
||||
);
|
||||
|
||||
if (!yes) {
|
||||
output.error(`User aborted.`);
|
||||
output.error(`User canceled.`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ export default async function move(
|
||||
client
|
||||
))
|
||||
) {
|
||||
output.log('Aborted');
|
||||
output.log('Canceled');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ export default async function move(
|
||||
client
|
||||
))
|
||||
) {
|
||||
output.log('Aborted');
|
||||
output.log('Canceled');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ export default async function rm(
|
||||
client
|
||||
))
|
||||
) {
|
||||
output.log('Aborted');
|
||||
output.log('Canceled');
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ async function removeDomain(
|
||||
!skipConfirmation &&
|
||||
!(await promptBool(`Remove conflicts associated with domain?`, client))
|
||||
) {
|
||||
output.log('Aborted');
|
||||
output.log('Canceled');
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
2
packages/cli/src/commands/env/pull.ts
vendored
2
packages/cli/src/commands/env/pull.ts
vendored
@@ -84,7 +84,7 @@ export default async function pull(
|
||||
false
|
||||
))
|
||||
) {
|
||||
output.log('Aborted');
|
||||
output.log('Canceled');
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
2
packages/cli/src/commands/env/rm.ts
vendored
2
packages/cli/src/commands/env/rm.ts
vendored
@@ -111,7 +111,7 @@ export default async function rm(
|
||||
false
|
||||
))
|
||||
) {
|
||||
output.log('Aborted');
|
||||
output.log('Canceled');
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ export default async function connect(
|
||||
}
|
||||
|
||||
if (remoteUrl === '') {
|
||||
output.log('Aborted.');
|
||||
output.log('Canceled');
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ async function promptConnectArg({
|
||||
false
|
||||
);
|
||||
if (!shouldConnect) {
|
||||
client.output.log('Aborted. Repo not connected.');
|
||||
client.output.log('Canceled. Repo not connected.');
|
||||
}
|
||||
}
|
||||
return shouldConnect;
|
||||
@@ -404,7 +404,7 @@ async function confirmRepoConnect(
|
||||
true
|
||||
);
|
||||
if (!shouldReplaceProject) {
|
||||
client.output.log('Aborted. Repo not connected.');
|
||||
client.output.log('Canceled. Repo not connected.');
|
||||
}
|
||||
}
|
||||
return shouldReplaceProject;
|
||||
|
||||
@@ -43,7 +43,7 @@ export default async function disconnect(
|
||||
await disconnectGitProvider(client, org, project.id);
|
||||
output.log(`Disconnected ${chalk.cyan(`${linkOrg}/${repo}`)}.`);
|
||||
} else {
|
||||
output.log('Aborted.');
|
||||
output.log('Canceled');
|
||||
}
|
||||
} else {
|
||||
output.error(
|
||||
|
||||
@@ -53,7 +53,7 @@ export default async function init(
|
||||
);
|
||||
|
||||
if (!chosen) {
|
||||
output.log('Aborted');
|
||||
output.log('Canceled');
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -293,9 +293,7 @@ export default async function main(client: Client) {
|
||||
|
||||
// information to help the user find other deployments or instances
|
||||
log(
|
||||
`To list more deployments for a project, run ${getCommandName(
|
||||
'ls [project]'
|
||||
)}.`
|
||||
`To list deployments for a project, run ${getCommandName('ls [project]')}.`
|
||||
);
|
||||
|
||||
print('\n');
|
||||
@@ -338,7 +336,7 @@ export default async function main(client: Client) {
|
||||
if (pagination && pagination.count === 20) {
|
||||
const flags = getCommandFlags(argv, ['_', '--next']);
|
||||
log(
|
||||
`To display the next page run ${getCommandName(
|
||||
`To display the next page, run ${getCommandName(
|
||||
`ls${app ? ' ' + app : ''}${flags} --next ${pagination.next}`
|
||||
)}`
|
||||
);
|
||||
|
||||
@@ -226,7 +226,7 @@ export default async function main(client: Client) {
|
||||
).toLowerCase();
|
||||
|
||||
if (confirmation !== 'y' && confirmation !== 'yes') {
|
||||
output.log('Aborted');
|
||||
output.log('Canceled');
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ async function run({ output, contextName, currentTeam, client }) {
|
||||
argv.yes ||
|
||||
(await readConfirmation(client, output, theSecret, contextName));
|
||||
if (!yes) {
|
||||
output.print(`Aborted. Secret not deleted.\n`);
|
||||
output.print(`Canceled. Secret not deleted.\n`);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -59,7 +59,7 @@ export default async function add(client: Client): Promise<number> {
|
||||
});
|
||||
} catch (err: unknown) {
|
||||
if (isError(err) && err.message === 'USER_ABORT') {
|
||||
output.log('Aborted');
|
||||
output.log('Canceled');
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -426,7 +426,7 @@ export class UserAborted extends NowError<'USER_ABORTED', {}> {
|
||||
super({
|
||||
code: 'USER_ABORTED',
|
||||
meta: {},
|
||||
message: `The user aborted the operation.`,
|
||||
message: `The user canceled the operation.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,9 +58,9 @@ export async function connectGitProvider(
|
||||
(err.action === 'Install GitHub App' || err.code === 'repo_not_found')
|
||||
) {
|
||||
client.output.error(
|
||||
`Failed to link ${chalk.cyan(
|
||||
`Failed to connect ${chalk.cyan(
|
||||
repo
|
||||
)}. Make sure there aren't any typos and that you have access to the repository if it's private.`
|
||||
)} to project. Make sure there aren't any typos and that you have access to the repository if it's private.`
|
||||
);
|
||||
} else if (apiError && err.action === 'Add a Login Connection') {
|
||||
client.output.error(
|
||||
|
||||
@@ -39,7 +39,7 @@ export default function handleError(error: unknown, { debug = false } = {}) {
|
||||
} else if (status === 500) {
|
||||
console.error(errorOutput('Unexpected server error. Please retry.'));
|
||||
} else if (code === 'USER_ABORT') {
|
||||
info('Aborted');
|
||||
info('Canceled');
|
||||
} else {
|
||||
console.error(
|
||||
errorOutput(`Unexpected error. Please try again later. (${message})`)
|
||||
|
||||
@@ -21,7 +21,7 @@ interface ListOptions {
|
||||
choices: ListChoice[];
|
||||
pageSize?: number;
|
||||
separator?: boolean;
|
||||
abort?: 'start' | 'end';
|
||||
cancel?: 'start' | 'end';
|
||||
eraseFinalAnswer?: boolean;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ export default async function list(
|
||||
],
|
||||
pageSize = 15, // Show 15 lines without scrolling (~4 credit cards)
|
||||
separator = false, // Puts a blank separator between each choice
|
||||
abort = 'end', // Whether the `abort` option will be at the `start` or the `end`,
|
||||
cancel = 'end', // Whether the `cancel` option will be at the `start` or the `end`,
|
||||
eraseFinalAnswer = false, // If true, the line with the final answer that inquirer prints will be erased before returning
|
||||
}: ListOptions
|
||||
): Promise<string> {
|
||||
@@ -97,17 +97,17 @@ export default async function list(
|
||||
}
|
||||
}
|
||||
|
||||
const abortSeparator = new inquirer.Separator('─'.repeat(biggestLength));
|
||||
const _abort = {
|
||||
name: 'Abort',
|
||||
const cancelSeparator = new inquirer.Separator('─'.repeat(biggestLength));
|
||||
const _cancel = {
|
||||
name: 'Cancel',
|
||||
value: '',
|
||||
short: '',
|
||||
};
|
||||
|
||||
if (abort === 'start') {
|
||||
choices.unshift(_abort, abortSeparator);
|
||||
if (cancel === 'start') {
|
||||
choices.unshift(_cancel, cancelSeparator);
|
||||
} else {
|
||||
choices.push(abortSeparator, _abort);
|
||||
choices.push(cancelSeparator, _cancel);
|
||||
}
|
||||
|
||||
const answer = await client.prompt({
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
import { Dictionary } from '@vercel/client';
|
||||
import { parseRepoUrl } from '../git/connect-git-provider';
|
||||
import Client from '../client';
|
||||
import { Org, Project, ProjectSettings } from '../../types';
|
||||
import { handleOptions } from './handle-options';
|
||||
import {
|
||||
promptGitConnectMultipleUrls,
|
||||
promptGitConnectSingleUrl,
|
||||
} from './git-connect-prompts';
|
||||
|
||||
function getProjectSettings(project: Project): ProjectSettings {
|
||||
return {
|
||||
createdAt: project.createdAt,
|
||||
framework: project.framework,
|
||||
devCommand: project.devCommand,
|
||||
installCommand: project.installCommand,
|
||||
buildCommand: project.buildCommand,
|
||||
outputDirectory: project.outputDirectory,
|
||||
rootDirectory: project.rootDirectory,
|
||||
directoryListing: project.directoryListing,
|
||||
nodeVersion: project.nodeVersion,
|
||||
skipGitConnectDuringLink: project.skipGitConnectDuringLink,
|
||||
};
|
||||
}
|
||||
|
||||
export async function addGitConnection(
|
||||
client: Client,
|
||||
org: Org,
|
||||
project: Project,
|
||||
remoteUrls: Dictionary<string>,
|
||||
settings?: ProjectSettings
|
||||
): Promise<number | void> {
|
||||
if (!settings) {
|
||||
settings = getProjectSettings(project);
|
||||
}
|
||||
if (Object.keys(remoteUrls).length === 1) {
|
||||
return addSingleGitRemote(
|
||||
client,
|
||||
org,
|
||||
project,
|
||||
remoteUrls,
|
||||
settings || project
|
||||
);
|
||||
} else if (Object.keys(remoteUrls).length > 1 && !project.link) {
|
||||
return addMultipleGitRemotes(
|
||||
client,
|
||||
org,
|
||||
project,
|
||||
remoteUrls,
|
||||
settings || project
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function addSingleGitRemote(
|
||||
client: Client,
|
||||
org: Org,
|
||||
project: Project,
|
||||
remoteUrls: Dictionary<string>,
|
||||
settings: ProjectSettings
|
||||
) {
|
||||
const [remoteName, remoteUrl] = Object.entries(remoteUrls)[0];
|
||||
const repoInfo = parseRepoUrl(remoteUrl);
|
||||
if (!repoInfo) {
|
||||
client.output.debug(`Could not parse repo url ${repoInfo}.`);
|
||||
return 1;
|
||||
}
|
||||
const { org: parsedOrg, repo, provider } = repoInfo;
|
||||
const alreadyLinked =
|
||||
project.link &&
|
||||
project.link.org === parsedOrg &&
|
||||
project.link.repo === repo &&
|
||||
project.link.type === provider;
|
||||
if (alreadyLinked) {
|
||||
client.output.debug('Project already linked. Skipping...');
|
||||
return;
|
||||
}
|
||||
|
||||
const replace =
|
||||
project.link &&
|
||||
(project.link.org !== parsedOrg ||
|
||||
project.link.repo !== repo ||
|
||||
project.link.type !== provider);
|
||||
const shouldConnect = await promptGitConnectSingleUrl(
|
||||
client,
|
||||
project,
|
||||
remoteName,
|
||||
remoteUrl,
|
||||
replace
|
||||
);
|
||||
return handleOptions(shouldConnect, client, org, project, settings, repoInfo);
|
||||
}
|
||||
|
||||
async function addMultipleGitRemotes(
|
||||
client: Client,
|
||||
org: Org,
|
||||
project: Project,
|
||||
remoteUrls: Dictionary<string>,
|
||||
settings: ProjectSettings
|
||||
) {
|
||||
client.output.log('Found multiple Git remote URLs in Git config.');
|
||||
const remoteUrlOrOptions = await promptGitConnectMultipleUrls(
|
||||
client,
|
||||
remoteUrls
|
||||
);
|
||||
return handleOptions(remoteUrlOrOptions, client, org, project, settings);
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
import { Dictionary } from '@vercel/client';
|
||||
import chalk from 'chalk';
|
||||
import { Project } from '../../types';
|
||||
import Client from '../client';
|
||||
import { formatProvider } from '../git/connect-git-provider';
|
||||
import list from '../input/list';
|
||||
export async function promptGitConnectSingleUrl(
|
||||
client: Client,
|
||||
project: Project,
|
||||
remoteName: string,
|
||||
remoteUrl: string,
|
||||
hasDiffConnectedProvider = false
|
||||
) {
|
||||
const { output } = client;
|
||||
if (hasDiffConnectedProvider) {
|
||||
const currentRepoPath = `${project.link!.org}/${project.link!.repo}`;
|
||||
const currentProvider = project.link!.type;
|
||||
output.print('\n');
|
||||
output.log(
|
||||
`Found Git remote URL ${chalk.cyan(
|
||||
remoteUrl
|
||||
)}, which is different from the connected ${formatProvider(
|
||||
currentProvider
|
||||
)} repository ${chalk.cyan(currentRepoPath)}.`
|
||||
);
|
||||
} else {
|
||||
output.print('\n');
|
||||
output.log(
|
||||
`Found local Git remote "${remoteName}": ${chalk.cyan(remoteUrl)}`
|
||||
);
|
||||
}
|
||||
return await list(client, {
|
||||
message: hasDiffConnectedProvider
|
||||
? 'Do you want to replace it?'
|
||||
: `Do you want to connect "${remoteName}" to your Vercel project?`,
|
||||
choices: [
|
||||
{
|
||||
name: 'Yes',
|
||||
value: 'yes',
|
||||
short: 'yes',
|
||||
},
|
||||
{
|
||||
name: 'No',
|
||||
value: 'no',
|
||||
short: 'no',
|
||||
},
|
||||
{
|
||||
name: 'Do not ask again for this project',
|
||||
value: 'opt-out',
|
||||
short: 'no (opt out)',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
export async function promptGitConnectMultipleUrls(
|
||||
client: Client,
|
||||
remoteUrls: Dictionary<string>
|
||||
) {
|
||||
const staticOptions = [
|
||||
{
|
||||
name: 'No',
|
||||
value: 'no',
|
||||
short: 'no',
|
||||
},
|
||||
{
|
||||
name: 'Do not ask again for this project',
|
||||
value: 'opt-out',
|
||||
short: 'no (opt out)',
|
||||
},
|
||||
];
|
||||
let choices = [];
|
||||
for (const url of Object.values(remoteUrls)) {
|
||||
choices.push({
|
||||
name: url,
|
||||
value: url,
|
||||
short: url,
|
||||
});
|
||||
}
|
||||
choices = choices.concat(staticOptions);
|
||||
|
||||
return await list(client, {
|
||||
message: 'Do you want to connect a Git repository to your Vercel project?',
|
||||
choices,
|
||||
});
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
import chalk from 'chalk';
|
||||
import { Org, Project, ProjectSettings } from '../../types';
|
||||
import Client from '../client';
|
||||
import {
|
||||
connectGitProvider,
|
||||
disconnectGitProvider,
|
||||
formatProvider,
|
||||
RepoInfo,
|
||||
parseRepoUrl,
|
||||
} from '../git/connect-git-provider';
|
||||
import { Output } from '../output';
|
||||
import { getCommandName } from '../pkg-name';
|
||||
import updateProject from '../projects/update-project';
|
||||
|
||||
export async function handleOptions(
|
||||
option: string,
|
||||
client: Client,
|
||||
org: Org,
|
||||
project: Project,
|
||||
settings: ProjectSettings,
|
||||
repoInfo?: RepoInfo
|
||||
) {
|
||||
const { output } = client;
|
||||
if (option === 'no') {
|
||||
skip(output);
|
||||
return;
|
||||
} else if (option === 'opt-out') {
|
||||
optOut(client, project, settings);
|
||||
return;
|
||||
} else if (option !== '') {
|
||||
// Option is "yes" or a URL
|
||||
|
||||
// Ensure parsed url exists
|
||||
if (!repoInfo) {
|
||||
const _repoInfo = parseRepoUrl(option);
|
||||
if (!_repoInfo) {
|
||||
output.debug(`Could not parse repo url ${option}.`);
|
||||
return 1;
|
||||
}
|
||||
repoInfo = _repoInfo;
|
||||
}
|
||||
return connect(client, org, project, repoInfo);
|
||||
}
|
||||
}
|
||||
|
||||
async function optOut(
|
||||
client: Client,
|
||||
project: Project,
|
||||
settings: ProjectSettings
|
||||
) {
|
||||
settings.skipGitConnectDuringLink = true;
|
||||
await updateProject(client, project.name, settings);
|
||||
client.output
|
||||
.log(`Opted out. You can re-enable this prompt by visiting the Settings > Git page on the
|
||||
dashboard for this Project.`);
|
||||
}
|
||||
|
||||
function skip(output: Output) {
|
||||
output.log('Skipping...');
|
||||
output.log(
|
||||
`You can connect a Git repository in the future by running ${getCommandName(
|
||||
'git connect'
|
||||
)}.`
|
||||
);
|
||||
}
|
||||
|
||||
async function connect(
|
||||
client: Client,
|
||||
org: Org,
|
||||
project: Project,
|
||||
repoInfo: RepoInfo
|
||||
): Promise<number | void> {
|
||||
const { output } = client;
|
||||
const { provider, org: parsedOrg, repo } = repoInfo;
|
||||
const repoPath = `${parsedOrg}/${repo}`;
|
||||
|
||||
output.log('Connecting...');
|
||||
|
||||
if (project.link) {
|
||||
await disconnectGitProvider(client, org, project.id);
|
||||
}
|
||||
const connect = await connectGitProvider(
|
||||
client,
|
||||
org,
|
||||
project.id,
|
||||
provider,
|
||||
repoPath
|
||||
);
|
||||
if (connect !== 1) {
|
||||
output.log(
|
||||
`Connected ${formatProvider(provider)} repository ${chalk.cyan(
|
||||
repoPath
|
||||
)}!`
|
||||
);
|
||||
} else {
|
||||
return connect;
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,6 @@ import { EmojiLabel } from '../emoji';
|
||||
import createDeploy from '../deploy/create-deploy';
|
||||
import Now, { CreateOptions } from '../index';
|
||||
import { isAPIError } from '../errors-ts';
|
||||
import { getRemoteUrls } from '../create-git-meta';
|
||||
import { addGitConnection } from './add-git-connection';
|
||||
|
||||
export interface SetupAndLinkOptions {
|
||||
forceDelete?: boolean;
|
||||
@@ -89,7 +87,7 @@ export default async function setupAndLink(
|
||||
));
|
||||
|
||||
if (!shouldStartSetup) {
|
||||
output.print(`Aborted. Project not set up.\n`);
|
||||
output.print(`Canceled. Project not set up.\n`);
|
||||
return { status: 'not_linked', org: null, project: null };
|
||||
}
|
||||
|
||||
@@ -130,19 +128,6 @@ export default async function setupAndLink(
|
||||
} else {
|
||||
const project = projectOrNewProjectName;
|
||||
|
||||
const remoteUrls = await getRemoteUrls(join(path, '.git/config'), output);
|
||||
if (remoteUrls && !project.skipGitConnectDuringLink) {
|
||||
const connectGit = await addGitConnection(
|
||||
client,
|
||||
org,
|
||||
project,
|
||||
remoteUrls
|
||||
);
|
||||
if (typeof connectGit === 'number') {
|
||||
return { status: 'error', exitCode: connectGit };
|
||||
}
|
||||
}
|
||||
|
||||
await linkFolderToProject(
|
||||
output,
|
||||
path,
|
||||
@@ -257,20 +242,6 @@ export default async function setupAndLink(
|
||||
|
||||
const project = await createProject(client, newProjectName);
|
||||
|
||||
const remoteUrls = await getRemoteUrls(join(path, '.git/config'), output);
|
||||
if (remoteUrls) {
|
||||
const connectGit = await addGitConnection(
|
||||
client,
|
||||
org,
|
||||
project,
|
||||
remoteUrls,
|
||||
settings
|
||||
);
|
||||
if (typeof connectGit === 'number') {
|
||||
return { status: 'error', exitCode: connectGit };
|
||||
}
|
||||
}
|
||||
|
||||
await updateProject(client, project.id, settings);
|
||||
Object.assign(project, settings);
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ export default async function validatePaths(
|
||||
);
|
||||
|
||||
if (!shouldDeployHomeDirectory) {
|
||||
output.print(`Aborted\n`);
|
||||
output.print(`Canceled\n`);
|
||||
return { valid: false, exitCode: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import mod from '../increment.wasm?module';
|
||||
|
||||
export const config = { runtime: 'experimental-edge' };
|
||||
|
||||
const init$ = WebAssembly.instantiate(mod);
|
||||
|
||||
/** @param {Request} req */
|
||||
export default async req => {
|
||||
const givenNumber = Number(new URL(req.url).searchParams.get('number') || 0);
|
||||
const { exports } = await init$;
|
||||
const added = exports.add_one(givenNumber);
|
||||
return new Response(`${givenNumber} + 1 = ${added}`);
|
||||
};
|
||||
BIN
packages/cli/test/dev/fixtures/edge-function/increment.wasm
Executable file
BIN
packages/cli/test/dev/fixtures/edge-function/increment.wasm
Executable file
Binary file not shown.
@@ -53,6 +53,33 @@ test('[vercel dev] should support edge functions', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('[vercel dev] edge functions support WebAssembly files', async () => {
|
||||
const dir = fixture('edge-function');
|
||||
const { dev, port, readyResolver } = await testFixture(dir, {
|
||||
env: {
|
||||
ENV_VAR_IN_EDGE: '1',
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
await readyResolver;
|
||||
|
||||
for (const { number, result } of [
|
||||
{ number: 1, result: 2 },
|
||||
{ number: 2, result: 3 },
|
||||
{ number: 12, result: 13 },
|
||||
]) {
|
||||
let res = await fetch(
|
||||
`http://localhost:${port}/api/webassembly?number=${number}`
|
||||
);
|
||||
validateResponseHeaders(res);
|
||||
await expect(res.text()).resolves.toEqual(`${number} + 1 = ${result}`);
|
||||
}
|
||||
} finally {
|
||||
await dev.kill('SIGTERM');
|
||||
}
|
||||
});
|
||||
|
||||
test(
|
||||
'[vercel dev] edge functions respond properly the same as production',
|
||||
testFixtureStdio('edge-function', async (testPath: any) => {
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
!.vercel
|
||||
.vercel
|
||||
16
packages/cli/test/fixtures/unit/link-connect-git/multiple-remotes/git/config
generated
vendored
16
packages/cli/test/fixtures/unit/link-connect-git/multiple-remotes/git/config
generated
vendored
@@ -1,16 +0,0 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
ignorecase = true
|
||||
precomposeunicode = true
|
||||
[remote "origin"]
|
||||
url = https://github.com/user/repo.git
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
[remote "secondary"]
|
||||
url = https://github.com/user2/repo2.git
|
||||
fetch = +refs/heads/*:refs/remotes/secondary/*
|
||||
[remote "gitlab"]
|
||||
url = https://gitlab.com/user/repo.git
|
||||
fetch = +refs/heads/*:refs/remotes/gitlab/*
|
||||
@@ -1,2 +0,0 @@
|
||||
!.vercel
|
||||
.vercel
|
||||
13
packages/cli/test/fixtures/unit/link-connect-git/single-remote-existing-link/git/config
generated
vendored
13
packages/cli/test/fixtures/unit/link-connect-git/single-remote-existing-link/git/config
generated
vendored
@@ -1,13 +0,0 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
ignorecase = true
|
||||
precomposeunicode = true
|
||||
[remote "origin"]
|
||||
url = https://github.com/user2/repo2.git
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
[branch "master"]
|
||||
remote = origin
|
||||
merge = refs/heads/master
|
||||
@@ -1,2 +0,0 @@
|
||||
!.vercel
|
||||
.vercel
|
||||
13
packages/cli/test/fixtures/unit/link-connect-git/single-remote/git/config
generated
vendored
13
packages/cli/test/fixtures/unit/link-connect-git/single-remote/git/config
generated
vendored
@@ -1,13 +0,0 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
ignorecase = true
|
||||
precomposeunicode = true
|
||||
[remote "origin"]
|
||||
url = https://github.com/user/repo.git
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
[branch "master"]
|
||||
remote = origin
|
||||
merge = refs/heads/master
|
||||
@@ -9,7 +9,7 @@ export function readOutputStream(
|
||||
let lines = 0;
|
||||
const timeout = setTimeout(() => {
|
||||
reject(
|
||||
new Error(`Was waiting for ${length} lines, but only received ${chunks.length}`)
|
||||
new Error(`Was waiting for ${length} lines, but only received ${lines}`)
|
||||
);
|
||||
}, 3000);
|
||||
|
||||
|
||||
2
packages/cli/test/integration.js
vendored
2
packages/cli/test/integration.js
vendored
@@ -1862,7 +1862,7 @@ test('ensure we render a prompt when deploying home directory', async t => {
|
||||
'You are deploying your home directory. Do you want to continue? [y/N]'
|
||||
)
|
||||
);
|
||||
t.true(stderr.includes('Aborted'));
|
||||
t.true(stderr.includes('Canceled'));
|
||||
});
|
||||
|
||||
test('ensure the `scope` property works with email', async t => {
|
||||
|
||||
@@ -24,7 +24,6 @@ export function useDeployment({
|
||||
const deployment: Deployment = {
|
||||
id,
|
||||
url: url.hostname,
|
||||
inspectorUrl: `https://vercel.com/team/project/${id.replace('dpl_', '')}`,
|
||||
name,
|
||||
meta: {},
|
||||
regions: [],
|
||||
|
||||
@@ -39,11 +39,6 @@ describe('git', () => {
|
||||
await expect(client.stderr).toOutput('Found project');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
'Do you want to connect "origin" to your Vercel project?'
|
||||
);
|
||||
client.stdin.write('n\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
`Connecting Git remote: https://github.com/user/repo.git`
|
||||
);
|
||||
@@ -295,7 +290,7 @@ describe('git', () => {
|
||||
`Connecting Git remote: https://github.com/laksfj/asdgklsadkl`
|
||||
);
|
||||
await expect(client.stderr).toOutput(
|
||||
`Failed to link laksfj/asdgklsadkl. Make sure there aren't any typos and that you have access to the repository if it's private.`
|
||||
`Failed to connect laksfj/asdgklsadkl to project. Make sure there aren't any typos and that you have access to the repository if it's private.`
|
||||
);
|
||||
|
||||
const exitCode = await gitPromise;
|
||||
|
||||
@@ -1,310 +0,0 @@
|
||||
import { join } from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import link from '../../../src/commands/link';
|
||||
import { useUser } from '../../mocks/user';
|
||||
import { useTeams } from '../../mocks/team';
|
||||
import {
|
||||
defaultProject,
|
||||
useUnknownProject,
|
||||
useProject,
|
||||
} from '../../mocks/project';
|
||||
import { client } from '../../mocks/client';
|
||||
import { useDeploymentMissingProjectSettings } from '../../mocks/deployment';
|
||||
import { Project } from '../../../src/types';
|
||||
|
||||
describe('link', () => {
|
||||
describe('git prompt', () => {
|
||||
const originalCwd = process.cwd();
|
||||
const fixture = (name: string) =>
|
||||
join(__dirname, '../../fixtures/unit/link-connect-git', name);
|
||||
|
||||
it('should prompt to connect a new project with a single remote', async () => {
|
||||
const cwd = fixture('single-remote');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
useUser();
|
||||
useUnknownProject();
|
||||
useDeploymentMissingProjectSettings();
|
||||
useTeams('team_dummy');
|
||||
const linkPromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
await expect(client.stderr).toOutput('Which scope');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Link to existing project?');
|
||||
client.stdin.write('n\n');
|
||||
await expect(client.stderr).toOutput('What’s your project’s name?');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput(
|
||||
'In which directory is your code located?'
|
||||
);
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Want to modify these settings?');
|
||||
client.stdin.write('n\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
'Found local Git remote "origin": https://github.com/user/repo.git'
|
||||
);
|
||||
await expect(client.stderr).toOutput(
|
||||
'Do you want to connect "origin" to your Vercel project?'
|
||||
);
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput(
|
||||
'Connected GitHub repository user/repo!'
|
||||
);
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
|
||||
it('should prompt to connect an existing project with a single remote to git', async () => {
|
||||
const cwd = fixture('single-remote');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
useUser();
|
||||
useProject({
|
||||
...defaultProject,
|
||||
name: 'single-remote',
|
||||
id: 'single-remote',
|
||||
});
|
||||
useTeams('team_dummy');
|
||||
const linkPromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
await expect(client.stderr).toOutput('Which scope');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Found project');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
'Found local Git remote "origin": https://github.com/user/repo.git'
|
||||
);
|
||||
await expect(client.stderr).toOutput(
|
||||
'Do you want to connect "origin" to your Vercel project?'
|
||||
);
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput(
|
||||
'Connected GitHub repository user/repo!'
|
||||
);
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
it('should prompt to replace a connected repository if there is one remote', async () => {
|
||||
const cwd = fixture('single-remote-existing-link');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
useUser();
|
||||
const project = useProject({
|
||||
...defaultProject,
|
||||
name: 'single-remote-existing-link',
|
||||
id: 'single-remote-existing-link',
|
||||
});
|
||||
useTeams('team_dummy');
|
||||
project.project.link = {
|
||||
type: 'github',
|
||||
org: 'user',
|
||||
repo: 'repo',
|
||||
repoId: 1010,
|
||||
gitCredentialId: '',
|
||||
sourceless: true,
|
||||
createdAt: 1656109539791,
|
||||
updatedAt: 1656109539791,
|
||||
};
|
||||
|
||||
const linkPromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
await expect(client.stderr).toOutput('Which scope');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Found project');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
`Found Git remote URL https://github.com/user2/repo2.git, which is different from the connected GitHub repository user/repo.`
|
||||
);
|
||||
await expect(client.stderr).toOutput('Do you want to replace it?');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput(
|
||||
'Connected GitHub repository user2/repo2!'
|
||||
);
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
it('should prompt to connect an existing project with multiple remotes', async () => {
|
||||
const cwd = fixture('multiple-remotes');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
|
||||
useUser();
|
||||
useProject({
|
||||
...defaultProject,
|
||||
name: 'multiple-remotes',
|
||||
id: 'multiple-remotes',
|
||||
});
|
||||
useTeams('team_dummy');
|
||||
|
||||
const linkPromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
await expect(client.stderr).toOutput('Which scope');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Found project');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
`> Do you want to connect a Git repository to your Vercel project?`
|
||||
);
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput(
|
||||
'Connected GitHub repository user/repo!'
|
||||
);
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
it('should not prompt to replace a connected repository if there is more than one remote', async () => {
|
||||
const cwd = fixture('multiple-remotes');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
|
||||
useUser();
|
||||
const project = useProject({
|
||||
...defaultProject,
|
||||
name: 'multiple-remotes',
|
||||
id: 'multiple-remotes',
|
||||
});
|
||||
useTeams('team_dummy');
|
||||
project.project.link = {
|
||||
type: 'github',
|
||||
org: 'user',
|
||||
repo: 'repo',
|
||||
repoId: 1010,
|
||||
gitCredentialId: '',
|
||||
sourceless: true,
|
||||
createdAt: 1656109539791,
|
||||
updatedAt: 1656109539791,
|
||||
};
|
||||
|
||||
const linkPromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
await expect(client.stderr).toOutput('Which scope');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Found project');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
expect(client.stderr).not.toOutput('Found multiple Git remote URLs');
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
it('should set a project setting if user opts out', async () => {
|
||||
const cwd = fixture('single-remote');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
|
||||
useUser();
|
||||
useProject({
|
||||
...defaultProject,
|
||||
name: 'single-remote',
|
||||
id: 'single-remote',
|
||||
});
|
||||
useTeams('team_dummy');
|
||||
const linkPromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
await expect(client.stderr).toOutput('Which scope');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Found project');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
'Found local Git remote "origin": https://github.com/user/repo.git'
|
||||
);
|
||||
await expect(client.stderr).toOutput(
|
||||
'Do you want to connect "origin" to your Vercel project?'
|
||||
);
|
||||
client.stdin.write('\x1B[B'); // Down arrow
|
||||
client.stdin.write('\x1B[B');
|
||||
client.stdin.write('\r'); // Opt out
|
||||
|
||||
await expect(client.stderr).toOutput(`Opted out.`);
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
|
||||
const newProjectData: Project = await client.fetch(
|
||||
`/v8/projects/single-remote`
|
||||
);
|
||||
expect(newProjectData.skipGitConnectDuringLink).toBeTruthy();
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
it('should not prompt to connect git if the project has skipGitConnectDuringLink property', async () => {
|
||||
const cwd = fixture('single-remote');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
|
||||
useUser();
|
||||
const project = useProject({
|
||||
...defaultProject,
|
||||
name: 'single-remote',
|
||||
id: 'single-remote',
|
||||
});
|
||||
useTeams('team_dummy');
|
||||
project.project.skipGitConnectDuringLink = true;
|
||||
const linkPromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
await expect(client.stderr).toOutput('Which scope');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Found project');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
expect(client.stderr).not.toOutput('Found local Git remote "origin"');
|
||||
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/client",
|
||||
"version": "12.2.0",
|
||||
"version": "12.2.1",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"homepage": "https://vercel.com",
|
||||
@@ -43,7 +43,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "5.3.1",
|
||||
"@vercel/build-utils": "5.3.2",
|
||||
"@vercel/routing-utils": "2.0.2",
|
||||
"@zeit/fetch": "5.2.0",
|
||||
"async-retry": "1.2.3",
|
||||
|
||||
20
packages/go/go.mod
Normal file
20
packages/go/go.mod
Normal file
@@ -0,0 +1,20 @@
|
||||
module main
|
||||
|
||||
go 1.18
|
||||
|
||||
// This file exists to allow debugging of Go files within this package,
|
||||
// such as `util/analyze.go`.
|
||||
|
||||
// You can do this by creating a VS Code Launcher Configuration
|
||||
// replacing `YOUR_VERCEL_DIR` with your vercel directory, like:
|
||||
// {
|
||||
// "name": "Debug Go",
|
||||
// "type": "go",
|
||||
// "request": "launch",
|
||||
// "mode": "auto",
|
||||
// "program": "${fileDirname}",
|
||||
// "args": [
|
||||
// "-modpath=YOUR_VERCEL_DIR/packages/go/test/fixtures/24-bad-handler/api/",
|
||||
// "YOUR_VERCEL_DIR/packages/go/test/fixtures/24-bad-handler/api/index.go"
|
||||
// ]
|
||||
// }
|
||||
@@ -285,6 +285,10 @@ export async function build({
|
||||
|
||||
const outDir = await getWriteableDirectory();
|
||||
|
||||
// in order to allow the user to have `main.go`,
|
||||
// we need our `main.go` to be called something else
|
||||
const mainGoFileName = 'main__vc__go__.go';
|
||||
|
||||
if (packageName !== 'main') {
|
||||
const go = await createGo(
|
||||
workPath,
|
||||
@@ -321,9 +325,8 @@ export async function build({
|
||||
}
|
||||
}
|
||||
|
||||
const mainModGoFileName = 'main__mod__.go';
|
||||
const modMainGoContents = await readFile(
|
||||
join(__dirname, mainModGoFileName),
|
||||
join(__dirname, 'main.go'),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
@@ -348,30 +351,27 @@ export async function build({
|
||||
|
||||
if (isGoModExist && isGoModInRootDir) {
|
||||
debug('[mod-root] Write main file to ' + downloadPath);
|
||||
await writeFile(
|
||||
join(downloadPath, mainModGoFileName),
|
||||
mainModGoContents
|
||||
);
|
||||
await writeFile(join(downloadPath, mainGoFileName), mainModGoContents);
|
||||
undoFileActions.push({
|
||||
to: undefined, // delete
|
||||
from: join(downloadPath, mainModGoFileName),
|
||||
from: join(downloadPath, mainGoFileName),
|
||||
});
|
||||
} else if (isGoModExist && !isGoModInRootDir) {
|
||||
debug('[mod-other] Write main file to ' + goModPath);
|
||||
await writeFile(join(goModPath, mainModGoFileName), mainModGoContents);
|
||||
await writeFile(join(goModPath, mainGoFileName), mainModGoContents);
|
||||
undoFileActions.push({
|
||||
to: undefined, // delete
|
||||
from: join(goModPath, mainModGoFileName),
|
||||
from: join(goModPath, mainGoFileName),
|
||||
});
|
||||
} else {
|
||||
debug('[entrypoint] Write main file to ' + entrypointDirname);
|
||||
await writeFile(
|
||||
join(entrypointDirname, mainModGoFileName),
|
||||
join(entrypointDirname, mainGoFileName),
|
||||
mainModGoContents
|
||||
);
|
||||
undoFileActions.push({
|
||||
to: undefined, // delete
|
||||
from: join(entrypointDirname, mainModGoFileName),
|
||||
from: join(entrypointDirname, mainGoFileName),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -428,7 +428,7 @@ export async function build({
|
||||
const destPath = join(outDir, handlerFileName);
|
||||
|
||||
try {
|
||||
const src = [join(baseGoModPath, mainModGoFileName)];
|
||||
const src = [join(baseGoModPath, mainGoFileName)];
|
||||
|
||||
await go.build(src, destPath);
|
||||
} catch (err) {
|
||||
@@ -449,18 +449,13 @@ export async function build({
|
||||
},
|
||||
false
|
||||
);
|
||||
const origianlMainGoContents = await readFile(
|
||||
const originalMainGoContents = await readFile(
|
||||
join(__dirname, 'main.go'),
|
||||
'utf8'
|
||||
);
|
||||
const mainGoContents = origianlMainGoContents.replace(
|
||||
'__VC_HANDLER_FUNC_NAME',
|
||||
handlerFunctionName
|
||||
);
|
||||
|
||||
// in order to allow the user to have `main.go`,
|
||||
// we need our `main.go` to be called something else
|
||||
const mainGoFileName = 'main__vc__go__.go';
|
||||
const mainGoContents = originalMainGoContents
|
||||
.replace('"__VC_HANDLER_PACKAGE_NAME"', '')
|
||||
.replace('__VC_HANDLER_FUNC_NAME', handlerFunctionName);
|
||||
|
||||
// Go doesn't like to build files in different directories,
|
||||
// so now we place `main.go` together with the user code
|
||||
@@ -498,6 +493,7 @@ export async function build({
|
||||
files: { ...(await glob('**', outDir)), ...includedFiles },
|
||||
handler: handlerFileName,
|
||||
runtime: 'go1.x',
|
||||
supportsWrapper: true,
|
||||
environment: {},
|
||||
});
|
||||
|
||||
@@ -535,8 +531,14 @@ export async function build({
|
||||
async function renameHandlerFunction(fsPath: string, from: string, to: string) {
|
||||
let fileContents = await readFile(fsPath, 'utf8');
|
||||
|
||||
const fromRegex = new RegExp(`\\b${from}\\b`, 'g');
|
||||
fileContents = fileContents.replace(fromRegex, to);
|
||||
// This regex has to walk a fine line where it replaces the most-likely occurrences
|
||||
// of the handler's identifier without clobbering other syntax.
|
||||
// Left-hand Side: A single space was chosen because it can catch `func Handler`
|
||||
// as well as `var _ http.HandlerFunc = Index`.
|
||||
// Right-hand Side: a word boundary was chosen because this can be an end of line
|
||||
// or an open paren (as in `func Handler(`).
|
||||
const fromRegex = new RegExp(String.raw` ${from}\b`, 'g');
|
||||
fileContents = fileContents.replace(fromRegex, ` ${to}`);
|
||||
|
||||
await writeFile(fsPath, fileContents);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
vc "github.com/vercel/go-bridge/go/bridge"
|
||||
"net/http"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"__VC_HANDLER_PACKAGE_NAME"
|
||||
vc "github.com/vercel/go-bridge/go/bridge"
|
||||
)
|
||||
|
||||
func checkForLambdaWrapper() {
|
||||
wrapper := os.Getenv("AWS_LAMBDA_EXEC_WRAPPER")
|
||||
if wrapper == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// Removing the env var doesn't work
|
||||
// Set it to empty string to override the previous value
|
||||
os.Setenv("AWS_LAMBDA_EXEC_WRAPPER", "")
|
||||
argv := append([]string{wrapper}, os.Args...)
|
||||
err := syscall.Exec(wrapper, argv, os.Environ())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
checkForLambdaWrapper()
|
||||
vc.Start(http.HandlerFunc(__VC_HANDLER_FUNC_NAME))
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"__VC_HANDLER_PACKAGE_NAME"
|
||||
"net/http"
|
||||
|
||||
vc "github.com/vercel/go-bridge/go/bridge"
|
||||
)
|
||||
|
||||
func main() {
|
||||
vc.Start(http.HandlerFunc(__VC_HANDLER_FUNC_NAME))
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/go",
|
||||
"version": "2.1.1",
|
||||
"version": "2.2.2",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
||||
@@ -35,7 +35,7 @@
|
||||
"@types/jest": "28.1.6",
|
||||
"@types/node-fetch": "^2.3.0",
|
||||
"@types/tar": "^4.0.0",
|
||||
"@vercel/build-utils": "5.3.1",
|
||||
"@vercel/build-utils": "5.3.2",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"async-retry": "1.3.1",
|
||||
"execa": "^1.0.0",
|
||||
|
||||
1
packages/go/test/fixtures/22-large-environment/env/go.mod
vendored
Normal file
1
packages/go/test/fixtures/22-large-environment/env/go.mod
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module env
|
||||
19
packages/go/test/fixtures/22-large-environment/env/index.go
vendored
Normal file
19
packages/go/test/fixtures/22-large-environment/env/index.go
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Handler function
|
||||
func Handler(w http.ResponseWriter, r *http.Request) {
|
||||
rdm := os.Getenv("RANDOMNESS_ENV")
|
||||
if rdm == "" {
|
||||
fmt.Println("No env received")
|
||||
}
|
||||
|
||||
fmt.Fprintln(w, rdm)
|
||||
fmt.Fprintln(w, os.Getenv("LOREM"))
|
||||
fmt.Fprintln(w, os.Getenv("IPSUM"))
|
||||
}
|
||||
28
packages/go/test/fixtures/22-large-environment/now.json
vendored
Normal file
28
packages/go/test/fixtures/22-large-environment/now.json
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "env/index.go",
|
||||
"use": "@vercel/go"
|
||||
}
|
||||
],
|
||||
"env": {
|
||||
"RANDOMNESS_ENV": "RANDOMNESS_PLACEHOLDER",
|
||||
"LOREM": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean turpis nisl, porta vel dictum id, placerat eu massa. Curabitur id diam at urna elementum condimentum a eget augue. Sed vehicula, mauris quis tincidunt iaculis, lacus quam dictum nulla, eu pellentesque justo lectus a erat. Integer volutpat magna tortor, non mollis tortor rhoncus quis. Donec id urna ligula. Praesent et ligula id ligula blandit rhoncus. Proin consequat, justo id maximus lacinia, tortor dui facilisis nunc, at aliquet odio orci nec tellus. Vestibulum sagittis nec sem id mollis. Donec eleifend risus eget lectus mattis convallis. Nam ac urna commodo, venenatis massa ut, varius magna. Aliquam erat volutpat. Ut ac lacinia erat. Mauris finibus vehicula elementum. Proin mauris neque, fringilla a erat fermentum, convallis elementum urna. Pellentesque bibendum nisl eget nisi sodales, a faucibus felis scelerisque. Fusce blandit imperdiet nunc, ac hendrerit ante placerat sed. Cras metus dolor, cursus non orci sed, iaculis tempor nunc. Quisque vitae enim pharetra, viverra massa non, mollis magna. Vivamus sit amet ultricies ligula, in vulputate sapien. Praesent ullamcorper justo in elit vulputate, et varius augue egestas. Donec quis rutrum mauris. Suspendisse placerat volutpat gravida. Nunc laoreet velit a accumsan faucibus. Nunc eu lorem sem. Sed id nunc a metus gravida accumsan. Morbi aliquet purus id ipsum dictum, nec finibus quam ullamcorper. Quisque sapien nulla, laoreet a accumsan non, luctus quis ante. Sed sit amet pellentesque magna. Aenean pulvinar porta est sed posuere. Aenean id nisl dictum, varius diam vel, facilisis ex. Praesent quis justo id mi eleifend eleifend. Aliquam imperdiet purus non ligula lobortis laoreet. Sed mollis aliquet dui et luctus. Donec ut lacus vel tellus porta feugiat. Nam lacinia euismod libero. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi facilisis quam nec nisl pretium, id blandit sapien pretium. Donec id sapien varius, ornare mi sed, pretium magna. Phasellus tortor ligula, porttitor sit amet magna in, semper condimentum elit.",
|
||||
"IPSUM": "Phasellus ac orci eleifend, dignissim turpis et, aliquet libero. Praesent aliquet justo augue, vel vulputate ex dictum ut. Donec eu interdum ex, sit amet hendrerit felis. Maecenas eget iaculis orci, eget porta eros. Pellentesque vitae neque in velit dapibus luctus. Pellentesque ornare et tellus eu congue. Aliquam eu sem vel neque varius faucibus. Ut eget tortor ornare, fermentum enim nec, pellentesque massa. Phasellus rhoncus aliquet nunc nec semper. Nullam sed iaculis tellus. Mauris a sollicitudin velit, id egestas odio. Suspendisse commodo commodo turpis, et sollicitudin sem commodo a. Vivamus condimentum, arcu ac tempus blandit, lectus ligula pulvinar est, in congue mi nunc et lacus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi sodales ipsum quis scelerisque vehicula. Quisque gravida nibh vitae mattis sollicitudin. Donec fringilla dapibus urna non gravida. Phasellus et eros id magna tristique consequat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In lacus neque, auctor sed arcu at, varius volutpat est. Maecenas eget ante sed ipsum sagittis laoreet ut nec nisi. Quisque scelerisque, risus ut efficitur sollicitudin, neque est faucibus lacus, vitae eleifend nulla sem a magna. Integer viverra, diam eget venenatis pretium, augue ex pulvinar justo, ac ultrices neque nisl laoreet risus. Pellentesque commodo ultrices laoreet. Nulla nec ipsum non augue hendrerit vulputate sed eget diam. Maecenas semper rutrum ligula. Sed egestas, orci sed volutpat varius, eros mi lacinia magna, tincidunt aliquet nibh lacus eget dui. Integer vestibulum velit in interdum ultrices. Mauris porta vitae quam non placerat. In nisi risus, hendrerit rhoncus hendrerit at, lacinia vel mauris. Curabitur tempus mattis eros nec consequat. Sed posuere elit lobortis libero porta, sed pharetra tortor ornare. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse pulvinar ante vitae metus ullamcorper euismod. Nulla facilisi. Donec quam nulla, eleifend vel consequat sed, maximus et nisi. Donec molestie euismod semper. Fusce eget arcu feugiat, efficitur lectus sed, feugiat justo. Mauris ultricies pretium ante non faucibus. Aenean egestas ante nunc, id pellentesque metus blandit eu. Nullam faucibus fringilla lectus, quis dapibus turpis elementum eu. Nunc eget dolor in velit molestie interdum id eu justo. Aliquam ornare arcu quis tincidunt posuere. Mauris sed porttitor ligula. Vestibulum tincidunt non lacus id lacinia. Donec ex augue, convallis vel justo vel, faucibus ultricies tortor."
|
||||
},
|
||||
"probes": [
|
||||
{
|
||||
"path": "/env",
|
||||
"mustContain": "RANDOMNESS_PLACEHOLDER"
|
||||
},
|
||||
{
|
||||
"path": "/env",
|
||||
"mustContain": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean turpis nisl, porta vel dictum id, placerat eu massa. Curabitur id diam at urna elementum condimentum a eget augue. Sed vehicula, mauris quis tincidunt iaculis, lacus quam dictum nulla, eu pellentesque justo lectus a erat. Integer volutpat magna tortor, non mollis tortor rhoncus quis. Donec id urna ligula. Praesent et ligula id ligula blandit rhoncus. Proin consequat, justo id maximus lacinia, tortor dui facilisis nunc, at aliquet odio orci nec tellus. Vestibulum sagittis nec sem id mollis. Donec eleifend risus eget lectus mattis convallis. Nam ac urna commodo, venenatis massa ut, varius magna. Aliquam erat volutpat. Ut ac lacinia erat. Mauris finibus vehicula elementum. Proin mauris neque, fringilla a erat fermentum, convallis elementum urna. Pellentesque bibendum nisl eget nisi sodales, a faucibus felis scelerisque. Fusce blandit imperdiet nunc, ac hendrerit ante placerat sed. Cras metus dolor, cursus non orci sed, iaculis tempor nunc. Quisque vitae enim pharetra, viverra massa non, mollis magna. Vivamus sit amet ultricies ligula, in vulputate sapien. Praesent ullamcorper justo in elit vulputate, et varius augue egestas. Donec quis rutrum mauris. Suspendisse placerat volutpat gravida. Nunc laoreet velit a accumsan faucibus. Nunc eu lorem sem. Sed id nunc a metus gravida accumsan. Morbi aliquet purus id ipsum dictum, nec finibus quam ullamcorper. Quisque sapien nulla, laoreet a accumsan non, luctus quis ante. Sed sit amet pellentesque magna. Aenean pulvinar porta est sed posuere. Aenean id nisl dictum, varius diam vel, facilisis ex. Praesent quis justo id mi eleifend eleifend. Aliquam imperdiet purus non ligula lobortis laoreet. Sed mollis aliquet dui et luctus. Donec ut lacus vel tellus porta feugiat. Nam lacinia euismod libero. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi facilisis quam nec nisl pretium, id blandit sapien pretium. Donec id sapien varius, ornare mi sed, pretium magna. Phasellus tortor ligula, porttitor sit amet magna in, semper condimentum elit."
|
||||
},
|
||||
{
|
||||
"path": "/env",
|
||||
"mustContain": "Phasellus ac orci eleifend, dignissim turpis et, aliquet libero. Praesent aliquet justo augue, vel vulputate ex dictum ut. Donec eu interdum ex, sit amet hendrerit felis. Maecenas eget iaculis orci, eget porta eros. Pellentesque vitae neque in velit dapibus luctus. Pellentesque ornare et tellus eu congue. Aliquam eu sem vel neque varius faucibus. Ut eget tortor ornare, fermentum enim nec, pellentesque massa. Phasellus rhoncus aliquet nunc nec semper. Nullam sed iaculis tellus. Mauris a sollicitudin velit, id egestas odio. Suspendisse commodo commodo turpis, et sollicitudin sem commodo a. Vivamus condimentum, arcu ac tempus blandit, lectus ligula pulvinar est, in congue mi nunc et lacus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi sodales ipsum quis scelerisque vehicula. Quisque gravida nibh vitae mattis sollicitudin. Donec fringilla dapibus urna non gravida. Phasellus et eros id magna tristique consequat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In lacus neque, auctor sed arcu at, varius volutpat est. Maecenas eget ante sed ipsum sagittis laoreet ut nec nisi. Quisque scelerisque, risus ut efficitur sollicitudin, neque est faucibus lacus, vitae eleifend nulla sem a magna. Integer viverra, diam eget venenatis pretium, augue ex pulvinar justo, ac ultrices neque nisl laoreet risus. Pellentesque commodo ultrices laoreet. Nulla nec ipsum non augue hendrerit vulputate sed eget diam. Maecenas semper rutrum ligula. Sed egestas, orci sed volutpat varius, eros mi lacinia magna, tincidunt aliquet nibh lacus eget dui. Integer vestibulum velit in interdum ultrices. Mauris porta vitae quam non placerat. In nisi risus, hendrerit rhoncus hendrerit at, lacinia vel mauris. Curabitur tempus mattis eros nec consequat. Sed posuere elit lobortis libero porta, sed pharetra tortor ornare. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse pulvinar ante vitae metus ullamcorper euismod. Nulla facilisi. Donec quam nulla, eleifend vel consequat sed, maximus et nisi. Donec molestie euismod semper. Fusce eget arcu feugiat, efficitur lectus sed, feugiat justo. Mauris ultricies pretium ante non faucibus. Aenean egestas ante nunc, id pellentesque metus blandit eu. Nullam faucibus fringilla lectus, quis dapibus turpis elementum eu. Nunc eget dolor in velit molestie interdum id eu justo. Aliquam ornare arcu quis tincidunt posuere. Mauris sed porttitor ligula. Vestibulum tincidunt non lacus id lacinia. Donec ex augue, convallis vel justo vel, faucibus ultricies tortor."
|
||||
}
|
||||
]
|
||||
}
|
||||
5
packages/go/test/fixtures/23-main-go/api/go.mod
vendored
Normal file
5
packages/go/test/fixtures/23-main-go/api/go.mod
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
module github.com/vercel/does-not-exist
|
||||
|
||||
go 1.13
|
||||
|
||||
require github.com/dhruvbird/go-cowsay v0.0.0-20131019225157-6fd7bd0281c0 // indirect
|
||||
11
packages/go/test/fixtures/23-main-go/api/index.go
vendored
Normal file
11
packages/go/test/fixtures/23-main-go/api/index.go
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func Handler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "version:%s:RANDOMNESS_PLACEHOLDER", runtime.Version())
|
||||
}
|
||||
14
packages/go/test/fixtures/23-main-go/main.go
vendored
Normal file
14
packages/go/test/fixtures/23-main-go/main.go
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
server := http.Server{
|
||||
Addr: "localhost:3000",
|
||||
Handler: http.HandlerFunc(api.IndexHandler),
|
||||
}
|
||||
|
||||
server.ListenAndServe()
|
||||
}
|
||||
9
packages/go/test/fixtures/23-main-go/vercel.json
vendored
Normal file
9
packages/go/test/fixtures/23-main-go/vercel.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"version": 2,
|
||||
"probes": [
|
||||
{
|
||||
"path": "/api",
|
||||
"mustContain": "version:go1.13.15:RANDOMNESS_PLACEHOLDER"
|
||||
}
|
||||
]
|
||||
}
|
||||
1
packages/go/test/fixtures/24-bad-handler/.gitignore
vendored
Normal file
1
packages/go/test/fixtures/24-bad-handler/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.vercel
|
||||
34
packages/go/test/fixtures/24-bad-handler/api/bad-receiver.go
vendored
Normal file
34
packages/go/test/fixtures/24-bad-handler/api/bad-receiver.go
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type SampleDecoder struct {
|
||||
}
|
||||
|
||||
type Servers struct {
|
||||
path string
|
||||
}
|
||||
|
||||
// the handler location logic looks for the first function that matches the proper signature;
|
||||
// this test makes sure that the BadReceiverHandler is not found because it is a receiver function
|
||||
|
||||
// this handler will not be found because it is a receiver function
|
||||
func (d *SampleDecoder) BadReceiverHandler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "from BadHandler")
|
||||
}
|
||||
|
||||
// this handler can be delegated to without being renamed
|
||||
func (s Servers) Handler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, s.path)
|
||||
}
|
||||
|
||||
// this handler will be found because it has the correct function signature
|
||||
func GoodHandler_api_bad_receiver_go(w http.ResponseWriter, r *http.Request) {
|
||||
server := Servers{"some/path"}
|
||||
|
||||
// this occurence of "Handler" should not be renamed
|
||||
server.Handler(w, r)
|
||||
}
|
||||
3
packages/go/test/fixtures/24-bad-handler/api/go.mod
vendored
Normal file
3
packages/go/test/fixtures/24-bad-handler/api/go.mod
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module handler
|
||||
|
||||
go 1.13
|
||||
8
packages/go/test/fixtures/24-bad-handler/probes.json
vendored
Normal file
8
packages/go/test/fixtures/24-bad-handler/probes.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"probes": [
|
||||
{
|
||||
"path": "/api/bad-receiver",
|
||||
"mustContain": "some/path"
|
||||
}
|
||||
]
|
||||
}
|
||||
1
packages/go/test/fixtures/24-bad-handler/vercel.json
vendored
Normal file
1
packages/go/test/fixtures/24-bad-handler/vercel.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -197,7 +197,9 @@ func main() {
|
||||
// find a valid `http.HandlerFunc` handler function
|
||||
params := rf[fn.Type.Params.Pos()-offset : fn.Type.Params.End()-offset]
|
||||
validHandlerFunc := (strings.Contains(string(params), "http.ResponseWriter") &&
|
||||
strings.Contains(string(params), "*http.Request") && len(fn.Type.Params.List) == 2)
|
||||
strings.Contains(string(params), "*http.Request") &&
|
||||
len(fn.Type.Params.List) == 2 &&
|
||||
(fn.Recv == nil || len(fn.Recv.List) == 0))
|
||||
|
||||
if validHandlerFunc {
|
||||
// we found the first exported function with `http.HandlerFunc`
|
||||
@@ -223,7 +225,7 @@ func main() {
|
||||
if fn.Name.IsExported() == true {
|
||||
for _, param := range fn.Type.Params.List {
|
||||
paramStr := fmt.Sprintf("%s", param.Type)
|
||||
if strings.Contains(string(paramStr), "http ResponseWriter") && len(fn.Type.Params.List) == 2 {
|
||||
if strings.Contains(string(paramStr), "http ResponseWriter") && len(fn.Type.Params.List) == 2 && (fn.Recv == nil || len(fn.Recv.List) == 0) {
|
||||
analyzed := analyze{
|
||||
PackageName: parsed.Name.Name,
|
||||
FuncName: fn.Name.Name,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/hydrogen",
|
||||
"version": "0.0.14",
|
||||
"version": "0.0.15",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"homepage": "https://vercel.com/docs",
|
||||
@@ -21,7 +21,7 @@
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/node": "*",
|
||||
"@vercel/build-utils": "5.3.1",
|
||||
"@vercel/build-utils": "5.3.2",
|
||||
"typescript": "4.6.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/next",
|
||||
"version": "3.1.18",
|
||||
"version": "3.1.21",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
||||
@@ -44,7 +44,7 @@
|
||||
"@types/semver": "6.0.0",
|
||||
"@types/text-table": "0.2.1",
|
||||
"@types/webpack-sources": "3.2.0",
|
||||
"@vercel/build-utils": "5.3.1",
|
||||
"@vercel/build-utils": "5.3.2",
|
||||
"@vercel/nft": "0.21.0",
|
||||
"@vercel/routing-utils": "2.0.2",
|
||||
"async-sema": "3.0.1",
|
||||
|
||||
@@ -36,7 +36,14 @@ import { Sema } from 'async-sema';
|
||||
// escape-string-regexp version must match Next.js version
|
||||
import escapeStringRegexp from 'escape-string-regexp';
|
||||
import findUp from 'find-up';
|
||||
import { lstat, pathExists, readFile, remove, writeFile } from 'fs-extra';
|
||||
import {
|
||||
lstat,
|
||||
pathExists,
|
||||
readFile,
|
||||
readJSON,
|
||||
remove,
|
||||
writeFile,
|
||||
} from 'fs-extra';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import resolveFrom from 'resolve-from';
|
||||
@@ -477,6 +484,14 @@ export const build: BuildV2 = async ({
|
||||
: '/404'
|
||||
]?.initialRevalidate === 'number';
|
||||
|
||||
const hasIsr500Page =
|
||||
typeof prerenderManifest.staticRoutes[
|
||||
routesManifest?.i18n
|
||||
? // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
|
||||
path.join('/', routesManifest?.i18n!.defaultLocale!, '/500')
|
||||
: '/500'
|
||||
]?.initialRevalidate === 'number';
|
||||
|
||||
const wildcardConfig: BuildResult['wildcard'] =
|
||||
routesManifest?.i18n?.domains && routesManifest.i18n.domains.length > 0
|
||||
? routesManifest.i18n.domains.map(item => {
|
||||
@@ -996,7 +1011,7 @@ export const build: BuildV2 = async ({
|
||||
buildId,
|
||||
'pages'
|
||||
);
|
||||
const pages = await getServerlessPages({
|
||||
const { pages } = await getServerlessPages({
|
||||
pagesDir,
|
||||
entryPath,
|
||||
outputDirectory,
|
||||
@@ -1073,10 +1088,15 @@ export const build: BuildV2 = async ({
|
||||
'pages'
|
||||
);
|
||||
|
||||
const pages = await getServerlessPages({
|
||||
const appPathRoutesManifest = await readJSON(
|
||||
path.join(entryPath, outputDirectory, 'app-path-routes-manifest.json')
|
||||
).catch(() => null);
|
||||
|
||||
const { pages, appPaths: lambdaAppPaths } = await getServerlessPages({
|
||||
pagesDir,
|
||||
entryPath,
|
||||
outputDirectory,
|
||||
appPathRoutesManifest,
|
||||
});
|
||||
const isApiPage = (page: string) =>
|
||||
page
|
||||
@@ -1265,10 +1285,12 @@ export const build: BuildV2 = async ({
|
||||
config,
|
||||
nextVersion,
|
||||
trailingSlash,
|
||||
appPathRoutesManifest,
|
||||
dynamicPages,
|
||||
canUsePreviewMode,
|
||||
staticPages,
|
||||
lambdaPages: pages,
|
||||
lambdaAppPaths,
|
||||
omittedPrerenderRoutes,
|
||||
isCorrectLocaleAPIRoutes,
|
||||
pagesDir,
|
||||
@@ -1296,6 +1318,7 @@ export const build: BuildV2 = async ({
|
||||
requiredServerFilesManifest,
|
||||
privateOutputs,
|
||||
hasIsr404Page,
|
||||
hasIsr500Page,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2597,18 +2620,39 @@ async function getServerlessPages(params: {
|
||||
pagesDir: string;
|
||||
entryPath: string;
|
||||
outputDirectory: string;
|
||||
appPathRoutesManifest?: Record<string, string>;
|
||||
}) {
|
||||
const [pages, middlewareManifest] = await Promise.all([
|
||||
const [pages, appPaths, middlewareManifest] = await Promise.all([
|
||||
glob('**/!(_middleware).js', params.pagesDir),
|
||||
params.appPathRoutesManifest
|
||||
? glob('**/page.js', path.join(params.pagesDir, '../app'))
|
||||
: Promise.resolve({}),
|
||||
getMiddlewareManifest(params.entryPath, params.outputDirectory),
|
||||
]);
|
||||
|
||||
const normalizedAppPaths: typeof appPaths = {};
|
||||
|
||||
if (params.appPathRoutesManifest) {
|
||||
for (const [entry, normalizedEntry] of Object.entries(
|
||||
params.appPathRoutesManifest
|
||||
)) {
|
||||
const normalizedPath = `${path.join('.', normalizedEntry)}.js`;
|
||||
const globPath = `${path.join('.', entry)}.js`;
|
||||
|
||||
if (appPaths[globPath]) {
|
||||
normalizedAppPaths[normalizedPath] = appPaths[globPath];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Edge Functions do not consider as Serverless Functions
|
||||
for (const edgeFunctionFile of Object.keys(
|
||||
middlewareManifest?.functions ?? {}
|
||||
)) {
|
||||
delete pages[edgeFunctionFile.slice(1) + '.js'];
|
||||
const edgePath = edgeFunctionFile.slice(1) + '.js';
|
||||
delete normalizedAppPaths[edgePath];
|
||||
delete pages[edgePath];
|
||||
}
|
||||
|
||||
return pages;
|
||||
return { pages, appPaths: normalizedAppPaths };
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
getNextServerPath,
|
||||
getMiddlewareBundle,
|
||||
getFilesMapFromReasons,
|
||||
UnwrapPromise,
|
||||
} from './utils';
|
||||
import {
|
||||
nodeFileTrace,
|
||||
@@ -80,21 +81,25 @@ export async function serverBuild({
|
||||
headers,
|
||||
dataRoutes,
|
||||
hasIsr404Page,
|
||||
hasIsr500Page,
|
||||
imagesManifest,
|
||||
wildcardConfig,
|
||||
routesManifest,
|
||||
staticPages,
|
||||
lambdaPages,
|
||||
nextVersion,
|
||||
lambdaAppPaths,
|
||||
canUsePreviewMode,
|
||||
trailingSlash,
|
||||
prerenderManifest,
|
||||
appPathRoutesManifest,
|
||||
omittedPrerenderRoutes,
|
||||
trailingSlashRedirects,
|
||||
isCorrectLocaleAPIRoutes,
|
||||
lambdaCompressedByteLimit,
|
||||
requiredServerFilesManifest,
|
||||
}: {
|
||||
appPathRoutesManifest?: Record<string, string>;
|
||||
dynamicPages: string[];
|
||||
trailingSlash: boolean;
|
||||
config: Config;
|
||||
@@ -103,6 +108,7 @@ export async function serverBuild({
|
||||
canUsePreviewMode: boolean;
|
||||
omittedPrerenderRoutes: Set<string>;
|
||||
staticPages: { [key: string]: FileFsRef };
|
||||
lambdaAppPaths: { [key: string]: FileFsRef };
|
||||
lambdaPages: { [key: string]: FileFsRef };
|
||||
privateOutputs: { files: Files; routes: Route[] };
|
||||
entryPath: string;
|
||||
@@ -122,6 +128,7 @@ export async function serverBuild({
|
||||
dataRoutes: Route[];
|
||||
nextVersion: string;
|
||||
hasIsr404Page: boolean;
|
||||
hasIsr500Page: boolean;
|
||||
trailingSlashRedirects: Route[];
|
||||
routesManifest: RoutesManifest;
|
||||
lambdaCompressedByteLimit: number;
|
||||
@@ -130,6 +137,8 @@ export async function serverBuild({
|
||||
prerenderManifest: NextPrerenderedRoutes;
|
||||
requiredServerFilesManifest: NextRequiredServerFilesManifest;
|
||||
}): Promise<BuildResult> {
|
||||
lambdaPages = Object.assign({}, lambdaPages, lambdaAppPaths);
|
||||
|
||||
const lambdas: { [key: string]: Lambda } = {};
|
||||
const prerenders: { [key: string]: Prerender } = {};
|
||||
const lambdaPageKeys = Object.keys(lambdaPages);
|
||||
@@ -139,6 +148,14 @@ export async function serverBuild({
|
||||
nextVersion,
|
||||
EMPTY_ALLOW_QUERY_FOR_PRERENDERED_VERSION
|
||||
);
|
||||
let appBuildTraces: UnwrapPromise<ReturnType<typeof glob>> = {};
|
||||
let appDir: string | null = null;
|
||||
|
||||
if (appPathRoutesManifest) {
|
||||
appDir = path.join(pagesDir, '../app');
|
||||
appBuildTraces = await glob('**/*.js.nft.json', appDir);
|
||||
}
|
||||
|
||||
const isCorrectNotFoundRoutes = semver.gte(
|
||||
nextVersion,
|
||||
CORRECT_NOT_FOUND_ROUTES_VERSION
|
||||
@@ -531,9 +548,26 @@ export async function serverBuild({
|
||||
const mergedPageKeys = [...nonApiPages, ...apiPages, ...internalPages];
|
||||
const traceCache = {};
|
||||
|
||||
const getOriginalPagePath = (page: string) => {
|
||||
let originalPagePath = page;
|
||||
|
||||
if (appDir && lambdaAppPaths[page]) {
|
||||
const { fsPath } = lambdaAppPaths[page];
|
||||
originalPagePath = path.relative(appDir, fsPath);
|
||||
}
|
||||
return originalPagePath;
|
||||
};
|
||||
|
||||
const getBuildTraceFile = (page: string) => {
|
||||
return (
|
||||
pageBuildTraces[page + '.nft.json'] ||
|
||||
appBuildTraces[page + '.nft.json']
|
||||
);
|
||||
};
|
||||
|
||||
const pathsToTrace: string[] = mergedPageKeys
|
||||
.map(page => {
|
||||
if (!pageBuildTraces[page + '.nft.json']) {
|
||||
if (!getBuildTraceFile(page)) {
|
||||
return lambdaPages[page].fsPath;
|
||||
}
|
||||
})
|
||||
@@ -557,7 +591,8 @@ export async function serverBuild({
|
||||
|
||||
for (const page of mergedPageKeys) {
|
||||
const tracedFiles: { [key: string]: FileFsRef } = {};
|
||||
const pageBuildTrace = pageBuildTraces[page + '.nft.json'];
|
||||
const originalPagePath = getOriginalPagePath(page);
|
||||
const pageBuildTrace = getBuildTraceFile(originalPagePath);
|
||||
let fileList: string[];
|
||||
let reasons: NodeFileTraceReasons;
|
||||
|
||||
@@ -565,8 +600,38 @@ export async function serverBuild({
|
||||
const { files } = JSON.parse(
|
||||
await fs.readFile(pageBuildTrace.fsPath, 'utf8')
|
||||
);
|
||||
|
||||
// TODO: this will be moved to a separate worker in the future
|
||||
// although currently this is needed in the lambda
|
||||
const isAppPath = appDir && lambdaAppPaths[page];
|
||||
const serverComponentFile = isAppPath
|
||||
? pageBuildTrace.fsPath.replace(
|
||||
/\.js\.nft\.json$/,
|
||||
'.__sc_client__.js'
|
||||
)
|
||||
: null;
|
||||
|
||||
if (serverComponentFile && (await fs.pathExists(serverComponentFile))) {
|
||||
files.push(
|
||||
path.relative(
|
||||
path.dirname(pageBuildTrace.fsPath),
|
||||
serverComponentFile
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
const scTrace = JSON.parse(
|
||||
await fs.readFile(`${serverComponentFile}.nft.json`, 'utf8')
|
||||
);
|
||||
scTrace.files.forEach((file: string) => files.push(file));
|
||||
} catch (err) {
|
||||
/* non-fatal for now */
|
||||
}
|
||||
}
|
||||
|
||||
fileList = [];
|
||||
const pageDir = path.dirname(path.join(pagesDir, page));
|
||||
const curPagesDir = isAppPath && appDir ? appDir : pagesDir;
|
||||
const pageDir = path.dirname(path.join(curPagesDir, originalPagePath));
|
||||
const normalizedBaseDir = `${baseDir}${
|
||||
baseDir.endsWith('/') ? '' : '/'
|
||||
}`;
|
||||
@@ -1375,7 +1440,10 @@ export async function serverBuild({
|
||||
route.src.replace(/(^\^|\$$)/g, '') + '.json$'
|
||||
);
|
||||
|
||||
const { pathname } = new URL(route.dest || '/', 'http://n');
|
||||
const { pathname, search } = new URL(
|
||||
route.dest || '/',
|
||||
'http://n'
|
||||
);
|
||||
let isPrerender = !!prerenders[path.join('./', pathname)];
|
||||
|
||||
if (routesManifest.i18n) {
|
||||
@@ -1392,7 +1460,9 @@ export async function serverBuild({
|
||||
}
|
||||
|
||||
if (isPrerender) {
|
||||
route.dest = `/_next/data/${buildId}${pathname}.json`;
|
||||
route.dest = `/_next/data/${buildId}${pathname}.json${
|
||||
search || ''
|
||||
}`;
|
||||
}
|
||||
return route;
|
||||
})
|
||||
@@ -1529,10 +1599,8 @@ export async function serverBuild({
|
||||
},
|
||||
]),
|
||||
|
||||
// static 500 page if present
|
||||
...(!hasStatic500
|
||||
? []
|
||||
: i18n
|
||||
// custom 500 page if present
|
||||
...(i18n && (hasStatic500 || hasIsr500Page || lambdaPages['500.js'])
|
||||
? [
|
||||
{
|
||||
src: `${path.join(
|
||||
@@ -1544,6 +1612,7 @@ export async function serverBuild({
|
||||
.join('|')})(/.*|$)`,
|
||||
dest: path.join('/', entryDirectory, '/$nextLocale/500'),
|
||||
status: 500,
|
||||
caseSensitive: true,
|
||||
},
|
||||
{
|
||||
src: path.join('/', entryDirectory, '.*'),
|
||||
@@ -1558,7 +1627,15 @@ export async function serverBuild({
|
||||
: [
|
||||
{
|
||||
src: path.join('/', entryDirectory, '.*'),
|
||||
dest: path.join('/', entryDirectory, '/500'),
|
||||
dest: path.join(
|
||||
'/',
|
||||
entryDirectory,
|
||||
hasStatic500 ||
|
||||
hasIsr500Page ||
|
||||
lambdas[path.join(entryDirectory, '500')]
|
||||
? '/500'
|
||||
: '/_error'
|
||||
),
|
||||
status: 500,
|
||||
},
|
||||
]),
|
||||
|
||||
@@ -2020,7 +2020,7 @@ export const onPrerenderRoute =
|
||||
}
|
||||
};
|
||||
|
||||
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
|
||||
export type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
|
||||
|
||||
export async function getStaticFiles(
|
||||
entryPath: string,
|
||||
@@ -2326,8 +2326,16 @@ export async function getMiddlewareBundle({
|
||||
for (const worker of workerConfigs.values()) {
|
||||
const edgeFile = worker.edgeFunction.name;
|
||||
const shortPath = edgeFile.replace(/^pages\//, '');
|
||||
|
||||
worker.edgeFunction.name = shortPath;
|
||||
source.edgeFunctions[shortPath] = worker.edgeFunction;
|
||||
|
||||
// we don't add the route for edge functions as these
|
||||
// are already added in the routes-manifest under dynamicRoutes
|
||||
if (worker.type === 'function') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const route: Route = {
|
||||
continue: true,
|
||||
src: worker.routeSrc,
|
||||
@@ -2340,13 +2348,9 @@ export async function getMiddlewareBundle({
|
||||
],
|
||||
};
|
||||
|
||||
if (worker.type === 'function') {
|
||||
route.dest = shortPath;
|
||||
} else {
|
||||
route.middlewarePath = shortPath;
|
||||
if (isCorrectMiddlewareOrder) {
|
||||
route.override = true;
|
||||
}
|
||||
route.middlewarePath = shortPath;
|
||||
if (isCorrectMiddlewareOrder) {
|
||||
route.override = true;
|
||||
}
|
||||
|
||||
if (routesManifest.version > 3 && isDynamicRoute(worker.page)) {
|
||||
|
||||
7
packages/next/test/fixtures/00-app-dir/app/(newroot)/dashboard/another/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/(newroot)/dashboard/another/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function AnotherPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from newroot/dashboard/another</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
18
packages/next/test/fixtures/00-app-dir/app/(newroot)/layout.server.js
vendored
Normal file
18
packages/next/test/fixtures/00-app-dir/app/(newroot)/layout.server.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
export async function getServerSideProps() {
|
||||
return {
|
||||
props: {
|
||||
world: 'world',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function Root({ children, world }) {
|
||||
return (
|
||||
<html className="this-is-another-document-html">
|
||||
<head>
|
||||
<title>{`hello ${world}`}</title>
|
||||
</head>
|
||||
<body className="this-is-another-document-body">{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/(rootonly)/dashboard/changelog/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/(rootonly)/dashboard/changelog/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function ChangelogPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard/changelog</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/(rootonly)/dashboard/hello/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/(rootonly)/dashboard/hello/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function HelloPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard/rootonly/hello</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
18
packages/next/test/fixtures/00-app-dir/app/client-component-route/page.client.js
vendored
Normal file
18
packages/next/test/fixtures/00-app-dir/app/client-component-route/page.client.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
import style from './style.module.css';
|
||||
import './style.css';
|
||||
|
||||
export default function ClientComponentRoute() {
|
||||
const [count, setCount] = useState(0);
|
||||
useEffect(() => {
|
||||
setCount(1);
|
||||
}, [count]);
|
||||
return (
|
||||
<>
|
||||
<p className={style.red}>
|
||||
hello from app/client-component-route. <b>count: {count}</b>
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir/app/client-component-route/style.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir/app/client-component-route/style.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
b {
|
||||
color: blue;
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir/app/client-component-route/style.module.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir/app/client-component-route/style.module.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.red {
|
||||
color: red;
|
||||
}
|
||||
18
packages/next/test/fixtures/00-app-dir/app/client-nested/layout.client.js
vendored
Normal file
18
packages/next/test/fixtures/00-app-dir/app/client-nested/layout.client.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
import styles from './style.module.css';
|
||||
import './style.css';
|
||||
|
||||
export default function ClientNestedLayout({ children }) {
|
||||
const [count, setCount] = useState(0);
|
||||
useEffect(() => {
|
||||
setCount(1);
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<h1 className={styles.red}>Client Nested. Count: {count}</h1>
|
||||
<button onClick={() => setCount(count + 1)}>{count}</button>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/client-nested/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/client-nested/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function ClientPage() {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/client-nested</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir/app/client-nested/style.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir/app/client-nested/style.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
button {
|
||||
color: red;
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir/app/client-nested/style.module.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir/app/client-nested/style.module.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.red {
|
||||
color: red;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export default function DeploymentsBreakdownPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard/(custom)/deployments/breakdown</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
8
packages/next/test/fixtures/00-app-dir/app/dashboard/(custom)/layout.server.js
vendored
Normal file
8
packages/next/test/fixtures/00-app-dir/app/dashboard/(custom)/layout.server.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
export default function CustomDashboardRootLayout({ children }) {
|
||||
return (
|
||||
<>
|
||||
<h2>Custom dashboard</h2>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
15
packages/next/test/fixtures/00-app-dir/app/dashboard/deployments/[id]/page.server.js
vendored
Normal file
15
packages/next/test/fixtures/00-app-dir/app/dashboard/deployments/[id]/page.server.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
export async function getServerSideProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
id: params.id,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function DeploymentsPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard/deployments/[id]. ID is: {props.id}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/dashboard/deployments/info/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/dashboard/deployments/info/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function DeploymentsInfoPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard/deployments/info</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
16
packages/next/test/fixtures/00-app-dir/app/dashboard/deployments/layout.server.js
vendored
Normal file
16
packages/next/test/fixtures/00-app-dir/app/dashboard/deployments/layout.server.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
export function getServerSideProps() {
|
||||
return {
|
||||
props: {
|
||||
message: 'hello',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function DeploymentsLayout({ message, children }) {
|
||||
return (
|
||||
<>
|
||||
<h2>Deployments {message}</h2>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/dashboard/index/lazy.client.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/dashboard/index/lazy.client.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function LazyComponent() {
|
||||
return (
|
||||
<>
|
||||
<p>hello from lazy</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
10
packages/next/test/fixtures/00-app-dir/app/dashboard/index/page.server.js
vendored
Normal file
10
packages/next/test/fixtures/00-app-dir/app/dashboard/index/page.server.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import { ClientComponent } from './test.client.js';
|
||||
|
||||
export default function DashboardIndexPage() {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard/index</p>
|
||||
<ClientComponent />
|
||||
</>
|
||||
);
|
||||
}
|
||||
13
packages/next/test/fixtures/00-app-dir/app/dashboard/index/test.client.js
vendored
Normal file
13
packages/next/test/fixtures/00-app-dir/app/dashboard/index/test.client.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import { useState, lazy } from 'react';
|
||||
|
||||
const Lazy = lazy(() => import('./lazy.client.js'));
|
||||
|
||||
export function ClientComponent() {
|
||||
let [state] = useState('client');
|
||||
return (
|
||||
<>
|
||||
<Lazy />
|
||||
<p className="hi">hello from modern the {state}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/dashboard/integrations/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/dashboard/integrations/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function IntegrationsPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard/integrations</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
8
packages/next/test/fixtures/00-app-dir/app/dashboard/layout.server.js
vendored
Normal file
8
packages/next/test/fixtures/00-app-dir/app/dashboard/layout.server.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
export default function DashboardLayout(props) {
|
||||
return (
|
||||
<>
|
||||
<h1>Dashboard</h1>
|
||||
{props.children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/dashboard/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/dashboard/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function DashboardPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
19
packages/next/test/fixtures/00-app-dir/app/dynamic/[category]/[id]/layout.server.js
vendored
Normal file
19
packages/next/test/fixtures/00-app-dir/app/dynamic/[category]/[id]/layout.server.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
export async function getServerSideProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
params,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function IdLayout({ children, params }) {
|
||||
return (
|
||||
<>
|
||||
<h3>
|
||||
Id Layout. Params:{' '}
|
||||
<span id="id-layout-params">{JSON.stringify(params)}</span>
|
||||
</h3>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
19
packages/next/test/fixtures/00-app-dir/app/dynamic/[category]/[id]/page.server.js
vendored
Normal file
19
packages/next/test/fixtures/00-app-dir/app/dynamic/[category]/[id]/page.server.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
export async function getServerSideProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
params,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function IdPage({ children, params }) {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Id Page. Params:{' '}
|
||||
<span id="id-page-params">{JSON.stringify(params)}</span>
|
||||
</p>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
19
packages/next/test/fixtures/00-app-dir/app/dynamic/[category]/layout.server.js
vendored
Normal file
19
packages/next/test/fixtures/00-app-dir/app/dynamic/[category]/layout.server.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
export async function getServerSideProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
params,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function CategoryLayout({ children, params }) {
|
||||
return (
|
||||
<>
|
||||
<h2>
|
||||
Category Layout. Params:{' '}
|
||||
<span id="category-layout-params">{JSON.stringify(params)}</span>{' '}
|
||||
</h2>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
19
packages/next/test/fixtures/00-app-dir/app/dynamic/layout.server.js
vendored
Normal file
19
packages/next/test/fixtures/00-app-dir/app/dynamic/layout.server.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
export async function getServerSideProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
params,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function DynamicLayout({ children, params }) {
|
||||
return (
|
||||
<>
|
||||
<h1>
|
||||
Dynamic Layout. Params:{' '}
|
||||
<span id="dynamic-layout-params">{JSON.stringify(params)}</span>
|
||||
</h1>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
18
packages/next/test/fixtures/00-app-dir/app/layout.server.js
vendored
Normal file
18
packages/next/test/fixtures/00-app-dir/app/layout.server.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
export async function getServerSideProps() {
|
||||
return {
|
||||
props: {
|
||||
world: 'world',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function Root({ children, custom, world }) {
|
||||
return (
|
||||
<html className="this-is-the-document-html">
|
||||
<head>
|
||||
<title>{`hello ${world}`}</title>
|
||||
</head>
|
||||
<body className="this-is-the-document-body">{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
15
packages/next/test/fixtures/00-app-dir/app/partial-match-[id]/page.server.js
vendored
Normal file
15
packages/next/test/fixtures/00-app-dir/app/partial-match-[id]/page.server.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
export async function getServerSideProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
id: params.id,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function DeploymentsPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/partial-match-[id]. ID is: {props.id}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/shared-component-route/page.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/shared-component-route/page.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function SharedComponentRoute() {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/shared-component-route</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user