Skip to content

Commit

Permalink
feat: Add support to chain deployment and aliasing in a single command
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasdao committed Dec 19, 2017
0 parents commit 4d29b01
Show file tree
Hide file tree
Showing 8 changed files with 680 additions and 0 deletions.
29 changes: 29 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"env": {
"browser": true,
"commonjs": true,
"es6": true
},
"extends": "eslint:recommended",
"parserOptions": {
"sourceType": "module"
},
"rules": {
"indent": [
"error",
"tab"
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"never"
]
}
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
*.DS_Store
blabla.js
30 changes: 30 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
BSD License

For google-graphql-functions software

Copyright (c) 2017, Neap pty ltd. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name Facebook nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
133 changes: 133 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<a href="https://neap.co" target="_blank"><img src="https://neap.co/img/neap_black_small_logo.png" alt="Neap Pty Ltd logo" title="Neap" align="right" height="50" width="120"/></a>

# NowFlow - Automate your Zeit Now Deployments
[![NPM][1]][2]

[1]: https://img.shields.io/npm/v/now-flow.svg?style=flat
[2]: https://www.npmjs.com/package/now-flow

Define your alias and all your environment variables inside your traditional __*now.json*__, and let __*now-flow*__ do the rest.

_now.json_
```js
{
"env": {
"production": {
"scripts": {
"start": "NODE_ENV=production node index.js"
},
"alias": "yourapp-prod"
},
"test": {
"scripts": {
"start": "NODE_ENV=test node index.js"
},
"alias": "yourapp-test"
}
}
}
```

```
nowflow production
```

