Bulldozer
Deployment (CI) from Bitbucket or Github (and other) to your server. Simple.
Features
- supports Bitbucket or Github, public and private repos
- it has two parts: deployment server and client
- using tags
- downloads .zip (much faster than fetching the whole repo)
- it shares one configuration and library for server and client parts
- the configuration is
.js
file like gulpfile -> it is 100% programmable! - uses Winston for logging
- no post-commit hooks settings needed on Bitbucket or Github
Installation and configuration
Server part
1. Install bulldozer
npm install -g bulldozer
2. Configuration
Create a configuration file bulldozer.js
in the project (repository) root. You have to put this file manually on your server. It's a good idea to keep it in the project repository. Since it is a javascript file, you can easily require
and use stuff from your project. You can use 3rd party libraries. The world is your oyster.
var config = {
url: 'https://example.org',
port: 8000,
secret: 'YOUR_SECRET',
gitUrl: 'github',
name: 'steida/este',
branch: 'master',
auth: {
username: 'USERNAME',
password: 'PASSWORD'
},
preDeploy: function(utils) {
utils.getLogger().info('Pre-deploy started.');
return true;
},
postDeploy: function(utils) {
utils.getLogger().info('Post-deploy started.');
utils.run('npm install')
.then(function() {
utils.getLogger().info('Deploy finished.');
utils.getLogger().info('Starting production server.');
return utils.run('PORT=80 NODE_ENV=production forever stop src/server');
})
.fail(function() {return utils.getLogger().info('There was no running instance of production server.'); })
.then(function() {return utils.run('PORT=80 NODE_ENV=production forever start src/server'); })
.then(function() {
utils.getLogger().info('Production server started.');
utils.getLoggerOutput();
utils.resetLoggerOutput();
});
},
onError: function(utils) {
utils.getLoggerOutput();
utils.resetLoggerOutput();
}
};
module.exports = config;
I really recommend to install and use forever to run your app (it's used in the example).
npm install -g forever
3. Run
bulldozer start
This way you can see the real-time output. Or run it on a background.
nohup bulldozer start &
The deployment server is started. There is a simple GET API deploy/:tag?secret=YOUR_SECRET
. When you call it (with a proper tag and secret) the deployment starts.
Client part
To make your life easier there are some another built-in commands. These commands must be ran from the project (repository) root. It expects the same bulldozer.js
configuration that is used on the server.
1. Install bulldozer on your computer
npm install -g bulldozer
Yes, everything is in the same module.
2. Create a special deploy tag
bulldozer tag
This creates a tag rYYYYMMDDHHmmss
for the latest commit and branch that you set in the configuration file (master
is default).
3. Deploy
bulldozer deploy
This finds the latest deploy tag (rYYYYMMDDHHmmss
) and calls the deployment server /deploy
API. It uses the secret from the configuration file.
bulldozer deploy :tag
You can specify the tag. It can be any tag, not just a release tag (rYYYYMMDDHHmmss
).
Don't forget to git push --tags
between bulldozer tag
and bulldozer deploy
.
Deployment process
It's quite simple and naive right now.
- Calls
preDeploy()
hook. - Uses the tag name.
- GitHub and Bitbucket provide a
.zip
archive for every tag - Downloads the archive.
- Unpacks the archive to a temporary dir.
- Moves files from the temporary dir to the project root.
- Calls
postDeploy()
hook. - If something goes wrong, it calls
onError()
hook.
It's up to you to save logs. It's up to you to call npm install
. It's up to you to send an email with results...
Hooks and utils
There are three important hooks (callback) that you can use through the configuration file. preDeploy(utils)
, postDeploy(utils)
and onError(utils)
. When are they called? Check the Deployment process
section above.
They all accept and get utils
argument. That's a set of helper functions coming from the bulldozer.
utils.getLogger()
This returns the instance of Winston (logger utility) which is used by bulldozer. Have fun with it! It's particularly useful for logging, duh.
utils.getLogger().info('some message')
utils.getLogger().error('error message')
This calls onError()
hook.
utils.getLoggerOutput()
Returns all Winston messages as a string. Great for emailing.
utils.resetLoggerOutput()
Resets the previous string. You should do it at the end of every deployment.
utils.run(command)
This calls the command as a child process and returns a promise. It uses child-process-promise. The bulldozer is automatically logging stdout
and stderr
for you. This is a nice way how you can chain more commands (aka asynchronous child processes). See the example bulldozer.js
.
Known limitations
- you need one deployment server instance (with different port) for every project
- stuff can go wrong in
postDeploy()
and that's bad because it can modify the running app; on the other hand, it makes npm install
really fast
Future
postDeploy()
should not have access to the root directory, but it should also use the temporary dir. There will be probably a new hook postMove()
that can be used for a server start.- support for more projects under one deployment server
Contribution
Please, create issues and pull requests.
git clone https://github.com/tajo/bulldozer
cd bulldozer
npm install
npm run compile
npm link bulldozer
npm install -g bulldozer
Credits
Vojtech Miksu 2015, miksu.cz, @vmiksu