Knapsack Pro Ruby: Quickstart
Create an account to generate API tokens and use Knapsack Pro.
Installation
Install knapsack_pro
in your project:
bundle add knapsack_pro --group "development, test"
Now, fill in the following form to generate the instruction steps for your project.
Questions
Please answer the following questions to generate the configuration for your project:
Do you use Ruby on Rails?
Choose your testing tools:
What is your CI provider?
Instructions
Ruby Project
Since you are not using Rails, add the following at the bottom of your Rakefile
:
KnapsackPro.load_tasks if defined?(KnapsackPro)
RSpec
Add the following code at the beginning of your spec/rails_helper.rb
or spec/spec_helper.rb
:
require 'knapsack_pro'
# Custom Knapsack Pro config here
KnapsackPro::Adapters::RSpecAdapter.bind
Minitest
Add the following code after you load the app environment in test/test_helper.rb
:
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require 'knapsack_pro'
# Custom Knapsack Pro config here
knapsack_pro_adapter = KnapsackPro::Adapters::MinitestAdapter.bind
knapsack_pro_adapter.set_test_helper_path(__FILE__)
test-unit
Add the following code at the beginning of your test/test_helper.rb
:
require 'knapsack_pro'
# Custom Knapsack Pro config here
knapsack_pro_adapter = KnapsackPro::Adapters::TestUnitAdapter.bind
knapsack_pro_adapter.set_test_helper_path(__FILE__)
Cucumber
Create features/support/knapsack_pro.rb
with the following code:
require 'knapsack_pro'
# Custom Knapsack Pro config here
KnapsackPro::Adapters::CucumberAdapter.bind
Spinach
Create features/support/knapsack_pro.rb
with the following code:
require 'knapsack_pro'
# Custom Knapsack Pro config here
KnapsackPro::Adapters::SpinachAdapter.bind
AppVeyor
Generate an API token for each Knapsack Pro command on the CI. Each command needs its own API token to treat every test suite as a separate entity.
For each parallel job, define:
Remember to configure the number of parallel CI nodes in AppVeyor.
- Node 1
- Node 2
- Node N
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=0 \
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN \
bundle exec rake knapsack_pro:queue:rspec
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=0 \
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN \
bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=1 \
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN \
bundle exec rake knapsack_pro:queue:rspec
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=1 \
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN \
bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=N-1 \
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN \
bundle exec rake knapsack_pro:queue:rspec
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=N-1 \
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN \
bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
Buildkite
Generate an API token for each Knapsack Pro command on the CI. Each command needs its own API token to treat every test suite as a separate entity.
Remember to configure the parallelism
parameter in your build step.
- Node 1
- Node 2
- Node N
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN \
bundle exec rake knapsack_pro:queue:rspec
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN \
bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN \
bundle exec rake knapsack_pro:queue:rspec
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN \
bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN \
bundle exec rake knapsack_pro:queue:rspec
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN \
bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
When using the docker-compose
plugin on Buildkite, you have to pass the following environment variables:
steps:
- label: "Test"
parallelism: 2
plugins:
- docker-compose#3.0.3:
run: app
command: bundle exec rake knapsack_pro:queue:rspec
config: docker-compose.test.yml
env:
- BUILDKITE
- BUILDKITE_PARALLEL_JOB_COUNT
- BUILDKITE_PARALLEL_JOB
- BUILDKITE_BUILD_NUMBER
- BUILDKITE_COMMIT
- BUILDKITE_BRANCH
- BUILDKITE_BUILD_CHECKOUT_PATH
- BUILDKITE_BUILD_AUTHOR
- BUILDKITE_BUILD_CREATOR
Here you can find an article on how to set up a new pipeline for your project in Buildkite and configure Knapsack Pro.
You can also check out the following example repositories for Ruby on Rails projects:
- Buildkite Rails Parallel Example with Knapsack Pro
- Buildkite Rails Docker Parallel Example with Knapsack Pro
CircleCI
Generate an API token for each Knapsack Pro command on the CI. Each command needs its own API token to treat every test suite as a separate entity.
Remember to add additional parallel containers in the CircleCI settings.
jobs:
build:
parallelism: 2
steps:
- checkout
# ...
- run:
name: RSpec with knapsack_pro
command: |
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN \
bundle exec rake knapsack_pro:queue:rspec
- run:
name: Cucumber with knapsack_pro
command: |
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN \
bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
Here you can find an article about a Rails application configured with Knapsack Pro on CircleCI 2.0.
See how to configure advanced CircleCI features with Knapsack Pro to collect reports and rerun only failed tests.
Cirrus CI
Generate an API token for each Knapsack Pro command on the CI. Each command needs its own API token to treat every test suite as a separate entity.
Configure the number of parallel CI nodes with the matrix modification:
task:
environment:
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC: ENCRYPTED[MY_RSPEC_API_TOKEN]
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER: ENCRYPTED[MY_CUCUMBER_API_TOKEN]
matrix:
name: CI Node 0
name: CI Node 1
name: CI Node 2
test_script:
- bundle exec rake knapsack_pro:queue:rspec
- bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
Remember to set up the KNAPSACK_PRO_TEST_SUITE_TOKEN_*
as encrypted variables.
Here is an example of a .cirrus.yml
configuration file for a Ruby project.
CloudBees CodeShip
Generate an API token for each Knapsack Pro command on the CI. Each command needs its own API token to treat every test suite as a separate entity.
For each parallel pipeline, define:
- Node 1
- Node 2
- Node N
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=0 \
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN \
bundle exec rake knapsack_pro:queue:rspec
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=0 \
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN \
bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=1 \
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN \
bundle exec rake knapsack_pro:queue:rspec
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=1 \
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN \
bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=N-1 \
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN \
bundle exec rake knapsack_pro:queue:rspec
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=N-1 \
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN \
bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
Consider moving the KNAPSACK_PRO_TEST_SUITE_TOKEN_*
to the Environment page of your project settings in CodeShip.
Codefresh
Generate an API token for each Knapsack Pro command on the CI. Each command needs its own API token to treat every test suite as a separate entity.
Define in .codefresh/codefresh.yml
:
KNAPSACK_PRO_TEST_SUITE_TOKEN_*
KNAPSACK_PRO_CI_NODE_TOTAL
KNAPSACK_PRO_CI_NODE_INDEX
- In the
matrix
section, list all theKNAPSACK_PRO_CI_NODE_INDEX
es (from0
toKNAPSACK_PRO_CI_NODE_TOTAL-1
).
- In the
Remember to configure the YAML file path on Codefresh: Pipelines > Settings (cog icon next to the pipeline) > Workflow Tab (horizontal menu on the top) > Path to YAML > ./.codefresh/codefresh.yml
.
Here's an example config for Ruby on Rails and PostgreSQL in a Docker container:
- codefresh.yml
- Dockerfile
version: "1.0"
stages:
- "clone"
- "build"
- "tests"
steps:
main_clone:
type: "git-clone"
description: "Cloning main repository..."
repo: "${{CF_REPO_OWNER}}/${{CF_REPO_NAME}}"
revision: "${{CF_BRANCH}}"
stage: "clone"
BuildTestDockerImage:
title: Building Test Docker image
type: build
arguments:
image_name: "${{CF_ACCOUNT}}/${{CF_REPO_NAME}}-test"
tag: "${{CF_BRANCH_TAG_NORMALIZED}}-${{CF_SHORT_REVISION}}"
dockerfile: Test.Dockerfile
stage: "build"
run_tests:
stage: "tests"
image: "${{BuildTestDockerImage}}"
working_directory: /src
fail_fast: false
environment:
- RAILS_ENV=test
- KNAPSACK_PRO_CI_NODE_TOTAL=2
- PGHOST=postgres
- PGUSER=rails-app-with-knapsack_pro
- PGPASSWORD=password
services:
composition:
postgres:
image: postgres:latest
environment:
- POSTGRES_DB=rails-app-with-knapsack_pro_test
- POSTGRES_PASSWORD=password
- POSTGRES_USER=rails-app-with-knapsack_pro
ports:
- 5432
matrix:
environment:
- KNAPSACK_PRO_CI_NODE_INDEX=0
- KNAPSACK_PRO_CI_NODE_INDEX=1
commands:
- bin/rails db:prepare
- KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN bundle exec rake knapsack_pro:queue:rspec
- KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN bundle exec rake knapsack_pro:queue:cucumber
- KNAPSACK_PRO_TEST_SUITE_TOKEN_MINITEST=MY_MINITEST_API_TOKEN bundle exec rake knapsack_pro:queue:minitest
- KNAPSACK_PRO_TEST_SUITE_TOKEN_TEST_UNIT=MY_TEST_UNIT_API_TOKEN bundle exec rake knapsack_pro:test_unit
- KNAPSACK_PRO_TEST_SUITE_TOKEN_SPINACH=MY_SPINACH_API_TOKEN bundle exec rake knapsack_pro:spinach
Consider setting up the KNAPSACK_PRO_TEST_SUITE_TOKEN_*
on the Codefresh dashboard: Pipelines > Settings (cog icon next to the pipeline) > Variables Tab (vertical menu on the right-hand side).
FROM ruby:2.6.5-alpine3.10
# Prepare Docker image for Nokogiri
RUN apk add --update \
build-base \
libxml2-dev \
libxslt-dev \
jq \
nodejs \
npm \
postgresql-dev \
python3-dev \
sqlite-dev \
git \
&& rm -rf /var/cache/apk/*
# Install AWS CLI
RUN pip3 install awscli
# Use libxml2, libxslt packages from alpine for building nokogiri
RUN bundle config build.nokogiri --use-system-libraries
# Install Codefresh CLI
RUN wget https://github.com/codefresh-io/cli/releases/download/v0.31.1/codefresh-v0.31.1-alpine-x64.tar.gz
RUN tar -xf codefresh-v0.31.1-alpine-x64.tar.gz -C /usr/local/bin/
COPY . /src
WORKDIR /src
RUN bundle install
GitHub Actions
Generate an API token for each Knapsack Pro command on the CI. Each command needs its own API token to treat every test suite as a separate entity.
Define in .github/workflows/main.yaml
:
KNAPSACK_PRO_TEST_SUITE_TOKEN_*
in GitHub Settings > Secrets as described in GitHub Actions' docs.KNAPSACK_PRO_CI_NODE_TOTAL
using thematrix
propertyKNAPSACK_PRO_CI_NODE_INDEX
using thematrix
property
Here's an example config for a Ruby on Rails project:
name: Main
on: [push]
jobs:
test:
runs-on: ubuntu-latest
# If you need a DB, then define it in the service below.
# https://github.com/actions/example-services/tree/master/.github/workflows
services:
postgres:
image: postgres:10.8
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ""
POSTGRES_DB: postgres
ports:
- 5432:5432
# needed because the postgres container does not provide a healthcheck
# tmpfs makes DB faster by using RAM
options: >-
--mount type=tmpfs,destination=/var/lib/postgresql/data
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis
ports:
- 6379:6379
options: --entrypoint redis-server
strategy:
fail-fast: false
matrix:
ci_node_total: [2]
ci_node_index: [0, 1]
env:
RAILS_ENV: test
GEMFILE_RUBY_VERSION: 2.7.2
PGHOST: localhost
PGUSER: postgres
# Rails verifies the time zone in DB is the same as the time zone of the Rails app
TZ: "Europe/Warsaw"
steps:
- uses: actions/checkout@v2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
# Not needed with a .ruby-version file
ruby-version: 2.7
# runs 'bundle install' and caches installed gems automatically
bundler-cache: true
- name: Create DB
run: |
bin/rails db:prepare
- name: Run tests
env:
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC: ${{ secrets.KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC }}
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER: ${{ secrets.KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER }}
KNAPSACK_PRO_TEST_SUITE_TOKEN_MINITEST: ${{ secrets.KNAPSACK_PRO_TEST_SUITE_TOKEN_MINITEST }}
KNAPSACK_PRO_TEST_SUITE_TEST_UNIT: ${{ secrets.KNAPSACK_PRO_TEST_SUITE_TOKEN_TEST_UNIT }}
KNAPSACK_PRO_TEST_SUITE_TOKEN_SPINACH: ${{ secrets.KNAPSACK_PRO_TEST_SUITE_TOKEN_SPINACH }}
KNAPSACK_PRO_CI_NODE_TOTAL: ${{ matrix.ci_node_total }}
KNAPSACK_PRO_CI_NODE_INDEX: ${{ matrix.ci_node_index }}
KNAPSACK_PRO_LOG_LEVEL: info
run: |
bundle exec rake knapsack_pro:queue:rspec
bundle exec rake knapsack_pro:queue:cucumber
bundle exec rake knapsack_pro:queue:minitest
bundle exec rake knapsack_pro:test_unit
bundle exec rake knapsack_pro:spinach
GitLab CI
Generate an API token for each Knapsack Pro command on the CI. Each command needs its own API token to treat every test suite as a separate entity.
GitLab CI >= 11.5
test:
parallel: 2
script:
- KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN bundle exec rake knapsack_pro:queue:rspec
- KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN bundle exec rake knapsack_pro:queue:cucumber
- KNAPSACK_PRO_TEST_SUITE_TOKEN_MINITEST=MY_MINITEST_API_TOKEN bundle exec rake knapsack_pro:queue:minitest
- KNAPSACK_PRO_TEST_SUITE_TOKEN_TEST_UNIT=MY_TEST_UNIT_API_TOKEN bundle exec rake knapsack_pro:test_unit
- KNAPSACK_PRO_TEST_SUITE_TOKEN_SPINACH=MY_SPINACH_API_TOKEN bundle exec rake knapsack_pro:spinach
See also how to configure running parallel CI nodes in GitLab.
GitLab CI < 11.5
Define in .gitlab-ci.yml
:
Here's an example configuration for 2 parallel jobs:
stages:
- test
variables:
KNAPSACK_PRO_CI_NODE_TOTAL: 2
test_ci_first_node:
stage: test
script:
- export KNAPSACK_PRO_CI_NODE_INDEX=0
- KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN bundle exec rake knapsack_pro:queue:rspec
- KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN bundle exec rake knapsack_pro:queue:cucumber
- KNAPSACK_PRO_TEST_SUITE_TOKEN_MINITEST=MY_MINITEST_API_TOKEN bundle exec rake knapsack_pro:queue:minitest
- KNAPSACK_PRO_TEST_SUITE_TOKEN_TEST_UNIT=MY_TEST_UNIT_API_TOKEN bundle exec rake knapsack_pro:test_unit
- KNAPSACK_PRO_TEST_SUITE_TOKEN_SPINACH=MY_SPINACH_API_TOKEN bundle exec rake knapsack_pro:spinach
test_ci_second_node:
stage: test
script:
- export KNAPSACK_PRO_CI_NODE_INDEX=1
- KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN bundle exec rake knapsack_pro:queue:rspec
- KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN bundle exec rake knapsack_pro:queue:cucumber
- KNAPSACK_PRO_TEST_SUITE_TOKEN_MINITEST=MY_MINITEST_API_TOKEN bundle exec rake knapsack_pro:queue:minitest
- KNAPSACK_PRO_TEST_SUITE_TOKEN_TEST_UNIT=MY_TEST_UNIT_API_TOKEN bundle exec rake knapsack_pro:test_unit
- KNAPSACK_PRO_TEST_SUITE_TOKEN_SPINACH=MY_SPINACH_API_TOKEN bundle exec rake knapsack_pro:spinach
Remember to set up the KNAPSACK_PRO_TEST_SUITE_TOKEN_*
as Secret Variables in GitLab CI: Settings > CI/CD Pipelines > Secret Variables.
Heroku CI
Generate an API token for each Knapsack Pro command on the CI. Each command needs its own API token to treat every test suite as a separate entity.
Define in app.json
:
KNAPSACK_PRO_TEST_SUITE_TOKEN_*
quantity
: number of parallel dynostest
: the Knapsack Pro command (or multiple commands)
{
"environments": {
"test": {
"formation": {
"test": {
"quantity": 2
}
},
"addons": [
"heroku-postgresql:in-dyno",
"heroku-redis:in-dyno"
],
"scripts": {
"test": "bundle exec rake knapsack_pro:queue:rspec"
},
"env": {
"KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC": "MY_RSPEC_API_TOKEN"
}
}
}
}
Remember to set up the KNAPSACK_PRO_TEST_SUITE_TOKEN_*
outside of app.json
in your Heroku CI pipeline's settings.
Jenkins
Generate an API token for each Knapsack Pro command on the CI. Each command needs its own API token to treat every test suite as a separate entity.
In order to run parallel jobs with Jenkins you should use Jenkins Pipeline as described in Parallelism and Distributed Builds with Jenkins.
Here is an example of a Jenkinsfile
working with Jenkins Pipeline:
timeout(time: 60, unit: 'MINUTES') {
node() {
stage('Checkout') {
checkout([/* checkout code from git */])
// determine git commit hash because we need to pass it to Knapsack Pro
COMMIT_HASH = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
stash 'source'
}
}
def num_nodes = 4; // define your total number of CI nodes (how many parallel jobs will be executed)
def nodes = [:]
for (int i = 0; i < num_nodes; i++) {
def index = i;
nodes["ci_node_${i}"] = {
node() {
stage('Setup') {
unstash 'source'
// other setup steps
}
def knapsack_options = """\
KNAPSACK_PRO_CI_NODE_TOTAL=${num_nodes}\
KNAPSACK_PRO_CI_NODE_INDEX=${index}\
KNAPSACK_PRO_COMMIT_HASH=${COMMIT_HASH}\
KNAPSACK_PRO_BRANCH=${env.BRANCH_NAME}\
KNAPSACK_PRO_CI_NODE_BUILD_ID=${env.BUILD_TAG}\
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN\
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN
"""
stage('Run rspec') {
sh """${knapsack_options} bundle exec rake knapsack_pro:queue:rspec"""
}
stage('Run cucumber') {
sh """${knapsack_options} bundle exec rake knapsack_pro:queue:cucumber"""
}
// ...or bundle exec rake knapsack_pro:queue:minitest
// ...or bundle exec rake knapsack_pro:spinach
// ...or bundle exec rake knapsack_pro:test_unit
}
}
}
parallel nodes // run CI nodes in parallel
}
Consider setting up the KNAPSACK_PRO_TEST_SUITE_TOKEN_*
as global environment variables in Jenkins.
Semaphore CI
Generate an API token for each Knapsack Pro command on the CI. Each command needs its own API token to treat every test suite as a separate entity.
Define in .semaphore/semaphore.yml
:
KNAPSACK_PRO_TEST_SUITE_TOKEN_*
parallelism
Here's an example config for a Rails project:
version: v1.0
name: Demo Rails 5 app
agent:
machine:
type: e1-standard-2
os_image: ubuntu1804
blocks:
- name: Setup
task:
jobs:
- name: bundle
commands:
- checkout
- cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH-,gems-master-
- sem-version ruby 2.6.1
- bundle install --jobs=4 --retry=3 --path vendor/bundle
- cache store gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock) vendor/bundle
- name: RSpec tests
task:
env_vars:
- name: RAILS_ENV
value: test
- name: PGHOST
value: 127.0.0.1
- name: PGUSER
value: postgres
- name: KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC
value: MY_RSPEC_API_TOKEN
- name: KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER
value: MY_CUCUMBER_API_TOKEN
prologue:
commands:
- checkout
- cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH-,gems-master-
- sem-service start postgres
- sem-version ruby 2.6.1
- bundle install --jobs=4 --retry=3 --path vendor/bundle
- bundle exec rake db:setup
jobs:
- name: Run tests with Knapsack Pro
parallelism: 2
commands:
- bundle exec rake knapsack_pro:queue:rspec
- bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
Remember to set up KNAPSACK_PRO_TEST_SUITE_TOKEN_*
as a secret.
Travis CI
Generate an API token for each Knapsack Pro command on the CI. Each command needs its own API token to treat every test suite as a separate entity.
Define in .travis.yml
:
script:
- "bundle exec rake knapsack_pro:queue:rspec"
- "bundle exec rake knapsack_pro:queue:cucumber"
- "bundle exec rake knapsack_pro:queue:minitest"
- "bundle exec rake knapsack_pro:test_unit"
- "bundle exec rake knapsack_pro:spinach"
env:
global:
- KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN
- KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN
- KNAPSACK_PRO_TEST_SUITE_TOKEN_MINITEST=MY_MINITEST_API_TOKEN
- KNAPSACK_PRO_TEST_SUITE_TOKEN_TEST_UNIT=MY_TEST_UNIT_API_TOKEN
- KNAPSACK_PRO_TEST_SUITE_TOKEN_SPINACH=MY_SPINACH_API_TOKEN
- KNAPSACK_PRO_CI_NODE_TOTAL=3
jobs:
- KNAPSACK_PRO_CI_NODE_INDEX=0
- KNAPSACK_PRO_CI_NODE_INDEX=1
- KNAPSACK_PRO_CI_NODE_INDEX=2
Remember to set up KNAPSACK_PRO_TEST_SUITE_TOKEN_*
as tokens in the Travis settings to avoid exposing them in the build logs.
You can find more info about the global and matrix env configuration in the Travis' docs.
Other CI provider
Generate an API token for each Knapsack Pro command on the CI. Each command needs its own API token to treat every test suite as a separate entity.
Define the following global environment variables on your CI server:
KNAPSACK_PRO_TEST_SUITE_TOKEN_*
KNAPSACK_PRO_REPOSITORY_ADAPTER=git
KNAPSACK_PRO_PROJECT_DIR
KNAPSACK_PRO_CI_NODE_TOTAL
KNAPSACK_PRO_CI_NODE_INDEX
KNAPSACK_PRO_CI_NODE_BUILD_ID
- Node 1
- Node 2
- Node N
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=0 \
KNAPSACK_PRO_CI_NODE_BUILD_ID=MY_BUILD_ID \
KNAPSACK_PRO_REPOSITORY_ADAPTER=git \
KNAPSACK_PRO_PROJECT_DIR=MY_PROJECT_DIR \
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN \
bundle exec rake knapsack_pro:queue:rspec
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=0 \
KNAPSACK_PRO_CI_NODE_BUILD_ID=MY_BUILD_ID \
KNAPSACK_PRO_REPOSITORY_ADAPTER=git \
KNAPSACK_PRO_PROJECT_DIR=MY_PROJECT_DIR \
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN \
bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=1 \
KNAPSACK_PRO_CI_NODE_BUILD_ID=MY_BUILD_ID \
KNAPSACK_PRO_REPOSITORY_ADAPTER=git \
KNAPSACK_PRO_PROJECT_DIR=MY_PROJECT_DIR \
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN \
bundle exec rake knapsack_pro:queue:rspec
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=1 \
KNAPSACK_PRO_CI_NODE_BUILD_ID=MY_BUILD_ID \
KNAPSACK_PRO_REPOSITORY_ADAPTER=git \
KNAPSACK_PRO_PROJECT_DIR=MY_PROJECT_DIR \
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN \
bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=N-1 \
KNAPSACK_PRO_CI_NODE_BUILD_ID=MY_BUILD_ID \
KNAPSACK_PRO_REPOSITORY_ADAPTER=git \
KNAPSACK_PRO_PROJECT_DIR=MY_PROJECT_DIR \
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC=MY_RSPEC_API_TOKEN \
bundle exec rake knapsack_pro:queue:rspec
KNAPSACK_PRO_CI_NODE_TOTAL=N \
KNAPSACK_PRO_CI_NODE_INDEX=N-1 \
KNAPSACK_PRO_CI_NODE_BUILD_ID=MY_BUILD_ID \
KNAPSACK_PRO_REPOSITORY_ADAPTER=git \
KNAPSACK_PRO_PROJECT_DIR=MY_PROJECT_DIR \
KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER=MY_CUCUMBER_API_TOKEN \
bundle exec rake knapsack_pro:queue:cucumber
# ...or bundle exec rake knapsack_pro:queue:minitest
# ...or bundle exec rake knapsack_pro:spinach
# ...or bundle exec rake knapsack_pro:test_unit
Verify that everything works
Push a new commit to your repository and visit your dashboard to make sure all your CI nodes were recorded successfully in Show build metrics > Show (build).
The command knapsack_pro:queue:TEST_RUNNER
, starts Knapsack Pro in Queue Mode.
If you encounter any problems, take a look at troubleshooting, or try Regular Mode by running knapsack_pro:TEST_RUNNER
(notice the missing :queue
).
Congratulations! Now that Knapsack Pro knows the statistics of your test suite, your CI builds will be parallelized optimally.
Next up
For an even faster CI build, consider splitting by test examples.
Make sure you check out the Advanced and Using Knapsack Pro with... pages from the navigation to fine-tune your Knapsack Pro setup.
Need help?
We have helped TONS of teams and seen TONS of projects. We know each test suite is a different beast and we'd be happy to help you set up Knapsack Pro.