4 | Dummy
5 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
6 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
7 | <%= csrf_meta_tags %>
8 |
9 |
10 |
11 | <%= yield %>
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/controllers/tech_radar/technologies_controller.rb:
--------------------------------------------------------------------------------
1 | require_dependency "tech_radar/application_controller"
2 |
3 | module TechRadar
4 | class TechnologiesController < ApplicationController
5 | def index
6 | @technologies = TechRadar::Radar.new.technologies
7 | end
8 |
9 | def show
10 | @technology = TechRadar::Radar.new.technology(params[:id])
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActiveSupport.on_load(:action_controller) do
8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
3 |
4 | ENGINE_ROOT = File.expand_path('../..', __FILE__)
5 | ENGINE_PATH = File.expand_path('../../lib/tech_radar/engine', __FILE__)
6 |
7 | # Set up gems listed in the Gemfile.
8 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
9 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
10 |
11 | require 'rails/all'
12 | require 'rails/engine/commands'
13 |
--------------------------------------------------------------------------------
/lib/tech_radar.rb:
--------------------------------------------------------------------------------
1 | require "tech_radar/engine"
2 |
3 | module TechRadar
4 | # A Hash with keys named for the four rings as written in the en.yml file (i.e. not the translated values).
5 | # If the value is true, a warning is shown for any tech that doesn't have a "why_summary".
6 | #
7 | # Default is true for all rings.
8 | mattr_accessor :warn_on_missing_why_summary
9 |
10 | TechRadar.warn_on_missing_why_summary = Hash.new(true)
11 |
12 | mattr_accessor :summary_format
13 |
14 | TechRadar.summary_format = :plaintext
15 | end
16 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Version of your assets, change this if you want to expire all your assets.
4 | Rails.application.config.assets.version = '1.0'
5 |
6 | # Add additional assets to the asset load path
7 | # Rails.application.config.assets.paths << Emoji.images_path
8 |
9 | # Precompile additional assets.
10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
11 | # Rails.application.config.assets.precompile += %w( search.js )
12 |
--------------------------------------------------------------------------------
/test/models/tech_radar/rendering_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | module TechRadar
4 | class RenderingTest < ActiveSupport::TestCase
5 |
6 | test "plaintext" do
7 | TechRadar.summary_format = :plaintext
8 | renderer = Rendering.renderer
9 |
10 | assert_equal TechRadar::Rendering::Plaintext,renderer.class
11 | end
12 |
13 | test "markdown" do
14 | TechRadar.summary_format = :markdown
15 | renderer = Rendering.renderer
16 |
17 | assert_equal TechRadar::Rendering::Markdown,renderer.class
18 | end
19 |
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/test/controllers/tech_radar/radar_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | module TechRadar
4 | class RadarControllerTest < ActionController::TestCase
5 | setup do
6 | @routes = Engine.routes
7 | end
8 |
9 | test "parent app can override messages" do
10 | get :index
11 | assert_response :success
12 | assert response.body =~ /FOOBAR/, "expected #{response.body} to include FOOBAR"
13 | end
14 |
15 | test "the radar summary screen" do
16 | get :summary
17 | assert_response :success
18 | end
19 |
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/test/controllers/tech_radar/quadrants_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | module TechRadar
4 | class QuadrantsControllerTest < ActionController::TestCase
5 | setup do
6 | @routes = Engine.routes
7 | end
8 |
9 | test "show" do
10 | get :show, params: { id: "Tools" }
11 | assert_response :success
12 | assert response.body =~ /RabbitMQ.*Resque.*ElasticSearch.*HumbleKit.*Redis as a database.*Sidekiq.*JIRA.*SwiftTask/m,
13 | "Expected #{response.body} to contain all 'Tools' technologies, ordered by ring, then name"
14 | end
15 |
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/test/dummy/README.rdoc:
--------------------------------------------------------------------------------
1 | == README
2 |
3 | This README would normally document whatever steps are necessary to get the
4 | application up and running.
5 |
6 | Things you may want to cover:
7 |
8 | * Ruby version
9 |
10 | * System dependencies
11 |
12 | * Configuration
13 |
14 | * Database creation
15 |
16 | * Database initialization
17 |
18 | * How to run the test suite
19 |
20 | * Services (job queues, cache servers, search engines, etc.)
21 |
22 | * Deployment instructions
23 |
24 | * ...
25 |
26 |
27 | Please feel free to use a different markup language if you do not plan to run
28 | rake doc:app.
29 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | # Declare your gem's dependencies in tech_radar.gemspec.
4 | # Bundler will treat runtime dependencies like base dependencies, and
5 | # development dependencies will be added by default to the :development group.
6 | gemspec
7 |
8 | # Declare any dependencies that are still in development here instead of in
9 | # your gemspec. These might include edge Rails or gems from your path or
10 | # Git. Remember to move these dependencies to your gemspec before releasing
11 | # your gem to rubygems.org.
12 |
13 | # To use a debugger
14 | # gem 'byebug', group: [:development, :test]
15 |
16 |
--------------------------------------------------------------------------------
/app/assets/javascripts/tech_radar/application.js:
--------------------------------------------------------------------------------
1 | // This is a manifest file that'll be compiled into application.js, which will include all the files
2 | // listed below.
3 | //
4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6 | //
7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8 | // compiled file.
9 | //
10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11 | // about supported directives.
12 | //
13 | //= require_tree .
14 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // This is a manifest file that'll be compiled into application.js, which will include all the files
2 | // listed below.
3 | //
4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6 | //
7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8 | // compiled file.
9 | //
10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11 | // about supported directives.
12 | //
13 | //= require_tree .
14 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, '\1en'
8 | # inflect.singular /^(ox)en/i, '\1'
9 | # inflect.irregular 'person', 'people'
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym 'RESTful'
16 | # end
17 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | begin
2 | require 'bundler/setup'
3 | rescue LoadError
4 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5 | end
6 |
7 | require 'rdoc/task'
8 |
9 | RDoc::Task.new(:rdoc) do |rdoc|
10 | rdoc.rdoc_dir = 'rdoc'
11 | rdoc.title = 'TechRadar'
12 | rdoc.options << '--line-numbers'
13 | rdoc.rdoc_files.include('README.rdoc')
14 | rdoc.rdoc_files.include('lib/**/*.rb')
15 | end
16 |
17 |
18 |
19 | load 'rails/tasks/statistics.rake'
20 |
21 |
22 |
23 | Bundler::GemHelper.install_tasks
24 |
25 | require 'rake/testtask'
26 |
27 | Rake::TestTask.new(:test) do |t|
28 | t.libs << 'lib'
29 | t.libs << 'test'
30 | t.pattern = 'test/**/*_test.rb'
31 | t.verbose = false
32 | end
33 |
34 |
35 | task default: :test
36 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/tech_radar/application.scss:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a manifest file that'll be compiled into application.css, which will include all the files
3 | * listed below.
4 | *
5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7 | *
8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9 | * compiled file so the styles you add here take precedence over styles defined in any styles
10 | * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11 | * file per style scope.
12 | *
13 | *= require_tree .
14 | *= require_self
15 | */
16 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a manifest file that'll be compiled into application.css, which will include all the files
3 | * listed below.
4 | *
5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7 | *
8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9 | * compiled file so the styles you add here take precedence over styles defined in any styles
10 | * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11 | * file per style scope.
12 | *
13 | *= require_tree .
14 | *= require_self
15 | */
16 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | # Configure Rails Environment
2 | ENV["RAILS_ENV"] = "test"
3 |
4 | require File.expand_path("../../test/dummy/config/environment.rb", __FILE__)
5 | require "rails/test_help"
6 |
7 | # Filter out Minitest backtrace while allowing backtrace from other libraries
8 | # to be shown.
9 | Minitest.backtrace_filter = Minitest::BacktraceFilter.new
10 |
11 | # Load support files
12 | Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
13 |
14 | # Load fixtures from the engine
15 | if ActiveSupport::TestCase.respond_to?(:fixture_path=)
16 | ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
17 | ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path
18 | ActiveSupport::TestCase.fixtures :all
19 | end
20 |
--------------------------------------------------------------------------------
/app/helpers/tech_radar/application_helper.rb:
--------------------------------------------------------------------------------
1 | module TechRadar
2 | module ApplicationHelper
3 | def label_color_for_ring(ring_name)
4 | if ring_name == 'Adopt'
5 | :success
6 | elsif ring_name == 'Hold'
7 | :warning
8 | else
9 | :default
10 | end
11 | end
12 |
13 | def panel_type_for_technology_why(technology)
14 | if technology.why_summary.blank? && warn_on_missing_why?(technology)
15 | :warning
16 | else
17 | :default
18 | end
19 | end
20 |
21 | def warn_on_missing_why?(technology)
22 | technology.ring != 'Adopt' && technology.ring != 'Trial'
23 | end
24 |
25 | def render_summary(summary_text)
26 | TechRadar::Rendering.renderer.render_text(summary_text)
27 | end
28 |
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/app/views/layouts/tech_radar/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | TechRadar
5 | <%= stylesheet_link_tag "tech_radar/application", media: "all" %>
6 |
8 | <%= javascript_include_tag "tech_radar/application" %>
9 | <%= csrf_meta_tags %>
10 |
11 |
12 |
13 |
14 | <% unless @hide_nav %>
15 |
24 | <% end %>
25 |
26 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 | Thanks for using and improving *tech_radar*! If you'd like to help out, check out [the project's issues list](https://github.com/stitchfix/tech_radar/issues) for ideas on what could be improved. If there's an idea you'd like to propose, or a design change, feel free to file a new issue or send a pull request:
3 |
4 | 1. [Fork][fork] the repo.
5 | 1. [Create a topic branch.][branch]
6 | 1. Write tests.
7 | 1. Implement your feature or fix bug.
8 | 1. Add, commit, and push your changes.
9 | 1. [Submit a pull request.][pr]
10 |
11 | [fork]: https://help.github.com/articles/fork-a-repo/
12 | [branch]: https://help.github.com/articles/creating-and-deleting-branches-within-your-repository/
13 | [pr]: https://help.github.com/articles/using-pull-requests/
14 |
15 | ## General Guidelines
16 |
17 | * When in doubt, test it. If you can't test it, re-think what you are doing.
18 | * Code formatting and internal application architecture should be consistent.
19 |
--------------------------------------------------------------------------------
/tech_radar.gemspec:
--------------------------------------------------------------------------------
1 | $:.push File.expand_path("../lib", __FILE__)
2 |
3 | require "tech_radar/version"
4 |
5 | Gem::Specification.new do |s|
6 | s.name = "tech_radar"
7 | s.version = TechRadar::VERSION
8 | s.authors = ["Stitch Fix Engineering", "Dave Copeland"]
9 | s.email = ["eng@stitchfix.com", "davetron5000@gmail.com"]
10 | s.homepage = "https://github.com/stitchfix/tech_radar"
11 | s.summary = "Rails engine to create and manage your own team's Technology Radar"
12 | s.description = "Rails engine to create and manage your own team's Technology Radar"
13 | s.license = "MIT"
14 |
15 | s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"]
16 | s.test_files = Dir["test/**/*"]
17 |
18 | s.add_dependency "rails", ">= 4.2.5"
19 | s.add_dependency "i18n"
20 | s.add_dependency "immutable-struct"
21 |
22 | s.add_development_dependency "redcarpet"
23 | s.add_development_dependency "sass"
24 | s.add_development_dependency('rspec_junit_formatter')
25 | end
26 |
--------------------------------------------------------------------------------
/test/dummy/config/secrets.yml:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key is used for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 |
6 | # Make sure the secret is at least 30 characters and all random,
7 | # no regular words or you'll be exposed to dictionary attacks.
8 | # You can use `rake secret` to generate a secure secret key.
9 |
10 | # Make sure the secrets in this file are kept private
11 | # if you're sharing your code publicly.
12 |
13 | development:
14 | secret_key_base: ac9f03853205400989ad229d68f95b44338b19a4e6cfe58132cc40e2ee55299b293493201bb69d0c054f219b30579dfda312be0d06fc5fb0ed71f87e08a4aec8
15 |
16 | test:
17 | secret_key_base: 8bb1986a94e7f19c167034a9aadc75bcc3a03a248d806a6fd0815449ea6fe03bd1d75d79d89132cc965e9ecb210b236c2a37438873b8cfc5b43af55f78c9c680
18 |
19 | # Do not keep production secrets in the repository,
20 | # instead read values from the environment.
21 | production:
22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
23 |
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2015 Dave Copeland
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/app/models/tech_radar/rendering/markdown.rb:
--------------------------------------------------------------------------------
1 | module TechRadar
2 | module Rendering
3 | class Markdown
4 | def initialize
5 | require 'redcarpet'
6 | renderer = Redcarpet::Render::HTML.new(
7 | filter_html: true,
8 | no_styles: true,
9 | safe_links_only: true
10 | )
11 | @markdown = Redcarpet::Markdown.new(renderer,
12 | no_intra_emphasis: true,
13 | tables: true,
14 | fenced_code_blocks: true,
15 | autolink: true,
16 | disable_indented_code_blocks: true,
17 | strikethrough: true,
18 | superscript: true)
19 | rescue LoadError => ex
20 | raise "Since you speecified markdown rendering, you must include the redcarpet gem in your app: #{ex.message}"
21 | end
22 |
23 | def render_text(text)
24 | @markdown.render(text).html_safe
25 | end
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/app/views/tech_radar/radar/summary.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
16 | <% @radar.quadrants.each do |quadrant| %>
17 |
18 |
19 | <% ring.technologies.select { |technology| technology.quadrant == quadrant.name }.each_with_index do |technology,i| %>
20 | <% if i != 0 %>
21 | ·
22 | <% end %>
23 | <%= link_to technology.name, technology_path(technology.name) %>
24 | <% end %>
25 |
26 |
27 | <% end %>
28 |
29 |
30 |
31 | <% end %>
32 |
33 |
--------------------------------------------------------------------------------
/test/dummy/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 |
3 | # Pick the frameworks you want:
4 | # require "active_record/railtie"
5 | require "action_controller/railtie"
6 | require "action_mailer/railtie"
7 | require "action_view/railtie"
8 | require "sprockets/railtie"
9 | require "rails/test_unit/railtie"
10 |
11 | Bundler.require(*Rails.groups)
12 | require "tech_radar"
13 |
14 | module Dummy
15 | class Application < Rails::Application
16 | # Settings in config/environments/* take precedence over those specified here.
17 | # Application configuration should go into files in config/initializers
18 | # -- all .rb files in that directory are automatically loaded.
19 |
20 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
21 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
22 | # config.time_zone = 'Central Time (US & Canada)'
23 |
24 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
25 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
26 | # config.i18n.default_locale = :de
27 | end
28 | end
29 |
30 |
--------------------------------------------------------------------------------
/app/views/tech_radar/rings/show.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
31 |
32 | <% end %>
33 |
34 |
--------------------------------------------------------------------------------
/test/dummy/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Do not eager load code on boot.
10 | config.eager_load = false
11 |
12 | # Show full error reports and disable caching.
13 | config.consider_all_requests_local = true
14 | config.action_controller.perform_caching = false
15 |
16 | # Don't care if the mailer can't send.
17 | config.action_mailer.raise_delivery_errors = false
18 |
19 | # Print deprecation notices to the Rails logger.
20 | config.active_support.deprecation = :log
21 |
22 | # Debug mode disables concatenation and preprocessing of assets.
23 | # This option may cause significant delays in view rendering with a large
24 | # number of complex assets.
25 | config.assets.debug = true
26 |
27 | # Asset digests allow you to set far-future HTTP expiration dates on all assets,
28 | # yet still be able to expire them through the digest params.
29 | config.assets.digest = true
30 |
31 | # Adds additional error checking when serving assets at runtime.
32 | # Checks for improperly declared sprockets dependencies.
33 | # Raises helpful error messages.
34 | config.assets.raise_runtime_errors = true
35 |
36 | # Raises error for missing translations
37 | # config.action_view.raise_on_missing_translations = true
38 | end
39 |
--------------------------------------------------------------------------------
/test/dummy/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
We're sorry, but something went wrong.
62 |
63 |
If you are the application owner check the logs for more information.
Maybe you tried to change something you didn't have access to.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/test/dummy/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The page you were looking for doesn't exist.
62 |
You may have mistyped the address or the page may have moved.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/test/dummy/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # The test environment is used exclusively to run your application's
5 | # test suite. You never need to work with it otherwise. Remember that
6 | # your test database is "scratch space" for the test suite and is wiped
7 | # and recreated between test runs. Don't rely on the data there!
8 | config.cache_classes = true
9 |
10 | # Do not eager load code on boot. This avoids loading your whole application
11 | # just for the purpose of running a single test. If you are using a tool that
12 | # preloads Rails for running tests, you may have to set it to true.
13 | config.eager_load = false
14 |
15 | # Configure static file server for tests with Cache-Control for performance.
16 | config.serve_static_files = true
17 | config.static_cache_control = 'public, max-age=3600'
18 |
19 | # Show full error reports and disable caching.
20 | config.consider_all_requests_local = true
21 | config.action_controller.perform_caching = false
22 |
23 | # Raise exceptions instead of rendering exception templates.
24 | config.action_dispatch.show_exceptions = false
25 |
26 | # Disable request forgery protection in test environment.
27 | config.action_controller.allow_forgery_protection = false
28 |
29 | # Tell Action Mailer not to deliver emails to the real world.
30 | # The :test delivery method accumulates sent emails in the
31 | # ActionMailer::Base.deliveries array.
32 | config.action_mailer.delivery_method = :test
33 |
34 | # Randomize the order test cases are executed.
35 | config.active_support.test_order = :random
36 |
37 | # Print deprecation notices to the stderr.
38 | config.active_support.deprecation = :stderr
39 |
40 | # Raises error for missing translations
41 | # config.action_view.raise_on_missing_translations = true
42 | end
43 |
--------------------------------------------------------------------------------
/app/views/tech_radar/technologies/show.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
49 |
50 |
--------------------------------------------------------------------------------
/test/controllers/tech_radar/technologies_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | module TechRadar
4 | class TechnologiesControllerTest < ActionController::TestCase
5 | setup do
6 | @routes = Engine.routes
7 | TechRadar.summary_format = :markdown
8 | end
9 |
10 | test "index" do
11 | get :index
12 | assert_response :success
13 | regexp = Regexp.new([
14 | "AWS",
15 | "Cloudfront",
16 | "CoffeeScript",
17 | "Consumer-driven tests for services",
18 | "ElasticSearch",
19 | "Heroku",
20 | "HTTP Services",
21 | "HumbleKit",
22 | "iOS",
23 | "JIRA",
24 | "JQuery",
25 | "Objective-C",
26 | "RabbitMQ",
27 | "Redis as a database",
28 | "Resque",
29 | "Ruby",
30 | "Shared Gems",
31 | "Sidekiq",
32 | "SwiftTask",
33 | "Weekly sync-ups with Business Partners",
34 | ].map { |_| Regexp.escape(_) }.join(".*"), Regexp::MULTILINE)
35 | assert (response.body =~ regexp),"Expected #{response.body} to include the technologies in order"
36 | end
37 |
38 | test "show with no more_details_url or more_details_summary" do
39 | get :show, params: { id: "RabbitMQ" }
40 | assert_response :success
41 | assert response.body.include?("RabbitMQ"),"Expected #{response.body} to include 'RabbitMQ'"
42 | assert response.body.include?("Google"),"Expected #{response.body} to include a link to a Google search"
43 | end
44 |
45 | test "show with no more_details_url but has a more_details_summary" do
46 | get :show, params: { id: "Ruby" }
47 | assert_response :success
48 | assert response.body.include?("Ruby"),"Expected #{response.body} to include 'Ruby'"
49 | refute response.body.include?("Google"),"Expected #{response.body} NOT to include a link to a Google search"
50 | assert response.body.include?("object-oriented"),"Expected #{response.body} to include Ruby's summary, parsed as markdown"
51 | end
52 |
53 | test "show with more_details_url" do
54 | get :show, params: { id: "Resque" }
55 | assert_response :success
56 | assert response.body.include?("Resque"),"Expected #{response.body} to include 'Resque'"
57 | refute response.body.include?("Google"),"Expected #{response.body} NOT to include a link to a Google search"
58 | end
59 |
60 | end
61 | end
62 |
--------------------------------------------------------------------------------
/app/models/tech_radar/radar.rb:
--------------------------------------------------------------------------------
1 | module TechRadar
2 | class Radar
3 | attr_reader :data
4 | def initialize
5 | @data = YAML.load_file(Rails.root + "config" + "tech-radar.yml")
6 | end
7 |
8 | def quadrants
9 | @data.keys.map { |quadrant_name|
10 | quadrant(quadrant_name)
11 | }
12 | end
13 |
14 | def quadrant(quadrant_name)
15 | quadrant = @data.fetch(quadrant_name)
16 | by_ring = {}
17 | quadrant.each do |(ring,technologies)|
18 | by_ring[ring] ||= []
19 | (technologies || {}).each do |(name,data)|
20 | experts = Array(data["experts"]).map { |name_or_hash|
21 | if name_or_hash.kind_of?(String)
22 | Expert.new(name: name_or_hash)
23 | else
24 | Expert.new(name: name_or_hash.fetch("name"), email: name_or_hash["email"])
25 | end
26 | }.sort_by(&:name)
27 |
28 | examples = Array(data["examples"]).map { |url_or_hash|
29 | if url_or_hash.kind_of?(String)
30 | Example.new(url: url_or_hash)
31 | else
32 | Example.new(url: url_or_hash.fetch("url"), title: url_or_hash["title"])
33 | end
34 | }.sort_by { |example| example.title.to_s }
35 |
36 | by_ring[ring] << Technology.new(name: name,
37 | ring: ring,
38 | quadrant: quadrant_name,
39 | purpose: data["purpose"],
40 | more_details_url: data["more_details_url"],
41 | more_details_summary: data["more_details_summary"],
42 | why_url: data["why_url"],
43 | tags: Array(data["tags"]).sort,
44 | experts: experts,
45 | examples: examples,
46 | why_summary: data["why_summary"])
47 | end
48 | end
49 | TechRadar::Quadrant.new(
50 | name: quadrant_name,
51 | rings: by_ring.map { |ring_name,technologies|
52 | TechRadar::Ring.new(name: ring_name, technologies: technologies.sort_by { |tech| tech.name.downcase })
53 | }
54 | )
55 | end
56 |
57 | def rings
58 | quadrants.map(&:rings).flatten.group_by(&:name).map { |(ring_name,rings)|
59 | TechRadar::Ring.new(name: ring_name,technologies: rings.map(&:technologies).flatten.sort_by { |tech| tech.name.downcase })
60 | }
61 | end
62 |
63 | def ring(ring_name)
64 | rings.detect { |ring| ring.name == ring_name }
65 | end
66 |
67 | def technologies(options = {})
68 | results = quadrants.
69 | map(&:rings).
70 | flatten.
71 | map(&:technologies).
72 | flatten
73 |
74 | if options[:tagged]
75 | results = results.select { |technology|
76 | technology.tags.include?(options[:tagged])
77 | }
78 | end
79 | results.sort_by { |technology| technology.name.downcase }
80 | end
81 |
82 | def technology(name)
83 | technologies.detect { |technology| technology.name == name }
84 | end
85 |
86 | end
87 | end
88 |
--------------------------------------------------------------------------------
/test/models/tech_radar/radar_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | module TechRadar
4 | class RadarTest < ActiveSupport::TestCase
5 |
6 | setup do
7 | @radar = TechRadar::Radar.new
8 | end
9 |
10 | test "quadrants" do
11 | assert_equal ["Tools", "Platforms", "Techniques", "Languages and Frameworks"], @radar.quadrants.map(&:name)
12 | end
13 |
14 | test "quadrant" do
15 | assert_equal ["RabbitMQ", "Resque" ], @radar.quadrant("Tools").rings.detect { |ring| ring.name == "Adopt" }.technologies.map(&:name)
16 | end
17 |
18 | test "technologies" do
19 | expected_names = [
20 | "AWS",
21 | "Cloudfront",
22 | "CoffeeScript",
23 | "Consumer-driven tests for services",
24 | "ElasticSearch",
25 | "Heroku",
26 | "HTTP Services",
27 | "HumbleKit",
28 | "iOS",
29 | "JIRA",
30 | "JQuery",
31 | "Objective-C",
32 | "RabbitMQ",
33 | "Redis as a database",
34 | "Resque",
35 | "Ruby",
36 | "Shared Gems",
37 | "Sidekiq",
38 | "SwiftTask",
39 | "Weekly sync-ups with Business Partners",
40 | ]
41 | assert_equal expected_names,@radar.technologies.map(&:name)
42 | end
43 |
44 | test "technology" do
45 | technology = @radar.technology("Ruby")
46 | assert_equal "Ruby" , technology.name
47 | assert_equal "https://www.ruby-lang.org/en/" , technology.more_details_url
48 | assert_equal "Middleware Programming" , technology.purpose
49 | assert_equal ["cli", "middleware", "scripting"], technology.tags
50 |
51 | assert_equal "DHH", technology.experts[0].name
52 | assert_nil technology.experts[0].email
53 | assert_equal "Matz", technology.experts[1].name
54 | assert_nil technology.experts[1].email
55 | assert_equal "Tenderlove", technology.experts[2].name
56 | assert_equal "tl@example.com", technology.experts[2].email
57 |
58 | assert_equal "http://github.com/stitchfix/stitches", technology.examples[0].url
59 | assert_nil technology.examples[0].title
60 | assert_equal "http://rubyonrails.org", technology.examples[1].url
61 | assert_equal "Ruby on Rails Framework", technology.examples[1].title
62 |
63 | assert_nil technology.why_url
64 | assert_nil technology.why_summary
65 |
66 | assert_equal "Ruby is a dynamic, _object-oriented_ programming language that combines ideas from Smalltalk, Perl, and others",
67 | technology.more_details_summary
68 | end
69 |
70 | test "rings" do
71 | assert_equal ["Adopt","Trial","Assess","Hold"],@radar.rings.map(&:name)
72 | assert_equal [ "Heroku", "RabbitMQ", "Resque", "Ruby", "Weekly sync-ups with Business Partners",],@radar.rings.detect { |ring| ring.name == "Adopt" }.technologies.map(&:name)
73 | end
74 |
75 | test "tags" do
76 | technologies = @radar.technologies(tagged: "middleware")
77 | assert_equal 3, technologies.size
78 | assert_equal "Heroku", technologies[0].name
79 | assert_equal "Resque", technologies[1].name
80 | assert_equal "Ruby", technologies[2].name
81 | end
82 |
83 | end
84 | end
85 |
--------------------------------------------------------------------------------
/test/dummy/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # Code is not reloaded between requests.
5 | config.cache_classes = true
6 |
7 | # Eager load code on boot. This eager loads most of Rails and
8 | # your application in memory, allowing both threaded web servers
9 | # and those relying on copy on write to perform better.
10 | # Rake tasks automatically ignore this option for performance.
11 | config.eager_load = true
12 |
13 | # Full error reports are disabled and caching is turned on.
14 | config.consider_all_requests_local = false
15 | config.action_controller.perform_caching = true
16 |
17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application
18 | # Add `rack-cache` to your Gemfile before enabling this.
19 | # For large-scale production use, consider using a caching reverse proxy like
20 | # NGINX, varnish or squid.
21 | # config.action_dispatch.rack_cache = true
22 |
23 | # Disable serving static files from the `/public` folder by default since
24 | # Apache or NGINX already handles this.
25 | config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
26 |
27 | # Compress JavaScripts and CSS.
28 | config.assets.js_compressor = :uglifier
29 | # config.assets.css_compressor = :sass
30 |
31 | # Do not fallback to assets pipeline if a precompiled asset is missed.
32 | config.assets.compile = false
33 |
34 | # Asset digests allow you to set far-future HTTP expiration dates on all assets,
35 | # yet still be able to expire them through the digest params.
36 | config.assets.digest = true
37 |
38 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
39 |
40 | # Specifies the header that your server uses for sending files.
41 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
42 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
43 |
44 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
45 | # config.force_ssl = true
46 |
47 | # Use the lowest log level to ensure availability of diagnostic information
48 | # when problems arise.
49 | config.log_level = :debug
50 |
51 | # Prepend all log lines with the following tags.
52 | # config.log_tags = [ :subdomain, :uuid ]
53 |
54 | # Use a different logger for distributed setups.
55 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
56 |
57 | # Use a different cache store in production.
58 | # config.cache_store = :mem_cache_store
59 |
60 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
61 | # config.action_controller.asset_host = 'http://assets.example.com'
62 |
63 | # Ignore bad email addresses and do not raise email delivery errors.
64 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
65 | # config.action_mailer.raise_delivery_errors = false
66 |
67 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
68 | # the I18n.default_locale when a translation cannot be found).
69 | config.i18n.fallbacks = true
70 |
71 | # Send deprecation notices to registered listeners.
72 | config.active_support.deprecation = :notify
73 |
74 | # Use default logging formatter so that PID and timestamp are not suppressed.
75 | config.log_formatter = ::Logger::Formatter.new
76 | end
77 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | hello: "Hello world"
3 | tech_radar:
4 | radar:
5 | title: "Technology Radar"
6 | rings:
7 | name: "Rings"
8 | "Adopt":
9 | title: "Adopt"
10 | summary: "Use these, as they are supported and proven in production"
11 | description: "Technologies here are what we are using consistency across most, if not all, projects & teams. In general, you should use these unless you have a very good reason not to. Not using technologies here would be a technical risk."
12 | "Trial":
13 | summary: "Consider this if nothing in Adopt works"
14 | title: "Trial"
15 | description: "Technologies in production now, but not consistently across the team. These are worth pursuing, but we haven't yet rolled them out team-wide. They are great choices for projects where a solution doesn't exist in the Adopt ring. Prefer these over those in Assess."
16 | "Assess":
17 | title: "Assess"
18 | summary: "Not ready for heavy-duty use or not widely used."
19 | description: "This Indicates that a technology is worth exploring with the goal of understanding how it will affect us. It may be worth investing effort like development spikes or research projects to see if it will have a positive impact on us."
20 | "Hold":
21 | title: "Hold"
22 | summary: "Don't start new work with these."
23 | description: "Don't start new work with these technologies. They are too new to be evaluated, being discontinued, or have been found to be unsuitable."
24 | technologies:
25 | more_details_url:
26 | google: "Information from Google…"
27 | link: "More Information…"
28 | why_summary:
29 | link: "Detailed explanation…"
30 | why_url_only: "But, there is a link to a detailed explanation…"
31 | no_summary: "There is no summary of why this technology is here. Please provide a why_summary in config/tech-radar.yml."
32 | quadrants:
33 | name: "Quadrants"
34 | "Techniques":
35 | title: "Techniques"
36 | description: "Elements of a software development process, such as experience design; and ways of structuring software, such as micro-services."
37 | "Languages and Frameworks":
38 | title: "Languages and Frameworks"
39 | description: "Programming languages and frameworks (but not code libraries, which are considered Tools)"
40 | "Tools":
41 | title: "Tools"
42 | description: "Components, such as databases, software development tools, such as versions control systems; or more generic categories of tools, such as the notion of polyglot persistence."
43 | "Platforms":
44 | title: "Platforms"
45 | description: "Things that we build software on top of: mobile technologies like iOS, platforms-as-a-service like Heroku, or runtime containers like the JVM."
46 | index:
47 | preamble: "This represents the current thinking about what technologies should be used for various purposes. It's a guide for making technical decisions without having to have the entire team sync up on everything. It also allows you to experiment with new technologies safely by seeing what others have discovered, or not."
48 | summary_link: "View Summary…"
49 | all_list_link: "Technologies A–Z…"
50 | changing:
51 | title: "How the Radar Changes"
52 | preamble: "When using the radar, you may be tempted to suggest changes to it. You shouldn't. The radar is changed on a regular basis based on experience found since the last update. Try to stick to the radar for your day-to-day work, and keep notes on how things go. We want the radar to be generally stable, but able to evolve."
53 | howto:
54 | title: "How to Use This Radar"
55 | rings:
56 | preamble: "The Rings are indicators of how fit a technology or technique is for use, and these should be your guide when making technical decisions."
57 | quadrants:
58 | preamble: "Quadrants serve to partition the radar into logical groupings to make it more navigable and manageable."
59 |
--------------------------------------------------------------------------------
/test/dummy/config/tech-radar.yml:
--------------------------------------------------------------------------------
1 | "Tools":
2 | "Adopt":
3 | Resque:
4 | purpose: "Background Jobs"
5 | more_details_url: https://github.com/resque/resque/tree/1-x-stable
6 | tags:
7 | - background jobs
8 | - middleware
9 | RabbitMQ:
10 | purpose: "Messaging"
11 | "Trial":
12 | ElasticSearch:
13 | purpose: "Indexed Search"
14 | why_summary: "Erch and CXE using"
15 | HumbleKit:
16 | purpose: "CSS Framework"
17 | more_details_url: http://humblekit.com
18 | why_summary: "Used in many apps, not consistently"
19 | "Assess":
20 | Sidekiq:
21 | purpose: "Background Jobs"
22 | more_details_url:
23 | why_summary: "Only Erch using"
24 | "Redis as a database":
25 | purpose: "Primary Data Store"
26 | more_details_url: https://redis.io
27 | why_summary: "Only client-service using"
28 | "Hold":
29 | SwiftTask:
30 | purpose: "Promise Pattern in Swift"
31 | more_details_url: https://github.com/ReactKit/SwiftTask
32 | why_summary: "We had trouble designing a system around this and switched to PromiseKit"
33 | JIRA:
34 | purpose: "Issue & Task Management"
35 | more_details_url: https://www.atlassian.com/software/jira/
36 | why_summary: "Abandoned for lighterweight solutions"
37 | "Platforms":
38 | "Adopt":
39 | Heroku:
40 | purpose: "Infrastructure"
41 | more_details_url:
42 | tags:
43 | - middleware
44 | "Trial":
45 | iOS:
46 | purpose: "Mobile Application Development"
47 | more_details_url: https://en.wikipedia.org/wiki/IOS
48 | why_summary: "Only used for client-facing mobile app"
49 | "Assess":
50 | AWS:
51 | purpose: "Infrastructure"
52 | more_details_url: https://aws.amazon.com
53 | why_summary: "VPN"
54 | "Hold":
55 | Cloudfront:
56 | purpose: "Product image hosting"
57 | more_details_url: https://aws.amazon.com/cloudfront/
58 | why_summary: "Minx using, backed by Cloudinary"
59 | "Techniques":
60 | "Adopt":
61 | "Weekly sync-ups with Business Partners":
62 | purpose: "Roadmap Planning"
63 | more_details_url: :needed
64 | "Trial":
65 | "HTTP Services":
66 | purpose: "Application Integration"
67 | more_details_url: :needed
68 | why_summary: "Probably ready to adopt. Some older code still using gems & messages-as-APIs"
69 | "Assess":
70 | "Consumer-driven tests for services":
71 | purpose: "Ensure changes to services do not break upstream clients"
72 | more_details_url: http://martinfowler.com/articles/consumerDrivenContracts.html
73 | why_summary: "MOPS experimenting (see Pact)"
74 | "Hold":
75 | "Shared Gems":
76 | purpose: "Application Integration"
77 | more_details_url: :needed
78 | why_summary: "Difficult to manage, doesn't scale"
79 | "Languages and Frameworks":
80 | "Adopt":
81 | Ruby:
82 | purpose: Middleware Programming
83 | more_details_url: https://www.ruby-lang.org/en/
84 | more_details_summary: "Ruby is a dynamic, _object-oriented_ programming language that combines ideas from Smalltalk, Perl, and others"
85 | tags:
86 | - middleware
87 | - scripting
88 | - cli
89 | examples:
90 | - url: http://rubyonrails.org
91 | title: "Ruby on Rails Framework"
92 | - http://github.com/stitchfix/stitches
93 | experts:
94 | - Matz
95 | - name: Tenderlove
96 | email: tl@example.com
97 | - DHH
98 | "Trial":
99 | CoffeeScript:
100 | purpose: Browser Programming
101 | more_details_url:
102 | why_summary: "Most apps are using this, with Minx being a notable exception"
103 | "Assess":
104 | JQuery:
105 | purpose: "Front-end Framework"
106 | more_details_url:
107 | why_summary: "www, Kingmob use this for front-end"
108 | "Hold":
109 | "Objective-C":
110 | purpose: "iOS Development"
111 | more_details_url: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html
112 | why_summary: "We have seen much lower error rates in production using Swift than the devs have seen with similar apps written in Objective-C"
113 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # DO NOT MODIFY - this is managed by Git Reduce in goro and generated from build-matrix.json
2 | #
3 | ---
4 | version: 2
5 | jobs:
6 | generate-and-push-docs:
7 | docker:
8 | - image: cimg/ruby:3.0.3
9 | auth:
10 | username: "$DOCKERHUB_USERNAME"
11 | password: "$DOCKERHUB_PASSWORD"
12 | steps:
13 | - checkout
14 | - run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
15 | - run: bundle install
16 | - run:
17 | name: Generate documentation
18 | command: ' if [[ $(bundle exec rake -T docs:generate:custom) ]]; then echo
19 | "Generating docs using rake task docs:generate:custom" ; bundle exec rake
20 | docs:generate:custom ; elif [[ $(bundle exec rake -T docs:generate) ]];
21 | then echo "Generating docs using rake task docs:generate" ; bundle exec
22 | rake docs:generate ; else echo "Skipping doc generation" ; exit 0 ; fi '
23 | - run:
24 | name: Push documentation to Unwritten
25 | command: if [[ $(bundle exec rake -T docs:push) ]]; then bundle exec rake
26 | docs:push; fi
27 | release:
28 | docker:
29 | - image: cimg/ruby:3.0.3
30 | auth:
31 | username: "$DOCKERHUB_USERNAME"
32 | password: "$DOCKERHUB_PASSWORD"
33 | steps:
34 | - checkout
35 | - run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
36 | - run: bundle install
37 | - run:
38 | name: Artifactory login
39 | command: mkdir -p ~/.gem && curl -u$ARTIFACTORY_USER:$ARTIFACTORY_TOKEN https://stitchfix01.jfrog.io/stitchfix01/api/gems/eng-gems/api/v1/api_key.yaml
40 | > ~/.gem/credentials && chmod 0600 ~/.gem/credentials
41 | - run:
42 | name: Build/release gem to artifactory
43 | command: bundle exec rake push_artifactory
44 | ruby-3.0.3-rails-7.0:
45 | docker:
46 | - image: cimg/ruby:3.0.3
47 | auth:
48 | username: "$DOCKERHUB_USERNAME"
49 | password: "$DOCKERHUB_PASSWORD"
50 | environment:
51 | BUNDLE_GEMFILE: Gemfile.rails-7.0
52 | working_directory: "~/tech_radar"
53 | steps:
54 | - checkout
55 | - run:
56 | name: Check for Gemfile.lock presence
57 | command: ' if (test -f Gemfile.lock) then echo "Dont commit Gemfile.lock (see
58 | https://github.com/stitchfix/eng-wiki/blob/main/architecture-decisions/0009-rubygem-dependencies-will-be-managed-more-explicitly.md)"
59 | 1>&2 ; exit 1 ; else exit 0 ; fi '
60 | - run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
61 | - run: bundle install
62 | - run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
63 | --format=doc
64 | - run:
65 | name: Run Additional CI Steps
66 | command: if [ -e bin/additional-ci-steps ]; then bin/additional-ci-steps;
67 | fi
68 | - run:
69 | name: Notify Pager Duty
70 | command: bundle exec y-notify "eng-runtime-info"
71 | when: on_fail
72 | - store_test_results:
73 | path: "/tmp/test-results"
74 | ruby-2.7.5-rails-7.0:
75 | docker:
76 | - image: cimg/ruby:2.7.5
77 | auth:
78 | username: "$DOCKERHUB_USERNAME"
79 | password: "$DOCKERHUB_PASSWORD"
80 | environment:
81 | BUNDLE_GEMFILE: Gemfile.rails-7.0
82 | working_directory: "~/tech_radar"
83 | steps:
84 | - checkout
85 | - run:
86 | name: Check for Gemfile.lock presence
87 | command: ' if (test -f Gemfile.lock) then echo "Dont commit Gemfile.lock (see
88 | https://github.com/stitchfix/eng-wiki/blob/main/architecture-decisions/0009-rubygem-dependencies-will-be-managed-more-explicitly.md)"
89 | 1>&2 ; exit 1 ; else exit 0 ; fi '
90 | - run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
91 | - run: bundle install
92 | - run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
93 | --format=doc
94 | - run:
95 | name: Run Additional CI Steps
96 | command: if [ -e bin/additional-ci-steps ]; then bin/additional-ci-steps;
97 | fi
98 | - run:
99 | name: Notify Pager Duty
100 | command: bundle exec y-notify "eng-runtime-info"
101 | when: on_fail
102 | - store_test_results:
103 | path: "/tmp/test-results"
104 | ruby-3.0.3-rails-6.1:
105 | docker:
106 | - image: cimg/ruby:3.0.3
107 | auth:
108 | username: "$DOCKERHUB_USERNAME"
109 | password: "$DOCKERHUB_PASSWORD"
110 | environment:
111 | BUNDLE_GEMFILE: Gemfile.rails-6.1
112 | working_directory: "~/tech_radar"
113 | steps:
114 | - checkout
115 | - run:
116 | name: Check for Gemfile.lock presence
117 | command: ' if (test -f Gemfile.lock) then echo "Dont commit Gemfile.lock (see
118 | https://github.com/stitchfix/eng-wiki/blob/main/architecture-decisions/0009-rubygem-dependencies-will-be-managed-more-explicitly.md)"
119 | 1>&2 ; exit 1 ; else exit 0 ; fi '
120 | - run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
121 | - run: bundle install
122 | - run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
123 | --format=doc
124 | - run:
125 | name: Run Additional CI Steps
126 | command: if [ -e bin/additional-ci-steps ]; then bin/additional-ci-steps;
127 | fi
128 | - run:
129 | name: Notify Pager Duty
130 | command: bundle exec y-notify "eng-runtime-info"
131 | when: on_fail
132 | - store_test_results:
133 | path: "/tmp/test-results"
134 | ruby-2.7.5-rails-6.1:
135 | docker:
136 | - image: cimg/ruby:2.7.5
137 | auth:
138 | username: "$DOCKERHUB_USERNAME"
139 | password: "$DOCKERHUB_PASSWORD"
140 | environment:
141 | BUNDLE_GEMFILE: Gemfile.rails-6.1
142 | working_directory: "~/tech_radar"
143 | steps:
144 | - checkout
145 | - run:
146 | name: Check for Gemfile.lock presence
147 | command: ' if (test -f Gemfile.lock) then echo "Dont commit Gemfile.lock (see
148 | https://github.com/stitchfix/eng-wiki/blob/main/architecture-decisions/0009-rubygem-dependencies-will-be-managed-more-explicitly.md)"
149 | 1>&2 ; exit 1 ; else exit 0 ; fi '
150 | - run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
151 | - run: bundle install
152 | - run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
153 | --format=doc
154 | - run:
155 | name: Run Additional CI Steps
156 | command: if [ -e bin/additional-ci-steps ]; then bin/additional-ci-steps;
157 | fi
158 | - run:
159 | name: Notify Pager Duty
160 | command: bundle exec y-notify "eng-runtime-info"
161 | when: on_fail
162 | - store_test_results:
163 | path: "/tmp/test-results"
164 | workflows:
165 | version: 2
166 | on-commit:
167 | jobs:
168 | - release:
169 | context: org-global
170 | requires:
171 | - ruby-3.0.3-rails-7.0
172 | - ruby-2.7.5-rails-7.0
173 | - ruby-3.0.3-rails-6.1
174 | - ruby-2.7.5-rails-6.1
175 | filters:
176 | tags:
177 | only: /^[0-9]+\.[0-9]+\.[0-9]+(\.?(RC|rc)[-\.]?\w*)?$/
178 | branches:
179 | ignore: /.*/
180 | - generate-and-push-docs:
181 | context: org-global
182 | requires:
183 | - release
184 | filters:
185 | tags:
186 | only: /^[0-9]+\.[0-9]+\.[0-9]+(\.?(RC|rc)[-\.]?\w*)?$/
187 | branches:
188 | ignore: /.*/
189 | - ruby-3.0.3-rails-7.0:
190 | context: org-global
191 | filters:
192 | tags:
193 | only: &1 /.*/
194 | - ruby-2.7.5-rails-7.0:
195 | context: org-global
196 | filters:
197 | tags:
198 | only: *1
199 | - ruby-3.0.3-rails-6.1:
200 | context: org-global
201 | filters:
202 | tags:
203 | only: *1
204 | - ruby-2.7.5-rails-6.1:
205 | context: org-global
206 | filters:
207 | tags:
208 | only: *1
209 | scheduled:
210 | triggers:
211 | - schedule:
212 | cron: 59 21 * * 1,2,3,4,5
213 | filters:
214 | branches:
215 | only:
216 | - main
217 | jobs:
218 | - ruby-3.0.3-rails-7.0:
219 | context: org-global
220 | - ruby-2.7.5-rails-7.0:
221 | context: org-global
222 | - ruby-3.0.3-rails-6.1:
223 | context: org-global
224 | - ruby-2.7.5-rails-6.1:
225 | context: org-global
226 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # tech\_radar [](https://travis-ci.org/stitchfix/tech_radar)
2 |
3 | > A Rails engine for managing a [Tech Radar](https://www.thoughtworks.com/radar) for your team.
4 |
5 | It allows you to identify the technology in use on your team, where it is in your level of adoption and other bits of metadata, such as whitepapers, blog posts, etc.
6 |
7 | The Tech Radar is a way you can manage the use of technology on your team. This tool makes it easier to do that, but you'll still need
8 | process and good communication to make the most of it.
9 |
10 | ## See It In Action
11 |
12 | * View [Stitch Fix's Tech Radar](https://opensource.stitchfix.com/tech-radar/radar/index) to see how it looks on a mature team with a lot of software in production.
13 | * Try out the [example Rails app](https://github.com/stitchfix/example_tech_radar)
14 | * Deploy it to Heroku:
15 |
16 | [](https://heroku.com/deploy?template=https://github.com/stitchfix/example_tech_radar)
17 |
18 |
19 | ## Install and Setup
20 |
21 | You'll need to do four things to get this working:
22 |
23 | 1. Set up the engine
24 | 2. Fix any references to route helpers in your main application layout
25 | 3. Author your radar in the YAML file format
26 | 4. Modify any text or copy in your localization file
27 |
28 | ### Set up the engine
29 |
30 | First, add to your `Gemfile`:
31 |
32 | ```ruby
33 | gem 'tech_radar'
34 | ```
35 |
36 | After a `bundle install`, mount it in your Rails app:
37 |
38 | ```ruby
39 | # config/routes.rb
40 | Rails.application.routes.draw do
41 |
42 | # ...
43 |
44 | mount TechRadar::Engine, at: "/tech-radar", as: :tech_radar
45 | end
46 | ```
47 |
48 | The radar is now available at `/tech-radar` in your Rails app. If your main application layout uses any route helpers (e.g. for a nav),
49 | you'll need to change those.
50 |
51 | ### Fix References to Route Helpers in Application Layout
52 |
53 | The engine will use your application layout, so if your layout uses any route helpers, they won't work when on the tech radar's views.
54 | To fix this, you must prepend `main_app.` to your routes.
55 |
56 | For example, if you have this:
57 |
58 | ```html
59 |
65 | ```
66 |
67 | You'll change it to this:
68 |
69 | ```html
70 |
78 | ```
79 |
80 | To create links to the radar's views, use `rake routes` to view them as you normally would. Remember that the route helpers must be called on
81 | `tech_radar.`, like so:
82 |
83 | ```html
84 |
91 | ```
92 |
93 | With this in place, you now should author your radar.
94 |
95 | ### Authoring Your Radar
96 |
97 | The Radar is expected to be in `config/tech-radar.yml`. You should start with this YAML file:
98 |
99 | ```yaml
100 | "Tools":
101 | "Adopt":
102 | "vi":
103 | purpose :"text editing"
104 | more_details_url: "http://vim.org"
105 | more_details_summary: "Vim is mode-based text editor, based on vi that contains several enhancements"
106 | why_summary: "vi is a great text editor!"
107 | why_url: http://naildrivin5.com/blog/2013/04/24/how-to-switch-to-vim.html
108 | tags:
109 | - editor
110 | - lifestyle
111 | experts:
112 | - Bram
113 | - name: Drew Neil
114 | email: drew@example.com
115 | examples:
116 | - http://vim.org
117 | - url: http://neovim.io
118 | title: The next version of vim
119 | "Trial":
120 | "Assess":
121 | "Hold":
122 | "Platforms":
123 | "Adopt":
124 | "Trial":
125 | "Assess":
126 | "Hold":
127 | "Techniques":
128 | "Adopt":
129 | "Trial":
130 | "Assess":
131 | "Hold":
132 | "Languages and Frameworks":
133 | "Adopt":
134 | "Trial":
135 | "Assess":
136 | "Hold":
137 | ```
138 |
139 | Note that these keys are special. If you are not using English, you can customize how these are displayed in your localization file, so
140 | don't translate or change these values in `tech-radar.yml`.
141 |
142 | The top level are the _quadrants_ (e.g. “Techniques”). These are used to partition your technologies by a rough type. The next level
143 | down are _rings_ (e.g.“Adopt”). These rings represent a level of adoption in your organization.
144 |
145 | Inside each Ring should be a hash, which has the name of a technology as a key, and some metadata:
146 |
147 | * `purpose`: required, this is the explanation of what this technology is for.
148 | * `more_details_summary`: A brief summary of what this technology or technique is. It can be as long as you want and will be shown in-line. This can be
149 | Markdown and will be rendered as such if you set `summary_format` to `:markdown` (see below).
150 | * `more_details_url`: optional, a link to explain in more detail what the technology is. If `more_details_summary` and this are omitted, the engine will show a link to a Google search for the technology.
151 | * `why_summary`: optional, but recommended, this explains why this technology is in the ring that it's in. In particular, this is useful
152 | for technologies not in _Adopt_. Markdown will be rendered as such if you set `summary_format` to `:markdown` (see below).
153 | * `why_url`: optional, this is a link to a white paper or other explanation about why the technology in in the ring that it's in. This is
154 | where you'd reference a detailed analysis or experience report with the technology.
155 | * `tags`: this is a list of arbitrary tags you can use to make your radar more navigable. **This is not used by the views in the engine**.
156 | * `experts`: A list of names of people on yoru team that are knowledgable about the technology and can be a resource for learning more. **This is not used by the views in the engine**.
157 | * `examples`: A list of urls that exemplify the technology or technique. These should be instructions, walkthroughs, rubooks, or
158 | anything to help someone understand how to use the technology or technique in your organization. **This is not used by the views in the engine**.
159 |
160 | We'd recommend that, for your first pass, you document your current landscape, and not be too aspirational.
161 |
162 | With this set up, you can see the radar in your app. All copy is controlled by localization, and you can override it in your app. This
163 | is useful not just for translating the strings, but for customizing the messaging to your team.
164 |
165 | ### Modify any text or copy in your localization file
166 |
167 | Examine the `config/en.yml` in this engine's source. You can override any or all of those values for your team in the Rails app where you are using this
168 | engine. For example, the default summary of the _Adopt_ ring is as follows:
169 |
170 | > Use these, as they are supported and proven in production
171 |
172 | Suppose that, for your team, you need to get approval from the architecture team to use technologies not in _Adopt_. You could change that
173 | by adding this to your application's `config/locales/en.yml`:
174 |
175 | ```yaml
176 | en:
177 | tech_radar:
178 | radar:
179 | rings:
180 | "Adopt":
181 | summary: "Use these by default. See the architecture team if you need something else."
182 | ```
183 |
184 | All the text in the engine can be customized in this way.
185 |
186 | ## Configuration
187 |
188 | To customize the configuration of this engine, create `config/initializers/tech_radar.rb`. In there you can override any configuration
189 | options you need.
190 |
191 | ### `warn_on_missing_why_summary`
192 |
193 | If a technology is missing a `why_summary`, by default the engine's views will show a warning on that technology's page, urging you to
194 | provide a summary. You may only want this warning for certain rings. In that case, you can set `warn_on_missing_why_summary` to a hash,
195 | where each key is the ring name from the `config/tech-radar.yml` file, and the value is true or false, if a warning should be
196 | shown when there is no `why_summary`.
197 |
198 | ```ruby
199 | # For "Adopt" and "Trial", it's OK if the why_summary is missing
200 | TechRadar.warn_on_missing_why_summary = {
201 | "Hold" => true,
202 | "Assess" => true,
203 | }
204 |
205 | # Or, disable the warnings entirely
206 | TechRadar.warn_on_missing_why_summary = Hash.new(false)
207 | ```
208 |
209 | ### `summary_format`
210 |
211 | This allows you to set the interpretation of the values for `why_summary` and `more_details_summary` in `tech-radar.yml`. The main use of this is to use
212 | Markdown.
213 |
214 | Recognized values:
215 |
216 | * `:plaintext` (default)—render the text as-is, with no parsing or interpretation.
217 | * `:markdown`—render using Markdown, specifically by using the RedCarpet gem. **This gem is not installed by default**. You will need to include it in your app's `Gemfile`. This is so that users who don't want Markdown don't have to install a Markdown gem.
218 |
219 | ## Styling
220 |
221 | The radar's views use [Bootstrap](https://getbootstrap.com), for a few reasons:
222 |
223 | * We needed the default to look reasonably nice
224 | * Bootstrap is widely used and understood
225 | * Bootstrap can be brought in piecemeal alongside another framework, relatively easily
226 |
227 | Currently, you'll need only part of Bootstrap's styles to make things work. If you are using the SASS version of bootstrap, you can
228 | bring in what you need like so:
229 |
230 | ```sass
231 | @import "bootstrap-sprockets";
232 | @import "bootstrap/variables";
233 | @import "bootstrap/mixins";
234 |
235 | @import "bootstrap/grid";
236 | @import "bootstrap/navs";
237 | @import "bootstrap/pagination";
238 | @import "bootstrap/labels";
239 | @import "bootstrap/alerts";
240 | @import "bootstrap/panels";
241 | ```
242 |
243 | Also, each page is wrapped in a `section` with the css class `tech-radar`. Specific pages' `section` elements also have a more
244 | specific CSS class:
245 |
246 | * `tech-radar-index` - main page
247 | * `tech-radar-summary` - summary page
248 | * `tech-radar-technologies` - A-Z page
249 | * `tech-radar-technology` - Single technology page
250 | * `tech-radar-quadrant` - Single quadrant page
251 | * `tech-radar-ring` - Single ring page
252 |
253 | If you aren't using Bootstrap, you can use these styles to alter however Bootstrap and your CSS framework are interacting.
254 |
255 | You can, of course, create your own views by accessing the `TechRadar::Radar` model directly.
256 |
257 | ## Licence
258 |
259 | *tech_radar* is released under the [MIT License](http://www.opensource.org/licenses/MIT).
260 |
261 | ## Contributing
262 |
263 | *tech_radar* appreciates contributors! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
264 |
265 | Everyone interacting in *tech_radar*'s codebase, issue trackers, chat rooms, and mailing lists is expected to follow the *tech_radar* [code of conduct](CODE_OF_CONDUCT.md).
266 |
267 | ---
268 |
269 | Provided with :heart: by your friends at [Stitch Fix Engineering](http://multithreaded.stitchfix.com/)
270 |
--------------------------------------------------------------------------------