Compare commits

..

8 Commits

Author SHA1 Message Date
Sean Massa
6700630feb Publish Stable
- @vercel/build-utils@5.3.2
 - vercel@28.1.4
 - @vercel/client@12.2.1
 - @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
2022-08-24 09:09:02 -05:00
Sean Massa
34cd8b4144 [cli] revert git connect inside vc link (#8450) 2022-08-24 09:07:04 -05:00
Sean Massa
ad0ed6d852 Publish Stable
- vercel@28.1.3
 - @vercel/node@2.5.9
2022-08-23 16:58:19 -05:00
Gal Schlezinger
0bad09b47a [node] fix WebAssembly bindings evaluating to undefined (#8417)
This was broken since https://github.com/vercel/vercel/pull/8242, which accidentally pushed all WebAssembly modules to be nested under `global.wasmBindings` instead of being directly under the global scope.

### Related Issues

- This was broken since https://github.com/vercel/vercel/pull/8242

### 📋 Checklist

<!--
  Please keep your PR as a Draft until the checklist is complete
-->

#### Tests

- [ ] The code changed/added as part of this PR has been covered with tests
- [ ] All tests pass locally with `yarn test-unit`

#### Code Review

- [ ] This PR has a concise title and thorough description useful to a reviewer
- [ ] Issue from task tracker has a link to this PR
2022-08-23 21:56:13 +00:00
Steven
5120689bf2 [tests] Fix update-next script (#8452)
Follow up to #8447 since exec returns a buffer, not a string.
2022-08-23 17:28:38 -04:00
Steven
5a39fd9242 [tests] Automatically update Next.js example periodically (#8447)
Automatically update Next.js example every 4 hours using `create-next-app`
2022-08-23 17:19:55 +00:00
Sean Massa
352cd00ef0 Publish Stable
- vercel@28.1.2
 - @vercel/go@2.2.1
2022-08-23 10:15:26 -05:00
Sean Massa
abfe817f86 [go] ignore bad go handlers and rename functions with more precision (#8422)
Co-authored-by: Steven <steven@ceriously.com>
2022-08-23 10:14:21 -05:00
42 changed files with 245 additions and 816 deletions

25
.github/workflows/cron-update-next.yml vendored Normal file
View 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 })

View File

@@ -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",

View File

@@ -335,7 +335,6 @@ export interface ProjectSettings {
directoryListing?: boolean;
gitForkProtection?: boolean;
commandForIgnoringBuildStep?: string | null;
skipGitConnectDuringLink?: boolean;
}
export interface BuilderV2 {

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "28.1.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.2.0",
"@vercel/hydrogen": "0.0.14",
"@vercel/next": "3.1.20",
"@vercel/node": "2.5.8",
"@vercel/python": "3.1.10",
"@vercel/redwood": "1.0.18",
"@vercel/remix": "1.0.19",
"@vercel/ruby": "1.3.27",
"@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",

View File

@@ -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(

View File

@@ -1,127 +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>,
autoConfirm: Boolean,
settings?: ProjectSettings
): Promise<number | void> {
if (!settings) {
settings = getProjectSettings(project);
}
if (Object.keys(remoteUrls).length === 1) {
return addSingleGitRemote(
client,
org,
project,
remoteUrls,
settings || project,
autoConfirm
);
} else if (Object.keys(remoteUrls).length > 1 && !project.link) {
return addMultipleGitRemotes(
client,
org,
project,
remoteUrls,
settings || project,
autoConfirm
);
}
}
async function addSingleGitRemote(
client: Client,
org: Org,
project: Project,
remoteUrls: Dictionary<string>,
settings: ProjectSettings,
autoConfirm: Boolean
) {
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);
let shouldConnectOption: string | undefined;
if (autoConfirm) {
shouldConnectOption = 'yes';
} else {
shouldConnectOption = await promptGitConnectSingleUrl(
client,
project,
remoteName,
remoteUrl,
replace
);
}
return handleOptions(
shouldConnectOption,
client,
org,
project,
settings,
repoInfo
);
}
async function addMultipleGitRemotes(
client: Client,
org: Org,
project: Project,
remoteUrls: Dictionary<string>,
settings: ProjectSettings,
autoConfirm: Boolean
) {
let remoteUrl: string | undefined;
if (autoConfirm) {
remoteUrl = remoteUrls['origin'] || Object.values(remoteUrls)[0];
} else {
client.output.log('Found multiple Git remote URLs in Git config.');
remoteUrl = await promptGitConnectMultipleUrls(client, remoteUrls);
}
return handleOptions(remoteUrl, client, org, project, settings);
}

View File

@@ -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,
});
}

