Kender provides a consistent framework for continuous integration (CI). The principles of Kender are:
-
The definition of what constitutes your CI runs is dependent on your code, so it should be managed alongside that code and not isolated in your CI server's configuration.
-
CI runs are executed the same way, wherever they run, whoever runs them. Developers should be able to execute the same, simple command on their local machines to execute a CI run as is used on a dedicated CI server. No more publishing a branch that requires a CI configuration change, unsure of whether the CI server will pass or fail.
-
CI runs are executed the same way on every branch. A single CI project configuration should be suitable for every branch. No more mysterious failures on the CI server due to branch changes being incompatible with the current CI project configuration.
-
CI runs have directly visible status, e.g. in the GitHub pull requests. No more merging bad branches.
Add the following to your Gemfile
:
group :development, :test do
gem 'kender', :git => '[email protected]:mdsol/kender.git'
end
This gem and its dependencies should not be deployed in production, hence the
group
above.
Kender-based CI runs are executed using the ci
rake task. The following rake
tasks defined locally in your project will be run at the appropriate point in
the process if they exist:
config:all
db:migrate
db:create
db:drop
To create config:all
we strongly recommend you use Kender's companion
DiceBag gem:
gem 'dice_bag', '~> 0.7'
Unlike Kender, DiceBag is intended for use in all stages, including production.
The db
tasks are assumed to work like those found in Rails.
If you are using these Kender tasks outside of a Rails project, add the following to
your Rakefile
or wherever your local rake tasks are defined:
require 'kender/tasks'
Run the following command to see the new tasks:
[bundle exec] rake -D ci
The rake ci
task can be run locally in precisely the same way as it should be
on a CI server:
rake ci
This executes the three sub-tasks ci:config
, ci:run
and ci:clean
. Each of
these can be run in isolation.
Configuration typically requires values to be provided. Using DiceBag, this can be done through environment variables passed on the rake command line. For example, in a typical Rails project you would use the following:
rake DATABASE_USERNAME=root DATABASE_PASSWORD=password DATABASE_NAME=test ci
To bypass any configuration and clean-up side effects, for example if your
application is already configured, execute just the ci:run
task.
Kender will detect the test-related gems in your Gemfile and execute whatever CI-related commands make sense. Just ensure the gem is available in at least your test and development environments.
Currently supported gems are:
The Cucumber features will be run. Normally no command-line parameters or switches are passed, so ensure your default profile is correct for a CI run. If the cucumber command fails, the CI run will fail.
If you want to run scenarios that require a headed web browser, you can tell Kender
to use a specific browser as part of the CI run. You can set the environment
variable HEADED_BROWSER
to the name of the browser you want to run. Verify your project
can use the HEADED_BROWSER
environment variable.
The RSpec specs will be run. No command-line parameters or switches are
passed, so ensure your defaults in .rspec
are correct for a CI run. If the
rspec command fails, the CI run will fail.
The Jasmine rake task jasmine:phantom:ci
will be run. If the task fails,
the CI run will fail.
Additionally, you must have PhantomJS pre-installed on the system doing the CI run.
The Brakeman command is run in quiet mode. If any warnings are generated, the CI run will fail.
The Bundler-audit check
command is run. If any checks fail, the CI run
will fail.
The Reek command is run in quiet mode. The CI run will not fail, regardless of the output.
The Consistency Fail command is run. The CI run will not fail, regardless of the output.
The I18n Tasks commands to check for both missing and unused translations are executed. The CI run will not fail, regardless of the output.
The Shamus command is run. If the command fails, the CI run will fail.
When Shamus is used, RSpec, Jasmine and Cucumber are not run directly by Kender
but delegated to Shamus instead. As you may not want to run Shamus by default in
a CI context, you must set the environment variable VALIDATE_PROJECT
:
rake VALIDATE_PROJECT=true ci
The Crichton rdlint command is run. If the command fails, the CI run will fail. If there is no api_descriptors directory in the project, the command will not be run.
The ci
task sets the status of the current HEAD
commit in the associated
GitHub repository. If this commit represents a topic (feature) branch, any
associated pull request will show the status of the CI run.
The GitHub repository is determined by examining the origin
remote of the
current git repository.
To set the commit status, a GitHub OAuth authorization token is required
and must be provided in the GITHUB_AUTH_TOKEN
environment variable, for
example:
[bundle exec] rake GITHUB_AUTH_TOKEN=123... ci
CI servers like Jenkins let you set system-wide environment variables, saving the need of specifying this in every job.
Create an authorization token with the following command:
curl -u <username> -d '{"scopes":["repo:status"],"note":"CI status updater"}' https://api.github.com/authorizations
You will be prompted for your GitHub account password.
The token is restricted to creating commit statuses only. The token is associated to the given user, as are any commit statuses created through it. The note given is the display name used in the GitHub account management pages. Tokens can be revoked from there or via the API.
The commit status created uses the BUILD_NUMBER
and BUILD_URL
environment
variables as provided by Jenkins. Alternatively, these can be provided or
overridden on the command line, for example:
[bundle exec] rake BUILD_NUMBER=$MY_BUILD_NUM BUILD_URL=http://example.com/url ci
If you are using multiple remotes, you may specify one with the environment
variable GITHUB_REMOTE
:
[bundle exec] rake GITHUB_REMOTE=personal ci
if you are using Jenkins with multiple remotes, you may want to have it automatically select the right one for you. Here is a quick bash trick you can use.
export GITHUB_REMOTE=`echo "$GIT_BRANCH" | awk -F / '{print $1}'`