Skip to content

Commit

Permalink
Merge pull request #121 from Zero-Config-Rails/generator-for-gitlab-ci
Browse files Browse the repository at this point in the history
Generator for Gitlab CI
  • Loading branch information
abhaynikam authored Sep 19, 2024
2 parents d588010 + 9aa20b0 commit ac303c2
Show file tree
Hide file tree
Showing 17 changed files with 522 additions and 11 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## master (unreleased)

* Adds Gitlab CI generator. ([@coolprobn][])

## 0.14.0 (Aug 4th, 2024)

- Adds Figjam generator. ([@mausamp][])
Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
boring_generators (0.13.0)
boring_generators (0.14.0)
railties

GEM
Expand Down Expand Up @@ -143,4 +143,4 @@ DEPENDENCIES
sqlite3 (~> 1.4)

BUNDLED WITH
2.2.33
2.4.10
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ The boring generator introduces following generators:
- Install Rails ERD: `rails generate boring:rails_erd:install`
- Install Annotate: `rails generate boring:annotate:install`
- Install CanCanCan: `rails generate boring:cancancan:install`
- Install Gitlab CI: `rails generate boring:ci:gitlab_ci:install`

## Screencasts

Expand Down
16 changes: 14 additions & 2 deletions lib/boring_generators/generator_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ module GeneratorHelper
include Rails::Generators::Actions