View File

@@ -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;
}
}

View File

@@ -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;
@@ -130,20 +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,
autoConfirm
);
if (typeof connectGit === 'number') {
return { status: 'error', exitCode: connectGit };
}
}
await linkFolderToProject(
output,
path,
@@ -258,21 +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,
autoConfirm,
settings
);
if (typeof connectGit === 'number') {
return { status: 'error', exitCode: connectGit };
}
}
await updateProject(client, project.id, settings);
Object.assign(project, settings);

View File

@@ -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}`);
};

Binary file not shown.

View File

@@ -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) => {

View File

@@ -1,16 +0,0 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "secondary"]
url = https://github.com/user2/repo2.git
fetch = +refs/heads/*:refs/remotes/secondary/*
[remote "origin"]
url = https://github.com/user/repo.git
fetch = +refs/heads/*:refs/remotes/origin/*
[remote "gitlab"]
url = https://gitlab.com/user/repo.git
fetch = +refs/heads/*:refs/remotes/gitlab/*

View File

@@ -1,2 +0,0 @@
!.vercel
.vercel

View File

@@ -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/*

View File

@@ -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

View File

@@ -1,2 +0,0 @@
!.vercel
.vercel

View File

@@ -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

View File

@@ -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;

View File

@@ -1,357 +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('Whats your projects 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);
}
});
it('should respect --yes', 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');
client.setArgv('--yes');
const linkPromise = link(client);
expect(client.stderr).not.toOutput('Do you want to connect "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);
}
});
it('should respect --yes for multiple remotes when origin is not the first', async () => {
const cwd = fixture('multiple-remotes-prefer-origin');
try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser();
useProject({
...defaultProject,
name: 'multiple-remotes-prefer-origin',
id: 'multiple-remotes-prefer-origin',
});
useTeams('team_dummy');
client.setArgv('--yes');
const linkPromise = link(client);
expect(client.stderr).not.toOutput('Found multiple Git remote URLs');
await expect(client.stderr).toOutput(
'Connected GitHub repository user/repo'
);
await expect(linkPromise).resolves.toEqual(0);
} finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
}
});
});
});

View File

@@ -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
View 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"
// ]
// }

View File

@@ -351,10 +351,7 @@ export async function build({
if (isGoModExist && isGoModInRootDir) {
debug('[mod-root] Write main file to ' + downloadPath);
await writeFile(
join(downloadPath, mainGoFileName),
mainModGoContents
);
await writeFile(join(downloadPath, mainGoFileName), mainModGoContents);
undoFileActions.push({
to: undefined, // delete
from: join(downloadPath, mainGoFileName),
@@ -534,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);
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/go",
"version": "2.2.0",
"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",

View File

@@ -0,0 +1 @@
.vercel

View 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)
}

View File

@@ -0,0 +1,3 @@
module handler
go 1.13

View File

@@ -0,0 +1,8 @@
{
"probes": [
{
"path": "/api/bad-receiver",
"mustContain": "some/path"
}
]
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -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,

View File

@@ -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"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/next",
"version": "3.1.20",
"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",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/node",
"version": "2.5.8",
"version": "2.5.10",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
@@ -31,7 +31,7 @@
"dependencies": {
"@edge-runtime/vm": "1.1.0-beta.23",
"@types/node": "*",
"@vercel/build-utils": "5.3.1",
"@vercel/build-utils": "5.3.2",
"@vercel/node-bridge": "3.0.0",
"@vercel/static-config": "2.0.3",
"edge-runtime": "1.1.0-beta.23",

View File

@@ -253,7 +253,9 @@ async function createEdgeRuntime(params?: {
process: {
env: process.env,
},
wasmBindings,
// These are the global bindings for WebAssembly module
...wasmBindings,
});
return context;

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/python",
"version": "3.1.10",
"version": "3.1.11",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
@@ -22,7 +22,7 @@
"devDependencies": {
"@types/execa": "^0.9.0",
"@types/jest": "27.4.1",
"@vercel/build-utils": "5.3.1",
"@vercel/build-utils": "5.3.2",
"@vercel/ncc": "0.24.0",
"execa": "^1.0.0",
"typescript": "4.3.4"

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/redwood",
"version": "1.0.18",
"version": "1.0.19",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs",
@@ -27,6 +27,6 @@
"@types/aws-lambda": "8.10.19",
"@types/node": "*",
"@types/semver": "6.0.0",
"@vercel/build-utils": "5.3.1"
"@vercel/build-utils": "5.3.2"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/remix",
"version": "1.0.19",
"version": "1.0.20",
"license": "MIT",
"main": "./dist/index.js",
"homepage": "https://vercel.com/docs",
@@ -25,7 +25,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"
}
}

View File

@@ -1,7 +1,7 @@
{
"name": "@vercel/ruby",
"author": "Nathan Cahill <nathan@nathancahill.com>",
"version": "1.3.27",
"version": "1.3.28",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",
@@ -22,7 +22,7 @@
"devDependencies": {
"@types/fs-extra": "8.0.0",
"@types/semver": "6.0.0",
"@vercel/build-utils": "5.3.1",
"@vercel/build-utils": "5.3.2",
"@vercel/ncc": "0.24.0",
"execa": "2.0.4",
"fs-extra": "^7.0.1",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/static-build",
"version": "1.0.18",
"version": "1.0.19",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/build-step",
@@ -36,7 +36,7 @@
"@types/ms": "0.7.31",
"@types/node-fetch": "2.5.4",
"@types/promise-timeout": "1.3.0",
"@vercel/build-utils": "5.3.1",
"@vercel/build-utils": "5.3.2",
"@vercel/frameworks": "1.1.3",
"@vercel/ncc": "0.24.0",
"@vercel/routing-utils": "2.0.2",

61
utils/update-next.js vendored Normal file
View File

@@ -0,0 +1,61 @@
const { execFileSync } = require('child_process');
function exec(cmd, args, opts) {
// eslint-disable-next-line no-console
console.log({ input: `${cmd} ${args.join(' ')}` });
const output = execFileSync(cmd, args, opts).toString().trim();
console.log({ output });
console.log();
return output;
}
module.exports = async ({ github, context }) => {
const oldVersion = require('../examples/nextjs/package.json').dependencies
.next;
const newVersion = exec('npm', ['view', 'next', 'dist-tags.latest']);
const branch = `next-${newVersion.replaceAll('.', '-')}`;
if (oldVersion === newVersion) {
// eslint-disable-next-line no-console
console.log(
`Next.js version ${newVersion} did not change, skipping update.`
);
return;
}
if (
exec('git', ['ls-remote', '--heads', 'origin', branch]).toString().trim()
) {
// eslint-disable-next-line no-console
console.log(`Branch ${branch} already exists, skipping update.`);
return;
}
exec('rm', ['-rf', './examples/nextjs']);
exec('npx', ['--yes', 'create-next-app@latest', './examples/nextjs']);
exec('git', ['config', '--global', 'user.email', 'team@zeit.co']);
exec('git', ['config', '--global', 'user.name', 'Vercel Team Bot']);
exec('git', ['checkout', 'main']);
exec('git', ['checkout', '-b', branch]);
exec('git', ['add', '-A']);
exec('git', ['commit', '-m', branch]);
exec('git', ['push', 'origin', branch]);
const { repo, owner } = context.repo;
const pr = await github.rest.pulls.create({
owner,
repo,
head: branch,
base: 'main',
title: `[examples] Upgrade Next.js to version ${newVersion}`,
body: `This auto-generated PR updates Next.js to version ${newVersion}`,
});
await github.rest.pulls.requestReviewers({
owner,
repo,
pull_number: pr.data.number,
reviewers: ['ijjk', 'styfle'],
});
};