fixings 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Harry Brundage
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,93 @@
1
+ # Fixings
2
+
3
+ A Rails setup that makes you not have to think and works nice and good.
4
+
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'fixings'
12
+ ```
13
+
14
+ Add this line to your test helper:
15
+
16
+ ```ruby
17
+ require 'fixings/test_help
18
+ ```
19
+
20
+ Copy this file to `.rubocop.yml`
21
+
22
+ ```yml
23
+ inherit_gem:
24
+ fixings:
25
+ - .rubocop.yml
26
+ ```
27
+
28
+ And then set up the followings things in the app:
29
+
30
+ #### Sentry (via sentry-raven)
31
+
32
+ Sentry is auto included and lightly configured. Set it up for the specific application with something like this in `config/initializers/sentry.rb`:
33
+
34
+ ```ruby
35
+ Raven.configure do |config|
36
+ if Rails.env.production?
37
+ config.dsn = ENV["BACKEND_SENTRY_DSN"]
38
+ end
39
+ end
40
+ ```
41
+
42
+ #### Log Tags (via rails-semantic-logger)
43
+
44
+ Fixings sets up `rails-semantic-logger` and configures it to log to STDOUT in all environments, in plain text for development and in JSON for production.
45
+
46
+ To add more details from the request context, add keys to the `config.log_tags` hash in your `config/application.rb`:
47
+
48
+ ```ruby
49
+ class Application < Rails::Application
50
+ # ...
51
+ config.log_tags[:user_id] = ->(request) { request.session[:current_user_id] }
52
+ config.log_tags[:account_id] = ->(request) { request.session[:current_account_id] }
53
+ end
54
+ ```
55
+
56
+ #### Flipper
57
+
58
+ Fixings sets up Flipper for beta flag flipping.
59
+
60
+ #### VCR for testing
61
+
62
+ Fixings sets up VCR for testing and configures it to run for every test case automatically. It also automatically filters the `Authorization` headers from saved cassettes. You probably have parameters you want to filter out:
63
+
64
+
65
+ ```ruby
66
+ ENV["SHOPIFY_OAUTH_ACCESS_TOKEN"] ||= "test_access_token"
67
+
68
+ VCR.configure do |config|
69
+ config.filter_sensitive_data("<SHOPIFY_OAUTH_ACCESS_TOKEN>") { ENV["SHOPIFY_OAUTH_ACCESS_TOKEN"] }
70
+
71
+ config.fixings_query_matcher_param_exclusions << "appsecret_proof"
72
+ end
73
+
74
+ ```
75
+
76
+ ## Development
77
+
78
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
79
+
80
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
81
+
82
+ ## Contributing
83
+
84
+ Bug reports and pull requests are welcome on GitHub at https://github.com/hornairs/fixings. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/hornairs/fixings/blob/master/CODE_OF_CONDUCT.md).
85
+
86
+
87
+ ## License
88
+
89
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
90
+
91
+ ## Code of Conduct
92
+
93
+ Everyone interacting in the Fixings project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/hornairs/fixings/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+ require "bundler/gem_tasks"
3
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "fixings"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env bash
2
+ set -ex
3
+ bundle exec rufo --check lib fixings.gemspec
4
+ bundle exec rubocop
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env bash
2
+ set -x
3
+ bundle exec rufo lib fixings.gemspec
4
+ bundle exec rubocop -a
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+ require_relative "lib/fixings/version"
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "fixings"
6
+ spec.version = Fixings::VERSION
7
+ spec.authors = ["Harry Brundage"]
8
+ spec.email = ["harry.brundage@gmail.com"]
9
+
10
+ spec.summary = "Easy rails setup with infrastructure and a bunch of handy correctness pieces"
11
+ spec.homepage = "https://github.com/airhorns/fixings"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
14
+
15
+ spec.metadata["homepage_uri"] = spec.homepage
16
+ spec.metadata["source_code_uri"] = "https://github.com/airhorns/fixings"
17
+
18
+ # Specify which files should be added to the gem when it is released.
19
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ end
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_runtime_dependency "active_record_query_trace"
28
+ spec.add_runtime_dependency "annotate"
29
+ spec.add_runtime_dependency "ar_transaction_changes"
30
+ spec.add_runtime_dependency "bcrypt"
31
+ spec.add_runtime_dependency "flipper"
32
+ spec.add_runtime_dependency "flipper-active_record"
33
+ spec.add_runtime_dependency "flipper-active_support_cache_store"
34
+ spec.add_runtime_dependency "flipper-ui"
35
+ spec.add_runtime_dependency "health_check"
36
+ spec.add_runtime_dependency "letter_opener"
37
+ spec.add_runtime_dependency "letter_opener_web"
38
+ spec.add_runtime_dependency "marginalia"
39
+ spec.add_runtime_dependency "oj"
40
+ spec.add_runtime_dependency "rack-cors"
41
+ spec.add_runtime_dependency "rails", "~> 6.0"
42
+ spec.add_runtime_dependency "rails-middleware-extensions"
43
+ spec.add_runtime_dependency "rails_semantic_logger"
44
+
45
+ spec.add_runtime_dependency "bullet"
46
+ spec.add_runtime_dependency "rubocop"
47
+ spec.add_runtime_dependency "rubocop-performance"
48
+ spec.add_runtime_dependency "rubocop-rails"
49
+ spec.add_runtime_dependency "rufo"
50
+
51
+ spec.add_runtime_dependency "minitest-ci"
52
+ spec.add_runtime_dependency "minitest-snapshots"
53
+ spec.add_runtime_dependency "mocha"
54
+ spec.add_runtime_dependency "timecop"
55
+ spec.add_runtime_dependency "vcr"
56
+ spec.add_runtime_dependency "webmock"
57
+
58
+ spec.add_runtime_dependency "sentry-raven"
59
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+ # NOTE: only doing this in development as some production environments (Heroku)
3
+ # NOTE: are sensitive to local FS writes, and besides -- it's just not proper
4
+ # NOTE: to have a dev-mode tool do its thing in production.
5
+ if Rails.env.development?
6
+ require "annotate"
7
+ task :set_annotation_options do # rubocop:disable Rails/RakeEnvironment
8
+ # You can override any of these by setting an environment variable of the
9
+ # same name.
10
+ Annotate.set_defaults(
11
+ "additional_file_patterns" => [],
12
+ "routes" => "false",
13
+ "models" => "true",
14
+ "position_in_routes" => "before",
15
+ "position_in_class" => "before",
16
+ "position_in_test" => "before",
17
+ "position_in_fixture" => "before",
18
+ "position_in_factory" => "before",
19
+ "position_in_serializer" => "before",
20
+ "show_foreign_keys" => "true",
21
+ "show_complete_foreign_keys" => "false",
22
+ "show_indexes" => "true",
23
+ "simple_indexes" => "false",
24
+ "model_dir" => "app/models",
25
+ "root_dir" => "",
26
+ "include_version" => "false",
27
+ "require" => "",
28
+ "exclude_tests" => "false",
29
+ "exclude_fixtures" => "false",
30
+ "exclude_factories" => "false",
31
+ "exclude_serializers" => "false",
32
+ "exclude_scaffolds" => "true",
33
+ "exclude_controllers" => "true",
34
+ "exclude_helpers" => "true",
35
+ "exclude_sti_subclasses" => "false",
36
+ "ignore_model_sub_dir" => "false",
37
+ "ignore_columns" => nil,
38
+ "ignore_routes" => nil,
39
+ "ignore_unknown_models" => "false",
40
+ "hide_limit_column_types" => "integer,bigint,boolean",
41
+ "hide_default_column_types" => "json,jsonb,hstore",
42
+ "skip_on_db_migrate" => "false",
43
+ "format_bare" => "true",
44
+ "format_rdoc" => "false",
45
+ "format_markdown" => "false",
46
+ "sort" => "false",
47
+ "force" => "false",
48
+ "frozen" => "false",
49
+ "classified_sort" => "true",
50
+ "trace" => "false",
51
+ "wrapper_open" => nil,
52
+ "wrapper_close" => nil,
53
+ "with_comment" => "true",
54
+ )
55
+ end
56
+
57
+ Annotate.load_tasks
58
+ end
59
+
60
+ namespace :db do
61
+ desc "Truncate all existing data. Provided by the fixings gem"
62
+ task :truncate => "db:load_config" do
63
+ ActiveRecord::Base.establish_connection
64
+ ActiveRecord::Base.connection.tables.each do |table|
65
+ next if table == "schema_migrations"
66
+ ActiveRecord::Base.connection.execute("TRUNCATE #{table} CASCADE")
67
+ end
68
+ end
69
+ end
70
+
71
+ # frozen_string_literal: true
72
+ require "English"
73
+ require "optparse"
74
+
75
+ namespace :job do
76
+ desc "Run a Que job inline. Used by other infrastructure components. Provided by the fixings gem"
77
+ task :run_inline => :environment do
78
+ options = { args: [] }
79
+
80
+ optparse = OptionParser.new do |opts|
81
+ opts.on("-j", "--job-class ARG", "what job class to execute") do |klass|
82
+ options[:job_class] = klass.constantize
83
+ end
84
+
85
+ opts.on("-a", "--args ARG", "JSON serialized array of arguments to pass to class") do |args|
86
+ options[:args] = JSON.parse(args)
87
+ end
88
+
89
+ opts.on("-h", "--help", "Display this screen") do
90
+ puts opts
91
+ exit
92
+ end
93
+ end
94
+
95
+ begin
96
+ args = optparse.order!(ARGV) { }
97
+ optparse.parse!(args)
98
+
99
+ mandatory = [:job_class]
100
+ missing = mandatory.select { |param| options[param].nil? }
101
+ if !missing.empty?
102
+ puts "Missing options: #{missing.join(", ")}"
103
+ puts optparse
104
+ exit
105
+ end
106
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument
107
+ puts $ERROR_INFO.to_s
108
+ puts optparse
109
+ exit
110
+ end
111
+
112
+ Rails.logger.info "Running job inline", job_class: options[:job_class], args: options[:args]
113
+ options[:job_class].run(*options[:args])
114
+ true
115
+ end
116
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+ require "fixings/version"
3
+
4
+ module Fixings
5
+ end
6
+
7
+ require "fixings/railtie" if defined?(Rails)
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fixings::AppRelease
4
+ def self.current
5
+ @current ||= begin
6
+ release_file = Rails.root.join("RELEASE").to_s
7
+
8
+ if File.exist?(release_file)
9
+ File.read(release_file).chomp
10
+ elsif ENV["RELEASE"]
11
+ ENV["RELEASE"]
12
+ else
13
+ "unknown"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+ require "active_record_query_trace"
3
+ require "ar_transaction_changes"
4
+ require "health_check"
5
+ require "flipper"
6
+ require "flipper-active_record"
7
+ require "flipper-active_support_cache_store"
8
+ require "flipper-ui"
9
+ require "marginalia"
10
+ require "oj"
11
+ require "bcrypt"
12
+ require "rails-middleware-extensions"
13
+ require "rails_semantic_logger"
14
+ require "rack/cors"
15
+ require "sentry-raven"
16
+
17
+ require "fixings/app_release"
18
+ require "fixings/silent_log_middleware"
19
+
20
+ if !Rails.env.production?
21
+ require "annotate"
22
+ require "bullet"
23
+ require "letter_opener"
24
+ require "letter_opener_web"
25
+ end
26
+
27
+ module Fixings
28
+ class Railtie < Rails::Railtie
29
+ config.app_generators do |g|
30
+ g.factory_bot suffix: "factory"
31
+ end
32
+
33
+ rake_tasks do
34
+ load "fixings.rake"
35
+ end
36
+
37
+ initializer "fixings.configure_active_record_query_trace" do
38
+ if Rails.env.development?
39
+ ActiveRecordQueryTrace.colorize = :light_purple
40
+ ActiveRecordQueryTrace.enabled = ENV["TRACE_QUERIES"].present?
41
+ end
42
+ end
43
+
44
+ initializer "fixings.configure_rack_cors_middleware" do |app|
45
+ app.middleware.insert_before 0, Rack::Cors do
46
+ end
47
+ end
48
+
49
+ initializer "fixings.configure_flipper" do |app|
50
+ Flipper.configure do |config|
51
+ config.default do
52
+ database_adapter = Flipper::Adapters::ActiveRecord.new
53
+ adapter = Flipper::Adapters::ActiveSupportCacheStore.new(database_adapter, Rails.cache, expires_in: 5.minutes)
54
+ Flipper.new(adapter)
55
+ end
56
+ end
57
+
58
+ app.middleware.use Flipper::Middleware::Memoizer
59
+ end
60
+
61
+ initializer "fixings.configure_sentry" do
62
+ Raven.configure do |config|
63
+ config.silence_ready = true
64
+ config.logger = SemanticLogger[Raven]
65
+
66
+ if Rails.env.production?
67
+ config.release = AppRelease.current
68
+ end
69
+ end
70
+ end
71
+
72
+ initializer "fixings.configure_development_logger" do |app|
73
+ STDOUT.sync = true
74
+ app.config.rails_semantic_logger.semantic = true
75
+
76
+ if Rails.env.development?
77
+ # Always log to stdout in development. Rails somehow magically makes this happen for the webserver but not for other processes
78
+ # like the jobs server
79
+ if SemanticLogger.appenders.all? { |appender| appender.instance_variable_get(:@log) != STDOUT }
80
+ pp.config.semantic_logger.add_appender(io: STDOUT, level: app.config.log_level, formatter: app.config.rails_semantic_logger.format)
81
+ end
82
+ else
83
+ # Use semantic_logger logging setup to log JSON to STDOUT
84
+ app.config.rails_semantic_logger.add_file_appender = false
85
+ app.config.rails_semantic_logger.format = :json
86
+ app.config.semantic_logger.add_appender(io: STDOUT, level: app.config.log_level, formatter: app.config.rails_semantic_logger.format)
87
+ end
88
+ end
89
+
90
+ initializer "fixings.configure_logging_middleware" do |app|
91
+ app.config.log_tags ||= {}
92
+ app.config.log_tags[:request_id] = :request_id
93
+ app.config.log_tags[:client_session_id] = ->(request) { request.headers["X-Client-Session-Id"] }
94
+
95
+ # Make sure that the semantic logger middleware which evaluats the above log_tags procs has a session on the request
96
+ app.middleware.move_after ActionDispatch::Session::CacheStore, RailsSemanticLogger::Rack::Logger, app.config.log_tags
97
+ app.middleware.insert_before ActionDispatch::Static, Fixings::SilentLogMiddleware, silence: ["/health_check", %r{^/assets/}, "/favicon.ico"]
98
+ end
99
+
100
+ initializer "fixings.configure_bullet" do
101
+ if Rails.env.development?
102
+ Bullet.enable = true
103
+ Bullet.rails_logger = true
104
+ end
105
+ end
106
+
107
+ initializer "fixings.docker_for_mac_web_console" do |app|
108
+ if Rails.env.development?
109
+ # Whitelist docker-for-mac ips for web console
110
+ app.config.web_console.permissions = ["172.18.0.0/16", "172.19.0.0/16"]
111
+ end
112
+ end
113
+ end
114
+ end