mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-09 04:22:07 +00:00
[redwood] Fix file permissions and add support for build script (#4999)
Some files require execution privileges, such as Prisma, so we must preserve the file mode. We also want redwood to behave the same as other frameworks and use `yarn build` if available.
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
getNodeVersion,
|
||||
getSpawnOptions,
|
||||
runNpmInstall,
|
||||
runPackageJsonScript,
|
||||
execCommand,
|
||||
FileBlob,
|
||||
FileFsRef,
|
||||
@@ -54,10 +55,6 @@ export async function build({
|
||||
meta
|
||||
);
|
||||
|
||||
const {
|
||||
buildCommand = 'yarn rw db up --no-db-client --auto-approve && yarn rw build',
|
||||
} = config;
|
||||
|
||||
if (meta.isDev) {
|
||||
debug('Detected @vercel/redwood dev, returning routes...');
|
||||
|
||||
@@ -79,10 +76,27 @@ export async function build({
|
||||
}
|
||||
|
||||
debug('Running build command...');
|
||||
await execCommand(buildCommand, {
|
||||
const { buildCommand } = config;
|
||||
|
||||
const found =
|
||||
typeof buildCommand === 'string'
|
||||
? await execCommand(buildCommand, {
|
||||
...spawnOpts,
|
||||
cwd: workPath,
|
||||
});
|
||||
})
|
||||
: await runPackageJsonScript(
|
||||
workPath,
|
||||
['vercel-build', 'build'],
|
||||
spawnOpts
|
||||
);
|
||||
|
||||
if (!found) {
|
||||
throw new Error(
|
||||
`Missing required "${
|
||||
buildCommand || 'vercel-build'
|
||||
}" script in "${entrypoint}"`
|
||||
);
|
||||
}
|
||||
|
||||
const apiDistPath = join(workPath, 'api', 'dist', 'functions');
|
||||
const webDistPath = join(workPath, 'web', 'dist');
|
||||
@@ -119,9 +133,11 @@ export async function build({
|
||||
}),
|
||||
};
|
||||
|
||||
dependencies.forEach(fsPath => {
|
||||
lambdaFiles[relative(workPath, fsPath)] = new FileFsRef({ fsPath });
|
||||
for (const fsPath of dependencies) {
|
||||
lambdaFiles[relative(workPath, fsPath)] = await FileFsRef.fromFsPath({
|
||||
fsPath,
|
||||
});
|
||||
}
|
||||
|
||||
lambdaFiles[relative(workPath, fileFsRef.fsPath)] = fileFsRef;
|
||||
|
||||
|
||||
26
packages/redwood/test/fixtures/01-create-redwood-app/api/src/functions/permission.js
vendored
Executable file
26
packages/redwood/test/fixtures/01-create-redwood-app/api/src/functions/permission.js
vendored
Executable file
@@ -0,0 +1,26 @@
|
||||
const {
|
||||
promises: { access },
|
||||
constants: { X_OK },
|
||||
} = require('fs')
|
||||
|
||||
async function isExecutable(fsPath) {
|
||||
console.log(`Testing is file is executable: ${fsPath}`)
|
||||
try {
|
||||
await access(fsPath, X_OK)
|
||||
return true
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return e.message
|
||||
}
|
||||
}
|
||||
|
||||
async function handler() {
|
||||
const isExec = await isExecutable(module.id)
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
body: `File is executable: ${isExec}`,
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { handler }
|
||||
@@ -6,6 +6,9 @@
|
||||
"web"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rw db up --no-db-client --auto-approve && rw build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@redwoodjs/core": "0.15.0"
|
||||
},
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
"headers": { "Accept": "application/json" },
|
||||
"body": { "query": "{ redwood { version } }" },
|
||||
"mustContain": "0.15.0"
|
||||
},
|
||||
{
|
||||
"path": "/api/permission",
|
||||
"mustContain": "File is executable: true"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ const { createHash } = require('crypto');
|
||||
const path = require('path');
|
||||
const _fetch = require('node-fetch');
|
||||
const fetch = require('./fetch-retry.js');
|
||||
const fileModeSymbol = Symbol('fileMode');
|
||||
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
async function nowDeploy(bodies, randomness, uploadNowJson) {
|
||||
@@ -14,7 +15,9 @@ async function nowDeploy(bodies, randomness, uploadNowJson) {
|
||||
sha: digestOfFile(bodies[n]),
|
||||
size: bodies[n].length,
|
||||
file: n,
|
||||
mode: path.extname(n) === '.sh' ? 0o100755 : 0o100644,
|
||||
mode:
|
||||
bodies[n][fileModeSymbol] ||
|
||||
(path.extname(n) === '.sh' ? 0o100755 : 0o100644),
|
||||
}));
|
||||
|
||||
const { FORCE_BUILD_IN_REGION, NOW_DEBUG, VERCEL_DEBUG } = process.env;
|
||||
@@ -80,9 +83,7 @@ async function nowDeploy(bodies, randomness, uploadNowJson) {
|
||||
}
|
||||
|
||||
function digestOfFile(body) {
|
||||
return createHash('sha1')
|
||||
.update(body)
|
||||
.digest('hex');
|
||||
return createHash('sha1').update(body).digest('hex');
|
||||
}
|
||||
|
||||
async function filePost(body, digest) {
|
||||
@@ -247,4 +248,5 @@ module.exports = {
|
||||
fetchWithAuth,
|
||||
nowDeploy,
|
||||
fetchTokenWithRetry,
|
||||
fileModeSymbol,
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ const glob = require('util').promisify(require('glob'));
|
||||
const path = require('path');
|
||||
const { spawn } = require('child_process');
|
||||
const fetch = require('./fetch-retry.js');
|
||||
const { nowDeploy } = require('./now-deploy.js');
|
||||
const { nowDeploy, fileModeSymbol } = require('./now-deploy.js');
|
||||
|
||||
async function packAndDeploy(builderPath) {
|
||||
await spawnAsync('npm', ['--loglevel', 'warn', 'pack'], {
|
||||
@@ -37,6 +37,7 @@ async function testDeployment(
|
||||
const bodies = globResult.reduce((b, f) => {
|
||||
const r = path.relative(fixturePath, f);
|
||||
b[r] = fs.readFileSync(f);
|
||||
b[r][fileModeSymbol] = fs.statSync(f).mode;
|
||||
return b;
|
||||
}, {});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user