[cli] Normalize "src" property in vc build (#7943)

This matches the production behavior.
This commit is contained in:
Nathan Rajlich
2022-06-10 11:53:01 -07:00
committed by GitHub
parent f50bcbc0ba
commit b095031292
5 changed files with 96 additions and 6 deletions

View File

@@ -1,7 +1,7 @@
import fs from 'fs-extra';
import chalk from 'chalk';
import dotenv from 'dotenv';
import { join, relative } from 'path';
import { join, normalize, relative } from 'path';
import {
detectBuilders,
normalizePath,
@@ -15,6 +15,7 @@ import {
BuildResultV2,
BuildResultV2Typical,
BuildResultV3,
NowBuildError,
} from '@vercel/build-utils';
import minimatch from 'minimatch';
import {
@@ -475,17 +476,33 @@ export default async function main(client: Client): Promise<number> {
}
function expandBuild(files: string[], build: Builder): Builder[] {
if (!build.src) return [];
if (!build.use) {
throw new NowBuildError({
code: `invalid_build_specification`,
message: 'Field `use` is missing in build specification',
link: 'https://vercel.com/docs/configuration#project/builds',
action: 'View Documentation',
});
}
let pattern = build.src;
if (pattern[0] === '/') {
let src = normalize(build.src || '**');
if (src === '.' || src === './') {
throw new NowBuildError({
code: `invalid_build_specification`,
message: 'A build `src` path resolves to an empty string',
link: 'https://vercel.com/docs/configuration#project/builds',
action: 'View Documentation',
});
}
if (src[0] === '/') {
// Remove a leading slash so that the globbing is relative
// to `cwd` instead of the root of the filesystem.
pattern = pattern.substring(1);
src = src.substring(1);
}
const matches = files.filter(
name => name === pattern || minimatch(name, pattern, { dot: true })
name => name === src || minimatch(name, src, { dot: true })
);
return matches.map(m => {

View File

@@ -0,0 +1,7 @@
{
"orgId": ".",
"projectId": ".",
"settings": {
"framework": null
}
}

View File

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

View File

@@ -0,0 +1,15 @@
{
"version": 2,
"builds": [
{
"src": "./server.js",
"use": "@vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "/server.js"
}
]
}

View File

@@ -111,6 +111,56 @@ describe('build', () => {
}
});
it('should normalize "src" path in `vercel.json`', async () => {
const cwd = fixture('normalize-src');
const output = join(cwd, '.vercel/output');
try {
process.chdir(cwd);
const exitCode = await build(client);
expect(exitCode).toEqual(0);
// `builds.json` says that "@vercel/node" was run
const builds = await fs.readJSON(join(output, 'builds.json'));
expect(builds).toMatchObject({
target: 'preview',
builds: [
{
require: '@vercel/node',
apiVersion: 3,
use: '@vercel/node',
src: 'server.js',
},
],
});
// `config.json` includes "route" from `vercel.json`
const config = await fs.readJSON(join(output, 'config.json'));
expect(config).toMatchObject({
version: 3,
routes: [
{
src: '^/(.*)$',
dest: '/server.js',
},
],
});
// "static" directory is empty
const hasStaticFiles = await fs.pathExists(join(output, 'static'));
expect(
hasStaticFiles,
'Expected ".vercel/output/static" to not exist'
).toEqual(false);
// "functions" directory has output Function
const functions = await fs.readdir(join(output, 'functions'));
expect(functions.sort()).toEqual(['server.js.func']);
} finally {
process.chdir(originalCwd);
delete process.env.__VERCEL_BUILD_RUNNING;
}
});
it('should build with 3rd party Builder', async () => {
const cwd = fixture('third-party-builder');
const output = join(cwd, '.vercel/output');