Lately, I've been experimenting with hapi.js on Azure Websites and I got to the point where I wanted commits to get deployed automatically. In this post, I'll run through the steps to get a basic continuous deploy setup from GitHub going. The full code for this is available at https://github.com/robjoh/hapi-basic-cd
Get Hapi
If you are unfamiliar with hapi.js, it's a great node.js framework for building web applications and services. Assuming Node.js and npm are already installed, from a console I'll get the project started with the following command. For now, I just accept the default values for npm init
>md hapi-basic
>cd hapi-basic
>npm init
>npm install --save hapi
Hello service
For the purpose of this post, I'll just create the simplest hapi service possible in a file index.js.
var hapi = require('hapi');
var server = new hapi.Server();
server.connection({
host: process.env.HOST || 'localhost',
port: process.env.PORT || 8080
});
server.route({
path: '/',
method: 'GET',
handler: function(request, reply) {
reply('hello');
}
})
if (!module.parent) {
server.start(function() {
console.log('Server started: ' + server.info.uri);
});
}
With that, the service can be run from the console. You can try it out with your http client of choice.
>node index.js
Server started: http://localhost:8080
>curl http://localhost:8080/
hello
What about tests
Lab is the test utility of choice for hapi. I install it as a dev package along with the code assertion library.
>npm install --save-dev lab code
Lab expects tests to be in a test folder by default, so here's a basic test in test/index.js
var hapi = require('hapi'),
Lab = require('lab'),
lab = exports.lab = Lab.script(),
code = require('code'),
describe = lab.experiment,
it = lab.it,
expect = code.expect;
describe('hello service', function() {
var server = require('../index.js');
it('says hello', function(done) {
var options = {
method: 'GET',
url: '/'
};
server.inject(options, function(response) {
expect(response.statusCode).to.equal(200);
expect(response.result).to.equal('hello');
done();
});
});
});
To lay groundwork for later, I'm going to use npm to perform the test task. So I need to change package.json to have the scripts.test value be lab.
{
"name": "hapi-basic",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "lab" //<-- changed to lab
},
"author": "",
"license": "ISC",
"dependencies": {
"hapi": "^8.2.0"
},
"devDependencies": {
"code": "^1.3.0",
"lab": "^5.2.1"
}
}
Now I can use npm to run the tests.
>npm run-script test
.
1 tests complete
Test duration: 0ms
No global variable leaks detected
To the cloud
I'll use the azure cli for the azure portion of this. It can be installed via npm.
>npm install -g azure-cli
First, I need to grab a copy of the default azure websites deployment script so I can make a tweak or two.
>azure site deploymentscript --node
info: Executing command site deploymentscript
info: Generating deployment script for node.js Web Site
info: Generated deployment script files
info: site deploymentscript command OK
This creates a few files that azure will use during deployment. I am going to modify deploy.cmd to tell it to run tests as part of the deployment. In the Deployment section of the file:
-changed step 3 to remove the --production flag from install. Otherwise it won't install the lab and code dev pacakges.
-add step 4 to run the tests.
:: 3. Install npm packages
IF EXIST "%DEPLOYMENT_TARGET%\package.json" (
pushd "%DEPLOYMENT_TARGET%"
call :ExecuteCmd !NPM_CMD! install
IF !ERRORLEVEL! NEQ 0 goto error
popd
)
:: 4. Run Unit Tests
pushd "%DEPLOYMENT_TARGET%"
call :ExecuteCmd !NPM_CMD! run test
IF !ERRORLEVEL! NEQ 0 goto error
popd
Now I'll go ahead and create the azure website
>azure site create hapi-basic-cd
In prep for git I add a .gitignore file to make sure the node_modules and any log files are not included.
node_modules
*.log
Create the git repository, add and commit the code
>git init
>git add --all
>git commit -am "Initial commit"
Now I create the repository on GitHub and push to it.
>git remote add origin https://github.com/robjoh/hapi-basic-cd.git
>git push -u origin master
Lastly I connect the azure website with the GitHub repository. In the azure management portal for the site, I select Set up deployment from source control, choose GitHub and authorize the connection which sets up the deployment hook.
Now, any time changes committed to the GitHub repository are automatically deployed. Additionally, since tests are run, any failed test will roll back the deployment.
Wrapping up
This only scratches the surface of many scenarios available with Kudu, which is the engine behind the deployments, along with web hooks which could be used for deployment notifications, deployment slots for staging and much more. I hope to try out many of these over the coming months. Send me a tweet @robjoh if any are of particular interest.