Jobs

The fundamental unit of work in SaturnCI is a job. A job is a Ruby script that runs inside an environment. Workflows are what start jobs.

Defining a job

A job lives in a directory under .saturnci/jobs/. The directory holds a config.yml, which names the environment the job runs in, and a script named after the job. Here is a job named hello_world:

# .saturnci/jobs/hello_world/config.yml

environment: ruby
# .saturnci/jobs/hello_world/hello_world_job.rb

class HelloWorldJob
  def perform
    puts "hello world"
  end
end

if $PROGRAM_NAME == __FILE__
  HelloWorldJob.new.perform
end

SaturnCI runs the script directly, so the $PROGRAM_NAME guard is what actually invokes the job. The job passes or fails on the script's exit status.

A job that shells out can exit on the result of the command:

# .saturnci/jobs/rubocop/rubocop_job.rb

class RubocopJob
  def perform
    system("bundle exec rubocop")
  end
end

if $PROGRAM_NAME == __FILE__
  exit RubocopJob.new.perform
end

Starting a job

Jobs are started from your workflow:

hello_world_job_run = workflow_run.job_runs.create(
  job_name: "hello_world",
  task_adapter_name: "shell",
  idempotent: true
)

hello_world_job_run.start

Task adapters

Every job run names a task adapter, which is what SaturnCI uses to run the job and interpret its output.

  • shell — runs the job's script. This is the adapter for deployments, linters, image builds, and anything else that passes or fails as a whole.
  • rails_rspec — runs a Rails app's RSpec suite, splitting it across test runners and reporting individual test results. Use this one with workflow_run.test_suite_runs.create; see test suite jobs.
  • rails_minitest — the same, for Minitest.

Test suite jobs

A test suite job has no script and no config.yml. Everything that defines it is on the create call in your workflow: the environment it runs in, the Docker Compose service in that environment that runs the tests, and the command that runs them.

test_suite_run = workflow_run.test_suite_runs.create(
  job_name: "test_suite",
  task_adapter_name: "rails_rspec",
  environment_name: "rspec",
  service_name: "saturnci_test_app",
  command: "bundle exec rspec",
  idempotent: true
)

test_suite_run.start

SaturnCI runs the command once with --dry-run to list the examples, splits them across test runners, and then runs the command on each runner's share, adding the flags it needs to collect results. Anything that invokes RSpec works as the command, e.g. bundle exec appraisal rails-7.1 rspec.

Learn more