Write your GitLab pipeline configuration in Ruby!

This gem uses dynamic child pipelines

Why would you use this over plain YAML?

  • Easy to reuse structures
  • Easy to read complex pipelines
  • More powerful control flow

Installation

Add this line to your application's Gemfile:

gem 'gci'

And then execute:

    $ bundle install

Or install it yourself as:

    $ gem install gci

Usage

To generate a simple pipeline with one job to list all the files from the current directory, create a .gitlab-ci.rb file with the following content:

GCI.pipeline do |pipeline|
  pipeline.jobs.build(name: 'list-files') do |job|
    job.stage = 'test'
    job.script = ['ls -lah']
  end

  puts pipeline.to_yaml
end

to have this up and running you need a simple .gitlab-ci.yml config to trigger the dynamic pipelines:

---
:stages:
- build
- run

:image: ruby:alpine

generate-config:
  :stage: build
  :before_script:
  - gem install gci
  :script:
  - gci --config .gitlab-ci.rb generate
  :artifacts:
    :paths:
    - child.gitlab-ci.yml

execute-config:
  :stage: run
  :trigger:
    :include:
    - :artifact: child.gitlab-ci.yml
      :job: generate-config
    :strategy: depend

You can run gci --config .gitlab-ci.rb root locally to generate it and push it to the repo. You can change any part of it, for example, adding a ruby -v command at the beginning of the execution:

GCI.root_pipeline do |pipeline|
  pipeline
    .jobs["generate-config"]
    .before_script
    .unshift("ruby -v")
end

.gitlab-ci.rb shows a more advanced usage. A pipeline with two jobs that have a lot in common:

GCI.pipeline do |pipeline|
  pipeline.image = 'ruby:alpine'

  test_job = GCI::Job.new(stage: :test) do |job|
    job.before_script = [
      'apk add --update git',
      "bundle config set path 'vendor/ruby'",
      'bundle install'
    ]
    job.cache = {
      key: { files: ['Gemfile.lock'] },
      paths: ['vendor/ruby']
    }
  end

  {
    rspec: nil,
    rubocop: '--config .rubocop.yml'
  }.each do |job_name, options|
    test_job.change do |job|
      job.name = job_name
      job.script = ["bundle exec #{job_name} #{options}"]
      pipeline.jobs << job
    end
  end
end

This is how the YAML configuration for the child pipeline looks like:

---
:stages:
- build
- test
- deploy

:image: ruby:alpine

:rspec:
  :stage: test
  :before_script:
  - apk add --update git
  - bundle config set path 'vendor/ruby'
  - bundle install
  :cache:
    :key:
      :files:
      - Gemfile.lock
    :paths:
    - vendor/ruby
  :script:
  - 'bundle exec rspec '

:rubocop:
  :stage: test
  :before_script:
  - apk add --update git
  - bundle config set path 'vendor/ruby'
  - bundle install
  :cache:
    :key:
      :files:
      - Gemfile.lock
    :paths:
    - vendor/ruby
  :script:
  - bundle exec rubocop --config .rubocop.yml

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://gitlab.com/mbobin/gci.

License

The gem is available as open source under the terms of the MIT License.