Skip to content

Commit

Permalink
Replace netlify's zip-it-and-ship-it for serverless deploy (redwoodjs…
Browse files Browse the repository at this point in the history
  • Loading branch information
Irev-Dev authored and dac09 committed Jan 6, 2022
1 parent ab92e9b commit 843f6dc
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 57 deletions.
39 changes: 19 additions & 20 deletions packages/cli/src/commands/deploy/aws-providers/serverless.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
export const preRequisites = [
import ntfPack from '../packing/nft'

export const preRequisites = () => [
{
title: 'Checking if Serverless framework is installed...',
command: ['serverless', ['--version']],
errorMessage: [
'Looks like Serverless is not installed.',
'Please follow the steps at https://www.serverless.com/framework/docs/providers/aws/guide/installation/ to install Serverless.',
],
},
{
title: 'Checking if @netlify/zip-it-and-ship-it is installed...',
command: ['yarn', ['zip-it-and-ship-it', '--version']],
errorMessage: [
'Looks like @netlify/zip-it-and-ship-it is not installed.',
'Either run `yarn rw setup aws-serverless` or add it separately as a dev dependency in the api workspace.',
'Please follow the steps at https://www.serverless.com/framework/docs/getting-started to install Serverless.',
],
},
]

export const buildCommands = [
{ title: 'Building API...', command: ['yarn', ['rw', 'build', 'api']] },
export const buildCommands = () => [
{
title: 'Packaging API...',
command: [
'yarn',
['zip-it-and-ship-it', 'api/dist/functions/', 'api/dist/zipball'],
],
title: 'Building API...',
command: ['yarn', ['rw', 'build', 'api']],
},
{
title: 'Packing Functions...',
task: ntfPack,
},
]

export const deployCommand = {
title: 'Deploying...',
command: ['serverless', ['deploy']],
export const deployCommands = (yargs) => {
const stage = yargs.stage ? ['--stage', yargs.stage] : []
return [
{
title: 'Deploying...',
command: ['serverless', ['deploy', ...stage]],
},
]
}
82 changes: 46 additions & 36 deletions packages/cli/src/commands/deploy/aws.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import path from 'path'

import execa from 'execa'
import Listr from 'listr'
import VerboseRenderer from 'listr-verbose-renderer'
import terminalLink from 'terminal-link'

import { getPaths } from '../../lib'
Expand All @@ -29,6 +30,17 @@ export const builder = (yargs) => {
default: 'api',
type: 'array',
})
.option('verbose', {
describe: 'verbosity of logs',
default: true,
type: 'boolean',
})
.option('stage', {
describe:
'serverless stage pass through param: https://www.serverless.com/blog/stages-and-environments',
default: 'dev',
type: 'string',
})
.epilogue(
`Also see the ${terminalLink(
'Redwood CLI Reference',
Expand All @@ -37,63 +49,61 @@ export const builder = (yargs) => {
)
}

export const handler = async ({ provider }) => {
export const handler = async (yargs) => {
const { provider, verbose } = yargs
const BASE_DIR = getPaths().base
const providerData = await import(`./aws-providers/${provider}`)

const mapCommandsToListr = ({ title, command, task, errorMessage }) => {
return {
title: title,
task: task
? task
: async () => {
try {
const executingCommand = execa(...command, {
cwd: BASE_DIR,
})
executingCommand.stdout.pipe(process.stdout)
await executingCommand
} catch (error) {
if (errorMessage) {
error.message = error.message + '\n' + errorMessage.join(' ')
}
throw error
}
},
}
}

const tasks = new Listr(
[
providerData.preRequisites &&
providerData.preRequisites.length > 0 && {
title: 'Checking pre-requisites',
task: () =>
new Listr(
providerData.preRequisites.map((preReq) => {
return {
title: preReq.title,
task: async () => {
try {
await execa(...preReq.command)
} catch (error) {
error.message =
error.message + '\n' + preReq.errorMessage.join(' ')
throw error
}
},
}
})
providerData.preRequisites(yargs).map(mapCommandsToListr)
),
},
{
title: 'Building and Packaging...',
task: () =>
new Listr(
providerData.buildCommands.map((commandDetail) => {
return {
title: commandDetail.title,
task: async () => {
await execa(...commandDetail.command, {
cwd: BASE_DIR,
})
},
}
}),
{ collapse: false }
),
new Listr(providerData.buildCommands(yargs).map(mapCommandsToListr), {
collapse: false,
}),
},
{
title: 'Deploying to AWS',
task: () =>
new Listr(providerData.deployCommands(yargs).map(mapCommandsToListr)),
},
].filter(Boolean),
{ collapse: false }
{ collapse: false, renderer: verbose && VerboseRenderer }
)

try {
await tasks.run()

console.log(c.green(providerData.deployCommand.title))
const deploy = execa(...providerData.deployCommand.command, {
cwd: BASE_DIR,
})
deploy.stdout.pipe(process.stdout)
await deploy
} catch (e) {
console.log(c.error(e.message))
process.exit(1)
Expand Down
60 changes: 60 additions & 0 deletions packages/cli/src/commands/deploy/packing/nft.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import path from 'path'

import { nodeFileTrace } from '@vercel/nft'
import archiver from 'archiver'
import fse from 'fs-extra'

const ZIPBALL_DIR = './api/dist/zipball'

function zipDirectory(source, out) {
const archive = archiver('zip', { zlib: { level: 5 } })
const stream = fse.createWriteStream(out)

return new Promise((resolve, reject) => {
archive
.directory(source, false)
.on('error', (err) => reject(err))
.pipe(stream)

stream.on('close', () => resolve())
archive.finalize()
})
}

async function packageSingleFunction(functionFile) {
const { name: functionName } = path.parse(functionFile)
const { fileList: functionDependencyFileList } = await nodeFileTrace([
functionFile,
])
const copyPromises = []
for (const singleDependencyPath of functionDependencyFileList) {
copyPromises.push(
fse.copy(
'./' + singleDependencyPath,
`${ZIPBALL_DIR}/${functionName}/${singleDependencyPath}`
)
)
}
const functionEntryPromise = fse.outputFile(
`${ZIPBALL_DIR}/${functionName}/${functionName}.js`,
`module.exports = require('${functionFile}')`
)
copyPromises.push(functionEntryPromise)

await Promise.all(copyPromises)
await zipDirectory(
`${ZIPBALL_DIR}/${functionName}`,
`${ZIPBALL_DIR}/${functionName}.zip`
)
await fse.remove(`${ZIPBALL_DIR}/${functionName}`)
return
}

async function ntfPack() {
const filesToBePacked = (await fse.readdir('./api/dist/functions'))
.filter((path) => path.endsWith('.js'))
.map((path) => `./api/dist/functions/${path}`)
return Promise.all(filesToBePacked.map(packageSingleFunction))
}

export default ntfPack
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ export const preRequisites = [
]

export const apiDevPackages = [
'@netlify/zip-it-and-ship-it',
'@vercel/nft',
'archiver',
'fs-extra',
'serverless-dotenv-plugin',
]

Expand Down

0 comments on commit 843f6dc

Please sign in to comment.