Continuous Integration für Ruby

Pascal Zumkehr

Mit unserem Continuous Integration Server Jenkins lassen sich auch Ruby Applikationen permanent auf ihre messbare Qualität abklopfen. Die folgenden Konfigurationen bilden die Basis für die Ruby Build Jobs bei Puzzle ITC.

In der Regel verwenden wir zwei Build Jobs pro Projekt. Einer, welcher bei jedem Commit möglichst kurz läuft und ein anderer, welcher jede Nacht läuft und länger dauernde Analysen vornimmt. Alle Schritte der Jobs werden in spezifischen `ci:*` Rake Tasks erfasst und unter `lib/tasks/ci.rake` abgelegt.

Ohne Tests kein Build

Das Ausführen der vollständigen Test Suite ist unbestritten der wichtigste Schritt beim Build auf dem Continuous Integration Server. Damit die Resultate nahtlos im integrierten Jenkins JUnit Plugin angezeigt und analysiert werden können, verwenden wir das ci_reporter Gem. Dieses wird durch die folgende Ergänzung im `Rakefile` geladen (vorausgesetzt, dass RSpec verwendet wird):

require 'ci/reporter/rake/rspec' unless Rails.env.production?

Danach muss in den `ci` Rake Tasks nur noch der Task `ci:setup:rspec` vor `spec` aufgerufen werden und schon erhält man über die Jenkins Post Build Aktion „Publish JUnit Report“ die gewünschten Ansichten.

tests

Neben dem reinen Ausführen der Tests interessiert uns ebenfalls deren Abdeckungsrate, welche wir im Nightly Build verfolgen. Über das RubyMetrics Jenkins Plugin erhalten wir einen detaillierten Report, welcher von den beiden Gems simplecov und simplecov-rcov erstellt wird.

coverage

Die folgenden Zeilen zuoberst in der `spec_helper.rb` Datei reichen bereits, um die Reports zu erstellen:

 require 'simplecov'
 require 'simplecov-rcov'
 SimpleCov.start 'rails'
 SimpleCov.coverage_dir 'spec/coverage'
 SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter

Hier ist wichtig zu bedenken, dass eine Testabdeckung von etwa 50% geschenkt ist, da jede Klassen- und Methodendefinition in Ruby ein ausführbares Statement darstellt und entsprechend schon beim normalen Laden mitgerechnet wird, ohne dass ein einziger Test ausgeführt wurde. Entsprechend streben wir bei unseren Projekten Abdeckungsraten von über 90% an.

Wir haben Style

Rubocop etablierte sich in den letzten Jahren zu *dem* Werkzeug für statische Ruby Code Analyse. Wie auch Tests bringt diese nur etwas, wenn sie auch ausgeführt wird. Daher gehört Rubocop zwingend auf den Jenkins. Mit dem aus der Java Welt stammenden Checkstyle Plugin und dem rubocop-checkstyle_formatter können die Resultate visualisiert werden.

style

Wir verwenden zwei Rubocop Konfigurationen, welche über eigene Rake Tasks gestartet werden. Die erste ist für den Commit Job, welche nur die harten Regeln enthält und bei einer Verletzung den Build abbricht:

namespace :rubocop do
  desc 'Run .rubocop-must.yml and fail if there are issues'
  task :must do
    begin
      sh 'rubocop --config .rubocop-must.yml'
    rescue
      abort('RuboCop failed!')
    end
  end
end

Die andere verwenden wir im Nightly Job. Sie erstellt einen ausführlichen Report und veranschaulicht die zeitliche Entwicklung der Anzahl Issues. Hier streben wir klar ein negatives Wachstum an:

namespace :rubocop do
  desc 'Run .rubocop.yml and generate checkstyle report'
  task :report do
    sh %w(rubocop
          --require rubocop/formatter/checkstyle_formatter
          --format RuboCop::Formatter::CheckstyleFormatter
          --no-color
          --out rubocop-results.xml).join(' ') rescue nil
    true # do not fail if we find issues
  end
end

Sicherheit? Geschenkt!

Das hervorragende Brakeman Gem findet durch statische Analyse häufig auftretende, Sicherheits-kritische Stellen im Quellcode. Mit dem zugehörigen Jenkins Brakeman Plugin ist es geschenkt, ebenfalls einen entsprechenden Rake Task im Nightly Job zu  integrieren:

task :brakeman do
  FileUtils.rm_f('brakeman-output.tabs')
  sh %w(brakeman -o brakeman-output.tabs
        -q
        --no-progress).join(' ')
end

Natürlich ist mit Brakeman das Thema Sicherheit bei Weitem noch nicht erledigt. Hier setzen wir primär auf Ausbildung und regelmässige Code Reviews. Doch ein weiteres Sicherheitsnetz bringt in diesem Fall nur Vorteile mit sich.

Dokumentation und weiteres

Je nach Projekt generieren wir ebenfalls Teile der Dokumentation im Nightly Job, sodass auch Nicht-Entwickler einen Überblick über die Software erhalten können. So zum Beispiel bei hitobito, wo wir aus mehreren Markdown Dokumenten eine One-Page HTML Dokumentation generieren.

Als sehr praktisch hat sich das Gem Rails ERD erwiesen, welches, im Jenkins integriert, ein stets aktuelles Datenbankdiagramm zur Verfügung stellt.

Die Kombination all dieser Gems und Plugins liefert uns eine gute Grundlage, um die Qualität unserer Projekte im Auge zu behalten. Und falls in der Hektik einmal etwas vergessen geht, können wir uns darauf verlassen, von einem fehlschlagenden Build Job freundlich benachrichtigt zu werden.

Kommentare sind geschlossen.