Skip to content

Commit

Permalink
feat(cli): add --docker option to generate docker files
Browse files Browse the repository at this point in the history
  • Loading branch information
raymondfeng committed Feb 25, 2019
1 parent af5b16a commit 4cd2442
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 8 deletions.
3 changes: 3 additions & 0 deletions docs/site/Application-generator.md
Expand Up @@ -33,6 +33,9 @@ application project.

`--vscode`: Add VSCode config files to LoopBack4 application project

`--docker`: Generate Dockerfile and add npm scripts to build/run the project in
a docker container.

{% include_relative includes/CLI-std-options.md %}

### Arguments
Expand Down
19 changes: 18 additions & 1 deletion packages/cli/generators/app/index.js
Expand Up @@ -11,6 +11,10 @@ module.exports = class AppGenerator extends ProjectGenerator {
// Note: arguments and options should be defined in the constructor.
constructor(args, opts) {
super(args, opts);
this.buildOptions.push({
name: 'docker',
description: 'include Dockerfile and .dockerignore',
});
this.buildOptions.push({
name: 'repositories',
description: 'include repository imports and RepositoryMixin',
Expand All @@ -29,6 +33,11 @@ module.exports = class AppGenerator extends ProjectGenerator {
description: 'Application class name',
});

this.option('docker', {
type: Boolean,
description: 'Include Dockerfile and .dockerignore',
});

this.option('repositories', {
type: Boolean,
description: 'Include repository imports and RepositoryMixin',
Expand Down Expand Up @@ -112,7 +121,15 @@ module.exports = class AppGenerator extends ProjectGenerator {
}

scaffold() {
return super.scaffold();
const result = super.scaffold();
if (this.shouldExit()) return result;

const {docker} = this.projectInfo || {};
if (docker) return result;

this.fs.delete(this.destinationPath('Dockerfile'));
this.fs.delete(this.destinationPath('.dockerignore'));
return result;
}

install() {
Expand Down
4 changes: 4 additions & 0 deletions packages/cli/generators/app/templates/.dockerignore
@@ -0,0 +1,4 @@
node_modules
npm-debug.log
/dist

27 changes: 27 additions & 0 deletions packages/cli/generators/app/templates/Dockerfile
@@ -0,0 +1,27 @@
FROM node:10

# Set to a non-root built-in user `node`
USER node

# Create app directory (with user `node`)
RUN mkdir -p /home/node/app

WORKDIR /home/node/app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY --chown=node package*.json ./

RUN npm install

# Bundle app source code
COPY --chown=node . .

RUN npm run build

# Bind to all network interfaces so that it can be mapped to the host OS
ENV HOST=0.0.0.0 PORT=3000

EXPOSE ${PORT}
CMD [ "node", "." ]
4 changes: 2 additions & 2 deletions packages/cli/generators/app/templates/index.js.ejs
Expand Up @@ -6,8 +6,8 @@ if (require.main === module) {
// Run the application
const config = {
rest: {
port: +process.env.PORT || 3000,
host: process.env.HOST || 'localhost',
port: +(process.env.PORT || 3000),
host: process.env.HOST,
openApiSpec: {
// useful when used with OASGraph to locate your application
setServersFromRequest: true,
Expand Down
4 changes: 4 additions & 0 deletions packages/cli/generators/project/templates/package.json.ejs
Expand Up @@ -47,6 +47,10 @@
"test:dev": "lb-mocha --allow-console-logs dist/__tests__/**/*.js",
<% } -%>
<% if (project.projectType === 'application') { -%>
<% if (project.docker) { -%>
"docker:build": "docker build -t <%= project.name -%> .",
"docker:run": "docker run -p 3000:3000 -d <%= project.name -%>",
<% } -%>
"migrate": "node ./dist/migrate",
"prestart": "npm run build",
"start": "node .",
Expand Down
Expand Up @@ -46,6 +46,10 @@
"test:dev": "mocha dist/__tests__/**/*.js",
<% } -%>
<% if (project.projectType === 'application') { -%>
<% if (project.docker) { -%>
"docker:build": "docker build -t <%= project.name -%> .",
"docker:run": "docker run -p 3000:3000 -d <%= project.name -%>",
<% } -%>
"migrate": "node ./dist/migrate",
"start": "npm run build && node .",
<% } -%>
Expand Down
11 changes: 6 additions & 5 deletions packages/cli/lib/project-generator.js
Expand Up @@ -22,12 +22,11 @@ module.exports = class ProjectGenerator extends BaseGenerator {
},
{
name: 'prettier',
description:
'add new npm scripts to facilitate consistent code formatting',
description: 'install prettier to format code conforming to rules',
},
{
name: 'mocha',
description: 'install mocha to assist with running tests',
description: 'install mocha to run tests',
},
{
name: 'loopbackBuild',
Expand Down Expand Up @@ -167,21 +166,22 @@ module.exports = class ProjectGenerator extends BaseGenerator {

return this.prompt(prompts).then(props => {
Object.assign(this.projectInfo, props);
this.destinationRoot(this.projectInfo.outdir);
});
}

promptOptions() {
if (this.shouldExit()) return false;
const choices = [];
this.buildOptions.forEach(f => {
if (!this.options[f.name]) {
if (this.options[f.name] == null) {
choices.push({
name: `Enable ${f.name}: ${chalk.gray(f.description)}`,
key: f.name,
short: `Enable ${f.name}`,
checked: true,
});
} else {
this.projectInfo[f.name] = this.options[f.name];
}
});
const prompts = [
Expand Down Expand Up @@ -210,6 +210,7 @@ module.exports = class ProjectGenerator extends BaseGenerator {
scaffold() {
if (this.shouldExit()) return false;

this.destinationRoot(this.projectInfo.outdir);
// First copy common files from ../../project/templates
this.copyTemplatedFiles(
this.templatePath('../../project/templates/**/*'),
Expand Down
24 changes: 24 additions & 0 deletions packages/cli/test/integration/generators/app.integration.js
Expand Up @@ -104,12 +104,36 @@ describe('app-generator specific files', () => {
assert.fileContent('src/migrate.ts', /export async function migrate/);
});

it('generates docker files', () => {
assert.fileContent('Dockerfile', /FROM node:10/);
assert.fileContent('.dockerignore', /node_modules/);

assert.fileContent('package.json', /"docker:build": "docker build/);
assert.fileContent('package.json', /"docker:run": "docker run/);
});

it('creates npm script "migrate-db"', async () => {
const pkg = JSON.parse(await readFile('package.json'));
expect(pkg.scripts).to.have.property('migrate', 'node ./dist/migrate');
});
});

describe('app-generator with docker disabled', () => {
before(() => {
return helpers
.run(generator)
.withOptions({docker: false})
.withPrompts(props);
});
it('does not generate docker files', () => {
assert.noFile('Dockerfile');
assert.noFile('.dockerignore');

assert.noFileContent('package.json', /"docker:build": "docker build/);
assert.noFileContent('package.json', /"docker:run": "docker run/);
});
});

describe('app-generator with --applicationName', () => {
before(() => {
return helpers
Expand Down

0 comments on commit 4cd2442

Please sign in to comment.