diff --git a/packages/redwood/src/index.ts b/packages/redwood/src/index.ts index 6c7cd2a5b..37c623d8d 100644 --- a/packages/redwood/src/index.ts +++ b/packages/redwood/src/index.ts @@ -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, { - ...spawnOpts, - cwd: workPath, - }); + 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; diff --git a/packages/redwood/test/fixtures/01-create-redwood-app/api/src/functions/permission.js b/packages/redwood/test/fixtures/01-create-redwood-app/api/src/functions/permission.js new file mode 100755 index 000000000..ad49cccb8 --- /dev/null +++ b/packages/redwood/test/fixtures/01-create-redwood-app/api/src/functions/permission.js @@ -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 } diff --git a/packages/redwood/test/fixtures/01-create-redwood-app/package.json b/packages/redwood/test/fixtures/01-create-redwood-app/package.json index bbbb6ea08..60f750055 100644 --- a/packages/redwood/test/fixtures/01-create-redwood-app/package.json +++ b/packages/redwood/test/fixtures/01-create-redwood-app/package.json @@ -6,6 +6,9 @@ "web" ] }, + "scripts": { + "build": "rw db up --no-db-client --auto-approve && rw build" + }, "devDependencies": { "@redwoodjs/core": "0.15.0" }, diff --git a/packages/redwood/test/fixtures/01-create-redwood-app/vercel.json b/packages/redwood/test/fixtures/01-create-redwood-app/vercel.json index 5243c6970..381302d13 100644 --- a/packages/redwood/test/fixtures/01-create-redwood-app/vercel.json +++ b/packages/redwood/test/fixtures/01-create-redwood-app/vercel.json @@ -15,6 +15,10 @@ "headers": { "Accept": "application/json" }, "body": { "query": "{ redwood { version } }" }, "mustContain": "0.15.0" + }, + { + "path": "/api/permission", + "mustContain": "File is executable: true" } ] } diff --git a/test/lib/deployment/now-deploy.js b/test/lib/deployment/now-deploy.js index e09b0c7a6..11f9848e2 100644 --- a/test/lib/deployment/now-deploy.js +++ b/test/lib/deployment/now-deploy.js @@ -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, }; diff --git a/test/lib/deployment/test-deployment.js b/test/lib/deployment/test-deployment.js index 42f29ec4c..2dfb7f22f 100644 --- a/test/lib/deployment/test-deployment.js +++ b/test/lib/deployment/test-deployment.js @@ -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; }, {});