The above will make sure that the _package.json_ that is being deployed will contain the _start_ script `"NODE_ENV=production node index.js"` and that once the deployment to [Zeit](https://zeit.co/now) is finished, it is automatically aliased to `yourapp-prod`.

No more deployment then aliasing steps. No more worries that some environment variables have been properly deployed to the right environment.


# Install
Either install it globally
```
npm install now-flow -g
```

Or embed it inside your project to run it through npm

```
npm install now-flow --save
```

# How To Use It
## Basic
You must first create a __*now.json*__ file in the root of your project's directory as follow:
```js
{
"env": {
"production": {
"alias": "yourapp-prod"
},
"test": {
"alias": "yourapp-test"
}
}
}
```

Make sure there is at least one environment defined under the _env_ property. Then simply run:

```
nowflow production
```

The above will:
1. Deploy your project to [Zeit](https://zeit.co/now) using the _production_ config defined in the _now.json_.
2. Will alias that deployment using the alias defined in the _production_ config defined in the _now.json_ (i.e. 'yourapp-prod').

## Skipping Aliasing
If you do not want to alias your deployment, use the following:
```
nowflow production --noalias
```

## Modifying The package.json's "scripts" property For Each Environment
As described in the intro, this is one of the key feature of _now-flow_. In the _now.json_, under each specific environment, you can add a __*"script"*__ property that will completely override the one defined inside the _package.json_ during the deployment. Once the deployment is completed, the _package.json_ is restored to its original state.

```js
{
"env": {
"production": {
"scripts": {
"start": "NODE_ENV=production node index.js"
},
"alias": "yourapp-prod"
},
"test": {
"scripts": {
"start": "NODE_ENV=test node index.js"
},
"alias": "yourapp-test"
}
}
}
```

```
nowflow production
```

In the example above, we're making sure that the _package.json_ contains a _start_ script so that _now_ can, for example, correctly start an express server.

# This Is What We re Up To
We are Neap, an Australian Technology consultancy powering the startup ecosystem in Sydney. We simply love building Tech and also meeting new people, so don't hesitate to connect with us at [https://neap.co](https://neap.co).

# License
Copyright (c) 2017, Neap Pty Ltd.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Neap Pty Ltd nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL NEAP PTY LTD BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 changes: 24 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env node
/**
* Copyright (c) 2017, Neap Pty Ltd.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict'

const program = require('commander')
const { deploy } = require('./src/nowf')

program
.command('* <env>')
.usage('Deploy to Zeit Now using a specific environment configuration that will configure the \'now.json\' and the \'package.json\' accordingly.')
.option('-n, --noalias', 'When specified, prevent deployment to be aliased.')
.action((env, options={}) => {
deploy(env, ((options.parent || {}).rawArgs || []).some(x => (x == '--noalias' || x == '--noa')))
})

/*eslint-disable */
program.parse(process.argv)
/*eslint-enable */
40 changes: 40 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "now-flow",
"version": "0.0.1",
"description": "Add deployment workflows to Zeit now",
"main": "index.js",
"bin": {
"nowflow": "./index.js"
},
"scripts": {
"eslint": "eslint ./src index.js --fix",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/nicolasdao/now-workflow.git"
},
"keywords": [
"Zeit",
"now",
"deploy",
"deployment",
"worflow"
],
"author": "Nicolas Dao",
"license": "BSD-3-Clause",
"bugs": {
"url": "https://github.com/nicolasdao/now-workflow/issues"
},
"homepage": "https://github.com/nicolasdao/now-workflow#readme",
"dependencies": {
"colors": "^1.1.2",
"commander": "^2.12.2",
"lodash": "^4.17.4",
"rimraf": "^2.6.2",
"shortid": "^2.2.8"
},
"devDependencies": {
"eslint": "^4.13.1"
}
}
121 changes: 121 additions & 0 deletions src/nowf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/**
* Copyright (c) 2017, Neap Pty Ltd.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
const path = require('path')
require('colors')
const { writeToFile } = require('./utilities').files

/*eslint-disable */
const getAbsPath = relativePath => path.join(process.cwd(), relativePath)
const exit = msg => {
if (msg)
console.log(msg)
process.exit()
}
/*eslint-enable */

const duplicate = obj => obj ? JSON.parse(JSON.stringify(obj)) : obj

const updatePackageScripts = (env='default') => {
let nowConfig
nowConfig = require(getAbsPath('now.json')) || {}

const envConfig = (nowConfig.env || {})[env]
if (!envConfig)
throw new Error(`No environment named '${env.bold}' in ${'now.json'.bold}`)

const pkgPath = getAbsPath('package.json')
if (envConfig.scripts != undefined) {
const currentPkg = require(pkgPath) || {}
const newPkg = duplicate(currentPkg)

if (!currentPkg.scripts)
newPkg.scripts = {}

for (let script in envConfig.scripts)
newPkg.scripts[script] = envConfig.scripts[script]

return updateJsonFile(pkgPath, newPkg)
.then(() => ({ path: pkgPath, current: currentPkg, new: newPkg }))
// If updating the package.json fails, attempt to revert
.catch(err => {
return updateJsonFile(pkgPath, currentPkg)
.catch(() => null)
.then(() => { throw err })
})
}
else
return Promise.resolve({ path: pkgPath, current: null })
}

const updateNowAlias = (env='default', toogle=true) => {
const nowPath = getAbsPath('now.json')
const currentNowConfig = require(nowPath) || {}
const newNowConfig = duplicate(currentNowConfig)

const envConfig = (currentNowConfig.env || {})[env]
if (!envConfig)
throw new Error(`No environment named '${env.bold}' in ${'now.json'.bold}`)

if (envConfig.alias != undefined && toogle) {
newNowConfig.alias = envConfig.alias

return updateJsonFile(nowPath, newNowConfig)
.then(() => ({ alias: toogle, path: nowPath, current: currentNowConfig, new: newNowConfig }))
// If updating the now.json fails, attempt to revert
.catch(err => {
return updateJsonFile(nowPath, currentNowConfig)
.catch(() => null)
.then(() => { throw err })
})
}
else
return Promise.resolve({ alias: false, path: nowPath, current: null })
}

const updateJsonFile = (filePath, jsonObj={}) => {
const str = JSON.stringify(jsonObj, null, '\t')
return writeToFile(filePath, str)
}

const deploy = (env='default', noalias=false) => updatePackageScripts(env)
.catch(err => exit(err.message.italic.red))
.then(pkg => {
try {
require('child_process').execSync('now', { stdio: 'inherit' })
}
catch(err) {
return updateJsonFile(pkg.path, pkg.current)
.then(() => exit())
.catch(() => exit())
}

return updateJsonFile(pkg.path, pkg.current)
})
.catch(err => exit(err.message.italic.red))
.then(() => {
if (!noalias)
return updateNowAlias(env).then(now => {
if (now.alias) {
try {
require('child_process').execSync('now alias', { stdio: 'inherit' })
}
catch(err) {
return updateJsonFile(now.path, now.current)
.then(() => exit())
.catch(() => exit())
}

return updateJsonFile(now.path, now.current)
}
})
})

module.exports = {
deploy
}

Loading

0 comments on commit 4d29b01

Please sign in to comment.