├── .cfignore ├── .ruby-version ├── Gemfile ├── lib ├── app.rb ├── restarter │ ├── circle_project.rb │ ├── circle_project_loader.rb │ └── interval_calculator.rb └── restarter.rb ├── config.ru ├── manifest.yml ├── spec ├── spec_helper.rb └── unit │ ├── interval_calculator_spec.rb │ ├── circle_project_spec.rb │ └── circle_project_loader_spec.rb ├── bin └── deploy-ci.sh ├── .circleci └── config.yml ├── Gemfile.lock ├── .gitignore ├── LICENSE.md ├── README.md └── .rubocop.yml /.cfignore: -------------------------------------------------------------------------------- 1 | .gitignore -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | ruby "~> 2.7.2" 3 | 4 | gem "circleci" 5 | gem "sinatra" 6 | 7 | group :test do 8 | gem "rspec" 9 | gem "timecop" 10 | end 11 | -------------------------------------------------------------------------------- /lib/app.rb: -------------------------------------------------------------------------------- 1 | require "sinatra" 2 | 3 | # An app to render a 200 for New Relic monitoring 4 | class Application < Sinatra::Base 5 | get "/" do 6 | Time.now.to_s 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | require "./lib/app" 2 | require "./lib/restarter" 3 | 4 | # Start restarting builds 5 | Restarter.restart 6 | 7 | Rack::Handler.default.run Application.new, Port: ENV["PORT"] 8 | -------------------------------------------------------------------------------- /manifest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | applications: 3 | - name: analytics-restarter 4 | buildpack: ruby_buildpack 5 | instances: 1 6 | memory: 128M 7 | services: 8 | - circleci 9 | stack: cflinuxfs3 10 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require "rubygems" 2 | require "bundler" 3 | require_relative "../lib/restarter.rb" 4 | 5 | Bundler.require(:test) 6 | 7 | include Restarter 8 | 9 | # Observe safety protocols while time travelling 🕚 10 | Timecop.safe_mode = true 11 | -------------------------------------------------------------------------------- /bin/deploy-ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Install CF 6 | curl https://s3-us-west-1.amazonaws.com/cf-cli-releases/releases/v6.25.0/cf-cli_6.25.0_linux_x86-64.tgz | tar xzvf - 7 | sudo mv cf /usr/local/bin/cf 8 | 9 | # Log into cloud.gov 10 | cf api api.fr.cloud.gov 11 | cf login -u $CF_USERNAME -p $CF_PASSWORD -o gsa-opp-analytics -s analytics-dev 12 | 13 | # Push the app 14 | cf push analytics-restarter 15 | 16 | cf logout 17 | -------------------------------------------------------------------------------- /lib/restarter/circle_project.rb: -------------------------------------------------------------------------------- 1 | require "json" 2 | require "circleci" 3 | 4 | module Restarter 5 | class CircleProject 6 | attr_reader :name, :token 7 | 8 | def initialize(name:, token:, branch: nil) 9 | @name = name 10 | @token = token 11 | @branch = branch 12 | end 13 | 14 | def branch 15 | @branch || "master" 16 | end 17 | 18 | def rebuild 19 | circle_config = CircleCi::Config.new(token: token) 20 | project = CircleCi::Project.new( 21 | "18f", 22 | name, 23 | "github", 24 | circle_config, 25 | ) 26 | project.build_branch branch 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/restarter/circle_project_loader.rb: -------------------------------------------------------------------------------- 1 | require "json" 2 | 3 | module Restarter 4 | class CircleProjectLoader 5 | def load_projects 6 | circleci_service["credentials"].map do |_key, project_data_json| 7 | project_data = JSON.parse(project_data_json) 8 | CircleProject.new( 9 | name: project_data["NAME"], 10 | token: project_data["TOKEN"], 11 | branch: project_data["BRANCH"], 12 | ) 13 | end 14 | end 15 | 16 | private 17 | 18 | def circleci_service 19 | uup_services = JSON.parse(ENV["VCAP_SERVICES"])["user-provided"] 20 | uup_services.detect do |service| 21 | service["name"] == "circleci" 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/restarter/interval_calculator.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # 6:00 AM UTC is 2:00 AM or 1:00 AM ET depending on DST 3 | # 4 | RESTART_HOUR_UTC = 6 5 | 6 | module Restarter 7 | class IntervalCalculator 8 | def calculate_interval 9 | next_restart_time - Time.now 10 | end 11 | 12 | private 13 | 14 | def next_restart_time 15 | current_time_utc = Time.now.utc 16 | restart_time_today = Time.new( 17 | current_time_utc.year, 18 | current_time_utc.month, 19 | current_time_utc.day, 20 | RESTART_HOUR_UTC, 21 | 0, 22 | 0, 23 | "+00:00", 24 | ) 25 | if restart_time_today - current_time_utc > 0 26 | restart_time_today 27 | else 28 | restart_time_today + 24 * 60 * 60 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/unit/interval_calculator_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "IntervalCalculator" do 4 | describe "#calculate_interval" do 5 | it "calculates the interval correctly prior to 6:00 AM UTC" do 6 | # 2017/06/19 05:30:00 UTC 7 | run_time = Time.new(2017, 6, 19, 7, 30, 0, "+02:00") 8 | 9 | Timecop.freeze(run_time) do 10 | interval = IntervalCalculator.new.calculate_interval 11 | expect(interval).to eq(60 * 30) # 30 minutes 12 | end 13 | end 14 | 15 | it "calculates the interval correctly after 6:00 AM UTC" do 16 | # 2017/06/19 06:30:00 UTC 17 | run_time = Time.new(2017, 6, 19, 8, 30, 0, "+02:00") 18 | 19 | Timecop.freeze(run_time) do 20 | interval = IntervalCalculator.new.calculate_interval 21 | expect(interval).to eq(24 * 60 * 60 - 60 * 30) # 24 hours - 30 minutes 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: circleci/ruby:2.7-node-browsers 6 | steps: 7 | - checkout 8 | - restore_cache: 9 | keys: 10 | - v1-dependencies-{{ checksum "Gemfile.lock" }} 11 | - v1-dependencies- 12 | - run: 13 | name: install dependencies 14 | command: | 15 | bundle config set path 'vendor/bundle' 16 | bundle install --jobs=4 --retry=3 17 | - save_cache: 18 | paths: 19 | - ./vendor/bundle 20 | key: v1-dependencies-{{ checksum "Gemfile.lock" }} 21 | - run: 22 | name: run tests 23 | command: bundle exec rspec 24 | - run: 25 | name: deploy site 26 | command: | 27 | if [ "${CIRCLE_BRANCH}" == "master" ]; then 28 | bin/deploy-ci.sh 29 | fi 30 | -------------------------------------------------------------------------------- /lib/restarter.rb: -------------------------------------------------------------------------------- 1 | require "circleci" 2 | require "logger" 3 | 4 | module Restarter 5 | autoload :CircleProject, "./lib/restarter/circle_project" 6 | autoload :CircleProjectLoader, "./lib/restarter/circle_project_loader" 7 | autoload :IntervalCalculator, "./lib/restarter/interval_calculator" 8 | 9 | class << self 10 | def restart 11 | logger = Logger.new(STDERR) 12 | logger.level = Logger::INFO 13 | 14 | interval = IntervalCalculator.new.calculate_interval 15 | Thread.new do 16 | begin 17 | logger.info "Restarting in #{interval} seconds" 18 | sleep interval 19 | CircleProjectLoader.new.load_projects.each do |project| 20 | logger.info "Restarting #{project.name}" 21 | project.rebuild 22 | end 23 | rescue StandardError => e 24 | logger.error(e) 25 | end 26 | restart 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | circleci (2.0.3) 5 | diff-lcs (1.4.4) 6 | mustermann (1.1.1) 7 | ruby2_keywords (~> 0.0.1) 8 | rack (2.2.3) 9 | rack-protection (2.1.0) 10 | rack 11 | rspec (3.10.0) 12 | rspec-core (~> 3.10.0) 13 | rspec-expectations (~> 3.10.0) 14 | rspec-mocks (~> 3.10.0) 15 | rspec-core (3.10.1) 16 | rspec-support (~> 3.10.0) 17 | rspec-expectations (3.10.1) 18 | diff-lcs (>= 1.2.0, < 2.0) 19 | rspec-support (~> 3.10.0) 20 | rspec-mocks (3.10.1) 21 | diff-lcs (>= 1.2.0, < 2.0) 22 | rspec-support (~> 3.10.0) 23 | rspec-support (3.10.1) 24 | ruby2_keywords (0.0.2) 25 | sinatra (2.1.0) 26 | mustermann (~> 1.0) 27 | rack (~> 2.2) 28 | rack-protection (= 2.1.0) 29 | tilt (~> 2.0) 30 | tilt (2.0.10) 31 | timecop (0.9.2) 32 | 33 | PLATFORMS 34 | ruby 35 | 36 | DEPENDENCIES 37 | circleci 38 | rspec 39 | sinatra 40 | timecop 41 | 42 | RUBY VERSION 43 | ruby 2.7.2p137 44 | 45 | BUNDLED WITH 46 | 2.1.4 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | /.config 4 | /coverage/ 5 | /InstalledFiles 6 | /pkg/ 7 | /spec/reports/ 8 | /spec/examples.txt 9 | /test/tmp/ 10 | /test/version_tmp/ 11 | /tmp/ 12 | 13 | # Used by dotenv library to load environment variables. 14 | # .env 15 | 16 | ## Specific to RubyMotion: 17 | .dat* 18 | .repl_history 19 | build/ 20 | *.bridgesupport 21 | build-iPhoneOS/ 22 | build-iPhoneSimulator/ 23 | 24 | ## Specific to RubyMotion (use of CocoaPods): 25 | # 26 | # We recommend against adding the Pods directory to your .gitignore. However 27 | # you should judge for yourself, the pros and cons are mentioned at: 28 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 29 | # 30 | # vendor/Pods/ 31 | 32 | ## Documentation cache and generated files: 33 | /.yardoc/ 34 | /_yardoc/ 35 | /doc/ 36 | /rdoc/ 37 | 38 | ## Environment normalization: 39 | /.bundle/ 40 | /vendor/bundle 41 | /lib/bundler/man/ 42 | 43 | # for a library or gem, you might want to ignore these files since the code is 44 | # intended to run in multiple environments; otherwise, check them in: 45 | # Gemfile.lock 46 | # .ruby-version 47 | # .ruby-gemset 48 | 49 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 50 | .rvmrc 51 | -------------------------------------------------------------------------------- /spec/unit/circle_project_spec.rb: -------------------------------------------------------------------------------- 1 | describe "CircleProject" do 2 | describe "#branch" do 3 | it "returns the value set for the branch" do 4 | project = CircleProject.new( 5 | name: "my-project", 6 | token: "abc123", 7 | branch: "dev", 8 | ) 9 | expect(project.branch).to eq("dev") 10 | end 11 | 12 | it "returns 'master' if no value is set for the branch" do 13 | project = CircleProject.new( 14 | name: "my-project", 15 | token: "abc123", 16 | ) 17 | expect(project.branch).to eq("master") 18 | end 19 | end 20 | 21 | describe "#rebuild" do 22 | it "sends a request to rebuild the branch" do 23 | circleci_project = double 24 | expect(circleci_project).to receive(:build_branch).with("dev") 25 | 26 | allow(CircleCi::Project).to receive(:new) do |org, repo, vcs, config| 27 | expect(org).to eq("18f") 28 | expect(repo).to eq("fake-repo") 29 | expect(vcs).to eq("github") 30 | expect(config.token).to eq("fake-token") 31 | circleci_project 32 | end 33 | 34 | CircleProject.new( 35 | name: "fake-repo", 36 | token: "fake-token", 37 | branch: "dev", 38 | ).rebuild 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/unit/circle_project_loader_spec.rb: -------------------------------------------------------------------------------- 1 | require "json" 2 | 3 | describe "CircleProjectLoader" do 4 | before do 5 | vcap_services = { 6 | "user-provided" => [ 7 | "name" => "circleci", 8 | "credentials" => { 9 | "FIRST_APP" => { 10 | "NAME" => "first_app", 11 | "TOKEN" => "123abc", 12 | }.to_json, 13 | "SECOND_APP" => { 14 | "NAME" => "second_app", 15 | "TOKEN" => "456def", 16 | "BRANCH" => "dev", 17 | }.to_json, 18 | }, 19 | ], 20 | } 21 | ENV["VCAP_SERVICES"] = vcap_services.to_json 22 | end 23 | 24 | after do 25 | ENV.delete("VCAP_SERVICES") 26 | end 27 | 28 | describe "#load_projects" do 29 | it "loads an array of circle projects from the user provided service" do 30 | projects = CircleProjectLoader.new.load_projects 31 | expect(projects.length).to eq(2) 32 | expect(projects[0].name).to eq("first_app") 33 | expect(projects[0].token).to eq("123abc") 34 | expect(projects[0].branch).to eq("master") 35 | expect(projects[1].name).to eq("second_app") 36 | expect(projects[1].token).to eq("456def") 37 | expect(projects[1].branch).to eq("dev") 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | As a work of the United States Government, this project is in the 2 | public domain within the United States. 3 | 4 | Additionally, we waive copyright and related rights in the work 5 | worldwide through the CC0 1.0 Universal public domain dedication. 6 | 7 | ## CC0 1.0 Universal Summary 8 | 9 | This is a human-readable summary of the [Legal Code (read the full text)](https://creativecommons.org/publicdomain/zero/1.0/legalcode). 10 | 11 | ### No Copyright 12 | 13 | The person who associated a work with this deed has dedicated the work to 14 | the public domain by waiving all of his or her rights to the work worldwide 15 | under copyright law, including all related and neighboring rights, to the 16 | extent allowed by law. 17 | 18 | You can copy, modify, distribute and perform the work, even for commercial 19 | purposes, all without asking permission. 20 | 21 | ### Other Information 22 | 23 | In no way are the patent or trademark rights of any person affected by CC0, 24 | nor are the rights that other persons may have in the work or in how the 25 | work is used, such as publicity or privacy rights. 26 | 27 | Unless expressly stated otherwise, the person who associated a work with 28 | this deed makes no warranties about the work, and disclaims liability for 29 | all uses of the work, to the fullest extent permitted by applicable law. 30 | When using or citing the work, you should not imply endorsement by the 31 | author or the affirmer. 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Analytics Restarter 2 | 3 | This app triggers nightly builds for the apps that makeup the [analytics.usa.gov](https://analytics.usa.gov) system. These apps include: 4 | 5 | - [analytics.usa.gov](https://github.com/18F/analytics.usa.gov) 6 | - [analytics-reporter](https://github.com/18F/analytics-reporter) 7 | - [analytics-reporter-api](https://github.com/18F/analytics-reporter-api) 8 | 9 | This service will restart CI builds for the above apps at 06:00 UTC every day. 10 | 11 | ## Deploy 12 | 13 | To setup this app in cloud.gov, first deploy a user provided service to provide the app with the necessary information to start builds on circle. The app looks for a user provided service named `circleci`. It expects the service to have a key for each app referencing a JSON encoded string providing the repo name and a CircleCI token for the app. 14 | 15 | For example: 16 | 17 | ```shell 18 | $ cf cups -p ANALYTICS_USA_GOV,ANALYTICS_REPORTER,ANALYTICS_REPORTER_API 19 | 20 | ANALYTICS_USA_GOV> {"NAME": "analytics.usa.gov","TOKEN": "123abc"} 21 | ANALYTICS_REPORTER> {"NAME": "analytics-reporter","TOKEN": "456def"} 22 | ANALYTICS_REPORTER_API> {"NAME": "analytics-reporter-api","TOKEN": "789ghi"} 23 | ``` 24 | 25 | This app also provides a route at `/` to provide an endpoint for New Relic uptime monitoring. 26 | 27 | ## Tests 28 | 29 | This app ships with a lightweight testing suite. That can be run with `rspec`: 30 | 31 | ``` 32 | bundle install 33 | bundle exec rspec 34 | ``` 35 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - db/schema.rb 4 | 5 | Style/AccessorMethodName: 6 | Description: Check the naming of accessor methods for get_/set_. 7 | Enabled: false 8 | 9 | Style/Alias: 10 | Description: 'Use alias_method instead of alias.' 11 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#alias-method' 12 | Enabled: false 13 | 14 | Style/ArrayJoin: 15 | Description: 'Use Array#join instead of Array#*.' 16 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#array-join' 17 | Enabled: false 18 | 19 | Style/AsciiComments: 20 | Description: 'Use only ascii symbols in comments.' 21 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#english-comments' 22 | Enabled: false 23 | 24 | Style/AsciiIdentifiers: 25 | Description: 'Use only ascii symbols in identifiers.' 26 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#english-identifiers' 27 | Enabled: false 28 | 29 | Style/Attr: 30 | Description: 'Checks for uses of Module#attr.' 31 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr' 32 | Enabled: false 33 | 34 | Metrics/BlockNesting: 35 | Description: 'Avoid excessive block nesting' 36 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#three-is-the-number-thou-shalt-count' 37 | Enabled: false 38 | 39 | Style/CaseEquality: 40 | Description: 'Avoid explicit use of the case equality operator(===).' 41 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-case-equality' 42 | Enabled: false 43 | 44 | Style/CharacterLiteral: 45 | Description: 'Checks for uses of character literals.' 46 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-character-literals' 47 | Enabled: false 48 | 49 | Style/ClassAndModuleChildren: 50 | Description: 'Checks style of children classes and modules.' 51 | Enabled: true 52 | EnforcedStyle: nested 53 | 54 | Metrics/ClassLength: 55 | Description: 'Avoid classes longer than 100 lines of code.' 56 | Enabled: false 57 | 58 | Metrics/ModuleLength: 59 | Description: 'Avoid modules longer than 100 lines of code.' 60 | Enabled: false 61 | 62 | Style/ClassVars: 63 | Description: 'Avoid the use of class variables.' 64 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-class-vars' 65 | Enabled: false 66 | 67 | Style/CollectionMethods: 68 | Enabled: true 69 | PreferredMethods: 70 | find: detect 71 | inject: reduce 72 | collect: map 73 | find_all: select 74 | 75 | Style/ColonMethodCall: 76 | Description: 'Do not use :: for method call.' 77 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#double-colons' 78 | Enabled: false 79 | 80 | Style/CommentAnnotation: 81 | Description: >- 82 | Checks formatting of special comments 83 | (TODO, FIXME, OPTIMIZE, HACK, REVIEW). 84 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#annotate-keywords' 85 | Enabled: false 86 | 87 | Metrics/AbcSize: 88 | Description: >- 89 | A calculated magnitude based on number of assignments, 90 | branches, and conditions. 91 | Enabled: false 92 | 93 | Metrics/BlockLength: 94 | CountComments: true # count full line comments? 95 | Max: 25 96 | ExcludedMethods: [] 97 | Exclude: 98 | - "spec/**/*" 99 | 100 | Metrics/CyclomaticComplexity: 101 | Description: >- 102 | A complexity metric that is strongly correlated to the number 103 | of test cases needed to validate a method. 104 | Enabled: false 105 | 106 | Rails/Delegate: 107 | Description: 'Prefer delegate method for delegations.' 108 | Enabled: false 109 | 110 | Style/PreferredHashMethods: 111 | Description: 'Checks use of `has_key?` and `has_value?` Hash methods.' 112 | StyleGuide: '#hash-key' 113 | Enabled: false 114 | 115 | Style/Documentation: 116 | Description: 'Document classes and non-namespace modules.' 117 | Enabled: false 118 | 119 | Style/DoubleNegation: 120 | Description: 'Checks for uses of double negation (!!).' 121 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-bang-bang' 122 | Enabled: false 123 | 124 | Style/EachWithObject: 125 | Description: 'Prefer `each_with_object` over `inject` or `reduce`.' 126 | Enabled: false 127 | 128 | Style/EmptyLiteral: 129 | Description: 'Prefer literals to Array.new/Hash.new/String.new.' 130 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#literal-array-hash' 131 | Enabled: false 132 | 133 | # Checks whether the source file has a utf-8 encoding comment or not 134 | # AutoCorrectEncodingComment must match the regex 135 | # /#.*coding\s?[:=]\s?(?:UTF|utf)-8/ 136 | Style/Encoding: 137 | Enabled: false 138 | 139 | Style/EvenOdd: 140 | Description: 'Favor the use of Fixnum#even? && Fixnum#odd?' 141 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods' 142 | Enabled: false 143 | 144 | Style/FileName: 145 | Description: 'Use snake_case for source file names.' 146 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-files' 147 | Enabled: false 148 | 149 | Style/FrozenStringLiteralComment: 150 | Description: >- 151 | Add the frozen_string_literal comment to the top of files 152 | to help transition from Ruby 2.3.0 to Ruby 3.0. 153 | Enabled: false 154 | 155 | Style/FlipFlop: 156 | Description: 'Checks for flip flops' 157 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-flip-flops' 158 | Enabled: false 159 | 160 | Style/FormatString: 161 | Description: 'Enforce the use of Kernel#sprintf, Kernel#format or String#%.' 162 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#sprintf' 163 | Enabled: false 164 | 165 | Style/GlobalVars: 166 | Description: 'Do not introduce global variables.' 167 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#instance-vars' 168 | Reference: 'http://www.zenspider.com/Languages/Ruby/QuickRef.html' 169 | Enabled: false 170 | 171 | Style/GuardClause: 172 | Description: 'Check for conditionals that can be replaced with guard clauses' 173 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals' 174 | Enabled: false 175 | 176 | Style/IfUnlessModifier: 177 | Description: >- 178 | Favor modifier if/unless usage when you have a 179 | single-line body. 180 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#if-as-a-modifier' 181 | Enabled: false 182 | 183 | Style/IfWithSemicolon: 184 | Description: 'Do not use if x; .... Use the ternary operator instead.' 185 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-semicolon-ifs' 186 | Enabled: false 187 | 188 | Style/InlineComment: 189 | Description: 'Avoid inline comments.' 190 | Enabled: false 191 | 192 | Style/Lambda: 193 | Description: 'Use the new lambda literal syntax for single-line blocks.' 194 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#lambda-multi-line' 195 | Enabled: false 196 | 197 | Style/LambdaCall: 198 | Description: 'Use lambda.call(...) instead of lambda.(...).' 199 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#proc-call' 200 | Enabled: false 201 | 202 | Style/LineEndConcatenation: 203 | Description: >- 204 | Use \ instead of + or << to concatenate two string literals at 205 | line end. 206 | Enabled: false 207 | 208 | Metrics/LineLength: 209 | Description: 'Limit lines to 80 characters.' 210 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#80-character-limits' 211 | Max: 80 212 | 213 | Metrics/MethodLength: 214 | Description: 'Avoid methods longer than 10 lines of code.' 215 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#short-methods' 216 | Enabled: false 217 | 218 | Style/ModuleFunction: 219 | Description: 'Checks for usage of `extend self` in modules.' 220 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#module-function' 221 | Enabled: false 222 | 223 | Style/MultilineBlockChain: 224 | Description: 'Avoid multi-line chains of blocks.' 225 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#single-line-blocks' 226 | Enabled: false 227 | 228 | Style/NegatedIf: 229 | Description: >- 230 | Favor unless over if for negative conditions 231 | (or control flow or). 232 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#unless-for-negatives' 233 | Enabled: false 234 | 235 | Style/NegatedWhile: 236 | Description: 'Favor until over while for negative conditions.' 237 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#until-for-negatives' 238 | Enabled: false 239 | 240 | Style/Next: 241 | Description: 'Use `next` to skip iteration instead of a condition at the end.' 242 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals' 243 | Enabled: false 244 | 245 | Style/NilComparison: 246 | Description: 'Prefer x.nil? to x == nil.' 247 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods' 248 | Enabled: false 249 | 250 | Style/Not: 251 | Description: 'Use ! instead of not.' 252 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#bang-not-not' 253 | Enabled: false 254 | 255 | Style/NumericLiterals: 256 | Description: >- 257 | Add underscores to large numeric literals to improve their 258 | readability. 259 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscores-in-numerics' 260 | Enabled: false 261 | 262 | Style/OneLineConditional: 263 | Description: >- 264 | Favor the ternary operator(?:) over 265 | if/then/else/end constructs. 266 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#ternary-operator' 267 | Enabled: false 268 | 269 | Style/OpMethod: 270 | Description: 'When defining binary operators, name the argument other.' 271 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#other-arg' 272 | Enabled: false 273 | 274 | Metrics/ParameterLists: 275 | Description: 'Avoid parameter lists longer than three or four parameters.' 276 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#too-many-params' 277 | Enabled: false 278 | 279 | Style/PercentLiteralDelimiters: 280 | Description: 'Use `%`-literal delimiters consistently' 281 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-literal-braces' 282 | Enabled: false 283 | 284 | Style/PerlBackrefs: 285 | Description: 'Avoid Perl-style regex back references.' 286 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-perl-regexp-last-matchers' 287 | Enabled: false 288 | 289 | Style/PredicateName: 290 | Description: 'Check the names of predicate methods.' 291 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark' 292 | NamePrefixBlacklist: 293 | - is_ 294 | Exclude: 295 | - spec/**/* 296 | 297 | Style/Proc: 298 | Description: 'Use proc instead of Proc.new.' 299 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#proc' 300 | Enabled: false 301 | 302 | Style/RaiseArgs: 303 | Description: 'Checks the arguments passed to raise/fail.' 304 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#exception-class-messages' 305 | Enabled: false 306 | 307 | Style/RegexpLiteral: 308 | Description: 'Use / or %r around regular expressions.' 309 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-r' 310 | Enabled: false 311 | 312 | Style/SelfAssignment: 313 | Description: >- 314 | Checks for places where self-assignment shorthand should have 315 | been used. 316 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#self-assignment' 317 | Enabled: false 318 | 319 | Style/SingleLineBlockParams: 320 | Description: 'Enforces the names of some block params.' 321 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#reduce-blocks' 322 | Enabled: false 323 | 324 | Style/SingleLineMethods: 325 | Description: 'Avoid single-line methods.' 326 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-single-line-methods' 327 | Enabled: false 328 | 329 | Style/SignalException: 330 | Description: 'Checks for proper usage of fail and raise.' 331 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#fail-method' 332 | Enabled: false 333 | 334 | Style/SpecialGlobalVars: 335 | Description: 'Avoid Perl-style global variables.' 336 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-cryptic-perlisms' 337 | Enabled: false 338 | 339 | Style/StringLiterals: 340 | Description: 'Checks if uses of quotes match the configured preference.' 341 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#consistent-string-literals' 342 | EnforcedStyle: double_quotes 343 | Enabled: true 344 | 345 | Style/TrailingCommaInArguments: 346 | Description: 'Checks for trailing comma in argument lists.' 347 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas' 348 | EnforcedStyleForMultiline: comma 349 | SupportedStylesForMultiline: 350 | - comma 351 | - consistent_comma 352 | - no_comma 353 | Enabled: true 354 | 355 | Style/TrailingCommaInLiteral: 356 | Description: 'Checks for trailing comma in array and hash literals.' 357 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas' 358 | EnforcedStyleForMultiline: comma 359 | SupportedStylesForMultiline: 360 | - comma 361 | - consistent_comma 362 | - no_comma 363 | Enabled: true 364 | 365 | Style/TrivialAccessors: 366 | Description: 'Prefer attr_* methods to trivial readers/writers.' 367 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr_family' 368 | Enabled: false 369 | 370 | Style/VariableInterpolation: 371 | Description: >- 372 | Don't interpolate global, instance and class variables 373 | directly in strings. 374 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#curlies-interpolate' 375 | Enabled: false 376 | 377 | Style/WhenThen: 378 | Description: 'Use when x then ... for one-line cases.' 379 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#one-line-cases' 380 | Enabled: false 381 | 382 | Style/WhileUntilModifier: 383 | Description: >- 384 | Favor modifier while/until usage when you have a 385 | single-line body. 386 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#while-as-a-modifier' 387 | Enabled: false 388 | 389 | Style/WordArray: 390 | Description: 'Use %w or %W for arrays of words.' 391 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-w' 392 | Enabled: false 393 | 394 | # Layout 395 | 396 | Layout/AlignParameters: 397 | Description: 'Here we check if the parameters on a multi-line method call or definition are aligned.' 398 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-double-indent' 399 | Enabled: false 400 | 401 | Layout/DotPosition: 402 | Description: 'Checks the position of the dot in multi-line method calls.' 403 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#consistent-multi-line-chains' 404 | EnforcedStyle: trailing 405 | 406 | Layout/ExtraSpacing: 407 | Description: 'Do not use unnecessary spacing.' 408 | Enabled: true 409 | 410 | Layout/MultilineOperationIndentation: 411 | Description: >- 412 | Checks indentation of binary operations that span more than 413 | one line. 414 | Enabled: true 415 | EnforcedStyle: indented 416 | 417 | Layout/MultilineMethodCallIndentation: 418 | Description: >- 419 | Checks indentation of method calls with the dot operator 420 | that span more than one line. 421 | Enabled: true 422 | EnforcedStyle: indented 423 | 424 | Layout/InitialIndentation: 425 | Description: >- 426 | Checks the indentation of the first non-blank non-comment line in a file. 427 | Enabled: false 428 | 429 | # Lint 430 | 431 | Lint/AmbiguousOperator: 432 | Description: >- 433 | Checks for ambiguous operators in the first argument of a 434 | method invocation without parentheses. 435 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-as-args' 436 | Enabled: false 437 | 438 | Lint/AmbiguousRegexpLiteral: 439 | Description: >- 440 | Checks for ambiguous regexp literals in the first argument of 441 | a method invocation without parenthesis. 442 | Enabled: false 443 | 444 | Lint/AssignmentInCondition: 445 | Description: "Don't use assignment in conditions." 446 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#safe-assignment-in-condition' 447 | Enabled: false 448 | 449 | Lint/CircularArgumentReference: 450 | Description: "Don't refer to the keyword argument in the default value." 451 | Enabled: false 452 | 453 | Lint/ConditionPosition: 454 | Description: >- 455 | Checks for condition placed in a confusing position relative to 456 | the keyword. 457 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#same-line-condition' 458 | Enabled: false 459 | 460 | Lint/DeprecatedClassMethods: 461 | Description: 'Check for deprecated class method calls.' 462 | Enabled: false 463 | 464 | Lint/DuplicatedKey: 465 | Description: 'Check for duplicate keys in hash literals.' 466 | Enabled: false 467 | 468 | Lint/EachWithObjectArgument: 469 | Description: 'Check for immutable argument given to each_with_object.' 470 | Enabled: false 471 | 472 | Lint/ElseLayout: 473 | Description: 'Check for odd code arrangement in an else block.' 474 | Enabled: false 475 | 476 | Lint/FormatParameterMismatch: 477 | Description: 'The number of parameters to format/sprint must match the fields.' 478 | Enabled: false 479 | 480 | Lint/HandleExceptions: 481 | Description: "Don't suppress exception." 482 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions' 483 | Enabled: false 484 | 485 | Lint/InvalidCharacterLiteral: 486 | Description: >- 487 | Checks for invalid character literals with a non-escaped 488 | whitespace character. 489 | Enabled: false 490 | 491 | Lint/LiteralInCondition: 492 | Description: 'Checks of literals used in conditions.' 493 | Enabled: false 494 | 495 | Lint/LiteralInInterpolation: 496 | Description: 'Checks for literals used in interpolation.' 497 | Enabled: false 498 | 499 | Lint/Loop: 500 | Description: >- 501 | Use Kernel#loop with break rather than begin/end/until or 502 | begin/end/while for post-loop tests. 503 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#loop-with-break' 504 | Enabled: false 505 | 506 | Lint/NestedMethodDefinition: 507 | Description: 'Do not use nested method definitions.' 508 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-methods' 509 | Enabled: false 510 | 511 | Lint/NonLocalExitFromIterator: 512 | Description: 'Do not use return in iterator to cause non-local exit.' 513 | Enabled: false 514 | 515 | Lint/ParenthesesAsGroupedExpression: 516 | Description: >- 517 | Checks for method calls with a space before the opening 518 | parenthesis. 519 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-no-spaces' 520 | Enabled: false 521 | 522 | Lint/RequireParentheses: 523 | Description: >- 524 | Use parentheses in the method call to avoid confusion 525 | about precedence. 526 | Enabled: false 527 | 528 | Lint/UnderscorePrefixedVariableName: 529 | Description: 'Do not use prefix `_` for a variable that is used.' 530 | Enabled: false 531 | 532 | Lint/UnneededDisable: 533 | Description: >- 534 | Checks for rubocop:disable comments that can be removed. 535 | Note: this cop is not disabled when disabling all cops. 536 | It must be explicitly disabled. 537 | Enabled: false 538 | 539 | Lint/Void: 540 | Description: 'Possible use of operator/literal/variable in void context.' 541 | Enabled: false 542 | 543 | # Performance 544 | 545 | Performance/CaseWhenSplat: 546 | Description: >- 547 | Place `when` conditions that use splat at the end 548 | of the list of `when` branches. 549 | Enabled: false 550 | 551 | Performance/Count: 552 | Description: >- 553 | Use `count` instead of `select...size`, `reject...size`, 554 | `select...count`, `reject...count`, `select...length`, 555 | and `reject...length`. 556 | Enabled: false 557 | 558 | Performance/Detect: 559 | Description: >- 560 | Use `detect` instead of `select.first`, `find_all.first`, 561 | `select.last`, and `find_all.last`. 562 | Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code' 563 | Enabled: false 564 | 565 | Performance/FlatMap: 566 | Description: >- 567 | Use `Enumerable#flat_map` 568 | instead of `Enumerable#map...Array#flatten(1)` 569 | or `Enumberable#collect..Array#flatten(1)` 570 | Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code' 571 | Enabled: false 572 | 573 | Performance/ReverseEach: 574 | Description: 'Use `reverse_each` instead of `reverse.each`.' 575 | Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablereverseeach-vs-enumerablereverse_each-code' 576 | Enabled: false 577 | 578 | Performance/Sample: 579 | Description: >- 580 | Use `sample` instead of `shuffle.first`, 581 | `shuffle.last`, and `shuffle[Fixnum]`. 582 | Reference: 'https://github.com/JuanitoFatas/fast-ruby#arrayshufflefirst-vs-arraysample-code' 583 | Enabled: false 584 | 585 | Performance/Size: 586 | Description: >- 587 | Use `size` instead of `count` for counting 588 | the number of elements in `Array` and `Hash`. 589 | Reference: 'https://github.com/JuanitoFatas/fast-ruby#arraycount-vs-arraysize-code' 590 | Enabled: false 591 | 592 | Performance/StringReplacement: 593 | Description: >- 594 | Use `tr` instead of `gsub` when you are replacing the same 595 | number of characters. Use `delete` instead of `gsub` when 596 | you are deleting characters. 597 | Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringgsub-vs-stringtr-code' 598 | Enabled: false 599 | 600 | # Rails 601 | 602 | Rails/ActionFilter: 603 | Description: 'Enforces consistent use of action filter methods.' 604 | Enabled: false 605 | 606 | Rails/Date: 607 | Description: >- 608 | Checks the correct usage of date aware methods, 609 | such as Date.today, Date.current etc. 610 | Enabled: false 611 | 612 | Rails/FindBy: 613 | Description: 'Prefer find_by over where.first.' 614 | Enabled: false 615 | 616 | Rails/FindEach: 617 | Description: 'Prefer all.find_each over all.find.' 618 | Enabled: false 619 | 620 | Rails/HasAndBelongsToMany: 621 | Description: 'Prefer has_many :through to has_and_belongs_to_many.' 622 | Enabled: false 623 | 624 | Rails/Output: 625 | Description: 'Checks for calls to puts, print, etc.' 626 | Enabled: false 627 | 628 | Rails/ReadWriteAttribute: 629 | Description: >- 630 | Checks for read_attribute(:attr) and 631 | write_attribute(:attr, val). 632 | Enabled: false 633 | 634 | Rails/ScopeArgs: 635 | Description: 'Checks the arguments of ActiveRecord scopes.' 636 | Enabled: false 637 | 638 | Rails/TimeZone: 639 | Description: 'Checks the correct usage of time zone aware methods.' 640 | StyleGuide: 'https://github.com/bbatsov/rails-style-guide#time' 641 | Reference: 'http://danilenko.org/2012/7/6/rails_timezones' 642 | Enabled: false 643 | 644 | Rails/Validation: 645 | Description: 'Use validates :attribute, hash of validations.' 646 | Enabled: false 647 | --------------------------------------------------------------------------------