Class: ActiveSupport::ContinuousIntegration
- Defined in:
- lib/active_support/continuous_integration.rb
Overview
Provides a DSL for declaring a continuous integration workflow that can be run either locally or in the cloud. Each step is timed, reports success/error, and is aggregated into a collective report that reports total runtime, as well as whether the entire run was successful or not.
Example:
ActiveSupport::ContinuousIntegration.run do
step "Setup", "bin/setup --skip-server"
step "Style: Ruby", "bin/rubocop"
step "Security: Gem audit", "bin/bundler-audit"
step "Tests: Rails", "bin/rails test test:system"
if success?
step "Signoff: Ready for merge and deploy", "gh signoff"
else
failure "Skipping signoff; CI failed.", "Fix the issues and try again."
end
end
Starting with Rails 8.1, a default ‘bin/ci` and `config/ci.rb` file are created to provide out-of-the-box CI.
Constant Summary collapse
- COLORS =
{ banner: "\033[1;32m", # Green title: "\033[1;35m", # Purple subtitle: "\033[1;90m", # Medium Gray error: "\033[1;31m", # Red success: "\033[1;32m" # Green }
Instance Attribute Summary collapse
-
#results ⇒ Object
readonly
Returns the value of attribute results.
Class Method Summary collapse
-
.run(title = "Continuous Integration", subtitle = "Running tests, style checks, and security audits", &block) ⇒ Object
Perform a CI run.
Instance Method Summary collapse
-
#echo(text, type:) ⇒ Object
Echo text to the terminal in the color corresponding to the type of the text.
-
#failure(title, subtitle = nil) ⇒ Object
Display an error heading with the title and optional subtitle to reflect that the run failed.
-
#heading(heading, subtitle = nil, type: :banner, padding: true) ⇒ Object
Display a colorized heading followed by an optional subtitle.
-
#initialize ⇒ ContinuousIntegration
constructor
A new instance of ContinuousIntegration.
-
#report(title, &block) ⇒ Object
:nodoc:.
-
#step(title, *command) ⇒ Object
Declare a step with a title and a command.
-
#success? ⇒ Boolean
Returns true if all steps were successful.
Constructor Details
#initialize ⇒ ContinuousIntegration
Returns a new instance of ContinuousIntegration.
64 65 66 |
# File 'lib/active_support/continuous_integration.rb', line 64 def initialize @results = [] end |
Instance Attribute Details
#results ⇒ Object (readonly)
Returns the value of attribute results.
33 34 35 |
# File 'lib/active_support/continuous_integration.rb', line 33 def results @results end |
Class Method Details
.run(title = "Continuous Integration", subtitle = "Running tests, style checks, and security audits", &block) ⇒ Object
Perform a CI run. Execute each step, show their results and runtime, and exit with a non-zero status if there are any failures.
Pass an optional title, subtitle, and a block that declares the steps to be executed.
Sets the CI environment variable to “true” to allow for conditional behavior in the app, like enabling eager loading and disabling logging.
Example:
ActiveSupport::ContinuousIntegration.run do
step "Setup", "bin/setup --skip-server"
step "Style: Ruby", "bin/rubocop"
step "Security: Gem audit", "bin/bundler-audit"
step "Tests: Rails", "bin/rails test test:system"
if success?
step "Signoff: Ready for merge and deploy", "gh signoff"
else
failure "Skipping signoff; CI failed.", "Fix the issues and try again."
end
end
55 56 57 58 59 60 61 62 |
# File 'lib/active_support/continuous_integration.rb', line 55 def self.run(title = "Continuous Integration", subtitle = "Running tests, style checks, and security audits", &block) new.tap do |ci| ENV["CI"] = "true" ci.heading title, subtitle, padding: false ci.report(title, &block) abort unless ci.success? end end |
Instance Method Details
#echo(text, type:) ⇒ Object
Echo text to the terminal in the color corresponding to the type of the text.
Examples:
echo "This is going to be green!", type: :success
echo "This is going to be red!", type: :error
See ActiveSupport::ContinuousIntegration::COLORS for a complete list of options.
111 112 113 |
# File 'lib/active_support/continuous_integration.rb', line 111 def echo(text, type:) puts colorize(text, type) end |
#failure(title, subtitle = nil) ⇒ Object
Display an error heading with the title and optional subtitle to reflect that the run failed.
86 87 88 |
# File 'lib/active_support/continuous_integration.rb', line 86 def failure(title, subtitle = nil) heading title, subtitle, type: :error end |
#heading(heading, subtitle = nil, type: :banner, padding: true) ⇒ Object
Display a colorized heading followed by an optional subtitle.
Examples:
heading "Smoke Testing", "End-to-end tests verifying key functionality", padding: false
heading "Skipping video encoding tests", "Install FFmpeg to run these tests", type: :error
See ActiveSupport::ContinuousIntegration::COLORS for a complete list of options.
98 99 100 101 |
# File 'lib/active_support/continuous_integration.rb', line 98 def heading(heading, subtitle = nil, type: :banner, padding: true) echo "#{padding ? "\n\n" : ""}#{heading}", type: type echo "#{subtitle}#{padding ? "\n" : ""}", type: :subtitle if subtitle end |
#report(title, &block) ⇒ Object
:nodoc:
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/active_support/continuous_integration.rb', line 116 def report(title, &block) Signal.trap("INT") { abort colorize(:error, "\n❌ #{title} interrupted") } ci = self.class.new elapsed = timing { ci.instance_eval(&block) } if ci.success? echo "\n✅ #{title} passed in #{elapsed}", type: :success else echo "\n❌ #{title} failed in #{elapsed}", type: :error end results.concat ci.results ensure Signal.trap("INT", "-") end |
#step(title, *command) ⇒ Object
Declare a step with a title and a command. The command can either be given as a single string or as multiple strings that will be passed to ‘system` as individual arguments (and therefore correctly escaped for paths etc).
Examples:
step "Setup", "bin/setup"
step "Single test", "bin/rails", "test", "--name", "test_that_is_one"
75 76 77 78 |
# File 'lib/active_support/continuous_integration.rb', line 75 def step(title, *command) heading title, command.join(" "), type: :title report(title) { results << system(*command) } end |
#success? ⇒ Boolean
Returns true if all steps were successful.
81 82 83 |
# File 'lib/active_support/continuous_integration.rb', line 81 def success? results.all? end |