UNPKG

@doop/deploy

Version:
227 lines (183 loc) 11 kB
@Doop/Deploy ============ All purpose Doop server deployment script. This project exposes an executable command line script `doop-deploy` which is used to deploy [Doop](https://github.com/MomsFriendlyDevCo/Doop) projects based on their configuration from `app.config.deploy.profiles`. **Features**: * Simple pull from git + build + restart PM2 deployment process * Peer deployments of other profiles if required * Special branch expressions to query + deploy to complex branches * File date deltas to skip unnecessary package reinstall, build, restart steps * Automatic handling of PM2 processes and custom names * Optional branch Semver + version bumping on successful deploy NOTE: For verbose debugging set the `DEBUG=deploy` environment variable as per the [Debug](https://github.com/debug-js/debug) config. System-wide config ------------------ @Doop/Deploy generally reads from a Doop projects main config object but if the script is installed system-wide it will also check for a `~/.doop-deploy` INI file first. Any keys within this file are merged into the main ENV setup before processing anything else. An example of using `~/.doop-deploy` to specify a directory to change to before trying to read config: ``` # Change to site directory to read config DOOP_DEPLOY_BASE=/sites/acme.com ``` Environment Variables --------------------- Environment variables are read from the current shell and the above `~/.doop-deploy` file before execution. | Variable | Type | Description | |-----------------------|----------|-------------------------------------------------------------------| | `DOOP_DEPLOY_BASE` | `String` | Set the working direcotry before attempting to read in the config | | `DOOP_DEPLOY_PROFILE` | `String` | Profile to deploy if no CLI profile is selected | Configuration ------------- Configuration is read per-profile from the `app.config.deploy.profiles` object. Each key is the local ID of the profile with the object following the specification below. | Config key | Type | Default | Description | |-------------------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------------------------| | `id` | `String` | (key) | The key of the object, provided here for the template engine | | `enabled` | `Boolean` | `true` | Whether the profile is directly deployable, if disabled the profile can only be deployed via a `peerDeploy` | | `path` | `String` | (current path) | Change to this root directory before deploying a profile | | `script` | `Array` / `String` | | Script or other executable which will be run instead of any of the below processes | | `repo` | `String` | `--repo=<REPO>` or `"origin"` | Which source repository to use when deploying, `--repo` overrides the setting if present | | `branch` | `String` | `--branch=<BRANCH>` or `"master"` | The branch to use when deploying, can be a complex expression - see Branch Expressions | | `title` | `String` | (key via _.startCase) | The human readable name of the deployment profile | | `sort` | `Number` | `10` | Sort position if deploying multiple profiles (low-to-high) | | `peerDeploy` | `Array` / `String` | `""` | Additional deployments implied if this profile is deployed | | `peerDeny` | `Array` / `String` | `""` | Deployments that are not allowed alongside this profile - an error is raised if both are attempted at once | | `processes` | `Number` | `1` | The number of PM2 processes to manage during a deployment | | `env` | `Object` | `{}` | Environment variables to set when building (usually `NODE_ENV` needs to be set | | `semver` | `Boolean` / `String` | `false` | Whether to commit a new version completion, ENUM: 'patch' / `true`, 'minor', 'major' | | `semverPackage` | `Boolean` | `true` | Whether to also bump the new version in `package.json` | | `pm2Name` | `String` | `"${profile.id}-${process.alpha}"` | Templatable name of the PM2 processes | | `pm2Names` | `Array<String>` | (Computed from pm2Name if not specified) | Computed templatable names or manual overrides if needed | | `pm2Args` | `Object<Array>` | `{}` | Specific PM2 arguments per computed instance name | | `pm2Args.default` | `Array` | `['-e', (key)]` | Universal defaults for PM2 process arguments if no other key matches | **Notes:** * Profiles are always deployed according to `sort` order, even if specified by `peerDeploy` * Setting `semver` requires write access as it will try to commit the new version based on the result of the deployment (cherry-picks and all) * If `script` is specified it is deferred to instead of any other deploy process - no fetching, building or restarts are performed - only the script is run * When using `script` only the `path` and `env` settings are processed - all other settings are ignored Branch expressions ------------------ The `branch` property can be set to either: * A branch name (e.g. 'master', 'dev') * A tag (e.g. 'v1.2.3') * A patch hash (e.g. '36d050e', 'f9748544f569e38646a10e8aeecdd0fa47bba0ac') * One of the special expressions below The following branch expressions are also supported, they take the form `TYPE ARG1=VAL1,ARG2=VAL2,ARG3=VAL3` (e.g. `branch: tag semver=v1.x.x,sort=desc`) | Branch type | Arguments | Default | Description | |-------------|-----------|----------|---------------------------------------------------------------------------| | `tag` | `semver` | `"*"` | A semver expression to filter tags by, the first valid semver tag is used | | | `sort` | `"desc"` | Whether to sort tags asending, decending before filtering | String Templates ---------------- Some config options can be templated using [ES6 template syntax](https://github.com/MomsFriendlyDevCo/template). The following variables are available when templating: | Variable | Type | Description | |------------------|----------|---------------------------------------------------------| | `_` | `Object` | Lodash instance | | `semver` | `Object` | Semver instance | | `profile` | `Object` | Profile configuration object (see above for details) | | `process` | `Object` | Details about the current proceses iteration | | `process.offset` | `Number` | Offset (starting at zero) of the current iteration | | `process.alpha` | `String` | Alphabetical offset of the process (e.g. 'a', 'b' etc.) | | `process.name` | `String` | Computed process name | Example config ============== Project config -------------- The following is a recommended setup in `package.json`: ```json { "name": "acme-project", "version": "1.0.0", "description": "Project that does stuff", "main": "server/index.js", "scripts": { "build": "gulp build", "dev": "gulp serve", "deploy": "doop-deploy", "deploy:pre": "gulp preDeploy", "deploy:post": "gulp postDeploy", "start": "node server" } } ``` Basic config ------------ The following is a standard deployment setup with a "Dev" and "Live" profile located in two different paths. ```javascript # Within in a Doop `config/index.js` file: var config = { deploy: { profiles: { dev: { title: 'Dev', path: '/sites/dev.acme.com', sort: 1, processes: 2, env: {'NODE_ENV': 'dev'}, pm2Name: 'dev-${process.alpha}', pm2Args: { default: [ '-e', 'dev', '-o', 'port=${10000 + process.offset + 1}', '-o', 'papertrail-program=${process.name}', ], 'dev-a': [ '-e', 'dev', '-o', 'port=${10000 + process.offset + 1}', '-o', 'papertrail-program=${process.name}', '-o', 'cache.cleanAuto=true', '-o', 'mongo.migration=true', ], }, }, live: { title: 'Live', path: '/sites/acme.com', sort: 2, processes: 8, env: {'NODE_ENV': 'production'}, pm2Name: 'live-${process.alpha}', pm2Args: { default: [ '-e', 'production', '-o', 'port=${10100 + process.offset + 1}', '-o', 'papertrail-program=${process.name}', ], 'live-a': [ '-e', 'production', '-o', 'port=${10000 + process.offset + 1}', '-o', 'papertrail-program=${process.name}', '-o', 'cache.cleanAuto=true', '-o', 'mongo.migration=true', ], }, }, }, }, } ``` Chain deployments ----------------- The following is an example where: * Dev becomes the latest version (on `npm run deploy --dev`) * Live becomes the Dev version on deploy (on `npm run deploy --live`) * Fallback is always the previously deployed live version * Any deployment to Dev is incremented as a patch on semver, if live is deployed it uses the latest semver The config below should be spliced into the existing config profile: ```javascript var config = { deploy: { profiles: { dev: { semver: 'patch', // Increment semver when deploying Dev }, live: { peerDeploy: ['dev', 'fallback'], // Imply other profiles must be updated first }, fallback: { enabled: false, // Disable direct deployment }, }, }, }; ```