├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_proposal.md ├── release-drafter.yml └── workflows │ ├── auto-approve.yml │ ├── npm-publish.yml │ └── release-drafter.yml ├── .gitignore ├── .travis.yml ├── .woloxci ├── Dockerfile └── config.yml ├── CHANGELOG.md ├── CODEOWNERS ├── Jenkinsfile ├── LICENSE.md ├── README.md ├── generators └── app │ ├── command.js │ ├── constants.js │ ├── dependencies │ ├── package-lock.json │ └── package.json │ ├── index.js │ ├── prompts.js │ ├── templates │ ├── .ebextensions │ │ └── cloudwatch.config │ ├── .env.example │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .github │ │ └── ISSUE_TEMPLATE │ │ │ ├── bug_report.md │ │ │ └── feature_proposal.md │ ├── .nvmrc │ ├── .sequelizerc │ ├── .travis.yml │ ├── .woloxci │ │ ├── Dockerfile │ │ └── config.yml │ ├── CHANGELOG.md │ ├── Dockerfile │ ├── Dockerrun.aws.json │ ├── Jenkinsfile │ ├── LICENSE.md │ ├── Procfile │ ├── README.md │ ├── app.ejs │ ├── app │ │ ├── controllers │ │ │ └── healthCheck.js │ │ ├── errors.js │ │ ├── logger │ │ │ └── index.js │ │ ├── middlewares │ │ │ ├── apiInfo.js │ │ │ ├── docsAuth.ejs │ │ │ └── errors.js │ │ ├── models │ │ │ └── index.js │ │ ├── routes.js │ │ └── services │ │ │ └── .keep │ ├── config │ │ ├── db.ejs │ │ ├── development.ejs │ │ ├── index.ejs │ │ ├── production.ejs │ │ └── testing.ejs │ ├── console.ejs │ ├── documentation │ │ ├── index.js │ │ ├── paths │ │ │ ├── index.js │ │ │ └── user.js │ │ └── schemas │ │ │ ├── index.js │ │ │ └── user.js │ ├── gitignore │ ├── migrations │ │ ├── index.js │ │ └── migrations │ │ │ └── .keep │ ├── package.json │ ├── pull_request_template.md │ ├── server.ejs │ └── test │ │ ├── app.spec.ejs │ │ ├── factory │ │ └── factory_by_models.ejs │ │ └── setup.js │ └── utils.js ├── img ├── demo.gif └── demo.yml ├── package-lock.json ├── package.json ├── pull_request_template.md └── test ├── __snapshots__ ├── ci.spec.js.snap ├── deploy.spec.js.snap ├── general.spec.js.snap ├── mongoose.spec.js.snap ├── optionals.spec.js.snap ├── sequelize.spec.js.snap └── testing.spec.js.snap ├── ci.spec.js ├── deploy.spec.js ├── general.spec.js ├── helpers ├── constants.js ├── mocks.js └── utils.js ├── linter.spec.js ├── mongoose.spec.js ├── optionals.spec.js ├── sequelize.spec.js ├── testing.spec.js └── training.spec.js /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('eslint-config-wolox-node'); 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug Report 3 | about: Create a report to bug fixing 4 | title: 🐛 Bug Report 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## 🐛 Bug Report 11 | 12 | A clear and concise description of what the bug is. 13 | 14 | ## Steps to Reproduce 15 | 16 | Steps to reproduce the behavior: 17 | 18 | ## Expected behavior 19 | 20 | A clear and concise description of what you expected to happen. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_proposal.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🚀 Feature Proposal 3 | about: Submit a proposal for a new feature 4 | title: 🚀 Feature Proposal 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## 🚀 Feature Proposal 11 | 12 | A clear and concise description of what the feature is. 13 | 14 | ## Motivation 15 | 16 | Please outline the motivation for the proposal. 17 | 18 | ## Example 19 | 20 | Please provide an example for how this feature would be used. 21 | 22 | ## Pitch 23 | 24 | Why does this feature should be implemented? 25 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: "v$NEXT_PATCH_VERSION 🌈" 2 | tag-template: "v$NEXT_PATCH_VERSION" 3 | categories: 4 | - title: "🚀 Features" 5 | labels: 6 | - "feature" 7 | - title: "🐛 Bug Fixes" 8 | labels: 9 | - "fix" 10 | - "bugfix" 11 | - "bug" 12 | - title: "🧰 Maintenance" 13 | labels: 14 | - "chore" 15 | change-template: "- $TITLE @$AUTHOR (#$NUMBER)" 16 | template: | 17 | # What's changed (changelog) 18 | $CHANGES 19 | 20 | ## 👍 Thanks to 21 | $CONTRIBUTORS 22 | -------------------------------------------------------------------------------- /.github/workflows/auto-approve.yml: -------------------------------------------------------------------------------- 1 | name: Auto approve 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | auto-approve: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: hmarr/auto-approve-action@v2.0.0 10 | if: github.actor == 'dependabot[bot]' || github.actor == 'dependabot-preview[bot]' 11 | with: 12 | github-token: "${{ secrets.GITHUB_TOKEN }}" 13 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: Npm Publish 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | publish-npm: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v1 12 | - uses: actions/setup-node@v1 13 | with: 14 | node-version: 12 15 | - run: npm install 16 | - run: npm test 17 | - uses: JS-DevTools/npm-publish@v1 18 | with: 19 | token: ${{ secrets.NPM_TOKEN }} 20 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | update_release_draft: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: release-drafter/release-drafter@v5 13 | env: 14 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Frontend Dist Files 2 | app/dist 3 | 4 | # Mac Files 5 | .DS_Store 6 | */DS_Store 7 | 8 | # Logs 9 | logs 10 | *.log 11 | npm-debug.log* 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | 24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 25 | .grunt 26 | 27 | # node-waf configuration 28 | .lock-wscript 29 | 30 | # Compiled binary addons (http://nodejs.org/api/addons.html) 31 | build/Release 32 | 33 | # Dependency directory 34 | node_modules 35 | 36 | # Optional npm cache directory 37 | .npm 38 | 39 | # Optional REPL history 40 | .node_repl_history 41 | 42 | # Code coverage 43 | ./coverage 44 | 45 | # dotenv 46 | .env 47 | 48 | # VS Code 49 | .vscode/ 50 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "10.13.0" 5 | 6 | sudo: true 7 | 8 | env: 9 | - CXX=g++-4.8 NODE_ENV=testing 10 | addons: 11 | apt: 12 | sources: 13 | - ubuntu-toolchain-r-test 14 | packages: 15 | - g++-4.8 16 | -------------------------------------------------------------------------------- /.woloxci/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10.13.0 2 | 3 | WORKDIR /usr/src/app 4 | 5 | ENV NODE_ENV testing 6 | 7 | ENV HOME /usr/src/app 8 | 9 | ENV BABEL_DISABLE_CACHE 1 10 | 11 | RUN mkdir -p /install 12 | 13 | ENV NODE_PATH=/install/node_modules 14 | 15 | # Install app dependencies 16 | # A wildcard is used to ensure both package.json AND package-lock.json are copied 17 | # where available (npm@5+) 18 | COPY package*.json /install/ 19 | 20 | WORKDIR /install 21 | 22 | RUN npm install 23 | RUN npm install -g gulp 24 | # If you are building your code for production 25 | # RUN npm install --only=production 26 | 27 | RUN chmod a+r /usr/src/app 28 | 29 | WORKDIR /usr/src/app 30 | 31 | # Bundle app source 32 | COPY . . 33 | -------------------------------------------------------------------------------- /.woloxci/config.yml: -------------------------------------------------------------------------------- 1 | config: 2 | dockerfile: .woloxci/Dockerfile 3 | project_name: express-js-bootstrap 4 | 5 | steps: 6 | copy_node_modules: 7 | - cp -r $NODE_PATH/ ./ 8 | lint: 9 | - npm run lint 10 | test: 11 | - npm run test 12 | 13 | environment: 14 | GIT_COMMITTER_NAME: a 15 | GIT_COMMITTER_EMAIL: b 16 | LANG: C.UTF-8 17 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | From version 2.0.0+ changelog is in https://github.com/Wolox/express-js-bootstrap/releases 6 | 7 | ## 2.0.0 8 | 9 | * Changelog added. 10 | * Add start-dev option and change behavior of npm start (#121) 11 | * Replace 'assignObject' method in configuration for an immutable alternative (#153). 12 | * Add the scrips to create the seeds in the template (#163). 13 | * Updated linters: eslint-config-wolox to 3.0.2 and eslint-config-wolox-node to 2.2.0 (#124). 14 | * Added documentation authentication. It was implemented using Token authentication (#123). 15 | * Added .env.example file (#123). 16 | * Fixed code coverage script (#184). 17 | * Update dependencies (#202) 18 | * Add cloudwatch monitor (#201) 19 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @node-bootstrap-devs -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | @Library('wolox-ci') _ 2 | 3 | node { 4 | 5 | checkout scm 6 | 7 | woloxCi('.woloxci/config.yml'); 8 | } 9 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Wolox 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ExpressJS Bootstrap [![Build Status](https://api.travis-ci.org/Wolox/express-js-bootstrap.png)](https://travis-ci.org/Wolox/express-js-bootstrap) 2 | 3 | Yeoman generator for [ExpressJS](expressjs.com) applications. 4 | 5 |

