├── .ruby-version ├── test ├── dummy │ ├── log │ │ └── .keep │ ├── app │ │ ├── mailers │ │ │ └── .keep │ │ ├── models │ │ │ ├── .keep │ │ │ └── concerns │ │ │ │ └── .keep │ │ ├── assets │ │ │ ├── images │ │ │ │ └── .keep │ │ │ ├── config │ │ │ │ └── manifest.js │ │ │ ├── javascripts │ │ │ │ └── application.js │ │ │ └── stylesheets │ │ │ │ └── application.css │ │ ├── controllers │ │ │ ├── concerns │ │ │ │ └── .keep │ │ │ └── application_controller.rb │ │ ├── helpers │ │ │ └── application_helper.rb │ │ └── views │ │ │ └── layouts │ │ │ └── application.html.erb │ ├── lib │ │ └── assets │ │ │ └── .keep │ ├── public │ │ ├── favicon.ico │ │ ├── 500.html │ │ ├── 422.html │ │ └── 404.html │ ├── bin │ │ ├── rake │ │ ├── bundle │ │ ├── rails │ │ └── setup │ ├── config │ │ ├── routes.rb │ │ ├── locales │ │ │ └── en.yml │ │ ├── initializers │ │ │ ├── cookies_serializer.rb │ │ │ ├── session_store.rb │ │ │ ├── mime_types.rb │ │ │ ├── filter_parameter_logging.rb │ │ │ ├── wrap_parameters.rb │ │ │ ├── backtrace_silencers.rb │ │ │ ├── assets.rb │ │ │ └── inflections.rb │ │ ├── environment.rb │ │ ├── boot.rb │ │ ├── secrets.yml │ │ ├── application.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── test.rb │ │ │ └── production.rb │ │ └── tech-radar.yml │ ├── config.ru │ ├── Rakefile │ └── README.rdoc ├── integration │ └── navigation_test.rb ├── models │ └── tech_radar │ │ ├── rendering_test.rb │ │ └── radar_test.rb ├── controllers │ └── tech_radar │ │ ├── radar_controller_test.rb │ │ ├── quadrants_controller_test.rb │ │ └── technologies_controller_test.rb └── test_helper.rb ├── .ruby-gemset ├── app ├── assets │ ├── images │ │ └── tech_radar │ │ │ └── .keep │ ├── javascripts │ │ └── tech_radar │ │ │ └── application.js │ └── stylesheets │ │ └── tech_radar │ │ └── application.scss ├── models │ └── tech_radar │ │ ├── ring.rb │ │ ├── example.rb │ │ ├── expert.rb │ │ ├── quadrant.rb │ │ ├── rendering │ │ ├── plaintext.rb │ │ └── markdown.rb │ │ ├── technology.rb │ │ ├── rendering.rb │ │ └── radar.rb ├── controllers │ └── tech_radar │ │ ├── application_controller.rb │ │ ├── radar_controller.rb │ │ ├── rings_controller.rb │ │ ├── quadrants_controller.rb │ │ └── technologies_controller.rb ├── helpers │ └── tech_radar │ │ └── application_helper.rb └── views │ ├── layouts │ └── tech_radar │ │ └── application.html.erb │ └── tech_radar │ ├── technologies │ ├── index.html.erb │ └── show.html.erb │ ├── radar │ ├── summary.html.erb │ └── index.html.erb │ ├── rings │ └── show.html.erb │ └── quadrants │ └── show.html.erb ├── lib ├── tech_radar │ ├── version.rb │ └── engine.rb ├── tasks │ └── tech_radar_tasks.rake └── tech_radar.rb ├── owners.json ├── .github ├── PULL_REQUEST_TEMPLATE.md └── CODEOWNERS ├── Gemfile.rails-4.2 ├── Gemfile.rails-5.0 ├── Gemfile.rails-5.1 ├── Gemfile.rails-5.2 ├── Gemfile.rails-6.0 ├── Gemfile.rails-6.1 ├── Gemfile.rails-7.0 ├── CODE_OF_CONDUCT.md ├── .gitignore ├── config ├── routes.rb └── locales │ └── en.yml ├── .travis.yml ├── bin └── rails ├── Gemfile ├── Rakefile ├── CONTRIBUTING.md ├── tech_radar.gemspec ├── MIT-LICENSE ├── .circleci └── config.yml └── README.md /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7.2 2 | -------------------------------------------------------------------------------- /test/dummy/log/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | tech-radar 2 | -------------------------------------------------------------------------------- /test/dummy/app/mailers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/dummy/app/models/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/dummy/lib/assets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/dummy/public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/assets/images/tech_radar/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/dummy/app/assets/images/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/dummy/app/models/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/tech_radar/version.rb: -------------------------------------------------------------------------------- 1 | module TechRadar 2 | VERSION = "0.6.0" 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /owners.json: -------------------------------------------------------------------------------- 1 | { 2 | "owners": [ 3 | { 4 | "team": "eng-runtime" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /app/models/tech_radar/ring.rb: -------------------------------------------------------------------------------- 1 | module TechRadar 2 | end 3 | TechRadar::Ring = ImmutableStruct.new(:name, [:technologies]) 4 | -------------------------------------------------------------------------------- /test/dummy/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /test/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | 3 | mount TechRadar::Engine => "/tech_radar" 4 | end 5 | -------------------------------------------------------------------------------- /lib/tasks/tech_radar_tasks.rake: -------------------------------------------------------------------------------- 1 | # desc "Explaining what the task does" 2 | # task :tech_radar do 3 | # # Task goes here 4 | # end 5 | -------------------------------------------------------------------------------- /lib/tech_radar/engine.rb: -------------------------------------------------------------------------------- 1 | module TechRadar 2 | class Engine < ::Rails::Engine 3 | isolate_namespace TechRadar 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /test/dummy/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | hello: "Hello world" 3 | tech_radar: 4 | radar: 5 | index: 6 | preamble: "FOOBAR" 7 | -------------------------------------------------------------------------------- /test/dummy/app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../javascripts .js 3 | //= link_directory ../stylesheets .css 4 | -------------------------------------------------------------------------------- /app/models/tech_radar/example.rb: -------------------------------------------------------------------------------- 1 | require 'immutable-struct' 2 | 3 | module TechRadar 4 | end 5 | TechRadar::Example = ImmutableStruct.new(:url, :title) 6 | -------------------------------------------------------------------------------- /app/models/tech_radar/expert.rb: -------------------------------------------------------------------------------- 1 | require 'immutable-struct' 2 | 3 | module TechRadar 4 | end 5 | TechRadar::Expert = ImmutableStruct.new(:name, :email) 6 | -------------------------------------------------------------------------------- /app/models/tech_radar/quadrant.rb: -------------------------------------------------------------------------------- 1 | require 'immutable-struct' 2 | module TechRadar 3 | end 4 | TechRadar::Quadrant = ImmutableStruct.new(:name, [:rings]) 5 | -------------------------------------------------------------------------------- /test/dummy/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Problem 2 | 3 | «Brief overview of the problem» 4 | 5 | ## Solution 6 | 7 | «Brief description of how you solved the problem» 8 | -------------------------------------------------------------------------------- /test/dummy/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../../config/application', __FILE__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /test/dummy/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.action_dispatch.cookies_serializer = :json 4 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This file uses the GitHub CODEOWNERS convention to assign PR reviewers: 2 | # https://help.github.com/articles/about-codeowners/ 3 | 4 | * @stitchfix/runtime-infrastructure 5 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_dummy_session' 4 | -------------------------------------------------------------------------------- /test/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /test/integration/navigation_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class NavigationTest < ActionDispatch::IntegrationTest 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | 9 | -------------------------------------------------------------------------------- /Gemfile.rails-4.2: -------------------------------------------------------------------------------- 1 | # DO NOT MODIFY - this is managed by Git Reduce in goro 2 | # 3 | source 'https://gem.fury.io/me/' 4 | source 'https://www.rubygems.org' 5 | 6 | gemspec 7 | 8 | gem 'rails', '~> 4.2.0' 9 | -------------------------------------------------------------------------------- /Gemfile.rails-5.0: -------------------------------------------------------------------------------- 1 | # DO NOT MODIFY - this is managed by Git Reduce in goro 2 | # 3 | source 'https://gem.fury.io/me/' 4 | source 'https://www.rubygems.org' 5 | 6 | gemspec 7 | 8 | gem 'rails', '~> 5.0.0' 9 | -------------------------------------------------------------------------------- /Gemfile.rails-5.1: -------------------------------------------------------------------------------- 1 | # DO NOT MODIFY - this is managed by Git Reduce in goro 2 | # 3 | source 'https://stitchfix01.jfrog.io/stitchfix01/api/gems/eng-gems/' 4 | 5 | gemspec 6 | 7 | gem 'rails', '~> 5.1.0' 8 | -------------------------------------------------------------------------------- /Gemfile.rails-5.2: -------------------------------------------------------------------------------- 1 | # DO NOT MODIFY - this is managed by Git Reduce in goro 2 | # 3 | source 'https://stitchfix01.jfrog.io/stitchfix01/api/gems/eng-gems/' 4 | 5 | gemspec 6 | 7 | gem 'rails', '~> 5.2.0' 8 | -------------------------------------------------------------------------------- /Gemfile.rails-6.0: -------------------------------------------------------------------------------- 1 | # DO NOT MODIFY - this is managed by Git Reduce in goro 2 | # 3 | source 'https://stitchfix01.jfrog.io/stitchfix01/api/gems/eng-gems/' 4 | 5 | gemspec 6 | 7 | gem 'rails', '~> 6.0.0' 8 | -------------------------------------------------------------------------------- /Gemfile.rails-6.1: -------------------------------------------------------------------------------- 1 | # DO NOT MODIFY - this is managed by Git Reduce in goro 2 | # 3 | source 'https://stitchfix01.jfrog.io/stitchfix01/api/gems/eng-gems/' 4 | 5 | gemspec 6 | 7 | gem 'rails', '~> 6.1.0' 8 | -------------------------------------------------------------------------------- /Gemfile.rails-7.0: -------------------------------------------------------------------------------- 1 | # DO NOT MODIFY - this is managed by Git Reduce in goro 2 | # 3 | source 'https://stitchfix01.jfrog.io/stitchfix01/api/gems/eng-gems/' 4 | 5 | gemspec 6 | 7 | gem 'rails', '~> 7.0.0' 8 | -------------------------------------------------------------------------------- /app/models/tech_radar/rendering/plaintext.rb: -------------------------------------------------------------------------------- 1 | module TechRadar 2 | module Rendering 3 | class Plaintext 4 | def render_text(text) 5 | text 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | We are committed to keeping our community open and inclusive. 4 | 5 | **Our Code of Conduct can be found here**: 6 | http://opensource.stitchfix.com/code-of-conduct.html 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | log/*.log 3 | pkg/ 4 | test/dummy/db/*.sqlite3 5 | test/dummy/db/*.sqlite3-journal 6 | test/dummy/log/*.log 7 | test/dummy/tmp/ 8 | test/dummy/.sass-cache 9 | Session.vim 10 | Gemfile.lock 11 | -------------------------------------------------------------------------------- /app/controllers/tech_radar/application_controller.rb: -------------------------------------------------------------------------------- 1 | module TechRadar 2 | #class ApplicationController < ActionController::Base 3 | class ApplicationController < ::ApplicationController 4 | layout "application" 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | TechRadar::Engine.routes.draw do 2 | get 'radar/index' 3 | get 'radar/summary' 4 | resources :technologies, only: [ :index, :show ] 5 | resources :quadrants, only: [ :show ] 6 | resources :rings, only: [ :show ] 7 | 8 | end 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: 2 | ruby 3 | notifications: 4 | email: 5 | on_success: always 6 | script: 7 | - 'bundle exec rake test' 8 | rvm: 9 | - 2.6 10 | - 2.7 11 | - ruby-head 12 | matrix: 13 | allow_failures: 14 | - rvm: ruby-head 15 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | protect_from_forgery with: :exception 5 | end 6 | -------------------------------------------------------------------------------- /app/models/tech_radar/technology.rb: -------------------------------------------------------------------------------- 1 | require 'immutable-struct' 2 | 3 | module TechRadar 4 | end 5 | TechRadar::Technology = ImmutableStruct.new(:name, :ring, :quadrant, :purpose, :why_summary, :why_url, :more_details_summary, :more_details_url, [:tags], [:experts], [:examples]) 6 | -------------------------------------------------------------------------------- /test/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) 3 | 4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 5 | $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__) 6 | -------------------------------------------------------------------------------- /test/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app/models/tech_radar/rendering.rb: -------------------------------------------------------------------------------- 1 | module TechRadar 2 | module Rendering 3 | def self.renderer 4 | @renderers ||= {} 5 | @renderers[TechRadar.summary_format] ||= "tech_radar/rendering/#{TechRadar.summary_format}".classify.constantize.new 6 | @renderers[TechRadar.summary_format] 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/controllers/tech_radar/radar_controller.rb: -------------------------------------------------------------------------------- 1 | require_dependency "tech_radar/application_controller" 2 | 3 | module TechRadar 4 | class RadarController < ApplicationController 5 | def index 6 | @hide_nav = true 7 | @radar = TechRadar::Radar.new 8 | end 9 | 10 | def summary 11 | @radar = TechRadar::Radar.new 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/controllers/tech_radar/rings_controller.rb: -------------------------------------------------------------------------------- 1 | require_dependency "tech_radar/application_controller" 2 | 3 | module TechRadar 4 | class RingsController < ApplicationController 5 | def show 6 | tech_radar = TechRadar::Radar.new 7 | @all_ring_names = tech_radar.rings.map(&:name) 8 | @ring = tech_radar.ring(params[:id]) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/controllers/tech_radar/quadrants_controller.rb: -------------------------------------------------------------------------------- 1 | require_dependency "tech_radar/application_controller" 2 | 3 | module TechRadar 4 | class QuadrantsController < ApplicationController 5 | def show 6 | tech_radar = TechRadar::Radar.new 7 | @all_quadrant_names = tech_radar.quadrants.map(&:name) 8 | @quadrant = tech_radar.quadrant(params[:id]) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 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 |

<%= link_to t("tech_radar.radar.title").html_safe, radar_index_path %>

16 |
17 | <% end %> 18 | <%= yield %> 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /test/dummy/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | 4 | # path to your application root. 5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 6 | 7 | Dir.chdir APP_ROOT do 8 | # This script is a starting point to setup your application. 9 | # Add necessary setup steps to this file: 10 | 11 | puts "== Installing dependencies ==" 12 | system "gem install bundler --conservative" 13 | system "bundle check || bundle install" 14 | 15 | # puts "\n== Copying sample files ==" 16 | # unless File.exist?("config/database.yml") 17 | # system "cp config/database.yml.sample config/database.yml" 18 | # end 19 | 20 | puts "\n== Preparing database ==" 21 | system "bin/rake db:setup" 22 | 23 | puts "\n== Removing old logs and tempfiles ==" 24 | system "rm -f log/*" 25 | system "rm -rf tmp/cache" 26 | 27 | puts "\n== Restarting application server ==" 28 | system "touch tmp/restart.txt" 29 | end 30 | -------------------------------------------------------------------------------- /app/views/tech_radar/technologies/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

A-Z

3 | 8 | <% @technologies.group_by { |technology| technology.name[0].upcase }.each do |letter,technologies| %> 9 | 10 |

<%= letter %>

11 | 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 |
3 | <% @radar.quadrants.each do |quadrant| %> 4 |
5 |

<%= t("tech_radar.radar.quadrants.#{quadrant.name}.title") %>

6 |
7 | <% end %> 8 |
9 | <% @radar.rings.each do |ring| %> 10 |
11 |
12 | <%= t("tech_radar.radar.rings.#{ring.name}.title") %> 13 |
14 |
15 |
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 |

<%= t("tech_radar.radar.rings.#{@ring.name}.title").html_safe %>

11 |

<%= t("tech_radar.radar.rings.#{@ring.name}.description").html_safe %>

12 | 30 |
31 | -------------------------------------------------------------------------------- /app/views/tech_radar/quadrants/show.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 9 |
10 |

<%= t("tech_radar.radar.quadrants.#{@quadrant.name}.title") %>

11 |

<%= t("tech_radar.radar.quadrants.#{@quadrant.name}.description") %>

12 | <% @quadrant.rings.each do |ring| %> 13 |
14 |

15 | <%= t("tech_radar.radar.rings.#{ring.name}.title") %> 16 | <%= t("tech_radar.radar.rings.#{ring.name}.summary").html_safe %> 17 |

18 | 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.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /test/dummy/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

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 |

3 | <%= @technology.name %> 4 | 5 | <%= t("tech_radar.radar.quadrants.#{@technology.quadrant}.title") %> 6 | <%= t("tech_radar.radar.rings.#{@technology.ring}.title") %> 7 | 8 |

9 |

<%= @technology.purpose %>

10 |
11 | <% if @technology.more_details_url.blank? && @technology.more_details_summary.blank? %> 12 |

13 | <%= link_to t("tech_radar.radar.technologies.more_details_url.google"), "https://www.google.com/search?q=#{@technology.name}", class: "btn btn-default" %> 14 |

15 | <% else %> 16 | <% if @technology.more_details_summary.present? %> 17 |

18 | <%= render_summary(@technology.more_details_summary) %> 19 |

20 | <% end %> 21 | <% if @technology.more_details_url.present? %> 22 |

23 | <%= link_to t("tech_radar.radar.technologies.more_details_url.link"), @technology.more_details_url, class: "btn btn-default" %> 24 |

25 | <% end %> 26 | <% end %> 27 |
28 |
29 |
30 | <% if @technology.why_summary.present? %> 31 |

32 | 33 | <%= render_summary(@technology.why_summary) %> 34 | 35 | <% if @technology.why_url.present? %> 36 | <%= link_to t("tech_radar.radar.technologies.why_summary.link"), @technology.why_url %> 37 | <% end %> 38 |

39 | <% else %> 40 | <% if TechRadar.warn_on_missing_why_summary[@technology.ring] %> 41 |
42 | <%= t("tech_radar.radar.technologies.why_summary.no_summary").html_safe %> 43 | <% if @technology.why_url.present? %> 44 | <%= link_to t("tech_radar.radar.technologies.why_summary.url_only"), @technology.why_url %> 45 | <% end %> 46 |
47 | <% end %> 48 | <% end %> 49 |
50 |
51 | -------------------------------------------------------------------------------- /app/views/tech_radar/radar/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
 
4 |
5 |
6 |

<%= t("tech_radar.radar.title") %>

7 |
8 |

9 | <%= t("tech_radar.radar.index.preamble") %> 10 |

11 |

12 | <%= link_to t("tech_radar.radar.index.summary_link"), radar_summary_path, class: "btn btn-primary" %> 13 | <%= link_to t("tech_radar.radar.index.all_list_link"), technologies_path, class: "btn btn-default" %> 14 |

15 |
16 |

<%= t("tech_radar.radar.index.howto.title") %>

17 |

<%= t("tech_radar.radar.rings.name") %>

18 |

<%= t("tech_radar.radar.index.howto.rings.preamble") %>

19 | <% @radar.rings.each_slice(2) do |rings| %> 20 |
21 | <% rings.each do |ring| %> 22 |
23 |

<%= link_to t("tech_radar.radar.rings.#{ring.name}.title"), ring_path(ring.name) %>

24 |

<%= t("tech_radar.radar.rings.#{ring.name}.description").html_safe %>

25 |
26 | <% end %> 27 |
28 | <% end %> 29 |

<%= t("tech_radar.radar.quadrants.name") %>

30 |

<%= t("tech_radar.radar.index.howto.quadrants.preamble") %>

31 | <% @radar.quadrants.each_slice(2) do |quadrants| %> 32 |
33 | <% quadrants.each do |quadrant| %> 34 |
35 |

<%= link_to t("tech_radar.radar.quadrants.#{quadrant.name}.title"), quadrant_path(quadrant.name) %>

36 |

<%= t("tech_radar.radar.quadrants.#{quadrant.name}.description").html_safe %>

37 |
38 | <% end %> 39 |
40 | <% end %> 41 |
42 |
43 |
44 |

<%= t("tech_radar.radar.index.changing.title") %>

45 |

<%= t("tech_radar.radar.index.changing.preamble") %>

46 |
47 | 48 |
 
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 [![Build Status](https://travis-ci.org/stitchfix/tech_radar.svg)](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 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](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 | --------------------------------------------------------------------------------