def app_ruby_version
with_ruby_string = `grep "^ruby.*$" Gemfile` || `cat .ruby-version`
with_ruby_string = File.read("Gemfile")[/^ruby\s+["']?([\d.]+)["']?/] || File.read(".ruby-version").strip

# only keep 3.3.0
# only keep 3.3.0 from ruby-3.3.0
with_ruby_string.gsub(/[^\d\.]/, "").squish
end

Expand All @@ -30,5 +30,17 @@ def check_and_install_gem(*args)

bundle_install
end

def inject_into_file_if_new(*args)
file_name, content_to_add, = args

file_content = File.read(file_name)

content_exists = file_content.include?(content_to_add)

return if content_exists

inject_into_file *args
end
end
end
117 changes: 117 additions & 0 deletions lib/generators/boring/ci/gitlab_ci/install/install_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# frozen_string_literal: true

require "boring_generators/generator_helper"

module Boring
module Ci
module GitlabCi
class InstallGenerator < Rails::Generators::Base
desc "Adds Gitlab CI to the application"
source_root File.expand_path("templates", __dir__)

class_option :ruby_version,
aliases: "-rv",
type: :string,
desc:
"Ruby version used by your app. Defaults to .ruby_version or the version specified in your Gemfile."
class_option :app_test_framework,
aliases: "-tf",
type: :string,
enum: %w[minitest rspec],
default: "minitest",
desc:
"Tell us the test framework you use for the application. Defaults to Minitest."
class_option :environment_variable_manager,
aliases: "-evm",
type: :string,
enum: %w[rails_credentials dotenv figjam],
default: "rails_credentials",
desc:
"Tell us the environment variable manager you use. Defaults to Rails Credentials"
class_option :database,
aliases: "-d",
type: :string,
enum: %w[sqlite3 postgresql mysql],
default: "sqlite3",
desc: "Tell us the database you use in your app"
class_option :skip_sample_tests,
aliases: "-stt",
type: :boolean,
default: false,
desc:
"Skip sample tests. Useful when you are configuring Gitlab CI for existing Rails app"

include BoringGenerators::GeneratorHelper

def add_gitlab_ci_configurations
@ruby_version = options[:ruby_version] || app_ruby_version
@app_test_framework = options[:app_test_framework]
@environment_variable_manager = options[:environment_variable_manager]
@database = options[:database]

template("ci.yml", ".gitlab-ci.yml")
template("database.yml.ci", "config/database.yml.ci")
end

def add_gems_for_system_test
check_and_install_gem "capybara", group: :test
check_and_install_gem "selenium-webdriver", group: :test
end

def add_capybara_configurations
if options[:app_test_framework] == "minitest"
template("capybara_helper.rb", "test/helpers/capybara.rb")

inject_into_file_if_new "test/application_system_test_case.rb",
"require \"helpers/capybara\"\n",
before: "class ApplicationSystemTestCase"
gsub_file "test/application_system_test_case.rb",
/driven_by :selenium, using: :(?:chrome|headless_chrome).*\n/,
"driven_by :selenium_chrome_custom"

capybara_setup = <<-RUBY
\n
def setup
Capybara.server_host = "0.0.0.0" # bind to all interfaces
Capybara.server_port = 3000
ip = Socket.ip_address_list.detect(&:ipv4_private?).ip_address
Capybara.app_host = "http://\#{ip}:\#{Capybara.server_port}" if ENV["SELENIUM_REMOTE_URL"].present?
super
end
RUBY

inject_into_file_if_new "test/application_system_test_case.rb",
optimize_indentation(
capybara_setup,
amount = 2
),
after: "driven_by :selenium_chrome_custom"
else
template("capybara_helper.rb", "spec/support/capybara.rb")

inject_into_file_if_new "spec/rails_helper.rb",
"require_relative \"./support/capybara\"\n\n",
before: "RSpec.configure do |config|"
end
end

def add_sample_tests
return if options[:skip_sample_tests]

if options[:app_test_framework] == "minitest"
template("unit_sample_test.rb", "test/models/sample_test.rb")
template("system_sample_test.rb", "test/system/sample_test.rb")
else
template("unit_sample_spec.rb", "spec/models/sample_spec.rb")
template("system_sample_spec.rb", "spec/system/sample_spec.rb")
end
end

def show_readme
readme "README"
end
end
end
end
end
10 changes: 10 additions & 0 deletions lib/generators/boring/ci/gitlab_ci/install/templates/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

===============================================================================

You need to update your project's Gitlab CI variable configurations for the Gitlab CI to work correctly. Please take care of the following:

- Add your Gitlab personal access token under the variable `PRONTO_ACCESS_TOKEN`
- Copy your application's environment variables under `env` variable in CI/CD
- Add your Master Key required for decoding secret values under the variable `MASTER_KEY`

===============================================================================
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
require "selenium-webdriver"

Capybara.register_driver :selenium_chrome_custom do |app|
options = Selenium::WebDriver::Chrome::Options.new

options.add_argument("--headless=new") unless ENV["SELENIUM_HEADFUL"]

options.add_argument("--window-size=1400,1400")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")

remote_url = ENV.fetch("SELENIUM_REMOTE_URL", nil)

if remote_url
Capybara::Selenium::Driver.new(
app,
browser: :remote,
url: remote_url,
options:
)
else
Capybara::Selenium::Driver.new(app, browser: :chrome, options:)
end
end

<%- if @app_test_framework == "rspec" -%>
RSpec.configure do |config|
config.before(:each, type: :system, js: true) do
# Make the test app listen to outside requests, required for the remote Selenium instance
Capybara.server_host = "0.0.0.0"
Capybara.server_port = 3000

if ENV.fetch("SELENIUM_REMOTE_URL", nil)
# Use the application container's IP instead of localhost so Capybara knows where to direct Selenium
ip = Socket.ip_address_list.detect(&:ipv4_private?).ip_address
Capybara.app_host = "http://#{ip}:#{Capybara.server_port}"
end

driven_by :selenium_chrome_custom
end
end
<%- end -%>
94 changes: 94 additions & 0 deletions lib/generators/boring/ci/gitlab_ci/install/templates/ci.yml.tt
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
image: ruby:<%= @ruby_version %>

variables:
MASTER_KEY: $MASTER_KEY

cache:
paths:
- vendor/
<%- if File.exist?("package.json") -%>
- node_modules/
- yarn.lock
<%- end -%>

stages:
- test

.base_db:
<%- if @database == "postgresql" -%>
services:
- postgres:latest
<%- elsif @database == "mysql" -%>
services:
- mysql:latest
<%- end -%>
variables:
RAILS_ENV: test
<%- if @database == "postgresql" -%>
POSTGRES_HOST_AUTH_METHOD: trust
<%- end -%>
<%- if @database == "mysql" -%>
MYSQL_ALLOW_EMPTY_PASSWORD: true
<%- end -%>
before_script:
- gem install bundler -v "$(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1)" --no-document
- bundle config set --local path 'vendor'
<%- if File.exist?("package.json") -%>
- apt-get update -qq && apt-get install -y -qq nodejs
- curl -o- -L https://yarnpkg.com/install.sh | bash
- export PATH="$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$PATH"
- yarn install --pure-lockfile
<%- end -%>
<%- if @database == "sqlite3" -%>
- apt-get update && apt-get install --no-install-recommends -y sqlite3
<%- end -%>
- apt-get update && apt-get install --no-install-recommends -y cmake
- bundle install --jobs $(nproc)
- cp config/database.yml.ci config/database.yml
<%- if @environment_variable_manager == "dotenv" -%>
- cat $env > .env
<%- elsif @environment_variable_manager == "figjam" -%>
- cat $env > config/application.yml
<%- end -%>
- bundle exec rails db:test:prepare

unit_and_integration_tests:
extends: .base_db
stage: test
only:
- merge_requests
script:
<%- if @app_test_framework == "rspec" -%>
- bundle exec rspec --exclude-pattern "spec/system/**/*.rb"
<%- else -%>
- bundle exec rails test
<%- end -%>

system_tests:
extends: .base_db
stage: test
services:
- name: selenium/standalone-chrome:latest
alias: selenium
<%- if @database == "postgresql" -%>
- postgres:latest
<%- elsif @database == "mysql" -%>
- mysql:latest
<%- end -%>
variables:
RAILS_ENV: test
SELENIUM_REMOTE_URL: http://selenium:4444/wd/hub
only:
- merge_requests
script:
<%- if @app_test_framework == "rspec" -%>
- bundle exec rspec spec/system
<%- else -%>
- bundle exec rails test:system
<%- end -%>
artifacts:
when: on_failure
paths:
- log/test.log
- tmp/screenshots/
expire_in: 1 week
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
test:
<%- if @database == "postgresql" -%>
adapter: postgresql
encoding: unicode
host: postgres
username: test
password: test
<%- elsif @database == "mysql" -%>
adapter: mysql2
encoding: utf8mb4
host: mysql
username: root
socket: /tmp/mysql.sock
<%- else -%>
adapter: sqlite3
database: db/test.sqlite3
<%- end -%>
<%- unless @database == "sqlite3" -%>
database: ci_db
<%- end -%>
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require "rails_helper"

RSpec.describe "Sample System Test", type: :system, js: true do
it "checks if the system test is configured correctly" do
visit rails_health_check_path

# expect page body to have green background
expect(
page.evaluate_script(
"window.getComputedStyle(document.body).backgroundColor"
)
).to eq("rgb(0, 128, 0)")
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
require "application_system_test_case"

class SampleTest < ApplicationSystemTestCase
test "checks if the system test is configured correctly" do
visit rails_health_check_path

# assert page body has green background
assert_equal "rgb(0, 128, 0)",
page.evaluate_script(
"window.getComputedStyle(document.body).backgroundColor"
)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require "rails_helper"

RSpec.describe("Sample", type: :model) do
it "tests the truth" do
expect(true).to be_truthy
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require "test_helper"

class SampleTest < ActiveSupport::TestCase
test "the truth" do
assert true
end
end
Loading

0 comments on commit ac303c2

Please sign in to comment.