6 | 7 | ## Prerequisites 8 | 9 | - [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) 10 | - [Node with npm](https://github.com/creationix/nvm#install-script) 11 | - [Yeoman](https://yeoman.io) 12 | - Install `npm install -g yo` 13 | 14 | ## Getting Started 15 | 16 | 1. Install `npm install -g generator-w-express-js` 17 | 2. Run `yo w-express-js` 18 | 3. Pick your options 19 | 20 | At the end, a folder will be created in the current path with your project files, also a branch called `kickoff` will be generated with a commit message `Kickoff project`. 21 | 22 | ## Running Local 23 | 24 | 1. Clone this repository 25 | 2. Move to root folder and run `npm link` 26 | 3. Run `yo w-express-js` 27 | 28 | (Note: Any local changes are automatically refreshed) 29 | 30 | ## Contributing 31 | 32 | 1. Fork it 33 | 2. Create your feature branch (`git checkout -b my-new-feature`) 34 | 3. Run the tests (`npm test`) 35 | 4. Commit your changes (`git commit -am 'Add some feature'`) 36 | 5. Push to the branch (`git push origin my-new-feature`) 37 | 6. Create new Pull Request 38 | 39 | ## About 40 | 41 | This project is maintained by [Wolox](https://github.com/wolox) and it was written by [Wolox](http://www.wolox.com.ar). 42 | 43 | ![Wolox](https://raw.githubusercontent.com/Wolox/press-kit/master/logos/logo_banner.png) 44 | 45 | ## License 46 | 47 | **express-js-bootstrap** is available under the MIT [license](LICENSE.md). 48 | 49 | Copyright (c) 2020 Wolox 50 | 51 | Permission is hereby granted, free of charge, to any person obtaining a copy 52 | of this software and associated documentation files (the "Software"), to deal 53 | in the Software without restriction, including without limitation the rights 54 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 55 | copies of the Software, and to permit persons to whom the Software is 56 | furnished to do so, subject to the following conditions: 57 | 58 | The above copyright notice and this permission notice shall be included in 59 | all copies or substantial portions of the Software. 60 | 61 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 62 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 63 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 64 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 65 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 66 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 67 | THE SOFTWARE. 68 | -------------------------------------------------------------------------------- /generators/app/command.js: -------------------------------------------------------------------------------- 1 | const { spawn } = require('child_process'); 2 | const ora = require('ora'); 3 | 4 | exports.runCommand = ({ name, args, description = name, options = { verbose: false }, spawnOptions }) => 5 | new Promise((resolve, reject) => { 6 | const command = spawn(name, args, spawnOptions); 7 | const spinner = ora(options.spinner || { text: description }).start(); 8 | const result = []; 9 | 10 | const handleDataResponse = data => { 11 | const dataAsString = data.toString(); 12 | result.push(dataAsString); 13 | if (options.verbose) { 14 | spinner.info(dataAsString); 15 | } 16 | }; 17 | 18 | command.stdout.on('data', handleDataResponse); 19 | command.stderr.on('data', handleDataResponse); 20 | 21 | command.on('close', code => { 22 | if (code === 0) { 23 | spinner.succeed(options.successMessage); 24 | resolve(result); 25 | } else { 26 | spinner.fail(options.failMessage); 27 | reject(result); 28 | } 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /generators/app/constants.js: -------------------------------------------------------------------------------- 1 | const templatePackageJson = require('./dependencies/package.json'); 2 | 3 | const { engines } = require('./dependencies/package.json'); 4 | 5 | exports.NODE_DEFAULT_VERSION = engines.node; 6 | exports.NPM_DEFAULT_VERSION = engines.npm; 7 | exports.ORM_OPTIONS = ['sequelize', 'mongoose']; 8 | exports.SEQUELIZE_DEFAULT_VERSION = templatePackageJson.dependencies.sequelize; 9 | exports.SEQUELIZE_DEFAULT_DIALECT = 'postgres'; 10 | exports.SEQUELIZE_DIALECTS = ['mysql', 'sqlite', 'postgres', 'mssql']; 11 | exports.MONGOOSE_DEFAULT_VERSION = templatePackageJson.dependencies.mongoose; 12 | exports.MONGOOSE_DEFAULT_DIALECT = 'mongoDB'; 13 | exports.MONGOOSE_DIALECTS = ['mongoDB']; 14 | exports.DEPLOY_STRATEGIES = ['aws', 'heroku']; 15 | exports.OPTIONALS_FEATURES = ['coveralls', 'rollbar', 'cors', 'helmet']; 16 | exports.CI_OPTIONS = ['jenkins', 'travis']; 17 | exports.TESTING_OPTIONS = ['jest-supertest', 'mocha-chai']; 18 | 19 | exports.TRAINING_CONFIG = { 20 | projectName: 'w-training', 21 | projectDescription: 'w-training', 22 | nodeVersion: exports.NODE_DEFAULT_VERSION, 23 | npmVersion: exports.NPM_DEFAULT_VERSION, 24 | documentationRequiresAuth: false, 25 | database: true, 26 | orm: { sequelize: true }, 27 | sequelizeVersion: exports.SEQUELIZE_DEFAULT_VERSION, 28 | sequelizeDialect: exports.SEQUELIZE_DEFAULT_DIALECT, 29 | deployStrategy: { heroku: true }, 30 | optionalsFeatures: {}, 31 | ci: 'travis', 32 | testing: 'jest-supertest' 33 | }; 34 | 35 | // eslint-disable-next-line 36 | exports.URL_REGEX = /(?:git|ssh|https?|git@[-\w.]+):(\/\/)?(.*?)(\.git)?(\/?|\#[-\d\w._]+?)$/; 37 | exports.VERSION_REGEX = /[0-9]+.[0-9]+.[0-9]+/; 38 | exports.APP_NAME_REGEX = /^[\w-]+$/; 39 | 40 | exports.TUTORIALS = { 41 | GIT: 'https://git-scm.com/book/en/v2/Getting-Started-Installing-Git', 42 | NPM: 'https://github.com/creationix/nvm#install-script' 43 | }; 44 | 45 | exports.files = [ 46 | { 47 | name: 'Jenkinsfile', 48 | condition: answers => answers.ci === 'jenkins' 49 | }, 50 | { 51 | directory: '.woloxci', 52 | name: 'config.yml', 53 | condition: answers => answers.ci === 'jenkins' 54 | }, 55 | { 56 | directory: '.woloxci', 57 | name: 'Dockerfile', 58 | condition: answers => answers.ci === 'jenkins' 59 | }, 60 | { 61 | name: 'Procfile', 62 | condition: answers => answers.deployStrategy.heroku 63 | }, 64 | { 65 | name: 'Dockerfile', 66 | condition: answers => answers.docker 67 | }, 68 | { 69 | name: 'Dockerrun.aws.json', 70 | condition: answers => answers.docker && answers.deployStrategy.aws 71 | }, 72 | { 73 | name: '.travis.yml', 74 | condition: answers => answers.ci === 'travis' 75 | }, 76 | { 77 | name: '.sequelizerc', 78 | condition: answers => answers.orm && answers.orm.sequelize 79 | }, 80 | { 81 | directory: 'migrations', 82 | name: 'index.js', 83 | condition: answers => answers.orm && answers.orm.sequelize 84 | }, 85 | { 86 | directory: 'migrations/migrations', 87 | name: '.keep', 88 | condition: answers => answers.orm && answers.orm.sequelize 89 | }, 90 | { 91 | directory: 'config', 92 | name: 'db.ejs', 93 | condition: answers => answers.orm && (answers.orm.sequelize || answers.orm.mongoose) 94 | }, 95 | { 96 | directory: 'app/models', 97 | name: 'index.js', 98 | condition: answers => answers.orm && answers.orm.sequelize 99 | }, 100 | { 101 | directory: 'test/factory', 102 | name: 'factory_by_models.ejs', 103 | condition: answers => answers.orm && answers.orm.sequelize && answers.testing === 'jest-supertest' 104 | }, 105 | { 106 | directory: 'app/middlewares', 107 | name: 'docsAuth.ejs', 108 | condition: answers => answers.documentationRequiresAuth 109 | }, 110 | { 111 | directory: 'test', 112 | name: 'setup.js', 113 | condition: answers => answers.orm && answers.orm.sequelize && answers.testing === 'jest-supertest' 114 | }, 115 | { 116 | directory: 'test', 117 | name: 'app.spec.ejs', 118 | condition: answers => answers.testing === 'mocha-chai' 119 | }, 120 | { 121 | directory: '.ebextensions', 122 | name: 'cloudwatch.config', 123 | condition: answers => answers.deployStrategy.aws 124 | }, 125 | { 126 | name: 'README.md' 127 | }, 128 | { 129 | name: 'pull_request_template.md' 130 | }, 131 | { 132 | name: 'package.json' 133 | }, 134 | { 135 | name: 'LICENSE.md' 136 | }, 137 | { 138 | name: 'console.ejs' 139 | }, 140 | { 141 | name: 'app.ejs' 142 | }, 143 | { 144 | name: 'server.ejs' 145 | }, 146 | { 147 | directory: 'documentation', 148 | name: 'index.js' 149 | }, 150 | { 151 | directory: 'documentation/schemas', 152 | name: 'index.js' 153 | }, 154 | { 155 | directory: 'documentation/schemas', 156 | name: 'user.js' 157 | }, 158 | { 159 | directory: 'documentation/paths', 160 | name: 'index.js' 161 | }, 162 | { 163 | directory: 'documentation/paths', 164 | name: 'user.js' 165 | }, 166 | { 167 | name: '.nvmrc' 168 | }, 169 | { 170 | name: 'gitignore', 171 | newName: '.gitignore' 172 | }, 173 | { 174 | name: '.eslintrc.js' 175 | }, 176 | { 177 | name: '.eslintignore' 178 | }, 179 | { 180 | name: '.env.example' 181 | }, 182 | { 183 | directory: 'config', 184 | name: 'development.ejs' 185 | }, 186 | { 187 | directory: 'config', 188 | name: 'production.ejs' 189 | }, 190 | { 191 | directory: 'config', 192 | name: 'testing.ejs' 193 | }, 194 | { 195 | directory: 'config', 196 | name: 'index.ejs' 197 | }, 198 | { 199 | directory: 'app/controllers', 200 | name: 'healthCheck.js' 201 | }, 202 | { 203 | directory: 'app/services', 204 | name: '.keep' 205 | }, 206 | { 207 | directory: 'app', 208 | name: 'errors.js' 209 | }, 210 | { 211 | directory: 'app', 212 | name: 'routes.js' 213 | }, 214 | { 215 | directory: 'app/middlewares', 216 | name: 'errors.js' 217 | }, 218 | { 219 | directory: 'app/logger', 220 | name: 'index.js' 221 | }, 222 | { 223 | directory: 'app/middlewares', 224 | name: 'apiInfo.js' 225 | } 226 | ]; 227 | -------------------------------------------------------------------------------- /generators/app/dependencies/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Fake", 3 | "version": "0.1.0", 4 | "description": "Fake package json used for keep updated version of packages", 5 | "cacheDirectories": [ 6 | "node_modules" 7 | ], 8 | "engines": { 9 | "node": "14.17.0", 10 | "npm": "6.14.13" 11 | }, 12 | "main": "app.js", 13 | "author": "Wolox", 14 | "homepage": "", 15 | "license": "MIT", 16 | "repository": { 17 | "type": "git", 18 | "url": "" 19 | }, 20 | "bugs": { 21 | "url": "", 22 | "email": "tls@wolox.com.ar" 23 | }, 24 | "dependencies": { 25 | "axios": "^0.24.0", 26 | "bcryptjs": "^2.4.3", 27 | "body-parser": "^1.19.0", 28 | "cors": "^2.8.5", 29 | "express": "^4.17.1", 30 | "express-wolox-logger": "^2.0.0", 31 | "factory-girl": "^5.0.4", 32 | "helmet": "^4.6.0", 33 | "jwt-simple": "^0.5.6", 34 | "mongodb": "^4.1.3", 35 | "mongoose": "^6.0.12", 36 | "mysql2": "^2.3.2", 37 | "pg": "^8.7.1", 38 | "rollbar": "^2.24.0", 39 | "sequelize": "^6.8.0", 40 | "sqlite3": "^5.0.2", 41 | "swagger-ui-express": "^4.1.6", 42 | "tedious": "^14.0.0", 43 | "umzug": "^2.3.0" 44 | }, 45 | "devDependencies": { 46 | "babel": "6.23.0", 47 | "babel-core": "^6.26.3", 48 | "babel-eslint": "^10.1.0", 49 | "babel-jest": "^27.3.1", 50 | "babel-preset-es2015": "6.24.1", 51 | "chai": "^4.3.4", 52 | "chai-http": "^4.3.0", 53 | "coveralls": "^3.1.1", 54 | "dotenv": "^10.0.0", 55 | "eslint": "^6.8.0", 56 | "eslint-config-wolox": "^4.0.0", 57 | "eslint-config-wolox-node": "^3.0.0", 58 | "eslint-plugin-import": "^2.25.2", 59 | "eslint-plugin-prettier": "^3.0.1", 60 | "husky": "^7.0.4", 61 | "istanbul": "^0.4.3", 62 | "jest": "^27.3.1", 63 | "mocha": "^9.1.3", 64 | "mocha-lcov-reporter": "^1.3.0", 65 | "nodemon": "^2.0.14", 66 | "prettier": "^1.15.3", 67 | "prettier-eslint": "^9.0.1", 68 | "prompt": "^1.2.0", 69 | "sequelize-cli": "^6.2.0", 70 | "supertest": "^6.1.6" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /generators/app/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-underscore-dangle */ 2 | const Generator = require('yeoman-generator'); 3 | const cfonts = require('cfonts'); 4 | const terminalLink = require('terminal-link'); 5 | const { camelCase } = require('camel-case'); 6 | const { TRAINING_CONFIG, files, TUTORIALS } = require('./constants'); 7 | const { runCommand } = require('./command'); 8 | const prompts = require('./prompts'); 9 | const packageJsonTemplate = require('./dependencies/package.json'); 10 | 11 | const getDependenciesVersions = () => { 12 | const appendVersion = dependencies => 13 | Object.keys(dependencies).reduce((mappedDependencies, dependency) => { 14 | mappedDependencies[`${camelCase(dependency)}Version`] = dependencies[dependency]; 15 | return mappedDependencies; 16 | }, {}); 17 | const dependencies = { 18 | ...appendVersion(packageJsonTemplate.dependencies), 19 | ...appendVersion(packageJsonTemplate.devDependencies) 20 | }; 21 | return dependencies; 22 | }; 23 | 24 | const nodeGenerator = class extends Generator { 25 | constructor(args, opts) { 26 | super(args, opts); 27 | this.option('verbose'); 28 | } 29 | 30 | _checkInstalled(name, link, command) { 31 | return this._runCommand({ 32 | description: `Checking if ${name} is installed`, 33 | name: command || name, 34 | args: ['--version'], 35 | options: { 36 | failMessage: `${name} is required to run this generator, check ${terminalLink('this', link)}` 37 | } 38 | }); 39 | } 40 | 41 | async initializing() { 42 | try { 43 | cfonts.say('NODE JS|KICKOFF', { 44 | font: 'block', 45 | align: 'center', 46 | colors: ['green', 'green'], 47 | background: 'transparent', 48 | letterSpacing: 1, 49 | lineHeight: 1, 50 | space: true, 51 | maxLength: '0' 52 | }); 53 | 54 | await this._checkInstalled('git', TUTORIALS.GIT); 55 | await this._checkInstalled('npm', TUTORIALS.NPM); 56 | } catch (e) { 57 | this.env.error(e); 58 | } 59 | } 60 | 61 | async prompting() { 62 | this.answers = await this.prompt(prompts); 63 | this.useGit = this.answers.urlRepository !== ''; 64 | 65 | if (this.answers.inTraining) { 66 | this.answers = { ...this.answers, ...TRAINING_CONFIG }; 67 | } 68 | } 69 | 70 | _destinationPath(fileName) { 71 | return this.destinationPath(`${this.answers.projectName}/${fileName}`); 72 | } 73 | 74 | _copyTplPromise(templatePath, filePath, options) { 75 | return new Promise((resolve, reject) => { 76 | try { 77 | this.fs.copyTpl(this.templatePath(templatePath), this._destinationPath(filePath), options); 78 | resolve(); 79 | } catch (err) { 80 | reject(err); 81 | } 82 | }); 83 | } 84 | 85 | _runCommand(params) { 86 | if (!params.options || params.options.verbose === undefined) { 87 | params.options = { ...params.options, verbose: this.options.verbose }; 88 | } 89 | return runCommand(params); 90 | } 91 | 92 | async _copyTemplate(file) { 93 | const newName = file.name.endsWith('.ejs') 94 | ? `${file.name.substr(0, file.name.lastIndexOf('.'))}.js` 95 | : file.newName || file.name; 96 | const filePath = file.directory ? `${file.directory}/${newName}` : newName; 97 | const templatePath = file.directory ? `${file.directory}/${file.name}` : file.name; 98 | const options = 99 | newName === 'package.json' ? { ...getDependenciesVersions(), ...this.answers } : this.answers; 100 | await this._copyTplPromise(templatePath, filePath, options); 101 | } 102 | 103 | async writing() { 104 | try { 105 | if (this.useGit) { 106 | await this._runCommand({ 107 | description: `Cloning repository from ${this.answers.urlRepository}`, 108 | name: 'git', 109 | args: ['clone', this.answers.urlRepository, this.answers.projectName] 110 | }); 111 | } 112 | 113 | files 114 | .filter(file => !file.condition || file.condition(this.answers)) 115 | .map(file => this._copyTemplate(file)); 116 | } catch (e) { 117 | this.env.error(e); 118 | } 119 | } 120 | 121 | async install() { 122 | try { 123 | const spawnOptions = { cwd: this.destinationPath(this.answers.projectName) }; 124 | await this._runCommand({ 125 | description: 'Installing dependencies', 126 | name: 'npm', 127 | args: ['install'], 128 | spawnOptions 129 | }); 130 | await this._runCommand({ 131 | description: 'Running linter', 132 | name: 'npm', 133 | args: ['run', 'lint-fix'], 134 | spawnOptions 135 | }); 136 | if (this.useGit) { 137 | await this._runCommand({ 138 | description: 'Creating branch kickoff', 139 | name: 'git', 140 | args: ['checkout', '-b', 'kickoff'], 141 | spawnOptions 142 | }); 143 | await this._runCommand({ 144 | description: 'Add changes to git', 145 | name: 'git', 146 | args: ['add', '.'], 147 | spawnOptions 148 | }); 149 | await this._runCommand({ 150 | description: 'Commit changes to git', 151 | name: 'git', 152 | args: ['commit', '-m', 'Kickoff project'], 153 | spawnOptions 154 | }); 155 | } 156 | } catch (e) { 157 | this.env.error(e); 158 | } 159 | } 160 | }; 161 | 162 | module.exports = nodeGenerator; 163 | -------------------------------------------------------------------------------- /generators/app/prompts.js: -------------------------------------------------------------------------------- 1 | const { 2 | checkboxReducer, 3 | flattenPrompts, 4 | validateUrl, 5 | validateVersionNumber, 6 | validateAppName 7 | } = require('./utils'); 8 | const { 9 | NODE_DEFAULT_VERSION, 10 | NPM_DEFAULT_VERSION, 11 | ORM_OPTIONS, 12 | SEQUELIZE_DEFAULT_VERSION, 13 | SEQUELIZE_DEFAULT_DIALECT, 14 | SEQUELIZE_DIALECTS, 15 | MONGOOSE_DEFAULT_VERSION, 16 | MONGOOSE_DEFAULT_DIALECT, 17 | MONGOOSE_DIALECTS, 18 | DEPLOY_STRATEGIES, 19 | OPTIONALS_FEATURES, 20 | CI_OPTIONS, 21 | TESTING_OPTIONS 22 | } = require('./constants'); 23 | 24 | module.exports = flattenPrompts([ 25 | { 26 | type: 'input', 27 | name: 'urlRepository', 28 | message: 'Enter git repository for this project', 29 | validate: validateUrl 30 | }, 31 | { 32 | type: 'confirm', 33 | name: 'inTraining', 34 | message: 'Are you in w-training ?', 35 | promptsNegative: [ 36 | { 37 | type: 'input', 38 | name: 'projectName', 39 | message: 'Enter Project Name', 40 | validate: validateAppName 41 | }, 42 | { 43 | type: 'input', 44 | name: 'projectDescription', 45 | message: 'Enter Project Description', 46 | default: ({ projectName }) => projectName, 47 | validate: value => value.trim().length !== 0 || 'Please enter a valid description' 48 | }, 49 | { 50 | type: 'input', 51 | name: 'nodeVersion', 52 | message: 'Enter NodeJS Version', 53 | default: NODE_DEFAULT_VERSION, 54 | validate: validateVersionNumber 55 | }, 56 | { 57 | type: 'input', 58 | name: 'npmVersion', 59 | message: 'Enter NPM Version', 60 | default: NPM_DEFAULT_VERSION, 61 | validate: validateVersionNumber 62 | }, 63 | { 64 | type: 'confirm', 65 | name: 'documentationRequiresAuth', 66 | message: 'Would you like the documentation to require authentication?', 67 | default: false 68 | }, 69 | { 70 | type: 'confirm', 71 | name: 'database', 72 | message: 'Will you use a database?', 73 | promptsPositive: [ 74 | { 75 | type: 'checkbox', 76 | name: 'orm', 77 | message: 'Select the ORM for your project', 78 | filter: checkboxReducer, 79 | choices: ORM_OPTIONS, 80 | chosen: [ 81 | { 82 | condition: 'sequelize', 83 | prompts: [ 84 | { 85 | type: 'input', 86 | name: 'sequelizeVersion', 87 | message: 'Enter Sequelize Version', 88 | default: SEQUELIZE_DEFAULT_VERSION, 89 | validate: validateVersionNumber 90 | }, 91 | { 92 | type: 'list', 93 | name: 'sequelizeDialect', 94 | message: 'Enter Database Dialect', 95 | default: SEQUELIZE_DEFAULT_DIALECT, 96 | choices: SEQUELIZE_DIALECTS 97 | } 98 | ] 99 | }, 100 | { 101 | condition: 'mongoose', 102 | prompts: [ 103 | { 104 | type: 'input', 105 | name: 'mongooseVersion', 106 | message: 'Enter Mongoose Version', 107 | default: MONGOOSE_DEFAULT_VERSION, 108 | validate: validateVersionNumber 109 | }, 110 | { 111 | type: 'list', 112 | name: 'mongooseDialect', 113 | message: 'Enter Database Dialect', 114 | default: MONGOOSE_DEFAULT_DIALECT, 115 | choices: MONGOOSE_DIALECTS 116 | } 117 | ] 118 | } 119 | ] 120 | } 121 | ] 122 | }, 123 | { 124 | type: 'checkbox', 125 | name: 'deployStrategy', 126 | message: 'Select Deploy strategy for your project', 127 | filter: checkboxReducer, 128 | choices: DEPLOY_STRATEGIES 129 | }, 130 | { 131 | type: 'confirm', 132 | name: 'docker', 133 | message: 'Are you going to use docker for the deploy?' 134 | }, 135 | { 136 | type: 'checkbox', 137 | name: 'optionalsFeatures', 138 | message: 'Choose optionals features for your project', 139 | filter: checkboxReducer, 140 | choices: OPTIONALS_FEATURES 141 | }, 142 | { 143 | type: 'list', 144 | name: 'ci', 145 | message: 'Choose CI for your project', 146 | choices: CI_OPTIONS 147 | }, 148 | { 149 | type: 'list', 150 | name: 'testing', 151 | message: 'Choose your testing option', 152 | choices: TESTING_OPTIONS 153 | } 154 | ] 155 | } 156 | ]); 157 | -------------------------------------------------------------------------------- /generators/app/templates/.ebextensions/cloudwatch.config: -------------------------------------------------------------------------------- 1 | packages: 2 | yum: 3 | perl-DateTime: [] 4 | perl-Sys-Syslog: [] 5 | perl-LWP-Protocol-https: [] 6 | perl-Switch: [] 7 | perl-URI: [] 8 | perl-Bundle-LWP: [] 9 | sources: 10 | /opt/cloudwatch: https://aws-cloudwatch.s3.amazonaws.com/downloads/CloudWatchMonitoringScripts-1.2.1.zip 11 | 12 | container_commands: 13 | 01-setupcron: 14 | command: | 15 | echo '*/5 * * * * root perl /opt/cloudwatch/aws-scripts-mon/mon-put-instance-data.pl `{"Fn::GetOptionSetting" : { "OptionName" : "CloudWatchMetrics", "DefaultValue" : "--mem-util --disk-space-util --disk-path=/" }}` >> /var/log/cwpump.log 2>&1' > /etc/cron.d/cwpump 16 | 02-changeperm: 17 | command: chmod 644 /etc/cron.d/cwpump 18 | 03-changeperm: 19 | command: chmod u+x /opt/cloudwatch/aws-scripts-mon/mon-put-instance-data.pl 20 | option_settings: 21 | "aws:autoscaling:launchconfiguration" : 22 | IamInstanceProfile : "aws-elasticbeanstalk-ec2-role" 23 | "aws:elasticbeanstalk:customoption" : 24 | CloudWatchMetrics : "--mem-util --mem-used --mem-avail --disk-space-util --disk-space-used --disk-space-avail --disk-path=/ --auto-scaling" 25 | -------------------------------------------------------------------------------- /generators/app/templates/.env.example: -------------------------------------------------------------------------------- 1 | PORT=8081 2 | 3 | DB_HOST=localhost 4 | DB_PORT=5432 5 | DB_USERNAME=set_your_db_username 6 | DB_PASSWORD=set_your_db_password 7 | DB_NAME=db_<%=projectName%> 8 | DB_NAME_DEV=db_<%=projectName%>_dev 9 | DB_NAME_TEST=db_<%=projectName%>_test 10 | API_DATE=X-API-Date 11 | PACKAGE_VERSION=X-Package-Version 12 | NODE_VERSION=X-Node-Version 13 | 14 | #API_BODY_SIZE_LIMIT 15 | #API_PARAMETER_LIMIT 16 | 17 | NODE_ENV = development 18 | 19 | <% if(optionalsFeatures.rollbar) {%>ROLLBAR_ACCESS_TOKEN= 20 | ROLLBAR_ENV=<%}%> 21 | 22 | <% if(documentationRequiresAuth) {%>DOCUMENTATION_TOKEN= 23 | DOCUMENTATION_TOKEN_HEADER=<%}%> 24 | -------------------------------------------------------------------------------- /generators/app/templates/.eslintignore: -------------------------------------------------------------------------------- 1 | app/dist 2 | -------------------------------------------------------------------------------- /generators/app/templates/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('eslint-config-wolox-node'); 2 | -------------------------------------------------------------------------------- /generators/app/templates/.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug Report 3 | about: Create a report to bug fixing 4 | title: 🐛 Bug Report 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## 🐛 Bug Report 11 | 12 | A clear and concise description of what the bug is. 13 | 14 | ## Steps to Reproduce 15 | 16 | Steps to reproduce the behavior: 17 | 18 | ## Expected behavior 19 | 20 | A clear and concise description of what you expected to happen. 21 | -------------------------------------------------------------------------------- /generators/app/templates/.github/ISSUE_TEMPLATE/feature_proposal.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🚀 Feature Proposal 3 | about: Submit a proposal for a new feature 4 | title: 🚀 Feature Proposal 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## 🚀 Feature Proposal 11 | 12 | A clear and concise description of what the feature is. 13 | 14 | ## Motivation 15 | 16 | Please outline the motivation for the proposal. 17 | 18 | ## Example 19 | 20 | Please provide an example for how this feature would be used. 21 | 22 | ## Pitch 23 | 24 | Why does this feature should be implemented? 25 | -------------------------------------------------------------------------------- /generators/app/templates/.nvmrc: -------------------------------------------------------------------------------- 1 | <%= nodeVersion %> -------------------------------------------------------------------------------- /generators/app/templates/.sequelizerc: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | 'config': path.resolve('config', 'db.js'), 5 | 'migrations-path': path.resolve('migrations', 'migrations'), 6 | 'models-path': path.resolve('app', 'models') 7 | }; 8 | -------------------------------------------------------------------------------- /generators/app/templates/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "<%= nodeVersion %>" 5 | 6 | sudo: true 7 | 8 | env: 9 | - CXX=g++-4.8 NODE_ENV=testing 10 | addons: 11 | apt: 12 | sources: 13 | - ubuntu-toolchain-r-test 14 | packages: 15 | - g++-4.8 16 | <% if(database && orm.sequelize) {%> 17 | services: 18 | - postgresql 19 | 20 | before_script: 21 | - psql -c "CREATE DATABASE bookstest;" -U postgres 22 | - npm run migrations-test 23 | <%}%> -------------------------------------------------------------------------------- /generators/app/templates/.woloxci/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:<%= nodeVersion %> 2 | 3 | WORKDIR /usr/src/app 4 | 5 | ENV NODE_ENV testing 6 | 7 | ENV HOME /usr/src/app 8 | 9 | ENV BABEL_DISABLE_CACHE 1 10 | 11 | RUN mkdir -p /install 12 | 13 | ENV NODE_PATH=/install/node_modules 14 | 15 | # Install app dependencies 16 | # A wildcard is used to ensure both package.json AND package-lock.json are copied 17 | # where available (npm@5+) 18 | COPY package*.json /install/ 19 | 20 | WORKDIR /install 21 | 22 | RUN npm install 23 | RUN npm install -g gulp 24 | # If you are building your code for production 25 | # RUN npm install --only=production 26 | 27 | RUN chmod a+r /usr/src/app 28 | 29 | WORKDIR /usr/src/app 30 | 31 | # Bundle app source 32 | COPY . . 33 | -------------------------------------------------------------------------------- /generators/app/templates/.woloxci/config.yml: -------------------------------------------------------------------------------- 1 | config: 2 | dockerfile: .woloxci/Dockerfile 3 | project_name: <%= projectName %> 4 | <% if(database && orm.sequelize) {%> 5 | services: 6 | - <%= sequelizeDialect %> 7 | <%}%> 8 | steps: 9 | copy_node_modules: 10 | - cp -r $NODE_PATH/ ./<% if(database && orm.sequelize) {%> 11 | migrate_db: 12 | - node_modules/.bin/sequelize db:migrate<%}%> 13 | lint: 14 | - npm run lint 15 | test: 16 | - npm run test 17 | 18 | environment: 19 | GIT_COMMITTER_NAME: a 20 | GIT_COMMITTER_EMAIL: b 21 | LANG: C.UTF-8 22 | -------------------------------------------------------------------------------- /generators/app/templates/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## 0.1.0 6 | 7 | * First version. 8 | -------------------------------------------------------------------------------- /generators/app/templates/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:<%= nodeVersion %> 2 | 3 | WORKDIR /home/node/app 4 | 5 | COPY package.json . 6 | COPY package-lock.json . 7 | COPY .nvmrc . 8 | 9 | RUN npm install 10 | 11 | COPY . . 12 | 13 | EXPOSE 8080 14 | ENV NODE_ENV production 15 | CMD ["node", "server.js"] 16 | -------------------------------------------------------------------------------- /generators/app/templates/Dockerrun.aws.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSEBDockerrunVersion": "1", 3 | "Ports": [ 4 | { 5 | "ContainerPort": "8080" 6 | } 7 | ], 8 | "Volumes": [], 9 | "Logging": "/home/node/app/app/logger/logs" 10 | } 11 | -------------------------------------------------------------------------------- /generators/app/templates/Jenkinsfile: -------------------------------------------------------------------------------- 1 | @Library('wolox-ci') _ 2 | 3 | node { 4 | 5 | checkout scm 6 | 7 | woloxCi('.woloxci/config.yml'); 8 | } 9 | -------------------------------------------------------------------------------- /generators/app/templates/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Wolox 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /generators/app/templates/Procfile: -------------------------------------------------------------------------------- 1 | web: node server.js 2 | -------------------------------------------------------------------------------- /generators/app/templates/README.md: -------------------------------------------------------------------------------- 1 | # <%= projectName %> 2 | 3 | <%= projectDescription %> 4 | 5 | ## First steps 6 | 7 | #### Installing node 8 | 9 | Get the latest version of node from the [official website](https://nodejs.org/) or using [nvm](https://github.com/creationix/nvm) 10 | Nvm approach is preferred. 11 | 12 | #### Getting dependencies 13 | 14 | Run `npm install` or `yarn` from rootpath of the project. 15 | <% if(database && orm.sequelize) {%> 16 | 17 | #### Database configuration 18 | 19 | Before running the app, make sure you have [postgresql installed](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-14-04) and a db created, to create it run the following steps inside a psql terminal: 20 | 21 | 1. CREATE DATABASE db_project_name; 22 | 2. \c db_project_name 23 | 3. CREATE ROLE "project_name" LOGIN CREATEDB PASSWORD 'project_name'; 24 | 25 | Then, set in `.env` some variables: 26 | 27 | - DB_HOST=localhost 28 | - DB_PORT=5432 29 | - DB_USERNAME=project_name 30 | - DB_PASSWORD=project_name 31 | - DB_NAME=db_project_name 32 | - DB_NAME_DEV=db_project_name_dev 33 | - DB_NAME_TEST=db_project_name_test 34 | - API_DATE=X-API-Date 35 | - PACKAGE_VERSION=X-Package-Version 36 | - NODE_VERSION=X-Node-Version 37 | 38 | ### Migrations 39 | 40 | To create a migration, run `./node_modules/.bin/sequelize migration:create --name="my-migration-name" --config ./migrations/config.js --migrations-path ./migrations/migrations`. 41 | 42 | To run them, execute `npm run migrations`. 43 | <%}%><% if(database && orm.mongoose) {%> 44 | #### Database configuration 45 | 46 | Before running the app, make sure you have [mongoDB installed](https://hevodata.com/blog/install-mongodb-on-ubuntu/) and a db created, to create it run the following steps inside a terminal: 47 | 48 | 1. mongo 49 | 2. use db_project_name 50 | 3. db.createUser({user:"root", pwd:"superpass", roles:[{role:"root", db:"db_project_name"}]}) 51 | 4. *exit from mongo* 52 | 5. mongo -u root -p superpass --authenticationDatabase db_project_name 53 | 54 | Then, set in `.env` some variables: 55 | 56 | - DB_HOST=localhost 57 | - DB_PORT=5432 58 | - DB_USERNAME=project_name 59 | - DB_PASSWORD=project_name 60 | - DB_NAME=db_project_name 61 | - DB_NAME_DEV=db_project_name_dev 62 | - DB_NAME_TEST=db_project_name_test 63 | - API_DATE=X-API-Date 64 | - PACKAGE_VERSION=X-Package-Version 65 | - NODE_VERSION=X-Node-Version 66 | <%}%> 67 | 68 | #### Starting your app 69 | 70 | Now, we have two ways to start an app. To start your app in production mode run `npm start` in the root path of your project. To start your app in development mode (nodemon) run `npm run start-dev`. Then access your app at **localhost:port**. The port is logged in the console where you ran the start script. 71 | 72 | ## Development 73 | 74 | #### Environments 75 | 76 | By default, the environment will be **development**, but you can easily change it using the **NODE_ENV** environmental variable. 77 | 78 | #### Environment variables 79 | 80 | `Dotenv` is used for managing environment variables. They are stored in the `/.env` file. Take into account that the variables defined in the `bashrc` are not overrided. 81 | 82 | The environment variables should be added to the `.env` file in the form of `NAME=VALUE`, as the following example: 83 | 84 | ``` 85 | DB_USERNAME=root 86 | DB_PASS=superpass 87 | DB_PASSWORD=superpass 88 | PORT=8081 89 | CLIENTS_API=http://api.clients.example.org/ 90 | ``` 91 | 92 | **Remember not to push nor commit the `.env` file.** 93 | 94 | #### Logging 95 | 96 | To log useful information of your program to the console you just need to import the logger located at `app/logger`. There are two possible types of logging: `info` and `error`. You should use them depending on the type of message you want to show. 97 | 98 | Here is an example snippet: 99 | 100 | ``` 101 | const logger = require('/app/logger'); 102 | ... 103 | if (error) { 104 | logger.error('There is an error); 105 | } else { 106 | logger.info('There is no error); 107 | } 108 | ``` 109 | 110 | #### Testing 111 | 112 | To run your tests you first need to config your testing database by setting the env var `DB_NAME_TEST`. as explained 113 | before in [Database configuration](#database-configuration). Also you need to run the migrations in this exclusive 114 | testing database each time you have new ones, you can do this by running the command `npm run migrations-test`. 115 | Once you have all the above done you can run your tests with the following command: `npm test`. For more information refeer to the documentation of <% if(testing === 'mocha-chai') {%>[Mocha](https://mochajs.org/) and [Chai](https://www.chaijs.com/).<%}%><% if(testing === 'jest-supertest') {%>[Jest](https://jestjs.io/docs/en/getting-started).<%}%> 116 | <% if(database && orm.sequelize && testing === 'jest-supertest') {%> 117 | #### Factory Girl 118 | 119 | To simplify your tests, you can call the `factoryByModel('nameOfModel')` function in `factory_by_models.js` on your code, then, `factory.build('nameOfModel')` and it will define a json object with the attributes form the model you've passed as parameter taking random values. If you want to acceed to the object created, the values created will be on its `dataValues` field. 120 | Remember that you have to create a model before, and the `nameOfModel` will be the one you will have on the database (which is the first parameter on `sequelize.define()`). 121 | 122 | Factory By Models have also two additional functions, `factoryAllModels()` and `factoryWithPredeterminatedValue('nameOfModel', 'nameOfAttribute', 'value')`. The first one will define factories for ALL the models you have, so you don't have to worry to declare a factory every time you want to build another. The second one, maybe you have a customized attribute in your model, or with some values we don't know. So you may use it, you will have to pass the name of the model, the attribute name and the value you want it to have. 123 | 124 | Also, it takes values predefined in the `type` field (Sequelize Datatype) and the validations you have in your MODEL (`validate` field),so if you want to validate those values on middlewares or somewhere else, factoryByModel won't take this in count. We strongly recommend to check if those validations cover the cases you expect, and if it doesn't, you can add your own code on this file (or just define a new factory). 125 | <%}%> 126 | 127 | #### Debugging 128 | 129 | As we know, a NodeJS application is not something easy to debug and because of that we've added the `--inspect` flag to make it simpler. You can download a node inspection manager for Chrome, so Chrome DevTools will automatically start when you run your app using `npm run start-dev`, making your debugging easier. You can read more about the different inspector clients here: 130 | 131 | #### REPL console 132 | 133 | We can use a node console with `npm run console`. There your service objects are exposed as _servicename_ + "Service". Let's suppose that we have a service `users` which has a function `getAll`. In your console you can call `usersService.getAll()` and see the result. Note that this works also with functions that return promises! To exit the console use `.exit`. 134 | 135 | #### Documentation 136 | 137 | Documentation will be served at `/docs`. We use [OpenAPI](https://github.com/OAI/OpenAPI-Specification) A.K.A `Swagger`. Check [this link](https://medium.com/wolox-driving-innovation/documenting-a-nodejs-rest-api-with-openapi-3-swagger-5deee9f50420) for more details on how to use it. 138 | 139 | ## Deploy 140 | 141 | #### Heroku 142 | 143 | Pushing the desired branch to heroku should be enough. 144 | For more information check: https://devcenter.heroku.com/articles/getting-started-with-nodejs#define-a-procfile. 145 | 146 | ## Contributing 147 | 148 | 1. Fork it 149 | 2. Create your feature branch (`git checkout -b my-new-feature`) 150 | 3. Run the tests (`npm test`) 151 | 4. Commit your changes (`git commit -am 'Add some feature'`) 152 | 5. Push to the branch (`git push origin my-new-feature`) 153 | 6. Create new Pull Request 154 | 155 | ## About 156 | 157 | This project is maintained by [Wolox](https://github.com/wolox) and it was written by [Wolox](http://www.wolox.com.ar). 158 | 159 | ![Wolox](https://raw.githubusercontent.com/Wolox/press-kit/master/logos/logo_banner.png) 160 | 161 | ## License 162 | 163 | **<%= projectName %>** is available under the MIT [license](LICENSE.md). 164 | 165 | Copyright (c) 2019 Wolox 166 | 167 | Permission is hereby granted, free of charge, to any person obtaining a copy 168 | of this software and associated documentation files (the "Software"), to deal 169 | in the Software without restriction, including without limitation the rights 170 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 171 | copies of the Software, and to permit persons to whom the Software is 172 | furnished to do so, subject to the following conditions: 173 | 174 | The above copyright notice and this permission notice shall be included in 175 | all copies or substantial portions of the Software. 176 | 177 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 178 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 179 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 180 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 181 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 182 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 183 | THE SOFTWARE. 184 | -------------------------------------------------------------------------------- /generators/app/templates/app.ejs: -------------------------------------------------------------------------------- 1 | const { expressMiddleware, expressRequestIdMiddleware } = require('express-wolox-logger'); 2 | const express = require('express'); 3 | const bodyParser = require('body-parser'); 4 | const swaggerUi = require('swagger-ui-express');<% if(optionalsFeatures.cors) {%> 5 | const cors = require('cors');<%}%><% if(optionalsFeatures.helmet) {%> 6 | const helmet = require('helmet');<%}%> 7 | const config = require('./config'); 8 | const routes = require('./app/routes'); 9 | const errors = require('./app/middlewares/errors'); 10 | const documentation = require('./documentation'); 11 | const logger = require('./app/logger'); 12 | <% if(documentationRequiresAuth) {%> const { verifyDocumentationToken } = require('./app/middlewares/docsAuth'); <%}%> 13 | 14 | const DEFAULT_BODY_SIZE_LIMIT = 1024 * 1024 * 10; 15 | const DEFAULT_PARAMETER_LIMIT = 10000; 16 | 17 | const bodyParserJsonConfig = () => ({ 18 | parameterLimit: config.common.api.parameterLimit || DEFAULT_PARAMETER_LIMIT, 19 | limit: config.common.api.bodySizeLimit || DEFAULT_BODY_SIZE_LIMIT 20 | }); 21 | 22 | const bodyParserUrlencodedConfig = () => ({ 23 | extended: true, 24 | parameterLimit: config.common.api.parameterLimit || DEFAULT_PARAMETER_LIMIT, 25 | limit: config.common.api.bodySizeLimit || DEFAULT_BODY_SIZE_LIMIT 26 | }); 27 | 28 | const app = express(); 29 | <% if(optionalsFeatures.cors) {%> 30 | app.use(cors());<%}%> 31 | 32 | <% if(optionalsFeatures.helmet) {%> 33 | app.use(helmet());<%}%> 34 | 35 | // Client must send "Content-Type: application/json" header 36 | app.use(bodyParser.json(bodyParserJsonConfig())); 37 | app.use(bodyParser.urlencoded(bodyParserUrlencodedConfig())); 38 | app.use(expressRequestIdMiddleware()); 39 | app.use('/docs', <% if(documentationRequiresAuth) {%> 40 | verifyDocumentationToken, 41 | <%}%> swaggerUi.serve, swaggerUi.setup(documentation)); 42 | 43 | if (!config.isTesting) app.use(expressMiddleware({ loggerFn: logger.info })); 44 | 45 | routes.init(app); 46 | 47 | app.use(errors.handle); 48 | 49 | module.exports = app; 50 | -------------------------------------------------------------------------------- /generators/app/templates/app/controllers/healthCheck.js: -------------------------------------------------------------------------------- 1 | exports.healthCheck = (_, res) => res.status(200).send({ uptime: process.uptime() }); 2 | -------------------------------------------------------------------------------- /generators/app/templates/app/errors.js: -------------------------------------------------------------------------------- 1 | const internalError = (message, internalCode) => ({ 2 | message, 3 | internalCode 4 | }); 5 | 6 | exports.DATABASE_ERROR = 'database_error'; 7 | exports.databaseError = message => internalError(message, exports.DATABASE_ERROR); 8 | 9 | exports.DEFAULT_ERROR = 'default_error'; 10 | exports.defaultError = message => internalError(message, exports.DEFAULT_ERROR); 11 | -------------------------------------------------------------------------------- /generators/app/templates/app/logger/index.js: -------------------------------------------------------------------------------- 1 | const { logger } = require('express-wolox-logger'); 2 | 3 | module.exports = logger; 4 | -------------------------------------------------------------------------------- /generators/app/templates/app/middlewares/apiInfo.js: -------------------------------------------------------------------------------- 1 | const pjson = require('../../package.json'); 2 | const config = require('../../config').common.headers; 3 | 4 | exports.apiInformation = (req, res, next) => { 5 | try { 6 | if (!res.headers) { 7 | res.headers = {}; 8 | } 9 | res.headers[config.apiDate] = new Date(); 10 | res.headers[config.packageVersion] = pjson.version; 11 | res.headers[config.nodeVersion] = pjson.engines.node; 12 | return next(); 13 | } catch (err) { 14 | return next(err); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /generators/app/templates/app/middlewares/docsAuth.ejs: -------------------------------------------------------------------------------- 1 | const logger = require('../logger'); 2 | const { documentationTokenHeader } = require('../../config').common.headers; 3 | const { documentationToken } = require('../../config').common.session; 4 | 5 | exports.verifyDocumentationToken = (req, res, next) => { 6 | const receivedDocumentationToken = req.headers[documentationTokenHeader]; 7 | 8 | if (!receivedDocumentationToken) { 9 | return next({ internalCode: 401, message: 'The documentation token was not given' }); 10 | } 11 | 12 | if (receivedDocumentationToken !== documentationToken) { 13 | return next({ internalCode: 401, message: 'The given documentation token was incorrect' }); 14 | } 15 | 16 | logger.info('Successful Authentication.'); 17 | return next(); 18 | }; 19 | -------------------------------------------------------------------------------- /generators/app/templates/app/middlewares/errors.js: -------------------------------------------------------------------------------- 1 | const errors = require('../errors'); 2 | const logger = require('../logger'); 3 | 4 | const DEFAULT_STATUS_CODE = 500; 5 | 6 | const statusCodes = { 7 | [errors.DATABASE_ERROR]: 503, 8 | [errors.DEFAULT_ERROR]: 500 9 | }; 10 | 11 | exports.handle = (error, req, res, next) => { 12 | if (error.internalCode) res.status(statusCodes[error.internalCode] || DEFAULT_STATUS_CODE); 13 | else { 14 | // Unrecognized error, notifying it to rollbar. 15 | next(error); 16 | res.status(DEFAULT_STATUS_CODE); 17 | } 18 | logger.error(error); 19 | return res.send({ message: error.message, internal_code: error.internalCode }); 20 | }; 21 | -------------------------------------------------------------------------------- /generators/app/templates/app/models/index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const Sequelize = require('sequelize'); 4 | const config = require('../../config'); 5 | const dbConfig = require('../../config/db')[config.environment]; 6 | 7 | const basename = path.basename(__filename); 8 | const db = {}; 9 | const sequelize = new Sequelize(dbConfig.database, dbConfig.username, dbConfig.password, dbConfig); 10 | 11 | fs.readdirSync(__dirname) 12 | .filter(file => file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js') 13 | .forEach(file => { 14 | // eslint-disable-next-line global-require 15 | const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes); 16 | db[model.name] = model; 17 | }); 18 | 19 | Object.keys(db).forEach(modelName => { 20 | if (db[modelName].associate) db[modelName].associate(db); 21 | }); 22 | 23 | db.sequelize = sequelize; 24 | db.Sequelize = Sequelize; 25 | 26 | module.exports = db; 27 | -------------------------------------------------------------------------------- /generators/app/templates/app/routes.js: -------------------------------------------------------------------------------- 1 | // const controller = require('./controllers/controller'); 2 | const { healthCheck } = require('./controllers/healthCheck'); 3 | 4 | exports.init = app => { 5 | app.get('/health', healthCheck); 6 | // app.get('/endpoint/get/path', [], controller.methodGET); 7 | // app.put('/endpoint/put/path', [], controller.methodPUT); 8 | // app.post('/endpoint/post/path', [], controller.methodPOST); 9 | }; 10 | -------------------------------------------------------------------------------- /generators/app/templates/app/services/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wolox/express-js-bootstrap/0dcd68b8717f30e9841215e28c060320a2479fe3/generators/app/templates/app/services/.keep -------------------------------------------------------------------------------- /generators/app/templates/config/db.ejs: -------------------------------------------------------------------------------- 1 | <% if(orm.mongoose && mongooseDialect === 'mongoDB') {%>const mongoose = require('mongoose'); 2 | <%}%>const config = require('../config').common.database; 3 | <% if(orm.sequelize) {%> 4 | module.exports = { 5 | development: { 6 | username: config.username, 7 | password: config.password, 8 | database: config.name, 9 | host: config.host, 10 | port: config.port, 11 | dialect: '<%= sequelizeDialect %>' 12 | }, 13 | testing: { 14 | username: config.username, 15 | password: config.password, 16 | database: config.name, 17 | host: config.host, 18 | port: config.port, 19 | dialect: '<%= sequelizeDialect %>', 20 | logging: false 21 | }, 22 | production: { 23 | username: config.username, 24 | password: config.password, 25 | database: config.name, 26 | host: config.host, 27 | port: config.port, 28 | dialect: '<%= sequelizeDialect %>', 29 | logging: false 30 | } 31 | };<%}%> 32 | <% if(orm.mongoose && mongooseDialect === 'mongoDB') {%> const host = config.host; 33 | const port = config.port; 34 | const name = config.name; 35 | const connectionString = `mongodb://${host}:${port}/${name}`; 36 | module.exports = mongoose.connect(connectionString); 37 | 38 | <%}%> 39 | -------------------------------------------------------------------------------- /generators/app/templates/config/development.ejs: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | environment: 'development',<% if(database && (orm.sequelize || orm.mongoose)) {%> 3 | common: { 4 | database: { 5 | name: process.env.DB_NAME_DEV 6 | } 7 | }, <%}%> 8 | isDevelopment: true 9 | }; 10 | -------------------------------------------------------------------------------- /generators/app/templates/config/index.ejs: -------------------------------------------------------------------------------- 1 | const ENVIRONMENT = process.env.NODE_ENV || 'development'; 2 | 3 | // eslint-disable-next-line global-require 4 | if (ENVIRONMENT !== 'production') require('dotenv').config(); 5 | 6 | const configFile = `./${ENVIRONMENT}`; 7 | 8 | const isObject = variable => variable instanceof Object && !(variable instanceof Array); 9 | 10 | /* 11 | * Deep immutable copy of source object into tarjet object and returns a new object. 12 | */ 13 | const deepMerge = (target, source) => { 14 | if (isObject(target) && isObject(source)) { 15 | return Object.keys(source).reduce( 16 | (output, key) => ({ 17 | ...output, 18 | [key]: isObject(source[key]) && key in target ? deepMerge(target[key], source[key]) : source[key] 19 | }), 20 | { ...target } 21 | ); 22 | } 23 | return target; 24 | }; 25 | 26 | const config = { 27 | common: { 28 | database: { 29 | host: process.env.DB_HOST, 30 | port: process.env.DB_PORT, 31 | username: process.env.DB_USERNAME, 32 | password: process.env.DB_PASSWORD 33 | }, 34 | api: { 35 | bodySizeLimit: process.env.API_BODY_SIZE_LIMIT, 36 | parameterLimit: process.env.API_PARAMETER_LIMIT, 37 | port: process.env.PORT 38 | },<% if(optionalsFeatures.rollbar) {%> 39 | rollbar: { 40 | accessToken: process.env.ROLLBAR_ACCESS_TOKEN, 41 | environment: process.env.ROLLBAR_ENV 42 | },<%}%> 43 | session: { 44 | header_name: 'authorization', 45 | secret: process.env.NODE_API_SESSION_SECRET,<% if(documentationRequiresAuth) {%> 46 | documentationToken: process.env.DOCUMENTATION_TOKEN<%}%> 47 | }, 48 | headers: { 49 | apiDate: process.env.API_DATE || 'X-API-Date', 50 | packageVersion: process.env.PACKAGE_VERSION || 'X-Package-Version', 51 | nodeVersion: process.env.NODE_VERSION || 'X-Node-Version',<% if(documentationRequiresAuth) {%> 52 | documentationTokenHeader: process.env.DOCUMENTATION_TOKEN_HEADER || 'X-documentation-token'<%}%> 53 | } 54 | } 55 | }; 56 | 57 | const customConfig = require(configFile).config; 58 | module.exports = deepMerge(config, customConfig); 59 | -------------------------------------------------------------------------------- /generators/app/templates/config/production.ejs: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | environment: 'production',<% if(database && (orm.sequelize || orm.mongoose)) {%> 3 | common: { 4 | database: { 5 | name: process.env.DB_NAME 6 | } 7 | }, <%}%> 8 | isProduction: true 9 | }; 10 | -------------------------------------------------------------------------------- /generators/app/templates/config/testing.ejs: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | environment: 'testing', 3 | isTesting: true, 4 | common: {<% if(database && (orm.sequelize || orm.mongoose)) {%> 5 | database: { 6 | name: process.env.DB_NAME_TEST 7 | }, 8 | <%}%> 9 | session: { 10 | secret: 'some-super-secret' 11 | } 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /generators/app/templates/console.ejs: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | const repl = require('repl'); 3 | const fs = require('fs'); 4 | <% if(database && orm.sequelize) {%>const models = require('./app/models');<%}%> 5 | const pjson = require('./package.json'); 6 | 7 | const convertFunctionToAsync = f => async (...args) => { 8 | const result = await f(...args); 9 | console.log(JSON.stringify(result, null, 2)); // eslint-disable-line no-console 10 | return result; 11 | }; 12 | 13 | const convertObjectFunctionsToAsync = serviceMethods => { 14 | const asyncServiceMethods = {}; 15 | Object.keys(serviceMethods).forEach(key => { 16 | if (typeof serviceMethods[key] === 'function') { 17 | asyncServiceMethods[key] = convertFunctionToAsync(serviceMethods[key]); 18 | } else asyncServiceMethods[key] = serviceMethods[key]; 19 | }); 20 | return asyncServiceMethods; 21 | }; 22 | 23 | Promise.resolve().then(() => { 24 | const replServer = repl.start({ 25 | prompt: `${pjson.name}> ` 26 | });<% if(database && orm.sequelize) {%> 27 | replServer.context.models = models;<%}%> 28 | const servicesPath = './app/services/'; 29 | fs.readdir(servicesPath, (err, files) => { 30 | files.forEach(file => { 31 | const serviceMethods = require(`${servicesPath}${file}`); 32 | const asyncServiceMethods = convertObjectFunctionsToAsync(serviceMethods); 33 | replServer.context[`${file.split('.')[0]}Service`] = asyncServiceMethods; 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /generators/app/templates/documentation/index.js: -------------------------------------------------------------------------------- 1 | const config = require('../config'); 2 | const schemas = require('./schemas'); 3 | const paths = require('./paths'); 4 | 5 | const port = config.common.api.port || 8080; 6 | 7 | module.exports = { 8 | openapi: '3.0.1', 9 | info: { 10 | version: '0.1.0', 11 | title: '<%= projectName %>', 12 | description: '<%= projectDescription %>', 13 | termsOfService: '', 14 | contact: { 15 | name: 'Wolox', 16 | email: 'tls@wolox.com.ar', 17 | url: 'https://www.wolox.com.ar/' 18 | }, 19 | license: { 20 | name: 'MIT' 21 | } 22 | }, 23 | servers: [ 24 | { 25 | url: `http://localhost:${port}/`, 26 | description: 'Local server' 27 | }, 28 | { 29 | url: 'https://api_url_testing', 30 | description: 'Testing server' 31 | } 32 | ], 33 | security: [], 34 | tags: [ 35 | { 36 | name: 'CRUD operations' 37 | } 38 | ], 39 | paths, 40 | components: { 41 | schemas, 42 | securitySchemes: {} 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /generators/app/templates/documentation/paths/index.js: -------------------------------------------------------------------------------- 1 | const user = require('./user'); 2 | 3 | module.exports = user; 4 | -------------------------------------------------------------------------------- /generators/app/templates/documentation/paths/user.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '/users': { 3 | get: { 4 | tags: ['CRUD operations'], 5 | description: 'Get users', 6 | operationId: 'getUsers', 7 | parameters: [ 8 | { 9 | name: 'page', 10 | in: 'query', 11 | schema: { 12 | type: 'integer', 13 | default: 1 14 | }, 15 | required: false 16 | } 17 | ], 18 | responses: { 19 | 200: { 20 | description: 'Users were obtained', 21 | content: { 22 | 'application/json': { 23 | schema: { 24 | $ref: '#/components/schemas/Users' 25 | } 26 | } 27 | } 28 | } 29 | } 30 | }, 31 | post: { 32 | tags: ['CRUD operations'], 33 | description: 'Create user', 34 | operationId: 'createUser', 35 | parameters: [], 36 | requestBody: { 37 | content: { 38 | 'application/json': { 39 | schema: { 40 | $ref: '#/components/schemas/User' 41 | } 42 | } 43 | }, 44 | required: true 45 | }, 46 | responses: { 47 | 200: { 48 | description: 'New user was created' 49 | }, 50 | 400: { 51 | description: 'Invalid parameters', 52 | content: { 53 | 'application/json': { 54 | schema: { 55 | $ref: '#/components/schemas/Error' 56 | }, 57 | example: { 58 | message: 'User´s email already exists', 59 | internal_code: 'invalid_parameters' 60 | } 61 | } 62 | } 63 | } 64 | } 65 | } 66 | } 67 | }; 68 | -------------------------------------------------------------------------------- /generators/app/templates/documentation/schemas/index.js: -------------------------------------------------------------------------------- 1 | const user = require('./user'); 2 | 3 | module.exports = { 4 | ...user, 5 | Error: { 6 | type: 'object', 7 | properties: { 8 | message: { 9 | type: 'string' 10 | }, 11 | internal_code: { 12 | type: 'string' 13 | } 14 | } 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /generators/app/templates/documentation/schemas/user.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | userId: { 3 | type: 'integer', 4 | example: 7 5 | }, 6 | username: { 7 | type: 'string', 8 | example: 'tom99' 9 | }, 10 | userEmail: { 11 | type: 'string', 12 | example: 'tom.engels@wolox.com.ar' 13 | }, 14 | User: { 15 | type: 'object', 16 | properties: { 17 | id: { 18 | $ref: '#/components/schemas/userId' 19 | }, 20 | username: { 21 | $ref: '#/components/schemas/username' 22 | }, 23 | email: { 24 | $ref: '#/components/schemas/userEmail' 25 | }, 26 | } 27 | }, 28 | Users: { 29 | type: 'object', 30 | properties: { 31 | users: { 32 | type: 'array', 33 | items: { 34 | $ref: '#/components/schemas/User' 35 | } 36 | } 37 | } 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /generators/app/templates/gitignore: -------------------------------------------------------------------------------- 1 | # Frontend Dist Files 2 | app/dist 3 | 4 | # Mac Files 5 | .DS_Store 6 | */DS_Store 7 | 8 | # Logs 9 | logs 10 | *.log 11 | npm-debug.log* 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | 24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 25 | .grunt 26 | 27 | # node-waf configuration 28 | .lock-wscript 29 | 30 | # Compiled binary addons (http://nodejs.org/api/addons.html) 31 | build/Release 32 | 33 | # Dependency directory 34 | node_modules 35 | 36 | # Optional npm cache directory 37 | .npm 38 | 39 | # Optional REPL history 40 | .node_repl_history 41 | 42 | # Code coverage 43 | ./coverage 44 | 45 | # dotenv 46 | .env 47 | 48 | # VS Code 49 | .vscode/ 50 | -------------------------------------------------------------------------------- /generators/app/templates/migrations/index.js: -------------------------------------------------------------------------------- 1 | const Umzug = require('umzug'); 2 | const config = require('./../config/'); 3 | const { sequelize } = require('../app/models'); 4 | const logger = require('../app/logger'); 5 | 6 | exports.check = () => { 7 | const umzug = new Umzug({ 8 | logging: logger.info, 9 | storage: 'sequelize', 10 | storageOptions: { sequelize }, 11 | migrations: { 12 | params: [ 13 | sequelize.getQueryInterface(), 14 | sequelize.constructor, 15 | () => { 16 | throw new Error('Migration tried to use old style "done" callback.upgrade'); 17 | } 18 | ], 19 | path: `${__dirname}/migrations`, 20 | pattern: /\.js$/ 21 | } 22 | }); 23 | return umzug.pending().then(migrations => { 24 | if (migrations.length) { 25 | if (!config.isProduction) { 26 | return Promise.reject(new Error('Pending migrations, run: npm run migrations')); 27 | } 28 | 29 | return umzug.up().catch(err => { 30 | logger.error(err); 31 | return Promise.reject(new Error('There are pending migrations that could not be executed')); 32 | }); 33 | } 34 | return Promise.resolve(); 35 | }); 36 | }; 37 | -------------------------------------------------------------------------------- /generators/app/templates/migrations/migrations/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wolox/express-js-bootstrap/0dcd68b8717f30e9841215e28c060320a2479fe3/generators/app/templates/migrations/migrations/.keep -------------------------------------------------------------------------------- /generators/app/templates/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= projectName %>", 3 | "version": "0.1.0", 4 | "description": "<%= projectDescription %>", 5 | "engines": { 6 | "node": "<%= nodeVersion %>", 7 | "npm": "<%= npmVersion %>" 8 | }, 9 | "scripts": { 10 | "console": "node console.js",<% if(testing === 'mocha-chai') {%> 11 | "cover": "NODE_ENV=testing istanbul cover ./node_modules/mocha/bin/_mocha test/app.spec.js", 12 | "test": "NODE_ENV=testing ./node_modules/mocha/bin/_mocha --timeout 6000 --exit test/app.spec.js", 13 | "test-inspect": "NODE_ENV=testing node --inspect-brk ./node_modules/mocha/bin/_mocha test/app.spec.js",<%} if(testing === 'jest-supertest') {%> 14 | "cover": "npm run test -- --coverage", 15 | "test": "NODE_ENV=testing jest --runInBand --forceExit --detectOpenHandles", 16 | "test-inspect": "NODE_ENV=testing node --inspect --debug-brk jest",<%} if(optionalsFeatures.coveralls) {%> 17 | "coveralls": "npm run cover -- --report lcovonly && cat ./coverage/lcov.info | coveralls",<%}%> 18 | "eslint-check": "eslint --print-config .eslintrc.js --ignore-pattern ./.eslintrc.js | eslint-config-prettier-check", 19 | "lint": "eslint \"**/*.js\" --ignore-pattern ./.eslintrc.js", 20 | "lint-diff": "git diff --diff-filter=ACM --name-only --cached --relative | grep \\\\.js$ | xargs eslint", 21 | "lint-fix": "npm run lint -- --fix", 22 | "outdated": "npm outdated --depth 0", 23 | "pretest": "npm run lint", 24 | "start-dev": "nodemon --inspect server.js", 25 | "prestart-dev": "npm run lint",<% if(database && orm.sequelize) {%> 26 | "migrations": "sequelize db:migrate",<% if(!inTraining) {%> 27 | "migrations-test": "NODE_ENV=testing sequelize db:migrate",<%}}%> 28 | "start": "node server.js", 29 | "seed": "sequelize db:seed:all", 30 | "create-seed": "sequelize seed:generate --name", 31 | "create-migration": "sequelize migration:generate --name" 32 | }, 33 | "cacheDirectories": [ 34 | "node_modules" 35 | ], 36 | "main": "app.js", 37 | "author": "Wolox", 38 | "homepage": "<%= urlRepository %>", 39 | "license": "MIT", 40 | "repository": { 41 | "type": "git", 42 | "url": "<%= urlRepository %>.git" 43 | }, 44 | "bugs": { 45 | "url": "<%= urlRepository %>/issues", 46 | "email": "tls@wolox.com.ar" 47 | },<% if(testing === 'jest-supertest') {%> 48 | "jest": { 49 | "coverageThreshold": { 50 | "global": { 51 | "branches": 80, 52 | "functions": 80, 53 | "lines": 80, 54 | "statements": 80 55 | } 56 | }, 57 | "collectCoverageFrom": [ 58 | "**/*.js", 59 | "!**/console.js", 60 | "!**/node_modules/**", 61 | "!**/build/**", 62 | "!**/migrations/**", 63 | "!**/config/**", 64 | "!**/scripts/**" 65 | ], 66 | "setupFilesAfterEnv": [ 67 | "/test/setup.js" 68 | ], 69 | "testEnvironment": "node", 70 | "transform": { 71 | "^.+\\.js$": "babel-jest" 72 | } 73 | },<%}%> 74 | "dependencies": { 75 | "bcryptjs": "<%= bcryptjsVersion %>",<% if(database && orm.mongoose){%> 76 | "mongoose": "<%= mongooseVersion %>",<%} if(database && orm.mongoose && mongooseDialect === 'mongoDB') {%> 77 | "mongodb" : "<%= mongodbVersion %>", <%}%> 78 | "body-parser": "<%= bodyParserVersion %>",<% if(optionalsFeatures.cors) {%> 79 | "cors": "<%= corsVersion %>",<%}%> 80 | "express": "<%= expressVersion %>",<% if(optionalsFeatures.helmet) {%> 81 | "helmet": "<%= helmetVersion %>",<% 82 | }%> 83 | "jwt-simple": "<%= jwtSimpleVersion %>",<% if(optionalsFeatures.rollbar) {%> 84 | "rollbar": "<%= rollbarVersion %>",<%} if(database && orm.sequelize) {%> 85 | "sequelize": "<%= sequelizeVersion %>",<%} if(database && orm.sequelize && testing === 'jest-supertest') {%> 86 | "factory-girl": "<%= factoryGirlVersion %>",<%} if(database && orm.sequelize && sequelizeDialect === 'postgres') {%> 87 | "pg": "<%= pgVersion %>",<%} if(database && orm.sequelize && sequelizeDialect === 'mysql') {%> 88 | "mysql2": "<%= mysql2Version %>",<%} if(database && orm.sequelize && sequelizeDialect === 'sqlite') {%> 89 | "sqlite3": "<%= sqlite3Version %>",<%} if(database && orm.sequelize && sequelizeDialect === 'mssql') {%> 90 | "tedious": "<%= tediousVersion %>",<%}%> 91 | "umzug": "<%= umzugVersion %>", 92 | "express-wolox-logger": "<%= expressWoloxLoggerVersion %>", 93 | "axios": "<%= axiosVersion %>", 94 | "swagger-ui-express": "<%= swaggerUiExpressVersion %>" 95 | }, 96 | "devDependencies": { 97 | "babel": "<%= babelVersion %>", 98 | "babel-core": "<%= babelCoreVersion %>", 99 | "babel-eslint": "<%= babelEslintVersion %>",<% if(testing === 'jest-supertest') {%> 100 | "babel-jest": "<%= babelJestVersion %>", 101 | "jest": "<%= jestVersion %>", 102 | "supertest": "<%= supertestVersion %>",<%}%> 103 | "babel-preset-es2015": "<%= babelPresetEs2015Version %>",<% if(testing === 'mocha-chai') {%> 104 | "chai": "<%= chaiVersion %>", 105 | "chai-http": "<%= chaiHttpVersion %>",<%} if(optionalsFeatures.coveralls) {%> 106 | "coveralls": "<%= coverallsVersion %>",<%}%> 107 | "dotenv": "<%= dotenvVersion %>", 108 | "eslint": "<%= eslintVersion %>", 109 | "eslint-config-wolox": "<%= eslintConfigWoloxVersion %>", 110 | "eslint-config-wolox-node": "<%= eslintConfigWoloxNodeVersion %>", 111 | "eslint-plugin-import": "<%= eslintPluginImportVersion %>", 112 | "eslint-plugin-prettier": "<%= eslintPluginPrettierVersion %>", 113 | "husky": "<%= huskyVersion %>", 114 | "istanbul": "<%= istanbulVersion %>", 115 | "mocha": "<%= mochaVersion %>", 116 | "mocha-lcov-reporter": "<%= mochaLcovReporterVersion %>", 117 | "nodemon": "<%= nodemonVersion %>", 118 | "prettier": "<%= prettierVersion %>", 119 | "prettier-eslint": "<%= prettierEslintVersion %>",<% if(database && orm.sequelize) {%> 120 | "sequelize-cli": "<%= sequelizeCliVersion %>",<%}%> 121 | "prompt": "<%= promptVersion %>" 122 | }, 123 | "husky": { 124 | "hooks": { 125 | "pre-commit": "npm run lint-diff", 126 | "pre-push": "npm test" 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /generators/app/templates/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | [Change!] Describe your feature, problems you had, notes, improvements and others. 4 | 5 | ## Known Issues 6 | 7 | [Change!] List any known issue of the feature you are implementing. 8 | 9 | ## Trello Card 10 | 11 | [Change!] Link to the associated Trello card. 12 | -------------------------------------------------------------------------------- /generators/app/templates/server.ejs: -------------------------------------------------------------------------------- 1 | const app = require('./app');<% if(optionalsFeatures.rollbar) {%> 2 | const Rollbar = require('rollbar');<%} if(database && orm.sequelize) {%> 3 | const migrationsManager = require('./migrations');<%}%> 4 | const config = require('./config'); 5 | const logger = require('./app/logger'); 6 | 7 | const port = config.common.api.port || 8080; 8 | 9 | Promise.resolve() 10 | <% if(database && orm.sequelize) {%>.then(() => migrationsManager.check()) <%}%> 11 | .then(() => { 12 | <% if(optionalsFeatures.rollbar) {%> 13 | const rollbar = new Rollbar({ 14 | accessToken: config.common.rollbar.accessToken, 15 | enabled: !!config.common.rollbar.accessToken, 16 | environment: config.common.rollbar.environment || config.environment 17 | }); 18 | app.use(rollbar.errorHandler());<%}%> 19 | 20 | app.listen(port); 21 | 22 | logger.info(`Listening on port: ${port}`); 23 | }) 24 | .catch(logger.error); -------------------------------------------------------------------------------- /generators/app/templates/test/app.spec.ejs: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 'use strict'; 3 | 4 | const fs = require('fs'); 5 | const path = require('path');<% if(testing === 'mocha-chai') {%> 6 | const chaiHttp = require('chai-http'); 7 | const chai = require('chai');<%} if(database && orm.sequelize) {%> 8 | const models = require('../app/models');<%}%> 9 | <% if(testing === 'mocha-chai') {%> 10 | chai.use(chaiHttp);<%}%> 11 | <% if(database && orm.sequelize) {%> 12 | const tables = Object.values(models.sequelize.models); 13 | const truncateTable = model => 14 | model.destroy({ truncate: true, cascade: true, force: true, restartIdentity: true }); 15 | const truncateDatabase = () => Promise.all(tables.map(truncateTable)); 16 | beforeEach(done => { 17 | truncateDatabase() 18 | .then(() => done()); 19 | }); 20 | <%}%> 21 | // including all test files 22 | const normalizedPath = path.join(__dirname, '.'); 23 | 24 | const requireAllTestFiles = pathToSearch => { 25 | fs.readdirSync(pathToSearch).forEach(file => { 26 | if (fs.lstatSync(`${pathToSearch}/${file}`).isDirectory()) requireAllTestFiles(`${pathToSearch}/${file}`); 27 | else require(`${pathToSearch}/${file}`); 28 | }); 29 | }; 30 | 31 | requireAllTestFiles(normalizedPath); 32 | -------------------------------------------------------------------------------- /generators/app/templates/test/factory/factory_by_models.ejs: -------------------------------------------------------------------------------- 1 | const { factory } = require('factory-girl'); 2 | const Chance = require('chance'); 3 | const db = require('../../app/models'); 4 | 5 | const INTEGER = 'INTEGER'; 6 | const STRING = 'STRING'; 7 | const BOOLEAN = 'BOOLEAN'; 8 | const TEXT = 'TEXT'; 9 | const DATE = 'DATE'; 10 | const DATEONLY = 'DATEONLY'; 11 | const JSONTYPE = 'JSON'; 12 | const FLOAT = 'FLOAT'; 13 | 14 | const IS_NUMERIC = 'isNumeric'; 15 | const IS_ALPHANUMERIC = 'isAlphanumeric'; 16 | const IS_LOWERCASE = 'isLowercase'; 17 | const IS_UPPERCASE = 'isUppercase'; 18 | const IS_IP = 'isIP'; 19 | const MAX = 'max'; 20 | const MIN = 'min'; 21 | const LEN = 'len'; 22 | 23 | const modelsByName = Object.keys(db) 24 | .filter(modelName => modelName !== 'sequelize' && modelName !== 'Sequelize') 25 | .reduce((models, modelName) => { 26 | models[modelName] = db[modelName]; 27 | return models; 28 | }, {}); 29 | 30 | const generatorIntByValidations = (key, validate) => { 31 | if (key === LEN) { 32 | return factory.chance('integer', { min: validate.len[0], max: validate.len[1] }); 33 | } 34 | return { 35 | [MAX]: factory.chance('integer', { max: validate.max }), 36 | [MIN]: factory.chance('integer', { min: validate.min }) 37 | }[key]; 38 | }; 39 | 40 | const generatorStringByValidations = key => 41 | ({ 42 | [IS_ALPHANUMERIC]: factory.chance('string', { pool: 'abcde6546' }), 43 | [IS_NUMERIC]: factory.chance('string', { pool: '123456789' }), 44 | [IS_LOWERCASE]: factory.chance('string', { pool: 'abcdefghijklmnopqrstuvwxyz' }), 45 | [IS_UPPERCASE]: factory.chance('string', { pool: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' }), 46 | [IS_IP]: factory.chance('ip') 47 | }[key]); 48 | 49 | const generateStringByValidations = validate => 50 | Object.keys(validate).map(key => generatorStringByValidations(key))[0]; 51 | 52 | const generateIntByValidations = validate => 53 | Object.keys(validate).map(key => generatorIntByValidations(key, validate))[0]; 54 | 55 | const intValidation = (model, key) => { 56 | if (model.rawAttributes[key].unique) { 57 | return factory.sequence(`${model.name}.${key}`, n => n); 58 | } 59 | if (model.rawAttributes[key].validate) { 60 | const { validate } = model.rawAttributes[key]; 61 | return generateIntByValidations(validate) || factory.chance('integer'); 62 | } 63 | return factory.chance('integer'); 64 | }; 65 | 66 | const emailFactory = (model, key) => { 67 | if (model.rawAttributes[key].validate.isEmail) { 68 | if (model.rawAttributes[key].unique) { 69 | return factory.sequence(`${model.name}.email`, n => `dummy-user-${n}@wolox.com.ar`); 70 | } 71 | return factory.chance('email', { domain: 'wolox.com.ar' }); 72 | } 73 | return false; 74 | }; 75 | 76 | const stringValidation = (model, key) => { 77 | const chance = new Chance(); 78 | if (model.rawAttributes[key].validate) { 79 | const { validate } = model.rawAttributes[key]; 80 | if (emailFactory(model, key)) { 81 | return emailFactory(model, key); 82 | } 83 | if (validate.contains) { 84 | const word = chance.string({ pool: 'abcdefghi' }); 85 | return factory.sequence(`${model.name}`, n => `${validate.contains}${word}${n}`); 86 | } 87 | return generateStringByValidations(validate); 88 | } 89 | return factory.chance('word'); 90 | }; 91 | 92 | const randomJsonCreate = () => { 93 | const chance = new Chance(); 94 | const attributeName = chance.string({ pool: 'abcdefghi' }); 95 | const value = factory.chance('string', { pool: 'abcdefghi' }); 96 | return { 97 | [attributeName]: value 98 | }; 99 | }; 100 | 101 | const generatorByDatatype = (type, model, key) => { 102 | const chance = new Chance(); 103 | return { 104 | [INTEGER]: intValidation(model, key), 105 | [STRING]: stringValidation(model, key), 106 | [BOOLEAN]: factory.chance('bool'), 107 | [TEXT]: factory.chance('paragraph'), 108 | [DATE]: factory.chance('date', { string: true }), 109 | [DATEONLY]: new Date(chance.date({ string: true })), 110 | [JSONTYPE]: randomJsonCreate(), 111 | [FLOAT]: factory.chance('floating') 112 | }[type]; 113 | }; 114 | 115 | const generateByDatatypes = (model, key, attribute, predeterminatedValue = false) => { 116 | if (predeterminatedValue && key === predeterminatedValue.attribute) { 117 | return predeterminatedValue.value; 118 | } 119 | if (model.rawAttributes[key].defaultValue !== undefined) { 120 | return model.rawAttributes[key].defaultValue; 121 | } 122 | return generatorByDatatype(attribute[key], model, key) || factory.chance('word'); 123 | }; 124 | 125 | const buildByModel = (model, predeterminatedValue = false) => { 126 | const attributeType = {}; 127 | const factorCreated = {}; 128 | for (const key in model.rawAttributes) { 129 | if (key) { 130 | attributeType[key] = model.rawAttributes[key].type.key; 131 | if (!model.rawAttributes[key].primaryKey) { 132 | factorCreated[key] = generateByDatatypes(model, key, attributeType, predeterminatedValue); 133 | } 134 | } 135 | } 136 | return factorCreated; 137 | }; 138 | 139 | exports.factoryByModel = (modelRequired, predeterminatedValue = false) => { 140 | const modelRequested = modelsByName[modelRequired]; 141 | const factorCreated = buildByModel(modelRequested, predeterminatedValue); 142 | return factory.define(modelRequested.name, db[modelRequested.name], factorCreated); 143 | }; 144 | 145 | exports.factoryAllModels = () => { 146 | const models = modelsByName; 147 | return Object.keys(models).forEach(model => this.factoryByModel(model)); 148 | }; 149 | 150 | exports.factoryWithCustomizedValue = (modelRequired, attribute, value) => { 151 | const predeterminatedValue = { 152 | attribute, 153 | value 154 | }; 155 | return this.factoryByModel(modelRequired, predeterminatedValue); 156 | }; 157 | -------------------------------------------------------------------------------- /generators/app/templates/test/setup.js: -------------------------------------------------------------------------------- 1 | const models = require('../app/models'); 2 | 3 | const tables = Object.values(models.sequelize.models); 4 | 5 | const truncateTable = model => 6 | model.destroy({ truncate: true, cascade: true, force: true, restartIdentity: true }); 7 | 8 | const truncateDatabase = () => Promise.all(tables.map(truncateTable)); 9 | 10 | global.beforeEach(async () => { 11 | await truncateDatabase(); 12 | }); 13 | -------------------------------------------------------------------------------- /generators/app/utils.js: -------------------------------------------------------------------------------- 1 | const { flatten } = require('lodash'); 2 | const { URL_REGEX, VERSION_REGEX, APP_NAME_REGEX } = require('./constants'); 3 | 4 | exports.checkboxReducer = values => 5 | values.reduce((answer, optional) => { 6 | answer[optional] = true; 7 | return answer; 8 | }, {}); 9 | 10 | exports.flattenPrompts = prompts => 11 | prompts.reduce((listPrompts, actualPrompt) => { 12 | listPrompts.push(actualPrompt); 13 | if (actualPrompt.promptsNegative || actualPrompt.promptsPositive || actualPrompt.chosen) { 14 | const newPrompts = []; 15 | const generateNewPrompt = (prompt, positive, hasSelected = false) => ({ 16 | ...prompt, 17 | when: answers => { 18 | if (hasSelected && answers[actualPrompt.name] && answers[actualPrompt.name][hasSelected]) { 19 | return answers[actualPrompt.name][hasSelected]; 20 | } 21 | return ( 22 | (actualPrompt.when ? actualPrompt.when(answers) : true) && 23 | answers[actualPrompt.name] === positive && 24 | (prompt.when ? prompt.when(answers) : true) 25 | ); 26 | } 27 | }); 28 | 29 | if (actualPrompt.promptsNegative) { 30 | newPrompts.push( 31 | ...actualPrompt.promptsNegative.map(promptNegative => generateNewPrompt(promptNegative, false)) 32 | ); 33 | } 34 | if (actualPrompt.promptsPositive) { 35 | newPrompts.push( 36 | ...actualPrompt.promptsPositive.map(promptPositive => generateNewPrompt(promptPositive, true)) 37 | ); 38 | } 39 | if (actualPrompt.chosen) { 40 | newPrompts.push( 41 | ...flatten( 42 | actualPrompt.chosen.map(seqOption => { 43 | const lift = seqOption.prompts; 44 | return lift.map(prom => generateNewPrompt(prom, true, seqOption.condition)); 45 | }) 46 | ) 47 | ); 48 | } 49 | listPrompts.push(...exports.flattenPrompts(newPrompts)); 50 | } 51 | return listPrompts; 52 | }, []); 53 | 54 | const validateRegex = (regex, message) => value => regex.test(value) || message; 55 | 56 | exports.validateUrl = value => !value || validateRegex(URL_REGEX, 'Please enter a valid url')(value); 57 | exports.validateVersionNumber = validateRegex( 58 | VERSION_REGEX, 59 | 'Please enter a valid version number (e.g. 1.2.3)' 60 | ); 61 | exports.validateAppName = validateRegex(APP_NAME_REGEX, 'Please enter a valid app name (alphanumeric)'); 62 | -------------------------------------------------------------------------------- /img/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wolox/express-js-bootstrap/0dcd68b8717f30e9841215e28c060320a2479fe3/img/demo.gif -------------------------------------------------------------------------------- /img/demo.yml: -------------------------------------------------------------------------------- 1 | # The configurations that used for the recording, feel free to edit them 2 | config: 3 | 4 | # Specify a command to be executed 5 | # like `/bin/bash -l`, `ls`, or any other commands 6 | # the default is bash for Linux 7 | # or powershell.exe for Windows 8 | command: zsh 9 | 10 | # Specify the current working directory path 11 | # the default is the current working directory path 12 | cwd: /demo 13 | 14 | # Export additional ENV variables 15 | env: 16 | recording: true 17 | 18 | # Explicitly set the number of columns 19 | # or use `auto` to take the current 20 | # number of columns of your shell 21 | cols: 96 22 | 23 | # Explicitly set the number of rows 24 | # or use `auto` to take the current 25 | # number of rows of your shell 26 | rows: 20 27 | 28 | # Amount of times to repeat GIF 29 | # If value is -1, play once 30 | # If value is 0, loop indefinitely 31 | # If value is a positive number, loop n times 32 | repeat: 0 33 | 34 | # Quality 35 | # 1 - 100 36 | quality: 100 37 | 38 | # Delay between frames in ms 39 | # If the value is `auto` use the actual recording delays 40 | frameDelay: auto 41 | 42 | # Maximum delay between frames in ms 43 | # Ignored if the `frameDelay` isn't set to `auto` 44 | # Set to `auto` to prevent limiting the max idle time 45 | maxIdleTime: 2000 46 | 47 | # The surrounding frame box 48 | # The `type` can be null, window, floating, or solid` 49 | # To hide the title use the value null 50 | # Don't forget to add a backgroundColor style with a null as type 51 | frameBox: 52 | type: floating 53 | title: null 54 | style: 55 | border: 0px black solid 56 | # boxShadow: none 57 | # margin: 0px 58 | 59 | # Add a watermark image to the rendered gif 60 | # You need to specify an absolute path for 61 | # the image on your machine or a URL, and you can also 62 | # add your own CSS styles 63 | watermark: 64 | imagePath: null 65 | style: 66 | position: absolute 67 | right: 15px 68 | bottom: 15px 69 | width: 100px 70 | opacity: 0.9 71 | 72 | # Cursor style can be one of 73 | # `block`, `underline`, or `bar` 74 | cursorStyle: block 75 | 76 | # Font family 77 | # You can use any font that is installed on your machine 78 | # in CSS-like syntax 79 | fontFamily: "Monaco, Lucida Console, Ubuntu Mono, Monospace" 80 | 81 | # The size of the font 82 | fontSize: 12 83 | 84 | # The height of lines 85 | lineHeight: 1 86 | 87 | # The spacing between letters 88 | letterSpacing: 0 89 | 90 | # Theme 91 | theme: 92 | background: "transparent" 93 | foreground: "#afafaf" 94 | cursor: "#c7c7c7" 95 | black: "#232628" 96 | red: "#fc4384" 97 | green: "#5FC245" 98 | yellow: "#ffa727" 99 | blue: "#75dff2" 100 | magenta: "#ae89fe" 101 | cyan: "#708387" 102 | white: "#d5d5d0" 103 | brightBlack: "#626566" 104 | brightRed: "#ff7fac" 105 | brightGreen: "#c8ed71" 106 | brightYellow: "#ebdf86" 107 | brightBlue: "#75dff2" 108 | brightMagenta: "#ae89fe" 109 | brightCyan: "#b1c6ca" 110 | brightWhite: "#f9f9f4" 111 | 112 | # Records, feel free to edit them 113 | records: 114 | - delay: 100 115 | content: "\e[1m\e[7m%\e[27m\e[1m\e[0m \r \r\e]2;wolox@wolox: ~/test\a\e]1;~/test\a" 116 | - delay: 39 117 | content: "\r\e[0m\e[27m\e[24m\e[J\e[35mwolox\e[00m\e[36m@\e[00m\e[33mwolox\e[00m\e[31m:\e[00m\e[36m~/test\e[00m\e[31m|\e[00m\e[36m⇒\e[00m \e[K\e[?1h\e=\e[?2004h" 118 | - delay: 80 119 | content: 'y' 120 | - delay: 50 121 | content: "\byo" 122 | - delay: 50 123 | content: ' ' 124 | - delay: 50 125 | content: w 126 | - delay: 50 127 | content: '-' 128 | - delay: 50 129 | content: e 130 | - delay: 50 131 | content: x 132 | - delay: 50 133 | content: p 134 | - delay: 50 135 | content: r 136 | - delay: 50 137 | content: e 138 | - delay: 50 139 | content: s 140 | - delay: 50 141 | content: s 142 | - delay: 50 143 | content: '-' 144 | - delay: 50 145 | content: j 146 | - delay: 50 147 | content: s 148 | - delay: 50 149 | content: "\e[?1l\e>\e[?2004l\r\r\n\e]2;yo w-express-js\a\e]1;yo\a" 150 | - delay: 80 151 | content: "\r\n\r\n \e[32m███\e[39m\e[32m╗\e[39m\e[32m ██\e[39m\e[32m╗\e[39m \e[32m██████\e[39m\e[32m╗ \e[39m \e[32m██████\e[39m\e[32m╗ \e[39m \e[32m███████\e[39m\e[32m╗\e[39m \e[32m ██\e[39m\e[32m╗\e[39m \e[32m███████\e[39m\e[32m╗\e[39m \r\n \e[32m████\e[39m\e[32m╗\e[39m\e[32m ██\e[39m\e[32m║\e[39m \e[32m██\e[39m\e[32m╔═══\e[39m\e[32m██\e[39m\e[32m╗\e[39m \e[32m██\e[39m\e[32m╔══\e[39m\e[32m██\e[39m\e[32m╗\e[39m \e[32m██\e[39m\e[32m╔════╝\e[39m \e[32m ██\e[39m\e[32m║\e[39m \e[32m██\e[39m\e[32m╔════╝\e[39m \r\n \e[32m██\e[39m\e[32m╔\e[39m\e[32m██\e[39m\e[32m╗\e[39m\e[32m ██\e[39m\e[32m║\e[39m \e[32m██\e[39m\e[32m║\e[39m\e[32m ██\e[39m\e[32m║\e[39m \e[32m██\e[39m\e[32m║\e[39m\e[32m ██\e[39m\e[32m║\e[39m \e[32m█████\e[39m\e[32m╗ \e[39m \e[32m ██\e[39m\e[32m║\e[39m \e[32m███████\e[39m\e[32m╗\e[39m \r\n \e[32m██\e[39m\e[32m║╚\e[39m\e[32m██\e[39m\e[32m╗\e[39m\e[32m██\e[39m\e[32m║\e[39m \e[32m██\e[39m\e[32m║\e[39m\e[32m ██\e[39m\e[32m║\e[39m \e[32m██\e[39m\e[32m║\e[39m\e[32m ██\e[39m\e[32m║\e[39m \e[32m██\e[39m\e[32m╔══╝ \e[39m \e[32m██ ██\e[39m\e[32m║\e[39m \e[32m╚════\e[39m\e[32m██\e[39m\e[32m║\e[39m \r\n \e[32m██\e[39m\e[32m║ ╚\e[39m\e[32m████\e[39m\e[32m║\e[39m \e[32m╚\e[39m\e[32m██████\e[39m\e[32m╔╝\e[39m \e[32m██████\e[39m\e[32m╔╝\e[39m \e[32m███████\e[39m\e[32m╗\e[39m \e[32m╚\e[39m\e[32m█████\e[39m\e[32m╔╝\e[39m \e[32m███████\e[39m\e[32m║\e[39m \r\n \e[32m╚═╝ ╚═══╝\e[39m \e[32m ╚═════╝ \e[39m \e[32m╚═════╝ \e[39m \e[32m╚══════╝\e[39m \e[32m ╚════╝ \e[39m \e[32m╚══════╝\e[39m \r\n\r\n \e[32m██\e[39m\e[32m╗\e[39m\e[32m ██\e[39m\e[32m╗\e[39m \e[32m██\e[39m\e[32m╗\e[39m \e[32m██████\e[39m\e[32m╗\e[39m \e[32m██\e[39m\e[32m╗\e[39m\e[32m ██\e[39m\e[32m╗\e[39m \e[32m██████\e[39m\e[32m╗ \e[39m \e[32m███████\e[39m\e[32m╗\e[39m \e[32m███████\e[39m\e[32m╗\e[39m \r\n \e[32m██\e[39m\e[32m║\e[39m\e[32m ██\e[39m\e[32m╔╝\e[39m \e[32m██\e[39m\e[32m║\e[39m \e[32m██\e[39m\e[32m╔════╝\e[39m \e[32m██\e[39m\e[32m║\e[39m\e[32m ██\e[39m\e[32m╔╝\e[39m \e[32m██\e[39m\e[32m╔═══\e[39m\e[32m██\e[39m\e[32m╗\e[39m \e[32m██\e[39m\e[32m╔════╝\e[39m \e[32m██\e[39m\e[32m╔════╝\e[39m \r\n \e[32m█████\e[39m\e[32m╔╝ \e[39m \e[32m██\e[39m\e[32m║\e[39m \e[32m██\e[39m\e[32m║ \e[39m \e[32m█████\e[39m\e[32m╔╝ \e[39m \e[32m██\e[39m\e[32m║\e[39m\e[32m ██\e[39m\e[32m║\e[39m \e[32m█████\e[39m\e[32m╗ \e[39m \e[32m█████\e[39m\e[32m╗ \e[39m \r\n \e[32m██\e[39m\e[32m╔═\e[39m\e[32m██\e[39m\e[32m╗ \e[39m \e[32m██\e[39m\e[32m║\e[39m \e[32m██\e[39m\e[32m║ \e[39m \e[32m██\e[39m\e[32m╔═\e[39m\e[32m██\e[39m\e[32m╗ \e[39m \e[32m██\e[39m\e[32m║\e[39m\e[32m ██\e[39m\e[32m║\e[39m \e[32m██\e[39m\e[32m╔══╝ \e[39m \e[32m██\e[39m\e[32m╔══╝ \e[39m \r\n \e[32m██\e[39m\e[32m║\e[39m\e[32m ██\e[39m\e[32m╗\e[39m \e[32m██\e[39m\e[32m║\e[39m \e[32m╚\e[39m\e[32m██████\e[39m\e[32m╗\e[39m \e[32m██\e[39m\e[32m║\e[39m\e[32m ██\e[39m\e[32m╗\e[39m \e[32m╚\e[39m\e[32m██████\e[39m\e[32m╔╝\e[39m \e[32m██\e[39m\e[32m║ \e[39m \e[32m██\e[39m\e[32m║ \e[39m \r\n \e[32m╚═╝ ╚═╝\e[39m \e[32m╚═╝\e[39m \e[32m ╚═════╝\e[39m \e[32m╚═╝ ╚═╝\e[39m \e[32m ╚═════╝ \e[39m \e[32m╚═╝ \e[39m \e[32m╚═╝ \e[39m \r\n\r\n\r\n\e[?25l\e[36m⠋\e[39m Checking if git is installed" 152 | - delay: 7 153 | content: "\e[2K\e[1G\e[?25h\e[32m✔\e[39m Checking if git is installed\r\n\e[?25l\e[36m⠋\e[39m Checking if npm is installed" 154 | - delay: 81 155 | content: "\e[2K\e[1G\e[36m⠙\e[39m Checking if npm is installed" 156 | - delay: 80 157 | content: "\e[2K\e[1G\e[36m⠹\e[39m Checking if npm is installed" 158 | - delay: 34 159 | content: "\e[2K\e[1G\e[?25h\e[32m✔\e[39m Checking if npm is installed\r\n" 160 | - delay: 12 161 | content: "\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0m\e[40D\e[40C" 162 | - delay: 200 163 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mh\e[41D\e[41C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mht\e[42D\e[42C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhtt\e[43D\e[43C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttp\e[44D\e[44C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps\e[45D\e[45C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps:\e[46D\e[46C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps:/\e[47D\e[47C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://\e[48D\e[48C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://g\e[49D\e[49C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://gi\e[50D\e[50C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://git\e[51D\e[51C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://gith\e[52D\e[52C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://githu\e[53D\e[53C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github\e[54D\e[54C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.\e[55D\e[55C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.c\e[56D\e[56C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.co\e[57D\e[57C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com\e[58D\e[58C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/\e[59D\e[59C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/m\e[60D\e[60C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/mp\e[61D\e[61C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/mpi\e[62D\e[62C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/mpic\e[63D\e[63C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/mpico\e[64D\e[64C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/mpicol\e[65D\e[65C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/mpicoll\e[66D\e[66C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox\e[67D\e[67C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-\e[68D\e[68C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-w\e[69D\e[69C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wo\e[70D\e[70C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wol\e[71D\e[71C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolo\e[72D\e[72C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox\e[73D\e[73C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/\e[74D\e[74C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/t\e[75D\e[75C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/te\e[76D\e[76C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/tes\e[77D\e[77C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/test\e[78D\e[78C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/test-\e[79D\e[79C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/test-k\e[80D\e[80C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/test-ki\e[81D\e[81C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/test-kic\e[82D\e[82C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/test-kick\e[83D\e[83C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/test-kicko\e[84D\e[84C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/test-kickof\e[85D\e[85C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/test-kickoff\e[86D\e[86C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/test-kickoff-\e[87D\e[87C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/test-kickoff-r\e[88D\e[88C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/test-kickoff-re\e[89D\e[89C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/test-kickoff-rep\e[90D\e[90C\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0mhttps://github.com/wolox-wolox/test-kickoff-repo\e[91D\e[91C" 164 | - delay: 712 165 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter git repository for this project\e[22m\e[0m \e[0m\e[36mhttps://github.com/wolox-wolox/test-kickoff-repo\e[39m\e[91D\e[91C\r\n\e[32m?\e[39m \e[1mAre you in WTraining ?\e[22m\e[0m \e[0m\e[2m(Y/n) \e[22m\e[31D\e[31C" 166 | - delay: 200 167 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mAre you in WTraining ?\e[22m\e[0m \e[0m\e[2m(Y/n) \e[22mn\e[32D\e[32C" 168 | - delay: 275 169 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mAre you in WTraining ?\e[22m\e[0m \e[0m\e[36mNo\e[39m\e[27D\e[27C\r\n\e[32m?\e[39m \e[1mEnter Project Name\e[22m\e[0m \e[0m\e[21D\e[21C" 170 | - delay: 201 171 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Name\e[22m\e[0m \e[0mt\e[22D\e[22C" 172 | - delay: 68 173 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Name\e[22m\e[0m \e[0mte\e[23D\e[23C" 174 | - delay: 148 175 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Name\e[22m\e[0m \e[0mtes\e[24D\e[24C" 176 | - delay: 119 177 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Name\e[22m\e[0m \e[0mtest\e[25D\e[25C" 178 | - delay: 200 179 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Name\e[22m\e[0m \e[0m\e[36mtest\e[39m\e[25D\e[25C\r\n\e[32m?\e[39m \e[1mEnter Project Description\e[22m\e[0m \e[0m\e[2m(test) \e[22m\e[35D\e[35C" 180 | - delay: 200 181 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Description\e[22m\e[0m \e[0mT\e[29D\e[29C" 182 | - delay: 258 183 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Description\e[22m\e[0m \e[0mTe\e[30D\e[30C" 184 | - delay: 171 185 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Description\e[22m\e[0m \e[0mTes\e[31D\e[31C" 186 | - delay: 129 187 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Description\e[22m\e[0m \e[0mTest\e[32D\e[32C" 188 | - delay: 120 189 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Description\e[22m\e[0m \e[0mTest \e[33D\e[33C" 190 | - delay: 356 191 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Description\e[22m\e[0m \e[0mTest p\e[34D\e[34C" 192 | - delay: 121 193 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Description\e[22m\e[0m \e[0mTest pr\e[35D\e[35C" 194 | - delay: 99 195 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Description\e[22m\e[0m \e[0mTest pro\e[36D\e[36C" 196 | - delay: 294 197 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Description\e[22m\e[0m \e[0mTest proj\e[37D\e[37C" 198 | - delay: 76 199 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Description\e[22m\e[0m \e[0mTest proje\e[38D\e[38C" 200 | - delay: 204 201 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Description\e[22m\e[0m \e[0mTest projec\e[39D\e[39C" 202 | - delay: 72 203 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Description\e[22m\e[0m \e[0mTest project\e[40D\e[40C" 204 | - delay: 529 205 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Project Description\e[22m\e[0m \e[0m\e[36mTest project\e[39m\e[40D\e[40C\r\n\e[32m?\e[39m \e[1mEnter NodeJS Version\e[22m\e[0m \e[0m\e[2m(10.14.1) \e[22m\e[33D\e[33C" 206 | - delay: 200 207 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter NodeJS Version\e[22m\e[0m \e[0m\e[36m10.14.1\e[39m\e[30D\e[30C\r\n\e[32m?\e[39m \e[1mEnter NPM Version\e[22m\e[0m \e[0m\e[2m(6.4.1) \e[22m\e[28D\e[28C" 208 | - delay: 373 209 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter NPM Version\e[22m\e[0m \e[0m\e[36m6.4.1\e[39m\e[25D\e[25C\r\n\e[32m?\e[39m \e[1mDo you want to use Sequelize as your ORM?\e[22m\e[0m \e[0m\e[2m(Y/n) \e[22m\e[50D\e[50C" 210 | - delay: 200 211 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mDo you want to use Sequelize as your ORM?\e[22m\e[0m \e[0m\e[2m(Y/n) \e[22mY\e[51D\e[51C" 212 | - delay: 363 213 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mDo you want to use Sequelize as your ORM?\e[22m\e[0m \e[0m\e[36mYes\e[39m\e[47D\e[47C\r\n\e[32m?\e[39m \e[1mEnter Sequelize Version\e[22m\e[0m \e[0m\e[2m(4.34.0) \e[22m\e[35D\e[35C" 214 | - delay: 200 215 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mEnter Sequelize Version\e[22m\e[0m \e[0m\e[36m4.34.0\e[39m\e[32D\e[32C\r\n\e[?25l\e[32m?\e[39m \e[1mEnter Database Dialect\e[22m\e[0m \e[0m\e[2m(Use arrow keys)\e[22m\r\n mysql \r\n sqlite \r\n\e[36m❯ postgres\e[39m \r\n mssql \e[8D\e[8C" 216 | - delay: 220 217 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mEnter Database Dialect\e[22m\e[0m \e[0m\e[36mpostgres\e[39m\e[33D\e[33C\r\n\e[?25h\e[?25l\e[32m?\e[39m \e[1mSelect Deploy strategy for your project\e[22m\e[0m \e[0m(Press \e[36m\e[1m\e[22m\e[39m to select, \e[36m\e[1m\e[22m\e[39m to toggle all, \e[36m\e[1m\e[22m\e[39m to in\r\nvert selection)\r\n\e[36m❯◯ aws\e[39m\r\n ◯ heroku\e[9D\e[9C" 218 | - delay: 930 219 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mSelect Deploy strategy for your project\e[22m\e[0m \e[0m\r\n\e[36m❯\e[32m◉\e[36m aws\e[39m\r\n ◯ heroku\e[9D\e[9C" 220 | - delay: 215 221 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mSelect Deploy strategy for your project\e[22m\e[0m \e[0m\r\n \e[32m◉\e[39m aws\r\n\e[36m❯◯ heroku\e[39m\e[9D\e[9C" 222 | - delay: 187 223 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mSelect Deploy strategy for your project\e[22m\e[0m \e[0m\r\n \e[32m◉\e[39m aws\r\n\e[36m❯\e[32m◉\e[36m heroku\e[39m\e[9D\e[9C" 224 | - delay: 262 225 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mSelect Deploy strategy for your project\e[22m\e[0m \e[0m\e[36maws, heroku\e[39m\e[53D\e[53C\r\n\e[?25h\e[32m?\e[39m \e[1mAre you going to use docker for the deploy?\e[22m\e[0m \e[0m\e[2m(Y/n) \e[22m\e[52D\e[52C" 226 | - delay: 200 227 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mAre you going to use docker for the deploy?\e[22m\e[0m \e[0m\e[2m(Y/n) \e[22mY\e[53D\e[53C" 228 | - delay: 546 229 | content: "\e[2K\e[G\e[32m?\e[39m \e[1mAre you going to use docker for the deploy?\e[22m\e[0m \e[0m\e[36mYes\e[39m\e[49D\e[49C\r\n\e[?25l\e[32m?\e[39m \e[1mChoose optionals features for your project\e[22m\e[0m \e[0m(Press \e[36m\e[1m\e[22m\e[39m to select, \e[36m\e[1m\e[22m\e[39m to toggle all, \e[36m\e[1m\e[22m\e[39m to\r\n invert selection)\r\n\e[36m❯◯ coveralls\e[39m\r\n ◯ rollbar\r\n ◯ cors\e[7D\e[7C" 230 | - delay: 200 231 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mChoose optionals features for your project\e[22m\e[0m \e[0m\r\n\e[36m❯\e[32m◉\e[36m coveralls\e[39m\r\n ◯ rollbar\r\n ◯ cors\e[7D\e[7C" 232 | - delay: 215 233 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mChoose optionals features for your project\e[22m\e[0m \e[0m\r\n \e[32m◉\e[39m coveralls\r\n\e[36m❯◯ rollbar\e[39m\r\n ◯ cors\e[7D\e[7C" 234 | - delay: 200 235 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mChoose optionals features for your project\e[22m\e[0m \e[0m\r\n \e[32m◉\e[39m coveralls\r\n\e[36m❯\e[32m◉\e[36m rollbar\e[39m\r\n ◯ cors\e[7D\e[7C" 236 | - delay: 139 237 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mChoose optionals features for your project\e[22m\e[0m \e[0m\r\n \e[32m◉\e[39m coveralls\r\n \e[32m◉\e[39m rollbar\r\n\e[36m❯◯ cors\e[39m\e[7D\e[7C" 238 | - delay: 171 239 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mChoose optionals features for your project\e[22m\e[0m \e[0m\r\n \e[32m◉\e[39m coveralls\r\n \e[32m◉\e[39m rollbar\r\n\e[36m❯\e[32m◉\e[36m cors\e[39m\e[7D\e[7C" 240 | - delay: 333 241 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mChoose optionals features for your project\e[22m\e[0m \e[0m\e[36mcoveralls, rollbar, cors\e[39m\e[69D\e[69C\r\n\e[?25h\e[?25l\e[32m?\e[39m \e[1mChoose CI for your project\e[22m\e[0m \e[0m\e[2m(Use arrow keys)\e[22m\r\n\e[36m❯ jenkins\e[39m \r\n travis \e[9D\e[9C" 242 | - delay: 200 243 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mChoose CI for your project\e[22m\e[0m \e[0m\r\n jenkins \r\n\e[36m❯ travis\e[39m \e[9D\e[9C" 244 | - delay: 364 245 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mChoose CI for your project\e[22m\e[0m \e[0m\r\n\e[36m❯ jenkins\e[39m \r\n travis \e[9D\e[9C" 246 | - delay: 200 247 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mChoose CI for your project\e[22m\e[0m \e[0m\r\n jenkins \r\n\e[36m❯ travis\e[39m \e[9D\e[9C" 248 | - delay: 200 249 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mChoose CI for your project\e[22m\e[0m \e[0m\e[36mtravis\e[39m\e[35D\e[35C\r\n\e[?25h\e[?25l\e[32m?\e[39m \e[1mChoose your testing option\e[22m\e[0m \e[0m\e[2m(Use arrow keys)\e[22m\r\n\e[36m❯ mocha-chai\e[39m \r\n jest-supertest \e[17D\e[17C" 250 | - delay: 200 251 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mChoose your testing option\e[22m\e[0m \e[0m\r\n mocha-chai \r\n\e[36m❯ jest-supertest\e[39m \e[17D\e[17C" 252 | - delay: 241 253 | content: "\e[2K\e[1A\e[2K\e[1A\e[2K\e[G\e[32m?\e[39m \e[1mChoose your testing option\e[22m\e[0m \e[0m\e[36mjest-supertest\e[39m\e[43D\e[43C\r\n\e[?25h" 254 | - delay: 5 255 | content: "\e[?25l\e[36m⠋\e[39m Cloning repository from https://github.com/wolox-wolox/test-kickoff-repo" 256 | - delay: 81 257 | content: "\e[2K\e[1G\e[36m⠙\e[39m Cloning repository from https://github.com/wolox-wolox/test-kickoff-repo" 258 | - delay: 83 259 | content: "\e[2K\e[1G\e[36m⠹\e[39m Cloning repository from https://github.com/wolox-wolox/test-kickoff-repo" 260 | - delay: 81 261 | content: "\e[2K\e[1G\e[36m⠸\e[39m Cloning repository from https://github.com/wolox-wolox/test-kickoff-repo" 262 | - delay: 85 263 | content: "\e[2K\e[1G\e[36m⠼\e[39m Cloning repository from https://github.com/wolox-wolox/test-kickoff-repo" 264 | - delay: 82 265 | content: "\e[2K\e[1G\e[36m⠴\e[39m Cloning repository from https://github.com/wolox-wolox/test-kickoff-repo" 266 | - delay: 81 267 | content: "\e[2K\e[1G\e[36m⠦\e[39m Cloning repository from https://github.com/wolox-wolox/test-kickoff-repo" 268 | - delay: 83 269 | content: "\e[2K\e[1G\e[36m⠧\e[39m Cloning repository from https://github.com/wolox-wolox/test-kickoff-repo" 270 | - delay: 83 271 | content: "\e[2K\e[1G\e[36m⠇\e[39m Cloning repository from https://github.com/wolox-wolox/test-kickoff-repo" 272 | - delay: 81 273 | content: "\e[2K\e[1G\e[36m⠏\e[39m Cloning repository from https://github.com/wolox-wolox/test-kickoff-repo" 274 | - delay: 80 275 | content: "\e[2K\e[1G\e[36m⠋\e[39m Cloning repository from https://github.com/wolox-wolox/test-kickoff-repo" 276 | - delay: 81 277 | content: "\e[2K\e[1G\e[36m⠙\e[39m Cloning repository from https://github.com/wolox-wolox/test-kickoff-repo" 278 | - delay: 81 279 | content: "\e[2K\e[1G\e[36m⠹\e[39m Cloning repository from https://github.com/wolox-wolox/test-kickoff-repo\e[2K\e[1G\e[?25h\e[32m✔\e[39m Cloning repository from https://github.com/wolox-wolox/test-kickoff-repo\r\n" 280 | - delay: 140 281 | content: "\e[32m create\e[39m test/Procfile\r\n\e[32m create\e[39m test/Dockerfile\r\n\e[32m create\e[39m test/Dockerrun.aws.json\r\n\e[32m create\e[39m test/.travis.yml\r\n\e[32m create\e[39m test/.sequelizerc\r\n\e[33m force\e[39m test/README.md\r\n\e[32m create\e[39m test/pull_request_template.md\r\n\e[32m create\e[39m test/package.json\r\n\e[32m create\e[39m test/LICENSE.md\r\n\e[32m create\e[39m test/console.js\r\n\e[32m create\e[39m test/app.js\r\n\e[32m create\e[39m test/server.js\r\n\e[32m create\e[39m test/.nvmrc\r\n\e[32m create\e[39m test/.gitignore\r\n\e[32m create\e[39m test/.eslintrc.js\r\n\e[32m create\e[39m test/.eslintignore\r\n\e[32m create\e[39m test/migrations/index.js\r\n\e[32m create\e[39m test/migrations/migrations/.keep\r\n\e[32m create\e[39m test/config/db.js\r\n\e[32m create\e[39m test/test/app.spec.js\r\n\e[32m create\e[39m test/docs/.keep\r\n\e[32m create\e[39m test/app/routes.js\r\n\e[32m create\e[39m test/app/logger/index.js\r\n\e[32m create\e[39m test/config/development.js\r\n\e[32m create\e[39m test/config/production.js\r\n\e[32m create\e[39m test/config/testing.js\r\n\e[32m create\e[39m test/config/index.js\r\n\e[32m create\e[39m test/app/errors.js\r\n" 282 | - delay: 21 283 | content: "\e[32m create\e[39m test/app/models/index.js\r\n\e[32m create\e[39m test/app/services/.keep\r\n\e[32m create\e[39m test/app/controllers/healthCheck.js\r\n\e[32m create\e[39m test/app/middlewares/errors.js\r\n\e[?25l\e[36m⠋\e[39m Installing dependencies" 284 | - delay: 83 285 | content: "\e[2K\e[1G\e[36m⠙\e[39m Installing dependencies" 286 | - delay: 85 287 | content: "\e[2K\e[1G\e[36m⠹\e[39m Installing dependencies" 288 | - delay: 80 289 | content: "\e[2K\e[1G\e[36m⠸\e[39m Installing dependencies" 290 | - delay: 84 291 | content: "\e[2K\e[1G\e[36m⠼\e[39m Installing dependencies" 292 | - delay: 81 293 | content: "\e[2K\e[1G\e[36m⠴\e[39m Installing dependencies" 294 | - delay: 81 295 | content: "\e[2K\e[1G\e[36m⠦\e[39m Installing dependencies" 296 | - delay: 81 297 | content: "\e[2K\e[1G\e[36m⠧\e[39m Installing dependencies" 298 | - delay: 85 299 | content: "\e[2K\e[1G\e[36m⠇\e[39m Installing dependencies" 300 | - delay: 81 301 | content: "\e[2K\e[1G\e[?25h\e[32m✔\e[39m Installing dependencies\r\n\e[?25l\e[36m⠋\e[39m Running linter" 302 | - delay: 81 303 | content: "\e[2K\e[1G\e[36m⠙\e[39m Running linter" 304 | - delay: 82 305 | content: "\e[2K\e[1G\e[36m⠹\e[39m Running linter" 306 | - delay: 82 307 | content: "\e[2K\e[1G\e[36m⠸\e[39m Running linter" 308 | - delay: 81 309 | content: "\e[2K\e[1G\e[36m⠼\e[39m Running linter" 310 | - delay: 80 311 | content: "\e[2K\e[1G\e[36m⠴\e[39m Running linter" 312 | - delay: 83 313 | content: "\e[2K\e[1G\e[36m⠦\e[39m Running linter" 314 | - delay: 9 315 | content: "\e[2K\e[1G\e[?25h\e[32m✔\e[39m Running linter\r\n\e[?25l\e[36m⠋\e[39m Creating branch kickoff" 316 | - delay: 24 317 | content: "\e[2K\e[1G\e[?25h\e[32m✔\e[39m Creating branch kickoff\r\n\e[?25l\e[36m⠋\e[39m Add changes to git" 318 | - delay: 34 319 | content: "\e[2K\e[1G\e[?25h\e[32m✔\e[39m Add changes to git\r\n\e[?25l\e[36m⠋\e[39m Commit changes to git" 320 | - delay: 84 321 | content: "\e[2K\e[1G\e[36m⠙\e[39m Commit changes to git" 322 | - delay: 81 323 | content: "\e[2K\e[1G\e[36m⠹\e[39m Commit changes to git" 324 | - delay: 85 325 | content: "\e[2K\e[1G\e[36m⠸\e[39m Commit changes to git" 326 | - delay: 85 327 | content: "\e[2K\e[1G\e[36m⠼\e[39m Commit changes to git" 328 | - delay: 83 329 | content: "\e[2K\e[1G\e[36m⠴\e[39m Commit changes to git" 330 | - delay: 80 331 | content: "\e[2K\e[1G\e[36m⠦\e[39m Commit changes to git" 332 | - delay: 81 333 | content: "\e[2K\e[1G\e[36m⠋\e[39m Commit changes to git\e[2K\e[1G\e[?25h\e[32m✔\e[39m Commit changes to git\r\n\e[?25h\e[?25h" 334 | - delay: 8 335 | content: "\e[1m\e[7m%\e[27m\e[1m\e[0m \r \r\e]2;wolox@wolox: ~/test\a\e]1;~/test\a" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-w-express-js", 3 | "version": "3.0.1", 4 | "description": "Yeoman Kickoff for ExpressJS applications", 5 | "engines": { 6 | "node": "14.17.0", 7 | "npm": "6.14.13" 8 | }, 9 | "files": [ 10 | "generators" 11 | ], 12 | "scripts": { 13 | "test": "jest --silent", 14 | "eslint-check": "eslint --print-config .eslintrc.js", 15 | "lint": "eslint --ignore-pattern 'generators/app/templates/' \"**/*.js\"", 16 | "lint-diff": "git diff --name-only --cached --relative | grep \\\\.js$ | xargs eslint", 17 | "lint-fix": "npm run lint -- --fix", 18 | "precommit": "npm run lint", 19 | "prepush": "npm test", 20 | "outdated": "npm outdated --depth 0", 21 | "pretest": "npm run lint", 22 | "prestart": "npm run lint", 23 | "lint-external": "eslint -c .eslintrc.js" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/Wolox/express-js-bootstrap.git" 28 | }, 29 | "author": "Wolox", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/Wolox/express-js-bootstrap/issues", 33 | "email": "tls@wolox.com.ar" 34 | }, 35 | "cacheDirectories": [ 36 | "node_modules" 37 | ], 38 | "homepage": "https://github.com/Wolox/express-js-bootstrap#readme", 39 | "dependencies": { 40 | "camel-case": "^4.1.1", 41 | "cfonts": "^2.4.5", 42 | "faker": "^4.1.0", 43 | "ora": "^4.0.3", 44 | "terminal-link": "^2.1.1", 45 | "yeoman-generator": "^4.13.0" 46 | }, 47 | "devDependencies": { 48 | "babel-eslint": "^10.0.3", 49 | "eslint": "^6.8.0", 50 | "eslint-config-wolox": "^4.0.0", 51 | "eslint-config-wolox-node": "^3.0.0", 52 | "eslint-plugin-import": "^2.20.1", 53 | "eslint-plugin-jest": "^23.7.0", 54 | "eslint-plugin-prettier": "^3.1.2", 55 | "jest": "^27.3.1", 56 | "lodash": "^4.17.21", 57 | "prettier": "^1.19.1", 58 | "prettier-eslint": "^12.0.0", 59 | "yeoman-assert": "^3.1.1", 60 | "yeoman-test": "^2.1.0" 61 | }, 62 | "jest": { 63 | "testEnvironment": "node", 64 | "testMatch": [ 65 | "**/test/**/*.spec.js?(x)" 66 | ], 67 | "modulePathIgnorePatterns": [ 68 | "/generators/app/templates" 69 | ], 70 | "clearMocks": true 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | [Change!] Describe your feature, problems you had, notes, improvements and others. 4 | 5 | ## Known Issues 6 | 7 | [Change!] List any known issue of the feature you are implementing. 8 | 9 | ## Trello Card 10 | 11 | [Change!] Link to the associated Trello card. 12 | -------------------------------------------------------------------------------- /test/__snapshots__/ci.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`jenkins project creates expected .woloxci/Dockerfile 1`] = ` 4 | "FROM node:8.9.12 5 | 6 | WORKDIR /usr/src/app 7 | 8 | ENV NODE_ENV testing 9 | 10 | ENV HOME /usr/src/app 11 | 12 | ENV BABEL_DISABLE_CACHE 1 13 | 14 | RUN mkdir -p /install 15 | 16 | ENV NODE_PATH=/install/node_modules 17 | 18 | # Install app dependencies 19 | # A wildcard is used to ensure both package.json AND package-lock.json are copied 20 | # where available (npm@5+) 21 | COPY package*.json /install/ 22 | 23 | WORKDIR /install 24 | 25 | RUN npm install 26 | RUN npm install -g gulp 27 | # If you are building your code for production 28 | # RUN npm install --only=production 29 | 30 | RUN chmod a+r /usr/src/app 31 | 32 | WORKDIR /usr/src/app 33 | 34 | # Bundle app source 35 | COPY . . 36 | " 37 | `; 38 | 39 | exports[`jenkins project creates expected .woloxci/config.yml 1`] = ` 40 | "config: 41 | dockerfile: .woloxci/Dockerfile 42 | project_name: CIProject 43 | 44 | steps: 45 | copy_node_modules: 46 | - cp -r $NODE_PATH/ ./ 47 | lint: 48 | - npm run lint 49 | test: 50 | - npm run test 51 | 52 | environment: 53 | GIT_COMMITTER_NAME: a 54 | GIT_COMMITTER_EMAIL: b 55 | LANG: C.UTF-8 56 | " 57 | `; 58 | 59 | exports[`jenkins project creates expected Jenkinsfile 1`] = ` 60 | "@Library('wolox-ci') _ 61 | 62 | node { 63 | 64 | checkout scm 65 | 66 | woloxCi('.woloxci/config.yml'); 67 | } 68 | " 69 | `; 70 | 71 | exports[`travis project creates expected .travis.yml 1`] = ` 72 | "language: node_js 73 | 74 | node_js: 75 | - \\"8.9.12\\" 76 | 77 | sudo: true 78 | 79 | env: 80 | - CXX=g++-4.8 NODE_ENV=testing 81 | addons: 82 | apt: 83 | sources: 84 | - ubuntu-toolchain-r-test 85 | packages: 86 | - g++-4.8 87 | " 88 | `; 89 | -------------------------------------------------------------------------------- /test/__snapshots__/deploy.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Deploy with aws creates expected .ebextensions/cloudwatch.config 1`] = ` 4 | "packages: 5 | yum: 6 | perl-DateTime: [] 7 | perl-Sys-Syslog: [] 8 | perl-LWP-Protocol-https: [] 9 | perl-Switch: [] 10 | perl-URI: [] 11 | perl-Bundle-LWP: [] 12 | sources: 13 | /opt/cloudwatch: https://aws-cloudwatch.s3.amazonaws.com/downloads/CloudWatchMonitoringScripts-1.2.1.zip 14 | 15 | container_commands: 16 | 01-setupcron: 17 | command: | 18 | echo '*/5 * * * * root perl /opt/cloudwatch/aws-scripts-mon/mon-put-instance-data.pl \`{\\"Fn::GetOptionSetting\\" : { \\"OptionName\\" : \\"CloudWatchMetrics\\", \\"DefaultValue\\" : \\"--mem-util --disk-space-util --disk-path=/\\" }}\` >> /var/log/cwpump.log 2>&1' > /etc/cron.d/cwpump 19 | 02-changeperm: 20 | command: chmod 644 /etc/cron.d/cwpump 21 | 03-changeperm: 22 | command: chmod u+x /opt/cloudwatch/aws-scripts-mon/mon-put-instance-data.pl 23 | option_settings: 24 | \\"aws:autoscaling:launchconfiguration\\" : 25 | IamInstanceProfile : \\"aws-elasticbeanstalk-ec2-role\\" 26 | \\"aws:elasticbeanstalk:customoption\\" : 27 | CloudWatchMetrics : \\"--mem-util --mem-used --mem-avail --disk-space-util --disk-space-used --disk-space-avail --disk-path=/ --auto-scaling\\" 28 | " 29 | `; 30 | 31 | exports[`Deploy with docker and aws creates expected .ebextensions/cloudwatch.config 1`] = ` 32 | "packages: 33 | yum: 34 | perl-DateTime: [] 35 | perl-Sys-Syslog: [] 36 | perl-LWP-Protocol-https: [] 37 | perl-Switch: [] 38 | perl-URI: [] 39 | perl-Bundle-LWP: [] 40 | sources: 41 | /opt/cloudwatch: https://aws-cloudwatch.s3.amazonaws.com/downloads/CloudWatchMonitoringScripts-1.2.1.zip 42 | 43 | container_commands: 44 | 01-setupcron: 45 | command: | 46 | echo '*/5 * * * * root perl /opt/cloudwatch/aws-scripts-mon/mon-put-instance-data.pl \`{\\"Fn::GetOptionSetting\\" : { \\"OptionName\\" : \\"CloudWatchMetrics\\", \\"DefaultValue\\" : \\"--mem-util --disk-space-util --disk-path=/\\" }}\` >> /var/log/cwpump.log 2>&1' > /etc/cron.d/cwpump 47 | 02-changeperm: 48 | command: chmod 644 /etc/cron.d/cwpump 49 | 03-changeperm: 50 | command: chmod u+x /opt/cloudwatch/aws-scripts-mon/mon-put-instance-data.pl 51 | option_settings: 52 | \\"aws:autoscaling:launchconfiguration\\" : 53 | IamInstanceProfile : \\"aws-elasticbeanstalk-ec2-role\\" 54 | \\"aws:elasticbeanstalk:customoption\\" : 55 | CloudWatchMetrics : \\"--mem-util --mem-used --mem-avail --disk-space-util --disk-space-used --disk-space-avail --disk-path=/ --auto-scaling\\" 56 | " 57 | `; 58 | 59 | exports[`Deploy with docker and aws creates expected Dockerfile 1`] = ` 60 | "FROM node:8.9.12 61 | 62 | WORKDIR /home/node/app 63 | 64 | COPY package.json . 65 | COPY package-lock.json . 66 | COPY .nvmrc . 67 | 68 | RUN npm install 69 | 70 | COPY . . 71 | 72 | EXPOSE 8080 73 | ENV NODE_ENV production 74 | CMD [\\"node\\", \\"server.js\\"] 75 | " 76 | `; 77 | 78 | exports[`Deploy with docker and aws creates expected Dockerrun.aws.json 1`] = ` 79 | "{ 80 | \\"AWSEBDockerrunVersion\\": \\"1\\", 81 | \\"Ports\\": [ 82 | { 83 | \\"ContainerPort\\": \\"8080\\" 84 | } 85 | ], 86 | \\"Volumes\\": [], 87 | \\"Logging\\": \\"/home/node/app/app/logger/logs\\" 88 | } 89 | " 90 | `; 91 | 92 | exports[`Deploy with docker creates expected Dockerfile 1`] = ` 93 | "FROM node:8.9.12 94 | 95 | WORKDIR /home/node/app 96 | 97 | COPY package.json . 98 | COPY package-lock.json . 99 | COPY .nvmrc . 100 | 101 | RUN npm install 102 | 103 | COPY . . 104 | 105 | EXPOSE 8080 106 | ENV NODE_ENV production 107 | CMD [\\"node\\", \\"server.js\\"] 108 | " 109 | `; 110 | 111 | exports[`Deploy with heroku creates expected Procfile 1`] = ` 112 | "web: node server.js 113 | " 114 | `; 115 | -------------------------------------------------------------------------------- /test/__snapshots__/mongoose.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Mongoose project creates expected README.md 1`] = ` 4 | "# MongooseProject 5 | 6 | MongooseProject 7 | 8 | ## First steps 9 | 10 | #### Installing node 11 | 12 | Get the latest version of node from the [official website](https://nodejs.org/) or using [nvm](https://github.com/creationix/nvm) 13 | Nvm approach is preferred. 14 | 15 | #### Getting dependencies 16 | 17 | Run \`npm install\` or \`yarn\` from rootpath of the project. 18 | 19 | #### Database configuration 20 | 21 | Before running the app, make sure you have [mongoDB installed](https://hevodata.com/blog/install-mongodb-on-ubuntu/) and a db created, to create it run the following steps inside a terminal: 22 | 23 | 1. mongo 24 | 2. use db_project_name 25 | 3. db.createUser({user:\\"root\\", pwd:\\"superpass\\", roles:[{role:\\"root\\", db:\\"db_project_name\\"}]}) 26 | 4. *exit from mongo* 27 | 5. mongo -u root -p superpass --authenticationDatabase db_project_name 28 | 29 | Then, set in \`.env\` some variables: 30 | 31 | - DB_HOST=localhost 32 | - DB_PORT=5432 33 | - DB_USERNAME=project_name 34 | - DB_PASSWORD=project_name 35 | - DB_NAME=db_project_name 36 | - DB_NAME_DEV=db_project_name_dev 37 | - DB_NAME_TEST=db_project_name_test 38 | - API_DATE=X-API-Date 39 | - PACKAGE_VERSION=X-Package-Version 40 | - NODE_VERSION=X-Node-Version 41 | 42 | 43 | #### Starting your app 44 | 45 | Now, we have two ways to start an app. To start your app in production mode run \`npm start\` in the root path of your project. To start your app in development mode (nodemon) run \`npm run start-dev\`. Then access your app at **localhost:port**. The port is logged in the console where you ran the start script. 46 | 47 | ## Development 48 | 49 | #### Environments 50 | 51 | By default, the environment will be **development**, but you can easily change it using the **NODE_ENV** environmental variable. 52 | 53 | #### Environment variables 54 | 55 | \`Dotenv\` is used for managing environment variables. They are stored in the \`/.env\` file. Take into account that the variables defined in the \`bashrc\` are not overrided. 56 | 57 | The environment variables should be added to the \`.env\` file in the form of \`NAME=VALUE\`, as the following example: 58 | 59 | \`\`\` 60 | DB_USERNAME=root 61 | DB_PASS=superpass 62 | DB_PASSWORD=superpass 63 | PORT=8081 64 | CLIENTS_API=http://api.clients.example.org/ 65 | \`\`\` 66 | 67 | **Remember not to push nor commit the \`.env\` file.** 68 | 69 | #### Logging 70 | 71 | To log useful information of your program to the console you just need to import the logger located at \`app/logger\`. There are two possible types of logging: \`info\` and \`error\`. You should use them depending on the type of message you want to show. 72 | 73 | Here is an example snippet: 74 | 75 | \`\`\` 76 | const logger = require('/app/logger'); 77 | ... 78 | if (error) { 79 | logger.error('There is an error); 80 | } else { 81 | logger.info('There is no error); 82 | } 83 | \`\`\` 84 | 85 | #### Testing 86 | 87 | To run your tests you first need to config your testing database by setting the env var \`DB_NAME_TEST\`. as explained 88 | before in [Database configuration](#database-configuration). Also you need to run the migrations in this exclusive 89 | testing database each time you have new ones, you can do this by running the command \`npm run migrations-test\`. 90 | Once you have all the above done you can run your tests with the following command: \`npm test\`. For more information refeer to the documentation of [Jest](https://jestjs.io/docs/en/getting-started). 91 | 92 | 93 | #### Debugging 94 | 95 | As we know, a NodeJS application is not something easy to debug and because of that we've added the \`--inspect\` flag to make it simpler. You can download a node inspection manager for Chrome, so Chrome DevTools will automatically start when you run your app using \`npm run start-dev\`, making your debugging easier. You can read more about the different inspector clients here: 96 | 97 | #### REPL console 98 | 99 | We can use a node console with \`npm run console\`. There your service objects are exposed as _servicename_ + \\"Service\\". Let's suppose that we have a service \`users\` which has a function \`getAll\`. In your console you can call \`usersService.getAll()\` and see the result. Note that this works also with functions that return promises! To exit the console use \`.exit\`. 100 | 101 | #### Documentation 102 | 103 | Documentation will be served at \`/docs\`. We use [OpenAPI](https://github.com/OAI/OpenAPI-Specification) A.K.A \`Swagger\`. Check [this link](https://medium.com/wolox-driving-innovation/documenting-a-nodejs-rest-api-with-openapi-3-swagger-5deee9f50420) for more details on how to use it. 104 | 105 | ## Deploy 106 | 107 | #### Heroku 108 | 109 | Pushing the desired branch to heroku should be enough. 110 | For more information check: https://devcenter.heroku.com/articles/getting-started-with-nodejs#define-a-procfile. 111 | 112 | ## Contributing 113 | 114 | 1. Fork it 115 | 2. Create your feature branch (\`git checkout -b my-new-feature\`) 116 | 3. Run the tests (\`npm test\`) 117 | 4. Commit your changes (\`git commit -am 'Add some feature'\`) 118 | 5. Push to the branch (\`git push origin my-new-feature\`) 119 | 6. Create new Pull Request 120 | 121 | ## About 122 | 123 | This project is maintained by [Wolox](https://github.com/wolox) and it was written by [Wolox](http://www.wolox.com.ar). 124 | 125 | ![Wolox](https://raw.githubusercontent.com/Wolox/press-kit/master/logos/logo_banner.png) 126 | 127 | ## License 128 | 129 | **MongooseProject** is available under the MIT [license](LICENSE.md). 130 | 131 | Copyright (c) 2019 Wolox 132 | 133 | Permission is hereby granted, free of charge, to any person obtaining a copy 134 | of this software and associated documentation files (the \\"Software\\"), to deal 135 | in the Software without restriction, including without limitation the rights 136 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 137 | copies of the Software, and to permit persons to whom the Software is 138 | furnished to do so, subject to the following conditions: 139 | 140 | The above copyright notice and this permission notice shall be included in 141 | all copies or substantial portions of the Software. 142 | 143 | THE SOFTWARE IS PROVIDED \\"AS IS\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 144 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 145 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 146 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 147 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 148 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 149 | THE SOFTWARE. 150 | " 151 | `; 152 | 153 | exports[`Mongoose project creates expected config/db.js 1`] = ` 154 | "const mongoose = require('mongoose'); 155 | const config = require('../config').common.database; 156 | 157 | const host = config.host; 158 | const port = config.port; 159 | const name = config.name; 160 | const connectionString = \`mongodb://\${host}:\${port}/\${name}\`; 161 | module.exports = mongoose.connect(connectionString); 162 | 163 | 164 | " 165 | `; 166 | 167 | exports[`Mongoose project creates expected console.js 1`] = ` 168 | "/* eslint-disable global-require */ 169 | const repl = require('repl'); 170 | const fs = require('fs'); 171 | 172 | const pjson = require('./package.json'); 173 | 174 | const convertFunctionToAsync = f => async (...args) => { 175 | const result = await f(...args); 176 | console.log(JSON.stringify(result, null, 2)); // eslint-disable-line no-console 177 | return result; 178 | }; 179 | 180 | const convertObjectFunctionsToAsync = serviceMethods => { 181 | const asyncServiceMethods = {}; 182 | Object.keys(serviceMethods).forEach(key => { 183 | if (typeof serviceMethods[key] === 'function') { 184 | asyncServiceMethods[key] = convertFunctionToAsync(serviceMethods[key]); 185 | } else asyncServiceMethods[key] = serviceMethods[key]; 186 | }); 187 | return asyncServiceMethods; 188 | }; 189 | 190 | Promise.resolve().then(() => { 191 | const replServer = repl.start({ 192 | prompt: \`\${pjson.name}> \` 193 | }); 194 | const servicesPath = './app/services/'; 195 | fs.readdir(servicesPath, (err, files) => { 196 | files.forEach(file => { 197 | const serviceMethods = require(\`\${servicesPath}\${file}\`); 198 | const asyncServiceMethods = convertObjectFunctionsToAsync(serviceMethods); 199 | replServer.context[\`\${file.split('.')[0]}Service\`] = asyncServiceMethods; 200 | }); 201 | }); 202 | }); 203 | " 204 | `; 205 | 206 | exports[`Mongoose project creates expected package.json 1`] = ` 207 | "{ 208 | \\"name\\": \\"MongooseProject\\", 209 | \\"version\\": \\"0.1.0\\", 210 | \\"description\\": \\"MongooseProject\\", 211 | \\"engines\\": { 212 | \\"node\\": \\"8.9.12\\", 213 | \\"npm\\": \\"6.4.1\\" 214 | }, 215 | \\"scripts\\": { 216 | \\"console\\": \\"node console.js\\", 217 | \\"cover\\": \\"npm run test -- --coverage\\", 218 | \\"test\\": \\"NODE_ENV=testing jest --runInBand --forceExit --detectOpenHandles\\", 219 | \\"test-inspect\\": \\"NODE_ENV=testing node --inspect --debug-brk jest\\", 220 | \\"eslint-check\\": \\"eslint --print-config .eslintrc.js --ignore-pattern ./.eslintrc.js | eslint-config-prettier-check\\", 221 | \\"lint\\": \\"eslint \\\\\\"**/*.js\\\\\\" --ignore-pattern ./.eslintrc.js\\", 222 | \\"lint-diff\\": \\"git diff --diff-filter=ACM --name-only --cached --relative | grep \\\\\\\\\\\\\\\\.js$ | xargs eslint\\", 223 | \\"lint-fix\\": \\"npm run lint -- --fix\\", 224 | \\"outdated\\": \\"npm outdated --depth 0\\", 225 | \\"pretest\\": \\"npm run lint\\", 226 | \\"start-dev\\": \\"nodemon --inspect server.js\\", 227 | \\"prestart-dev\\": \\"npm run lint\\", 228 | \\"start\\": \\"node server.js\\", 229 | \\"seed\\": \\"sequelize db:seed:all\\", 230 | \\"create-seed\\": \\"sequelize seed:generate --name\\", 231 | \\"create-migration\\": \\"sequelize migration:generate --name\\" 232 | }, 233 | \\"cacheDirectories\\": [ 234 | \\"node_modules\\" 235 | ], 236 | \\"main\\": \\"app.js\\", 237 | \\"author\\": \\"Wolox\\", 238 | \\"homepage\\": \\"https://test.com.ar\\", 239 | \\"license\\": \\"MIT\\", 240 | \\"repository\\": { 241 | \\"type\\": \\"git\\", 242 | \\"url\\": \\"https://test.com.ar.git\\" 243 | }, 244 | \\"bugs\\": { 245 | \\"url\\": \\"https://test.com.ar/issues\\", 246 | \\"email\\": \\"tls@wolox.com.ar\\" 247 | }, 248 | \\"jest\\": { 249 | \\"coverageThreshold\\": { 250 | \\"global\\": { 251 | \\"branches\\": 80, 252 | \\"functions\\": 80, 253 | \\"lines\\": 80, 254 | \\"statements\\": 80 255 | } 256 | }, 257 | \\"collectCoverageFrom\\": [ 258 | \\"**/*.js\\", 259 | \\"!**/console.js\\", 260 | \\"!**/node_modules/**\\", 261 | \\"!**/build/**\\", 262 | \\"!**/migrations/**\\", 263 | \\"!**/config/**\\", 264 | \\"!**/scripts/**\\" 265 | ], 266 | \\"setupFilesAfterEnv\\": [ 267 | \\"/test/setup.js\\" 268 | ], 269 | \\"testEnvironment\\": \\"node\\", 270 | \\"transform\\": { 271 | \\"^.+\\\\\\\\.js$\\": \\"babel-jest\\" 272 | } 273 | }, 274 | \\"dependencies\\": { 275 | \\"bcryptjs\\": \\"^2.4.3\\", 276 | \\"mongoose\\": \\"^5.6.4\\", 277 | \\"mongodb\\" : \\"^4.1.3\\", 278 | \\"body-parser\\": \\"^1.19.0\\", 279 | \\"express\\": \\"^4.17.1\\", 280 | \\"jwt-simple\\": \\"^0.5.6\\", 281 | \\"umzug\\": \\"^2.3.0\\", 282 | \\"express-wolox-logger\\": \\"^2.0.0\\", 283 | \\"axios\\": \\"^0.24.0\\", 284 | \\"swagger-ui-express\\": \\"^4.1.6\\" 285 | }, 286 | \\"devDependencies\\": { 287 | \\"babel\\": \\"6.23.0\\", 288 | \\"babel-core\\": \\"^6.26.3\\", 289 | \\"babel-eslint\\": \\"^10.1.0\\", 290 | \\"babel-jest\\": \\"^27.3.1\\", 291 | \\"jest\\": \\"^27.3.1\\", 292 | \\"supertest\\": \\"^6.1.6\\", 293 | \\"babel-preset-es2015\\": \\"6.24.1\\", 294 | \\"dotenv\\": \\"^10.0.0\\", 295 | \\"eslint\\": \\"^6.8.0\\", 296 | \\"eslint-config-wolox\\": \\"^4.0.0\\", 297 | \\"eslint-config-wolox-node\\": \\"^3.0.0\\", 298 | \\"eslint-plugin-import\\": \\"^2.25.2\\", 299 | \\"eslint-plugin-prettier\\": \\"^3.0.1\\", 300 | \\"husky\\": \\"^7.0.4\\", 301 | \\"istanbul\\": \\"^0.4.3\\", 302 | \\"mocha\\": \\"^9.1.3\\", 303 | \\"mocha-lcov-reporter\\": \\"^1.3.0\\", 304 | \\"nodemon\\": \\"^2.0.14\\", 305 | \\"prettier\\": \\"^1.15.3\\", 306 | \\"prettier-eslint\\": \\"^9.0.1\\", 307 | \\"prompt\\": \\"^1.2.0\\" 308 | }, 309 | \\"husky\\": { 310 | \\"hooks\\": { 311 | \\"pre-commit\\": \\"npm run lint-diff\\", 312 | \\"pre-push\\": \\"npm test\\" 313 | } 314 | } 315 | } 316 | " 317 | `; 318 | 319 | exports[`Mongoose project creates expected server.js 1`] = ` 320 | "const app = require('./app'); 321 | const config = require('./config'); 322 | const logger = require('./app/logger'); 323 | 324 | const port = config.common.api.port || 8080; 325 | 326 | Promise.resolve() 327 | 328 | .then(() => { 329 | 330 | 331 | app.listen(port); 332 | 333 | logger.info(\`Listening on port: \${port}\`); 334 | }) 335 | .catch(logger.error);" 336 | `; 337 | -------------------------------------------------------------------------------- /test/__snapshots__/optionals.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Project with cors creates expected app.js 1`] = ` 4 | "const { expressMiddleware, expressRequestIdMiddleware } = require('express-wolox-logger'); 5 | const express = require('express'); 6 | const bodyParser = require('body-parser'); 7 | const swaggerUi = require('swagger-ui-express'); 8 | const cors = require('cors'); 9 | const config = require('./config'); 10 | const routes = require('./app/routes'); 11 | const errors = require('./app/middlewares/errors'); 12 | const documentation = require('./documentation'); 13 | const logger = require('./app/logger'); 14 | const { verifyDocumentationToken } = require('./app/middlewares/docsAuth'); 15 | 16 | const DEFAULT_BODY_SIZE_LIMIT = 1024 * 1024 * 10; 17 | const DEFAULT_PARAMETER_LIMIT = 10000; 18 | 19 | const bodyParserJsonConfig = () => ({ 20 | parameterLimit: config.common.api.parameterLimit || DEFAULT_PARAMETER_LIMIT, 21 | limit: config.common.api.bodySizeLimit || DEFAULT_BODY_SIZE_LIMIT 22 | }); 23 | 24 | const bodyParserUrlencodedConfig = () => ({ 25 | extended: true, 26 | parameterLimit: config.common.api.parameterLimit || DEFAULT_PARAMETER_LIMIT, 27 | limit: config.common.api.bodySizeLimit || DEFAULT_BODY_SIZE_LIMIT 28 | }); 29 | 30 | const app = express(); 31 | 32 | app.use(cors()); 33 | 34 | 35 | 36 | // Client must send \\"Content-Type: application/json\\" header 37 | app.use(bodyParser.json(bodyParserJsonConfig())); 38 | app.use(bodyParser.urlencoded(bodyParserUrlencodedConfig())); 39 | app.use(expressRequestIdMiddleware()); 40 | app.use('/docs', 41 | verifyDocumentationToken, 42 | swaggerUi.serve, swaggerUi.setup(documentation)); 43 | 44 | if (!config.isTesting) app.use(expressMiddleware({ loggerFn: logger.info })); 45 | 46 | routes.init(app); 47 | 48 | app.use(errors.handle); 49 | 50 | module.exports = app; 51 | " 52 | `; 53 | 54 | exports[`Project with cors creates expected package.json 1`] = ` 55 | "{ 56 | \\"name\\": \\"OptionalProject\\", 57 | \\"version\\": \\"0.1.0\\", 58 | \\"description\\": \\"Example\\", 59 | \\"engines\\": { 60 | \\"node\\": \\"8.9.12\\", 61 | \\"npm\\": \\"6.4.1\\" 62 | }, 63 | \\"scripts\\": { 64 | \\"console\\": \\"node console.js\\", 65 | \\"cover\\": \\"npm run test -- --coverage\\", 66 | \\"test\\": \\"NODE_ENV=testing jest --runInBand --forceExit --detectOpenHandles\\", 67 | \\"test-inspect\\": \\"NODE_ENV=testing node --inspect --debug-brk jest\\", 68 | \\"eslint-check\\": \\"eslint --print-config .eslintrc.js --ignore-pattern ./.eslintrc.js | eslint-config-prettier-check\\", 69 | \\"lint\\": \\"eslint \\\\\\"**/*.js\\\\\\" --ignore-pattern ./.eslintrc.js\\", 70 | \\"lint-diff\\": \\"git diff --diff-filter=ACM --name-only --cached --relative | grep \\\\\\\\\\\\\\\\.js$ | xargs eslint\\", 71 | \\"lint-fix\\": \\"npm run lint -- --fix\\", 72 | \\"outdated\\": \\"npm outdated --depth 0\\", 73 | \\"pretest\\": \\"npm run lint\\", 74 | \\"start-dev\\": \\"nodemon --inspect server.js\\", 75 | \\"prestart-dev\\": \\"npm run lint\\", 76 | \\"start\\": \\"node server.js\\", 77 | \\"seed\\": \\"sequelize db:seed:all\\", 78 | \\"create-seed\\": \\"sequelize seed:generate --name\\", 79 | \\"create-migration\\": \\"sequelize migration:generate --name\\" 80 | }, 81 | \\"cacheDirectories\\": [ 82 | \\"node_modules\\" 83 | ], 84 | \\"main\\": \\"app.js\\", 85 | \\"author\\": \\"Wolox\\", 86 | \\"homepage\\": \\"https://test.com.ar\\", 87 | \\"license\\": \\"MIT\\", 88 | \\"repository\\": { 89 | \\"type\\": \\"git\\", 90 | \\"url\\": \\"https://test.com.ar.git\\" 91 | }, 92 | \\"bugs\\": { 93 | \\"url\\": \\"https://test.com.ar/issues\\", 94 | \\"email\\": \\"tls@wolox.com.ar\\" 95 | }, 96 | \\"jest\\": { 97 | \\"coverageThreshold\\": { 98 | \\"global\\": { 99 | \\"branches\\": 80, 100 | \\"functions\\": 80, 101 | \\"lines\\": 80, 102 | \\"statements\\": 80 103 | } 104 | }, 105 | \\"collectCoverageFrom\\": [ 106 | \\"**/*.js\\", 107 | \\"!**/console.js\\", 108 | \\"!**/node_modules/**\\", 109 | \\"!**/build/**\\", 110 | \\"!**/migrations/**\\", 111 | \\"!**/config/**\\", 112 | \\"!**/scripts/**\\" 113 | ], 114 | \\"setupFilesAfterEnv\\": [ 115 | \\"/test/setup.js\\" 116 | ], 117 | \\"testEnvironment\\": \\"node\\", 118 | \\"transform\\": { 119 | \\"^.+\\\\\\\\.js$\\": \\"babel-jest\\" 120 | } 121 | }, 122 | \\"dependencies\\": { 123 | \\"bcryptjs\\": \\"^2.4.3\\", 124 | \\"body-parser\\": \\"^1.19.0\\", 125 | \\"cors\\": \\"^2.8.5\\", 126 | \\"express\\": \\"^4.17.1\\", 127 | \\"jwt-simple\\": \\"^0.5.6\\", 128 | \\"umzug\\": \\"^2.3.0\\", 129 | \\"express-wolox-logger\\": \\"^2.0.0\\", 130 | \\"axios\\": \\"^0.24.0\\", 131 | \\"swagger-ui-express\\": \\"^4.1.6\\" 132 | }, 133 | \\"devDependencies\\": { 134 | \\"babel\\": \\"6.23.0\\", 135 | \\"babel-core\\": \\"^6.26.3\\", 136 | \\"babel-eslint\\": \\"^10.1.0\\", 137 | \\"babel-jest\\": \\"^27.3.1\\", 138 | \\"jest\\": \\"^27.3.1\\", 139 | \\"supertest\\": \\"^6.1.6\\", 140 | \\"babel-preset-es2015\\": \\"6.24.1\\", 141 | \\"dotenv\\": \\"^10.0.0\\", 142 | \\"eslint\\": \\"^6.8.0\\", 143 | \\"eslint-config-wolox\\": \\"^4.0.0\\", 144 | \\"eslint-config-wolox-node\\": \\"^3.0.0\\", 145 | \\"eslint-plugin-import\\": \\"^2.25.2\\", 146 | \\"eslint-plugin-prettier\\": \\"^3.0.1\\", 147 | \\"husky\\": \\"^7.0.4\\", 148 | \\"istanbul\\": \\"^0.4.3\\", 149 | \\"mocha\\": \\"^9.1.3\\", 150 | \\"mocha-lcov-reporter\\": \\"^1.3.0\\", 151 | \\"nodemon\\": \\"^2.0.14\\", 152 | \\"prettier\\": \\"^1.15.3\\", 153 | \\"prettier-eslint\\": \\"^9.0.1\\", 154 | \\"prompt\\": \\"^1.2.0\\" 155 | }, 156 | \\"husky\\": { 157 | \\"hooks\\": { 158 | \\"pre-commit\\": \\"npm run lint-diff\\", 159 | \\"pre-push\\": \\"npm test\\" 160 | } 161 | } 162 | } 163 | " 164 | `; 165 | 166 | exports[`Project with coveralls creates expected package.json 1`] = ` 167 | "{ 168 | \\"name\\": \\"OptionalProject\\", 169 | \\"version\\": \\"0.1.0\\", 170 | \\"description\\": \\"Example\\", 171 | \\"engines\\": { 172 | \\"node\\": \\"8.9.12\\", 173 | \\"npm\\": \\"6.4.1\\" 174 | }, 175 | \\"scripts\\": { 176 | \\"console\\": \\"node console.js\\", 177 | \\"cover\\": \\"npm run test -- --coverage\\", 178 | \\"test\\": \\"NODE_ENV=testing jest --runInBand --forceExit --detectOpenHandles\\", 179 | \\"test-inspect\\": \\"NODE_ENV=testing node --inspect --debug-brk jest\\", 180 | \\"coveralls\\": \\"npm run cover -- --report lcovonly && cat ./coverage/lcov.info | coveralls\\", 181 | \\"eslint-check\\": \\"eslint --print-config .eslintrc.js --ignore-pattern ./.eslintrc.js | eslint-config-prettier-check\\", 182 | \\"lint\\": \\"eslint \\\\\\"**/*.js\\\\\\" --ignore-pattern ./.eslintrc.js\\", 183 | \\"lint-diff\\": \\"git diff --diff-filter=ACM --name-only --cached --relative | grep \\\\\\\\\\\\\\\\.js$ | xargs eslint\\", 184 | \\"lint-fix\\": \\"npm run lint -- --fix\\", 185 | \\"outdated\\": \\"npm outdated --depth 0\\", 186 | \\"pretest\\": \\"npm run lint\\", 187 | \\"start-dev\\": \\"nodemon --inspect server.js\\", 188 | \\"prestart-dev\\": \\"npm run lint\\", 189 | \\"start\\": \\"node server.js\\", 190 | \\"seed\\": \\"sequelize db:seed:all\\", 191 | \\"create-seed\\": \\"sequelize seed:generate --name\\", 192 | \\"create-migration\\": \\"sequelize migration:generate --name\\" 193 | }, 194 | \\"cacheDirectories\\": [ 195 | \\"node_modules\\" 196 | ], 197 | \\"main\\": \\"app.js\\", 198 | \\"author\\": \\"Wolox\\", 199 | \\"homepage\\": \\"https://test.com.ar\\", 200 | \\"license\\": \\"MIT\\", 201 | \\"repository\\": { 202 | \\"type\\": \\"git\\", 203 | \\"url\\": \\"https://test.com.ar.git\\" 204 | }, 205 | \\"bugs\\": { 206 | \\"url\\": \\"https://test.com.ar/issues\\", 207 | \\"email\\": \\"tls@wolox.com.ar\\" 208 | }, 209 | \\"jest\\": { 210 | \\"coverageThreshold\\": { 211 | \\"global\\": { 212 | \\"branches\\": 80, 213 | \\"functions\\": 80, 214 | \\"lines\\": 80, 215 | \\"statements\\": 80 216 | } 217 | }, 218 | \\"collectCoverageFrom\\": [ 219 | \\"**/*.js\\", 220 | \\"!**/console.js\\", 221 | \\"!**/node_modules/**\\", 222 | \\"!**/build/**\\", 223 | \\"!**/migrations/**\\", 224 | \\"!**/config/**\\", 225 | \\"!**/scripts/**\\" 226 | ], 227 | \\"setupFilesAfterEnv\\": [ 228 | \\"/test/setup.js\\" 229 | ], 230 | \\"testEnvironment\\": \\"node\\", 231 | \\"transform\\": { 232 | \\"^.+\\\\\\\\.js$\\": \\"babel-jest\\" 233 | } 234 | }, 235 | \\"dependencies\\": { 236 | \\"bcryptjs\\": \\"^2.4.3\\", 237 | \\"body-parser\\": \\"^1.19.0\\", 238 | \\"express\\": \\"^4.17.1\\", 239 | \\"jwt-simple\\": \\"^0.5.6\\", 240 | \\"umzug\\": \\"^2.3.0\\", 241 | \\"express-wolox-logger\\": \\"^2.0.0\\", 242 | \\"axios\\": \\"^0.24.0\\", 243 | \\"swagger-ui-express\\": \\"^4.1.6\\" 244 | }, 245 | \\"devDependencies\\": { 246 | \\"babel\\": \\"6.23.0\\", 247 | \\"babel-core\\": \\"^6.26.3\\", 248 | \\"babel-eslint\\": \\"^10.1.0\\", 249 | \\"babel-jest\\": \\"^27.3.1\\", 250 | \\"jest\\": \\"^27.3.1\\", 251 | \\"supertest\\": \\"^6.1.6\\", 252 | \\"babel-preset-es2015\\": \\"6.24.1\\", 253 | \\"coveralls\\": \\"^3.1.1\\", 254 | \\"dotenv\\": \\"^10.0.0\\", 255 | \\"eslint\\": \\"^6.8.0\\", 256 | \\"eslint-config-wolox\\": \\"^4.0.0\\", 257 | \\"eslint-config-wolox-node\\": \\"^3.0.0\\", 258 | \\"eslint-plugin-import\\": \\"^2.25.2\\", 259 | \\"eslint-plugin-prettier\\": \\"^3.0.1\\", 260 | \\"husky\\": \\"^7.0.4\\", 261 | \\"istanbul\\": \\"^0.4.3\\", 262 | \\"mocha\\": \\"^9.1.3\\", 263 | \\"mocha-lcov-reporter\\": \\"^1.3.0\\", 264 | \\"nodemon\\": \\"^2.0.14\\", 265 | \\"prettier\\": \\"^1.15.3\\", 266 | \\"prettier-eslint\\": \\"^9.0.1\\", 267 | \\"prompt\\": \\"^1.2.0\\" 268 | }, 269 | \\"husky\\": { 270 | \\"hooks\\": { 271 | \\"pre-commit\\": \\"npm run lint-diff\\", 272 | \\"pre-push\\": \\"npm test\\" 273 | } 274 | } 275 | } 276 | " 277 | `; 278 | 279 | exports[`Project with rollbar creates expected app.js 1`] = ` 280 | "const { expressMiddleware, expressRequestIdMiddleware } = require('express-wolox-logger'); 281 | const express = require('express'); 282 | const bodyParser = require('body-parser'); 283 | const swaggerUi = require('swagger-ui-express'); 284 | const config = require('./config'); 285 | const routes = require('./app/routes'); 286 | const errors = require('./app/middlewares/errors'); 287 | const documentation = require('./documentation'); 288 | const logger = require('./app/logger'); 289 | const { verifyDocumentationToken } = require('./app/middlewares/docsAuth'); 290 | 291 | const DEFAULT_BODY_SIZE_LIMIT = 1024 * 1024 * 10; 292 | const DEFAULT_PARAMETER_LIMIT = 10000; 293 | 294 | const bodyParserJsonConfig = () => ({ 295 | parameterLimit: config.common.api.parameterLimit || DEFAULT_PARAMETER_LIMIT, 296 | limit: config.common.api.bodySizeLimit || DEFAULT_BODY_SIZE_LIMIT 297 | }); 298 | 299 | const bodyParserUrlencodedConfig = () => ({ 300 | extended: true, 301 | parameterLimit: config.common.api.parameterLimit || DEFAULT_PARAMETER_LIMIT, 302 | limit: config.common.api.bodySizeLimit || DEFAULT_BODY_SIZE_LIMIT 303 | }); 304 | 305 | const app = express(); 306 | 307 | 308 | 309 | 310 | // Client must send \\"Content-Type: application/json\\" header 311 | app.use(bodyParser.json(bodyParserJsonConfig())); 312 | app.use(bodyParser.urlencoded(bodyParserUrlencodedConfig())); 313 | app.use(expressRequestIdMiddleware()); 314 | app.use('/docs', 315 | verifyDocumentationToken, 316 | swaggerUi.serve, swaggerUi.setup(documentation)); 317 | 318 | if (!config.isTesting) app.use(expressMiddleware({ loggerFn: logger.info })); 319 | 320 | routes.init(app); 321 | 322 | app.use(errors.handle); 323 | 324 | module.exports = app; 325 | " 326 | `; 327 | 328 | exports[`Project with rollbar creates expected package.json 1`] = ` 329 | "{ 330 | \\"name\\": \\"OptionalProject\\", 331 | \\"version\\": \\"0.1.0\\", 332 | \\"description\\": \\"Example\\", 333 | \\"engines\\": { 334 | \\"node\\": \\"8.9.12\\", 335 | \\"npm\\": \\"6.4.1\\" 336 | }, 337 | \\"scripts\\": { 338 | \\"console\\": \\"node console.js\\", 339 | \\"cover\\": \\"npm run test -- --coverage\\", 340 | \\"test\\": \\"NODE_ENV=testing jest --runInBand --forceExit --detectOpenHandles\\", 341 | \\"test-inspect\\": \\"NODE_ENV=testing node --inspect --debug-brk jest\\", 342 | \\"eslint-check\\": \\"eslint --print-config .eslintrc.js --ignore-pattern ./.eslintrc.js | eslint-config-prettier-check\\", 343 | \\"lint\\": \\"eslint \\\\\\"**/*.js\\\\\\" --ignore-pattern ./.eslintrc.js\\", 344 | \\"lint-diff\\": \\"git diff --diff-filter=ACM --name-only --cached --relative | grep \\\\\\\\\\\\\\\\.js$ | xargs eslint\\", 345 | \\"lint-fix\\": \\"npm run lint -- --fix\\", 346 | \\"outdated\\": \\"npm outdated --depth 0\\", 347 | \\"pretest\\": \\"npm run lint\\", 348 | \\"start-dev\\": \\"nodemon --inspect server.js\\", 349 | \\"prestart-dev\\": \\"npm run lint\\", 350 | \\"start\\": \\"node server.js\\", 351 | \\"seed\\": \\"sequelize db:seed:all\\", 352 | \\"create-seed\\": \\"sequelize seed:generate --name\\", 353 | \\"create-migration\\": \\"sequelize migration:generate --name\\" 354 | }, 355 | \\"cacheDirectories\\": [ 356 | \\"node_modules\\" 357 | ], 358 | \\"main\\": \\"app.js\\", 359 | \\"author\\": \\"Wolox\\", 360 | \\"homepage\\": \\"https://test.com.ar\\", 361 | \\"license\\": \\"MIT\\", 362 | \\"repository\\": { 363 | \\"type\\": \\"git\\", 364 | \\"url\\": \\"https://test.com.ar.git\\" 365 | }, 366 | \\"bugs\\": { 367 | \\"url\\": \\"https://test.com.ar/issues\\", 368 | \\"email\\": \\"tls@wolox.com.ar\\" 369 | }, 370 | \\"jest\\": { 371 | \\"coverageThreshold\\": { 372 | \\"global\\": { 373 | \\"branches\\": 80, 374 | \\"functions\\": 80, 375 | \\"lines\\": 80, 376 | \\"statements\\": 80 377 | } 378 | }, 379 | \\"collectCoverageFrom\\": [ 380 | \\"**/*.js\\", 381 | \\"!**/console.js\\", 382 | \\"!**/node_modules/**\\", 383 | \\"!**/build/**\\", 384 | \\"!**/migrations/**\\", 385 | \\"!**/config/**\\", 386 | \\"!**/scripts/**\\" 387 | ], 388 | \\"setupFilesAfterEnv\\": [ 389 | \\"/test/setup.js\\" 390 | ], 391 | \\"testEnvironment\\": \\"node\\", 392 | \\"transform\\": { 393 | \\"^.+\\\\\\\\.js$\\": \\"babel-jest\\" 394 | } 395 | }, 396 | \\"dependencies\\": { 397 | \\"bcryptjs\\": \\"^2.4.3\\", 398 | \\"body-parser\\": \\"^1.19.0\\", 399 | \\"express\\": \\"^4.17.1\\", 400 | \\"jwt-simple\\": \\"^0.5.6\\", 401 | \\"rollbar\\": \\"^2.24.0\\", 402 | \\"umzug\\": \\"^2.3.0\\", 403 | \\"express-wolox-logger\\": \\"^2.0.0\\", 404 | \\"axios\\": \\"^0.24.0\\", 405 | \\"swagger-ui-express\\": \\"^4.1.6\\" 406 | }, 407 | \\"devDependencies\\": { 408 | \\"babel\\": \\"6.23.0\\", 409 | \\"babel-core\\": \\"^6.26.3\\", 410 | \\"babel-eslint\\": \\"^10.1.0\\", 411 | \\"babel-jest\\": \\"^27.3.1\\", 412 | \\"jest\\": \\"^27.3.1\\", 413 | \\"supertest\\": \\"^6.1.6\\", 414 | \\"babel-preset-es2015\\": \\"6.24.1\\", 415 | \\"dotenv\\": \\"^10.0.0\\", 416 | \\"eslint\\": \\"^6.8.0\\", 417 | \\"eslint-config-wolox\\": \\"^4.0.0\\", 418 | \\"eslint-config-wolox-node\\": \\"^3.0.0\\", 419 | \\"eslint-plugin-import\\": \\"^2.25.2\\", 420 | \\"eslint-plugin-prettier\\": \\"^3.0.1\\", 421 | \\"husky\\": \\"^7.0.4\\", 422 | \\"istanbul\\": \\"^0.4.3\\", 423 | \\"mocha\\": \\"^9.1.3\\", 424 | \\"mocha-lcov-reporter\\": \\"^1.3.0\\", 425 | \\"nodemon\\": \\"^2.0.14\\", 426 | \\"prettier\\": \\"^1.15.3\\", 427 | \\"prettier-eslint\\": \\"^9.0.1\\", 428 | \\"prompt\\": \\"^1.2.0\\" 429 | }, 430 | \\"husky\\": { 431 | \\"hooks\\": { 432 | \\"pre-commit\\": \\"npm run lint-diff\\", 433 | \\"pre-push\\": \\"npm test\\" 434 | } 435 | } 436 | } 437 | " 438 | `; 439 | -------------------------------------------------------------------------------- /test/__snapshots__/testing.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`jest-supertest project creates expected package.json 1`] = ` 4 | "{ 5 | \\"name\\": \\"TestingProject\\", 6 | \\"version\\": \\"0.1.0\\", 7 | \\"description\\": \\"Example\\", 8 | \\"engines\\": { 9 | \\"node\\": \\"8.9.12\\", 10 | \\"npm\\": \\"6.4.1\\" 11 | }, 12 | \\"scripts\\": { 13 | \\"console\\": \\"node console.js\\", 14 | \\"cover\\": \\"npm run test -- --coverage\\", 15 | \\"test\\": \\"NODE_ENV=testing jest --runInBand --forceExit --detectOpenHandles\\", 16 | \\"test-inspect\\": \\"NODE_ENV=testing node --inspect --debug-brk jest\\", 17 | \\"eslint-check\\": \\"eslint --print-config .eslintrc.js --ignore-pattern ./.eslintrc.js | eslint-config-prettier-check\\", 18 | \\"lint\\": \\"eslint \\\\\\"**/*.js\\\\\\" --ignore-pattern ./.eslintrc.js\\", 19 | \\"lint-diff\\": \\"git diff --diff-filter=ACM --name-only --cached --relative | grep \\\\\\\\\\\\\\\\.js$ | xargs eslint\\", 20 | \\"lint-fix\\": \\"npm run lint -- --fix\\", 21 | \\"outdated\\": \\"npm outdated --depth 0\\", 22 | \\"pretest\\": \\"npm run lint\\", 23 | \\"start-dev\\": \\"nodemon --inspect server.js\\", 24 | \\"prestart-dev\\": \\"npm run lint\\", 25 | \\"start\\": \\"node server.js\\", 26 | \\"seed\\": \\"sequelize db:seed:all\\", 27 | \\"create-seed\\": \\"sequelize seed:generate --name\\", 28 | \\"create-migration\\": \\"sequelize migration:generate --name\\" 29 | }, 30 | \\"cacheDirectories\\": [ 31 | \\"node_modules\\" 32 | ], 33 | \\"main\\": \\"app.js\\", 34 | \\"author\\": \\"Wolox\\", 35 | \\"homepage\\": \\"https://test.com.ar\\", 36 | \\"license\\": \\"MIT\\", 37 | \\"repository\\": { 38 | \\"type\\": \\"git\\", 39 | \\"url\\": \\"https://test.com.ar.git\\" 40 | }, 41 | \\"bugs\\": { 42 | \\"url\\": \\"https://test.com.ar/issues\\", 43 | \\"email\\": \\"tls@wolox.com.ar\\" 44 | }, 45 | \\"jest\\": { 46 | \\"coverageThreshold\\": { 47 | \\"global\\": { 48 | \\"branches\\": 80, 49 | \\"functions\\": 80, 50 | \\"lines\\": 80, 51 | \\"statements\\": 80 52 | } 53 | }, 54 | \\"collectCoverageFrom\\": [ 55 | \\"**/*.js\\", 56 | \\"!**/console.js\\", 57 | \\"!**/node_modules/**\\", 58 | \\"!**/build/**\\", 59 | \\"!**/migrations/**\\", 60 | \\"!**/config/**\\", 61 | \\"!**/scripts/**\\" 62 | ], 63 | \\"setupFilesAfterEnv\\": [ 64 | \\"/test/setup.js\\" 65 | ], 66 | \\"testEnvironment\\": \\"node\\", 67 | \\"transform\\": { 68 | \\"^.+\\\\\\\\.js$\\": \\"babel-jest\\" 69 | } 70 | }, 71 | \\"dependencies\\": { 72 | \\"bcryptjs\\": \\"^2.4.3\\", 73 | \\"body-parser\\": \\"^1.19.0\\", 74 | \\"express\\": \\"^4.17.1\\", 75 | \\"jwt-simple\\": \\"^0.5.6\\", 76 | \\"umzug\\": \\"^2.3.0\\", 77 | \\"express-wolox-logger\\": \\"^2.0.0\\", 78 | \\"axios\\": \\"^0.24.0\\", 79 | \\"swagger-ui-express\\": \\"^4.1.6\\" 80 | }, 81 | \\"devDependencies\\": { 82 | \\"babel\\": \\"6.23.0\\", 83 | \\"babel-core\\": \\"^6.26.3\\", 84 | \\"babel-eslint\\": \\"^10.1.0\\", 85 | \\"babel-jest\\": \\"^27.3.1\\", 86 | \\"jest\\": \\"^27.3.1\\", 87 | \\"supertest\\": \\"^6.1.6\\", 88 | \\"babel-preset-es2015\\": \\"6.24.1\\", 89 | \\"dotenv\\": \\"^10.0.0\\", 90 | \\"eslint\\": \\"^6.8.0\\", 91 | \\"eslint-config-wolox\\": \\"^4.0.0\\", 92 | \\"eslint-config-wolox-node\\": \\"^3.0.0\\", 93 | \\"eslint-plugin-import\\": \\"^2.25.2\\", 94 | \\"eslint-plugin-prettier\\": \\"^3.0.1\\", 95 | \\"husky\\": \\"^7.0.4\\", 96 | \\"istanbul\\": \\"^0.4.3\\", 97 | \\"mocha\\": \\"^9.1.3\\", 98 | \\"mocha-lcov-reporter\\": \\"^1.3.0\\", 99 | \\"nodemon\\": \\"^2.0.14\\", 100 | \\"prettier\\": \\"^1.15.3\\", 101 | \\"prettier-eslint\\": \\"^9.0.1\\", 102 | \\"prompt\\": \\"^1.2.0\\" 103 | }, 104 | \\"husky\\": { 105 | \\"hooks\\": { 106 | \\"pre-commit\\": \\"npm run lint-diff\\", 107 | \\"pre-push\\": \\"npm test\\" 108 | } 109 | } 110 | } 111 | " 112 | `; 113 | 114 | exports[`mocha-chai project creates expected package.json 1`] = ` 115 | "{ 116 | \\"name\\": \\"TestingProject\\", 117 | \\"version\\": \\"0.1.0\\", 118 | \\"description\\": \\"Example\\", 119 | \\"engines\\": { 120 | \\"node\\": \\"8.9.12\\", 121 | \\"npm\\": \\"6.4.1\\" 122 | }, 123 | \\"scripts\\": { 124 | \\"console\\": \\"node console.js\\", 125 | \\"cover\\": \\"NODE_ENV=testing istanbul cover ./node_modules/mocha/bin/_mocha test/app.spec.js\\", 126 | \\"test\\": \\"NODE_ENV=testing ./node_modules/mocha/bin/_mocha --timeout 6000 --exit test/app.spec.js\\", 127 | \\"test-inspect\\": \\"NODE_ENV=testing node --inspect-brk ./node_modules/mocha/bin/_mocha test/app.spec.js\\", 128 | \\"eslint-check\\": \\"eslint --print-config .eslintrc.js --ignore-pattern ./.eslintrc.js | eslint-config-prettier-check\\", 129 | \\"lint\\": \\"eslint \\\\\\"**/*.js\\\\\\" --ignore-pattern ./.eslintrc.js\\", 130 | \\"lint-diff\\": \\"git diff --diff-filter=ACM --name-only --cached --relative | grep \\\\\\\\\\\\\\\\.js$ | xargs eslint\\", 131 | \\"lint-fix\\": \\"npm run lint -- --fix\\", 132 | \\"outdated\\": \\"npm outdated --depth 0\\", 133 | \\"pretest\\": \\"npm run lint\\", 134 | \\"start-dev\\": \\"nodemon --inspect server.js\\", 135 | \\"prestart-dev\\": \\"npm run lint\\", 136 | \\"start\\": \\"node server.js\\", 137 | \\"seed\\": \\"sequelize db:seed:all\\", 138 | \\"create-seed\\": \\"sequelize seed:generate --name\\", 139 | \\"create-migration\\": \\"sequelize migration:generate --name\\" 140 | }, 141 | \\"cacheDirectories\\": [ 142 | \\"node_modules\\" 143 | ], 144 | \\"main\\": \\"app.js\\", 145 | \\"author\\": \\"Wolox\\", 146 | \\"homepage\\": \\"https://test.com.ar\\", 147 | \\"license\\": \\"MIT\\", 148 | \\"repository\\": { 149 | \\"type\\": \\"git\\", 150 | \\"url\\": \\"https://test.com.ar.git\\" 151 | }, 152 | \\"bugs\\": { 153 | \\"url\\": \\"https://test.com.ar/issues\\", 154 | \\"email\\": \\"tls@wolox.com.ar\\" 155 | }, 156 | \\"dependencies\\": { 157 | \\"bcryptjs\\": \\"^2.4.3\\", 158 | \\"body-parser\\": \\"^1.19.0\\", 159 | \\"express\\": \\"^4.17.1\\", 160 | \\"jwt-simple\\": \\"^0.5.6\\", 161 | \\"umzug\\": \\"^2.3.0\\", 162 | \\"express-wolox-logger\\": \\"^2.0.0\\", 163 | \\"axios\\": \\"^0.24.0\\", 164 | \\"swagger-ui-express\\": \\"^4.1.6\\" 165 | }, 166 | \\"devDependencies\\": { 167 | \\"babel\\": \\"6.23.0\\", 168 | \\"babel-core\\": \\"^6.26.3\\", 169 | \\"babel-eslint\\": \\"^10.1.0\\", 170 | \\"babel-preset-es2015\\": \\"6.24.1\\", 171 | \\"chai\\": \\"^4.3.4\\", 172 | \\"chai-http\\": \\"^4.3.0\\", 173 | \\"dotenv\\": \\"^10.0.0\\", 174 | \\"eslint\\": \\"^6.8.0\\", 175 | \\"eslint-config-wolox\\": \\"^4.0.0\\", 176 | \\"eslint-config-wolox-node\\": \\"^3.0.0\\", 177 | \\"eslint-plugin-import\\": \\"^2.25.2\\", 178 | \\"eslint-plugin-prettier\\": \\"^3.0.1\\", 179 | \\"husky\\": \\"^7.0.4\\", 180 | \\"istanbul\\": \\"^0.4.3\\", 181 | \\"mocha\\": \\"^9.1.3\\", 182 | \\"mocha-lcov-reporter\\": \\"^1.3.0\\", 183 | \\"nodemon\\": \\"^2.0.14\\", 184 | \\"prettier\\": \\"^1.15.3\\", 185 | \\"prettier-eslint\\": \\"^9.0.1\\", 186 | \\"prompt\\": \\"^1.2.0\\" 187 | }, 188 | \\"husky\\": { 189 | \\"hooks\\": { 190 | \\"pre-commit\\": \\"npm run lint-diff\\", 191 | \\"pre-push\\": \\"npm test\\" 192 | } 193 | } 194 | } 195 | " 196 | `; 197 | -------------------------------------------------------------------------------- /test/ci.spec.js: -------------------------------------------------------------------------------- 1 | const utils = require('./helpers/utils'); 2 | const { mockCommand } = require('./helpers/mocks'); 3 | const { basicFiles, jenkinsFiles, travisFiles, examplePrompts } = require('./helpers/constants'); 4 | 5 | beforeAll(() => mockCommand()); 6 | 7 | const ciOptions = [ 8 | ['travis', travisFiles], 9 | ['jenkins', jenkinsFiles] 10 | ]; 11 | 12 | describe.each(ciOptions)('%s project', (ciName, files) => { 13 | beforeAll(() => 14 | utils.runKickoff({ 15 | ...examplePrompts, 16 | projectName: 'CIProject', 17 | ci: ciName 18 | }) 19 | ); 20 | 21 | test(`creates files for ${ciName} project`, () => { 22 | utils.checkExistentFiles([basicFiles, files], 'CIProject'); 23 | }); 24 | 25 | test.each(files)('creates expected %s', file => { 26 | expect(utils.getFileContent(`CIProject/${file}`)).toMatchSnapshot(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/deploy.spec.js: -------------------------------------------------------------------------------- 1 | const utils = require('./helpers/utils'); 2 | const { mockCommand } = require('./helpers/mocks'); 3 | const { examplePrompts } = require('./helpers/constants'); 4 | 5 | beforeAll(() => mockCommand()); 6 | 7 | const deployOptions = [ 8 | ['docker', { files: ['Dockerfile'], kickoffOptions: { docker: true, deployStrategy: { aws: false } } }], 9 | [ 10 | 'docker and aws', 11 | { 12 | files: ['Dockerfile', 'Dockerrun.aws.json', '.ebextensions/cloudwatch.config'], 13 | kickoffOptions: { docker: true, deployStrategy: { aws: true } } 14 | } 15 | ], 16 | [ 17 | 'heroku', 18 | { files: ['Procfile'], kickoffOptions: { docker: false, deployStrategy: { aws: false, heroku: true } } } 19 | ], 20 | [ 21 | 'aws', 22 | { 23 | files: ['.ebextensions/cloudwatch.config'], 24 | kickoffOptions: { docker: true, deployStrategy: { aws: true } } 25 | } 26 | ] 27 | ]; 28 | 29 | describe.each(deployOptions)('Deploy with %s', (deployOption, { files, kickoffOptions }) => { 30 | beforeAll(() => 31 | utils.runKickoff({ 32 | ...examplePrompts, 33 | ...kickoffOptions, 34 | projectName: 'DeployProject' 35 | }) 36 | ); 37 | 38 | test(`creates files for ${deployOption}`, () => { 39 | utils.checkExistentFiles(files, 'DeployProject'); 40 | }); 41 | 42 | test.each(files)('creates expected %s', file => { 43 | expect(utils.getFileContent(`DeployProject/${file}`)).toMatchSnapshot(); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /test/general.spec.js: -------------------------------------------------------------------------------- 1 | const { flatten } = require('lodash'); 2 | const utils = require('./helpers/utils'); 3 | const { mockCommand } = require('./helpers/mocks'); 4 | const { exampleProjects, basicFiles } = require('./helpers/constants'); 5 | 6 | beforeAll(() => mockCommand()); 7 | 8 | describe.each(exampleProjects)( 9 | 'Example project with %s', 10 | (projectName, { kickoffOptions, files, templateFiles }) => { 11 | beforeAll(() => 12 | utils.runKickoff({ 13 | ...kickoffOptions, 14 | nodeVersion: '8.9.12', 15 | npmVersion: '6.4.1', 16 | inTraining: false, 17 | projectName: 'Project', 18 | projectDescription: 'Project', 19 | urlRepository: 'https://test.com.ar' 20 | }) 21 | ); 22 | 23 | test(`creates basic files for ${projectName}`, () => { 24 | utils.checkExistentFiles(files, 'Project'); 25 | utils.checkExistentFiles(basicFiles, 'Project'); 26 | }); 27 | 28 | test.each(flatten([...templateFiles, ...basicFiles]))('creates expected %s', file => { 29 | expect(utils.getFileContent(`Project/${file}`)).toMatchSnapshot(); 30 | }); 31 | } 32 | ); 33 | -------------------------------------------------------------------------------- /test/helpers/constants.js: -------------------------------------------------------------------------------- 1 | exports.sequelizeFiles = [ 2 | '.sequelizerc', 3 | 'migrations/index.js', 4 | 'migrations/migrations/.keep', 5 | 'config/db.js', 6 | 'app/models/index.js' 7 | ]; 8 | 9 | exports.documentationRequiresAuth = ['app/middlewares/docsAuth.js']; 10 | 11 | exports.sequelizeTemplateFiles = ['package.json', 'README.md', 'console.js', 'server.js', 'config/db.js']; 12 | 13 | exports.mongooseTemplateFiles = ['package.json', 'README.md', 'console.js', 'server.js', 'config/db.js']; 14 | 15 | exports.testingFiles = ['package.json']; 16 | 17 | exports.jenkinsFiles = ['Jenkinsfile', '.woloxci/config.yml', '.woloxci/Dockerfile']; 18 | 19 | exports.herokuFiles = ['Procfile']; 20 | 21 | exports.dockerFiles = ['Dockerfile', 'Dockerrun.aws.json']; 22 | 23 | exports.travisFiles = ['.travis.yml']; 24 | 25 | exports.basicFiles = [ 26 | 'README.md', 27 | 'pull_request_template.md', 28 | 'package.json', 29 | 'LICENSE.md', 30 | 'console.js', 31 | 'app.js', 32 | 'server.js', 33 | '.nvmrc', 34 | '.gitignore', 35 | '.eslintrc.js', 36 | '.eslintignore', 37 | 'config/development.js', 38 | 'config/production.js', 39 | 'config/testing.js', 40 | 'config/index.js', 41 | 'app/controllers/healthCheck.js', 42 | 'app/services/.keep', 43 | 'app/errors.js', 44 | 'app/routes.js', 45 | 'app/middlewares/errors.js', 46 | 'app/logger/index.js' 47 | ]; 48 | 49 | exports.examplePrompts = { 50 | inTraining: false, 51 | projectName: 'Example', 52 | projectDescription: 'Example', 53 | urlRepository: 'https://test.com.ar', 54 | nodeVersion: '8.9.12', 55 | npmVersion: '6.4.1', 56 | documentationRequiresAuth: true, 57 | database: true, 58 | orm: { sequelize: false }, 59 | docker: false, 60 | deployStrategy: {}, 61 | optionalsFeatures: {}, 62 | ci: 'travis', 63 | testing: 'jest-supertest' 64 | }; 65 | 66 | exports.jestAndSequelizeFiles = ['test/factory/factory_by_models.js']; 67 | 68 | exports.exampleProjects = [ 69 | [ 70 | 'Sequelize (Postgres), AWS, Docker, Jest, Jenkins and all optionals', 71 | { 72 | kickoffOptions: { 73 | documentationRequiresAuth: true, 74 | database: true, 75 | orm: { sequelize: true }, 76 | sequelizeVersion: '^1.1.2', 77 | sequelizeDialect: 'postgres', 78 | docker: true, 79 | deployStrategy: { aws: true }, 80 | optionalsFeatures: { 81 | cors: true, 82 | rollbar: true, 83 | coveralls: true 84 | }, 85 | ci: 'jenkins', 86 | testing: 'jest-supertest' 87 | }, 88 | templateFiles: [exports.dockerFiles, exports.sequelizeTemplateFiles, exports.jenkinsFiles], 89 | files: [ 90 | exports.sequelizeFiles, 91 | exports.dockerFiles, 92 | exports.jenkinsFiles, 93 | exports.jestAndSequelizeFiles 94 | ] 95 | } 96 | ], 97 | [ 98 | 'Sequelize (MySQL), AWS, Docker, Jest, Jenkins and non optionals', 99 | { 100 | kickoffOptions: { 101 | documentationRequiresAuth: true, 102 | database: true, 103 | orm: { sequelize: true }, 104 | sequelizeVersion: '^1.1.2', 105 | sequelizeDialect: 'mysql', 106 | docker: true, 107 | deployStrategy: { aws: true }, 108 | optionalsFeatures: {}, 109 | ci: 'jenkins', 110 | testing: 'jest-supertest' 111 | }, 112 | templateFiles: [exports.dockerFiles, exports.sequelizeTemplateFiles, exports.jenkinsFiles], 113 | files: [ 114 | exports.sequelizeFiles, 115 | exports.dockerFiles, 116 | exports.jenkinsFiles, 117 | exports.jestAndSequelizeFiles 118 | ] 119 | } 120 | ], 121 | [ 122 | 'Sequelize (mssql), AWS, Docker, Mocha, Travis and all optionals', 123 | { 124 | kickoffOptions: { 125 | documentationRequiresAuth: true, 126 | database: true, 127 | orm: { sequelize: true }, 128 | sequelizeVersion: '^1.1.2', 129 | sequelizeDialect: 'postgres', 130 | docker: true, 131 | deployStrategy: { aws: true }, 132 | optionalsFeatures: { 133 | cors: true, 134 | rollbar: true, 135 | coveralls: true 136 | }, 137 | ci: 'travis', 138 | testing: 'mocha-chai' 139 | }, 140 | templateFiles: [exports.dockerFiles, exports.sequelizeTemplateFiles, exports.travisFiles], 141 | files: [exports.sequelizeFiles, exports.dockerFiles, exports.travisFiles] 142 | } 143 | ], 144 | [ 145 | 'Sequelize (sqlite), AWS, Docker, Mocha, Travis and non optionals', 146 | { 147 | kickoffOptions: { 148 | documentationRequiresAuth: true, 149 | database: true, 150 | orm: { sequelize: true }, 151 | sequelizeVersion: '^1.1.2', 152 | sequelizeDialect: 'sqlite', 153 | docker: true, 154 | deployStrategy: { aws: true }, 155 | optionalsFeatures: {}, 156 | ci: 'travis', 157 | testing: 'mocha-chai' 158 | }, 159 | templateFiles: [exports.dockerFiles, exports.sequelizeTemplateFiles, exports.travisFiles], 160 | files: [exports.sequelizeFiles, exports.dockerFiles, exports.travisFiles] 161 | } 162 | ], 163 | [ 164 | 'AWS, Docker, Jest, Jenkins and all optionals', 165 | { 166 | kickoffOptions: { 167 | documentationRequiresAuth: true, 168 | database: true, 169 | orm: { sequelize: false }, 170 | docker: true, 171 | deployStrategy: { aws: true }, 172 | optionalsFeatures: { 173 | cors: true, 174 | rollbar: true, 175 | coveralls: true 176 | }, 177 | ci: 'jenkins', 178 | testing: 'jest-supertest' 179 | }, 180 | templateFiles: [exports.dockerFiles, exports.jenkinsFiles], 181 | files: [exports.dockerFiles, exports.jenkinsFiles] 182 | } 183 | ], 184 | [ 185 | 'AWS, Docker, Jest, Jenkins and non optionals', 186 | { 187 | kickoffOptions: { 188 | documentationRequiresAuth: true, 189 | database: true, 190 | orm: { sequelize: false }, 191 | docker: true, 192 | deployStrategy: { aws: true }, 193 | optionalsFeatures: {}, 194 | ci: 'jenkins', 195 | testing: 'jest-supertest' 196 | }, 197 | templateFiles: [exports.dockerFiles, exports.jenkinsFiles], 198 | files: [exports.dockerFiles, exports.jenkinsFiles] 199 | } 200 | ], 201 | [ 202 | 'AWS, Docker, Jest, Travis and all optionals', 203 | { 204 | kickoffOptions: { 205 | documentationRequiresAuth: true, 206 | database: true, 207 | orm: { sequelize: false }, 208 | docker: true, 209 | deployStrategy: { aws: true }, 210 | optionalsFeatures: { 211 | cors: true, 212 | rollbar: true, 213 | coveralls: true 214 | }, 215 | ci: 'travis', 216 | testing: 'jest-supertest' 217 | }, 218 | templateFiles: [exports.dockerFiles, exports.travisFiles], 219 | files: [exports.dockerFiles, exports.travisFiles] 220 | } 221 | ], 222 | [ 223 | 'AWS, Docker, Jest, Travis and non optionals', 224 | { 225 | kickoffOptions: { 226 | documentationRequiresAuth: true, 227 | database: true, 228 | orm: { sequelize: false }, 229 | docker: true, 230 | deployStrategy: { aws: true }, 231 | optionalsFeatures: {}, 232 | ci: 'travis', 233 | testing: 'jest-supertest' 234 | }, 235 | templateFiles: [exports.dockerFiles, exports.travisFiles], 236 | files: [exports.dockerFiles, exports.travisFiles] 237 | } 238 | ] 239 | ]; 240 | 241 | exports.linterCommands = [ 242 | { 243 | description: 'Lint fix', 244 | name: 'npm', 245 | args: ['run', 'lint-external', '--', '--fix', '--no-eslintrc'] 246 | }, 247 | { description: 'Lint', name: 'npm', args: ['run', 'lint-external', '--', '--no-eslintrc'] } 248 | ]; 249 | -------------------------------------------------------------------------------- /test/helpers/mocks.js: -------------------------------------------------------------------------------- 1 | const command = require('../../generators/app/command'); 2 | 3 | exports.mockCommand = (implementation = () => Promise.resolve()) => 4 | jest.spyOn(command, 'runCommand').mockImplementation(implementation); 5 | -------------------------------------------------------------------------------- /test/helpers/utils.js: -------------------------------------------------------------------------------- 1 | const { flatten } = require('lodash'); 2 | const helpers = require('yeoman-test'); 3 | const path = require('path'); 4 | const fs = require('fs'); 5 | const assert = require('yeoman-assert'); 6 | 7 | let testDirectory = path.join(__dirname, 'tmp'); 8 | 9 | exports.getTestDirectory = filePath => (filePath ? `${testDirectory}/${filePath}` : testDirectory); 10 | 11 | exports.runKickoff = options => 12 | helpers 13 | .run(require.resolve('../../generators/app')) 14 | .inTmpDir(dir => { 15 | testDirectory = dir; 16 | }) 17 | .withPrompts(options) 18 | .toPromise(); 19 | 20 | const checkFiles = (checkFunction, files, directory) => 21 | assert[checkFunction](flatten(files).map(file => exports.getTestDirectory(`${directory}/${file}`))); 22 | 23 | exports.checkNonExistentFiles = (files, directory) => checkFiles('noFile', files, directory); 24 | 25 | exports.checkExistentFiles = (files, directory) => checkFiles('file', files, directory); 26 | 27 | exports.getFileContent = filePath => 28 | fs.readFileSync(exports.getTestDirectory(filePath), { encoding: 'utf-8' }); 29 | -------------------------------------------------------------------------------- /test/linter.spec.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const utils = require('./helpers/utils'); 4 | const { mockCommand } = require('./helpers/mocks'); 5 | const { runCommand } = require('../generators/app/command'); 6 | const { exampleProjects, linterCommands } = require('./helpers/constants'); 7 | 8 | const actualDirectory = path.resolve(__dirname); 9 | 10 | describe.each(exampleProjects)('Example project with %s', (projectName, { kickoffOptions }) => { 11 | beforeAll(() => { 12 | mockCommand(); 13 | return utils.runKickoff({ 14 | ...kickoffOptions, 15 | nodeVersion: '8.9.12', 16 | npmVersion: '6.4.1', 17 | inTraining: false, 18 | projectName: 'linter', 19 | projectDescription: 'Fake project to test linter', 20 | urlRepository: 'https://test.com.ar' 21 | }); 22 | }); 23 | 24 | test.each(linterCommands)('run the EsLinter for each project generated', command => { 25 | jest.setTimeout(30000); 26 | const tmpDirectory = utils.getTestDirectory('linter'); 27 | const args = [...command.args, `${tmpDirectory}`]; 28 | const projectRootDirectory = actualDirectory 29 | .split('/') 30 | .slice(0, -1) 31 | .join('/'); 32 | return runCommand({ 33 | ...command, 34 | args, 35 | spawnOptions: { cwd: projectRootDirectory } 36 | }).catch(err => { 37 | throw new Error(`Eslinter for project failed on command: ${command.description} with error: ${err}`); 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /test/mongoose.spec.js: -------------------------------------------------------------------------------- 1 | const utils = require('./helpers/utils'); 2 | const { mockCommand } = require('./helpers/mocks'); 3 | const { basicFiles, mongooseTemplateFiles, examplePrompts } = require('./helpers/constants'); 4 | 5 | const mongooseKickoff = options => 6 | utils.runKickoff({ 7 | ...examplePrompts, 8 | projectName: 'MongooseProject', 9 | projectDescription: 'MongooseProject', 10 | orm: { mongoose: true }, 11 | mongooseVersion: '^5.6.4', 12 | mongooseDialect: 'mongoDB', 13 | ...options 14 | }); 15 | 16 | beforeAll(() => mockCommand()); 17 | 18 | describe('Mongoose project ', () => { 19 | beforeAll(() => mongooseKickoff()); 20 | 21 | test('creates basic files and does not create sequelize files', () => { 22 | utils.checkExistentFiles([basicFiles], 'MongooseProject'); 23 | utils.checkNonExistentFiles( 24 | [['.sequelizerc', 'migrations/index.js', 'migrations/migrations/.keep', 'app/models/index.js']], 25 | 'MongooseProject' 26 | ); 27 | }); 28 | 29 | test.each(mongooseTemplateFiles)('creates expected %s', file => { 30 | expect(utils.getFileContent(`MongooseProject/${file}`)).toMatchSnapshot(); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/optionals.spec.js: -------------------------------------------------------------------------------- 1 | const utils = require('./helpers/utils'); 2 | const { mockCommand } = require('./helpers/mocks'); 3 | const { examplePrompts } = require('./helpers/constants'); 4 | 5 | beforeAll(() => mockCommand()); 6 | 7 | const optionals = [ 8 | ['rollbar', ['package.json', 'app.js']], 9 | ['cors', ['package.json', 'app.js']], 10 | ['coveralls', ['package.json']] 11 | ]; 12 | 13 | describe.each(optionals)('Project with %s', (optionalFeature, files) => { 14 | beforeAll(() => 15 | utils.runKickoff({ 16 | ...examplePrompts, 17 | projectName: 'OptionalProject', 18 | optionalsFeatures: { [optionalFeature]: true } 19 | }) 20 | ); 21 | 22 | test.each(files)('creates expected %s', file => { 23 | expect(utils.getFileContent(`OptionalProject/${file}`)).toMatchSnapshot(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/sequelize.spec.js: -------------------------------------------------------------------------------- 1 | const utils = require('./helpers/utils'); 2 | const { mockCommand } = require('./helpers/mocks'); 3 | const { 4 | basicFiles, 5 | sequelizeFiles, 6 | sequelizeTemplateFiles, 7 | jenkinsFiles, 8 | examplePrompts 9 | } = require('./helpers/constants'); 10 | 11 | const sequelizeKickoff = (dialect, options) => 12 | utils.runKickoff({ 13 | ...examplePrompts, 14 | projectName: 'SequelizeProject', 15 | projectDescription: 'SequelizeProject', 16 | orm: { sequelize: true }, 17 | sequelizeVersion: '^1.1.2', 18 | sequelizeDialect: dialect, 19 | ...options 20 | }); 21 | 22 | beforeAll(() => mockCommand()); 23 | 24 | const availableDialects = ['mysql', 'postgres', 'mssql', 'sqlite']; 25 | 26 | describe.each(availableDialects)('Sequelize project (%s)', dialect => { 27 | beforeAll(() => sequelizeKickoff(dialect)); 28 | 29 | test(`creates sequelize files for ${dialect}`, () => { 30 | utils.checkExistentFiles([basicFiles, sequelizeFiles], 'SequelizeProject'); 31 | }); 32 | 33 | test.each(sequelizeTemplateFiles)('creates expected %s', file => { 34 | expect(utils.getFileContent(`SequelizeProject/${file}`)).toMatchSnapshot(); 35 | }); 36 | }); 37 | 38 | describe.each(availableDialects)('Sequelize project (%s) along with Jenkins', dialect => { 39 | beforeAll(() => sequelizeKickoff(dialect, { ci: 'jenkins' })); 40 | 41 | test(`creates sequelize files for ${dialect}`, () => { 42 | utils.checkExistentFiles([basicFiles, sequelizeFiles, jenkinsFiles], 'SequelizeProject'); 43 | }); 44 | 45 | test.each([...sequelizeTemplateFiles, '.woloxci/config.yml'])('creates expected %s', file => { 46 | expect(utils.getFileContent(`SequelizeProject/${file}`)).toMatchSnapshot(); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /test/testing.spec.js: -------------------------------------------------------------------------------- 1 | const utils = require('./helpers/utils'); 2 | const { mockCommand } = require('./helpers/mocks'); 3 | const { basicFiles, examplePrompts, testingFiles } = require('./helpers/constants'); 4 | 5 | beforeAll(() => mockCommand()); 6 | 7 | const ciOptions = ['mocha-chai', 'jest-supertest']; 8 | 9 | describe.each(ciOptions)('%s project', testing => { 10 | beforeAll(() => 11 | utils.runKickoff({ 12 | ...examplePrompts, 13 | projectName: 'TestingProject', 14 | testing 15 | }) 16 | ); 17 | 18 | test(`creates files for ${testing} project`, () => { 19 | utils.checkExistentFiles([basicFiles, testingFiles], 'TestingProject'); 20 | }); 21 | 22 | test.each(testingFiles)('creates expected %s', file => { 23 | expect(utils.getFileContent(`TestingProject/${file}`)).toMatchSnapshot(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/training.spec.js: -------------------------------------------------------------------------------- 1 | const utils = require('./helpers/utils'); 2 | const { mockCommand } = require('./helpers/mocks'); 3 | const { 4 | basicFiles, 5 | sequelizeFiles, 6 | travisFiles, 7 | herokuFiles, 8 | jenkisFiles, 9 | dockerFiles, 10 | examplePrompts 11 | } = require('./helpers/constants'); 12 | 13 | describe('w-training project', () => { 14 | beforeAll(() => { 15 | mockCommand(); 16 | return utils.runKickoff({ ...examplePrompts, inTraining: true }); 17 | }); 18 | test('creates training files', () => { 19 | utils.checkExistentFiles([basicFiles, sequelizeFiles, travisFiles, herokuFiles], 'w-training'); 20 | utils.checkNonExistentFiles([jenkisFiles, dockerFiles], 'w-training'); 21 | }); 22 | }); 23 | --------------------------------------------------------------------------------