diff --git a/bin/nariya.js b/bin/nariya.js index fb40c60..edbd84d 100644 --- a/bin/nariya.js +++ b/bin/nariya.js @@ -72,12 +72,23 @@ if(action == 'start') { if(yes) { + deployer.findStartScript(process.cwd(), startScriptFounded); + + } else { + console.error('+ This is not an valid git project'.bold.red); + } + } + + function startScriptFounded(err, script) { + + if(!err) { var repoInfo = { location: process.cwd(), logpath: path.resolve(nariyaHome, './' + name), type: 'github', secret: md5('' + Math.random()), - branch: 'master' + branch: 'master', + startScript: script } //create the log path mkdirp(repoInfo.logpath, 0755); @@ -90,7 +101,7 @@ if(action == 'start') { startNariya(); } else { - console.error('+ This is not an valid git project'.bold.red); + console.error('+ Error loading Startup Script: %s'.bold.red, err.message); } } diff --git a/conf/nariya.conf b/conf/nariya.conf index e0d01ff..ee10556 100644 --- a/conf/nariya.conf +++ b/conf/nariya.conf @@ -26,7 +26,9 @@ */ "type": "github", - "logpath": "/tmp" + "logpath": "/tmp", + + "startScript": "start-nh.js" }, "nariya-helloworld": { diff --git a/conf/sample.conf b/conf/sample.conf index 29f5fd8..1fbeb82 100644 --- a/conf/sample.conf +++ b/conf/sample.conf @@ -38,17 +38,17 @@ "port": 587, "ssl": false, "use_authentication": true, - "user": "admin@dfdsdf.com", - "pass": "sdfdsfsd" + "user": "admin@sample.com", + "pass": "sample" }, "me": { - "name": "Arunoda Susiripala", - "email": "admin@dfdsdf.com" + "name": "Sample Man", + "email": "admin@sample.com" }, "receivers": [ - "df.sdsd@gmail.com" + "hello@gmail.com" ] }, diff --git a/lib/deployer.js b/lib/deployer.js index fac1e63..db1666b 100644 --- a/lib/deployer.js +++ b/lib/deployer.js @@ -29,7 +29,12 @@ function Deployer() { function(error, deployed: boolean) deployed would get false if NO_DEPLOY file exists without an error */ - this.deploy = function(appname, location, logpath, callback) { + this.deploy = function(repoInfo, callback) { + + var appname = repoInfo.name; + var location = repoInfo.location; + var logpath = repoInfo.logpath; + var startScript = repoInfo.startScript; logger.info('deploying app', {location: location, appname: appname}); @@ -69,8 +74,9 @@ function Deployer() { var outLogs = path.resolve(logpath, appname + '.log'); var errLogs = path.resolve(logpath, appname + '.err.log'); - var appStartCommad = 'forever stop start.js && SL_NAME=' + appname + ' forever start -o ' + outLogs + ' -e ' + errLogs + ' start.js'; - self.executeIfExists(location, 'start.js', appStartCommad, afterAppStarted); + var appStartCommad = 'forever stop ' + startScript + ' && SL_NAME=' + appname + ' forever start -o ' + outLogs + ' -e ' + errLogs + ' -a ' + startScript; + + self.executeIfExists(location, startScript, appStartCommad, afterAppStarted); } else { logger.error('error on executing pre.sh', {error: error}); @@ -191,4 +197,29 @@ function Deployer() { } }); } + + /** + Find the valid startScript to start with node + it should match /^start.*\.js$/ + */ + this.findStartScript = function(location, callback) { + + fs.readdir(location, function(err, files) { + + if(!err) { + + for(var index in files) { + var file = files[index]; + if(file.match(/^start.*\.js$/)) { + return callback(null, file); + } + } + //if no one selected + return callback(); + + } else { + callback(err); + } + }); + }; } \ No newline at end of file diff --git a/lib/webhookListener.js b/lib/webhookListener.js index 81b3b4c..130dd09 100644 --- a/lib/webhookListener.js +++ b/lib/webhookListener.js @@ -41,7 +41,7 @@ function WebhookListener(configurationManager, repositories, deployer, notifiers if(!err) { - deployer.deploy(repoInfo.name, repoInfo.location, repoInfo.logpath, afterDeployed); + deployer.deploy(repoInfo, afterDeployed); } else { logger.error('repository update failed', {err: err, appname: repoInfo.name}); notifiers.emit('deploy.failed', repoInfo.name, err); diff --git a/package.json b/package.json index f3fe17e..ddd9d61 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nariya", - "version": "0.1.2", + "version": "0.1.3", "directories": { "lib": "./lib" }, diff --git a/readme.md b/readme.md index acbab56..7a0aee5 100644 --- a/readme.md +++ b/readme.md @@ -1,82 +1,50 @@ Nariya ====== -Continuous Deploymentor for NodeJS +Simple [Continuous Deployment](http://www.avc.com/a_vc/2011/02/continuous-deployment.html) Server -Nariya is powered by Git and Web Hooks. Nariya gets updates for the project using `git pull master` -And a valid nariya project should have followings +Nariya is a Continuous Deployment Server written in node.js and Design for easy of use. Currently It supports Github based deployments. -* `package.json` file -* `start.js` - which should inititate the application -* `start.js` should takes whateever the port required to starts the app using arguments - eg:- if the app required 2 ports - node start.js 8090 8091 +Great for NodeJS project but designed to be work with any project + +Currently Nariya supports Github based projects only. (But can be added others easlily) + +How It Works +------------ + +* First you add your Github based project to Nariya (its very easy) +* You'll get an unique web url +* Then you've to configure above as an Github Service Hook (webhook) +* After that when you did a commit following happens +* Nariya will get the updates codebase to the server from github +* Then if it is an NodeJS project it will `npm install` +* After if your projet folder has `pre.sh` file it will be executed +* Then If your node project has `start*.js` file Nariya will start that script with forever eg:- `start-app.js`, `startApp.js` +* Then it will look for `post.sh` and execute if exists +* You will get an email notification once this completed (look for configurations) Install ------- + sudo npm install forever -g sudo npm install nariya -g Usage ------ - -* Visit to the project folder (git enabled) -* If your project only required one port and we need two workers +------- - `nariya --api 8000 -p 8081 -p 8082` +* Start the Server - `nariya start` +* Visit your github based project and add it - `nariya add ` +* You'll be shown an url +* Then add the url you generated as an Github Service Hook
+ eg:- https://github.com/arunoda/nariya/admin/hooks +* That's all. Push some commit to master branch ans see for your self +* Add any number of projects you want -Trigger Update +Configurations -------------- -* As in the above example nariya's api runs on port `8000` -* If you need to trigger the deployment send an HTTP request - - `curl http://localhost:8000/update -X POST` -* This always start new app by port by port. If you have 3 workers running with the every deployment you always have 2 workers running everytime - -Logs ----- - -Logs available at the following folder - - $HOME/.nariya/$APPNAME/logs/$PORT.log - -* $HOME - home folder of the machine -* $APPNAME - appname retrieved from the `package.json` -* $PORT - port where worker is running - -Temporary App Folder --------------------- - -Tempory apps are copied to following folder - - $HOME/.nariya/$APPNAME/apps - -Email Notificator ------------------ - -### Config File - -Following configuration should stored in `email.json` file at the root folder - - { - "smtp": { - "host": "smtp.gmail.com", - "port": 587, - "ssl": false, - "use_authentication": true, - "user": "admin@dfdsdf.com", - "pass": "sdfdsfsd" - }, - - "me": { - "name": "Arunoda Susiripala", - "email": "admin@dfdsdf.com" - }, - - "receivers": [ - "df.sdsd@gmail.com" - ] - } - - +* Nariya create an folder called `.nariya` on your home folder +* It contains `nariya.conf` file where you can add and edit project +* Also it contains log files for both nariya it self and projects as well +* In order work email notification correctly. You've to edit the `nariya.conf` +* Most of the configurations for the app is auto generated when adding. You can config via `nariya.conf`. Such as custom logpath, branch to get pulls diff --git a/tests/deployer.js b/tests/deployer.js index 6365791..e5590ac 100644 --- a/tests/deployer.js +++ b/tests/deployer.js @@ -1,5 +1,6 @@ var fs = require('fs'); - +var mkdirp = require('mkdirp'); +var path = require('path'); var Deployer = require('deployer'); exports.testFileExistsYes = function(test) { @@ -72,6 +73,26 @@ exports.testExecuteIfExistsError = function(test) { }); }; + +exports.testFindStartScript = function(test) { + + var deployer = new Deployer(); + var projectFolder = '/tmp/aaaaa'; + mkdirp(projectFolder, 0755, function() { + fs.writeFileSync(path.resolve(projectFolder, './start-hello.js'), 'data', 'utf8'); + fs.writeFileSync(path.resolve(projectFolder, './aa-hello.js'), 'data', 'utf8'); + deployer.findStartScript(projectFolder, function(err, file) { + + test.ok(!err); + test.equal(file, 'start-hello.js'); + + fs.unlinkSync(path.resolve(projectFolder, './start-hello.js')); + fs.unlinkSync(path.resolve(projectFolder, './aa-hello.js')); + test.done(); + }); + }); +}; + /** USE WITH CARE - HIGHLY SYSTEM Dependant */ @@ -80,7 +101,13 @@ exports.testExecuteIfExistsError = function(test) { // var winstoon = require('winstoon'); // winstoon.add(winstoon.transports.Console, {colorize: true}); // var deployer = new Deployer(); -// deployer.deploy('sms-simulator', '/edu/projects/kodeincloud/multiuser-sms-simulator', '/tmp', function(err) { +// var repoInfo = { +// logpath: '/tmp', +// location: '/edu/projects/kodeincloud/multiuser-sms-simulator', +// name: 'sms-simulator', +// startScript: 'start-app.js' +// }; +// deployer.deploy(repoInfo, function(err) { // console.log(err); // test.ok(!err) diff --git a/tests/webhookListener.js b/tests/webhookListener.js index 6d865c3..cf597cb 100644 --- a/tests/webhookListener.js +++ b/tests/webhookListener.js @@ -136,12 +136,14 @@ exports.testGetDeployError = function(test) { type: 'github', location: 'location', logpath: 'logpath', - secret: secret + secret: secret, + startScript: "ssd" }; var configurationManager = nodemock.mock('getRepositoryInfo').takes(secret).returns(repoInfo); var github = nodemock.mock('checkForDeploy').takes(repoInfo, '{"ref": "aa/aa/master"}').returns(true); github.mock('getUpdates').takes(repoInfo, function() {}).calls(1); - var deployer = nodemock.mock('deploy').takes(repoInfo.name, repoInfo.location, repoInfo.logpath, function() {}).calls(3, [{}]); + + var deployer = nodemock.mock('deploy').takes(repoInfo, function() {}).calls(1, [{}]); var repositories = { "github": github @@ -172,12 +174,13 @@ exports.testGetDeployOK = function(test) { type: 'github', location: 'location', logpath: 'logpath', - secret: secret + secret: secret, + startScript: "ssd" }; var configurationManager = nodemock.mock('getRepositoryInfo').takes(secret).returns(repoInfo); var github = nodemock.mock('checkForDeploy').takes(repoInfo, '{"ref": "aa/aa/master"}').returns(true); github.mock('getUpdates').takes(repoInfo, function() {}).calls(1); - var deployer = nodemock.mock('deploy').takes(repoInfo.name, repoInfo.location, repoInfo.logpath, function() {}).calls(3, []); + var deployer = nodemock.mock('deploy').takes(repoInfo, function() {}).calls(1, []); var repositories = { "github": github