├── spec
├── dummy
│ ├── public
│ │ └── favicon.ico
│ ├── app
│ │ ├── views
│ │ │ ├── pages
│ │ │ │ ├── include_index.html.erb
│ │ │ │ ├── embedded.html.erb
│ │ │ │ ├── include_index_empty_block.html.erb
│ │ │ │ └── include_index_head_and_body.html.erb
│ │ │ └── layouts
│ │ │ │ └── application.html.erb
│ │ └── controllers
│ │ │ └── application_controller.rb
│ ├── config
│ │ ├── initializers
│ │ │ ├── ember.rb
│ │ │ └── high_voltage.rb
│ │ └── routes.rb
│ ├── Rakefile
│ ├── .gitignore
│ └── application.rb
├── fixtures
│ ├── logo.png
│ └── application.hbs
├── support
│ └── capybara.rb
├── lib
│ ├── ember-cli-rails_spec.rb
│ ├── ember_cli_spec.rb
│ └── ember_cli
│ │ ├── deploy
│ │ └── file_spec.rb
│ │ ├── helpers_spec.rb
│ │ ├── ember_constraint_spec.rb
│ │ ├── runner_spec.rb
│ │ ├── app_spec.rb
│ │ ├── command_spec.rb
│ │ ├── build_monitor_spec.rb
│ │ └── path_set_spec.rb
├── requests
│ └── assets
│ │ └── my-app.js_spec.rb
├── spec_helper.rb
├── features
│ └── user_views_ember_app_spec.rb
└── generators
│ └── ember
│ └── heroku
│ └── heroku_generator_spec.rb
├── .rspec
├── lib
├── generators
│ └── ember
│ │ ├── heroku
│ │ ├── templates
│ │ │ ├── yarn.lock.erb
│ │ │ └── package.json.erb
│ │ ├── USAGE
│ │ └── heroku_generator.rb
│ │ └── init
│ │ ├── templates
│ │ └── initializer.rb
│ │ ├── USAGE
│ │ └── init_generator.rb
├── ember-cli-rails.rb
├── ember_cli
│ ├── version.rb
│ ├── errors.rb
│ ├── engine.rb
│ ├── trailing_slash_constraint.rb
│ ├── configuration.rb
│ ├── ember_constraint.rb
│ ├── helpers.rb
│ ├── route_helpers.rb
│ ├── runner.rb
│ ├── command.rb
│ ├── deploy
│ │ └── file.rb
│ ├── build_monitor.rb
│ ├── shell.rb
│ ├── app.rb
│ └── path_set.rb
├── tasks
│ └── ember-cli.rake
└── ember_cli.rb
├── bin
├── clean
├── rake
├── rspec
├── setup
└── setup_ember
├── app
├── views
│ └── ember_cli
│ │ └── ember
│ │ └── index.html.erb
├── helpers
│ └── ember_rails_helper.rb
└── controller
│ └── ember_cli
│ └── ember_controller.rb
├── .gitignore
├── Rakefile
├── Gemfile
├── SECURITY.md
├── RELEASING.md
├── .github
├── ISSUE_TEMPLATE.md
└── workflows
│ └── tests.yml
├── LICENSE.txt
├── ember-cli-rails.gemspec
├── UPGRADING.md
├── CONTRIBUTING.md
├── CHANGELOG.md
└── README.md
/spec/dummy/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 | --require spec_helper
3 |
--------------------------------------------------------------------------------
/lib/generators/ember/heroku/templates/yarn.lock.erb:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/ember-cli-rails.rb:
--------------------------------------------------------------------------------
1 | require "ember_cli"
2 |
3 | EmberCLI = EmberCli
4 |
--------------------------------------------------------------------------------
/bin/clean:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | rm -rf spec/dummy/{my-app,tmp}
6 |
--------------------------------------------------------------------------------
/lib/ember_cli/version.rb:
--------------------------------------------------------------------------------
1 | module EmberCli
2 | VERSION = "0.12.2".freeze
3 | end
4 |
--------------------------------------------------------------------------------
/spec/dummy/app/views/pages/include_index.html.erb:
--------------------------------------------------------------------------------
1 | <%= render_ember_app "my-app" %>
2 |
--------------------------------------------------------------------------------
/spec/dummy/config/initializers/ember.rb:
--------------------------------------------------------------------------------
1 | EmberCli.configure do |c|
2 | c.app "my-app"
3 | end
4 |
--------------------------------------------------------------------------------
/spec/fixtures/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tricknotes/ember-cli-rails/HEAD/spec/fixtures/logo.png
--------------------------------------------------------------------------------
/lib/generators/ember/init/templates/initializer.rb:
--------------------------------------------------------------------------------
1 | EmberCli.configure do |c|
2 | c.app :frontend
3 | end
4 |
--------------------------------------------------------------------------------
/spec/fixtures/application.hbs:
--------------------------------------------------------------------------------
1 |
Welcome to Ember
2 |
3 |
4 | {{outlet}}
5 |
--------------------------------------------------------------------------------
/spec/dummy/Rakefile:
--------------------------------------------------------------------------------
1 | require File.expand_path("../application", __FILE__)
2 |
3 | Rails.application.load_tasks
4 |
--------------------------------------------------------------------------------
/lib/ember_cli/errors.rb:
--------------------------------------------------------------------------------
1 | module EmberCli
2 | class BuildError < StandardError; end
3 | class DependencyError < BuildError; end
4 | end
5 |
--------------------------------------------------------------------------------
/spec/dummy/app/views/pages/embedded.html.erb:
--------------------------------------------------------------------------------
1 | <%= include_ember_script_tags "my-app" %>
2 | <%= include_ember_stylesheet_tags "my-app" %>
3 |
--------------------------------------------------------------------------------
/spec/dummy/app/views/pages/include_index_empty_block.html.erb:
--------------------------------------------------------------------------------
1 | <%= render_ember_app "my-app" do %>
2 | <%= csrf_meta_tags %>
3 | <% end %>
4 |
--------------------------------------------------------------------------------
/spec/dummy/config/initializers/high_voltage.rb:
--------------------------------------------------------------------------------
1 | require "high_voltage"
2 |
3 | HighVoltage.configure do |config|
4 | config.layout = false
5 | end
6 |
--------------------------------------------------------------------------------
/app/views/ember_cli/ember/index.html.erb:
--------------------------------------------------------------------------------
1 | <%= render_ember_app params[:ember_app] do |head| %>
2 | <% head.append do %>
3 | <%= csrf_meta_tags %>
4 | <% end %>
5 | <% end %>
6 |
--------------------------------------------------------------------------------
/lib/ember_cli/engine.rb:
--------------------------------------------------------------------------------
1 | module EmberCli
2 | class Engine < Rails::Engine
3 | initializer "ember-cli-rails.setup" do
4 | require "ember_cli/route_helpers"
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/lib/generators/ember/init/USAGE:
--------------------------------------------------------------------------------
1 | Description:
2 | Generates `ember.rb` initializer.
3 |
4 | Example:
5 | rails generate ember:init
6 |
7 | This will create:
8 | config/initializers/ember.rb
9 |
--------------------------------------------------------------------------------
/spec/dummy/.gitignore:
--------------------------------------------------------------------------------
1 | !.keep
2 | *.DS_Store
3 | *.swo
4 | *.swp
5 | /.bundle
6 | /.env
7 | /.foreman
8 | /coverage/*
9 | /db/*.sqlite3
10 | /log/*
11 | /public/system
12 | /public/assets
13 | /tags
14 | /tmp/*
15 |
--------------------------------------------------------------------------------
/lib/ember_cli/trailing_slash_constraint.rb:
--------------------------------------------------------------------------------
1 | module EmberCli
2 | class TrailingSlashConstraint
3 | def matches?(request)
4 | !request.original_fullpath.to_s.split("?").first.end_with?("/")
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/spec/dummy/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Dummy
5 | <%= csrf_meta_tags %>
6 |
7 |
8 |
9 | <%= yield %>
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/lib/generators/ember/heroku/templates/package.json.erb:
--------------------------------------------------------------------------------
1 | {
2 | <% if EmberCli.any?(&:bower?) %>
3 | "dependencies": {
4 | "bower": "*"
5 | },
6 | <% end %>
7 | "cacheDirectories": <%= cache_directories.to_json %>
8 | }
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.bundle/
2 | /.yardoc
3 | /Gemfile.lock
4 | /_yardoc/
5 | /coverage/
6 | /doc/
7 | /pkg/
8 | /spec/reports/
9 | /tmp/
10 | *.bundle
11 | *.so
12 | *.o
13 | *.a
14 | *.gemfile.lock
15 | mkmf.log
16 | /log/
17 | spec/dummy/my-app/
18 |
--------------------------------------------------------------------------------
/spec/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 |
--------------------------------------------------------------------------------
/spec/dummy/app/views/pages/include_index_head_and_body.html.erb:
--------------------------------------------------------------------------------
1 | <%= render_ember_app "my-app" do |head, body| %>
2 | <% head.append do %>
3 | <%= csrf_meta_tags %>
4 | <% end %>
5 |
6 | <% body.append do %>
7 | Hello from Rails
8 | <% end %>
9 | <% end %>
10 |
--------------------------------------------------------------------------------
/lib/generators/ember/init/init_generator.rb:
--------------------------------------------------------------------------------
1 | module EmberCli
2 | class InitGenerator < Rails::Generators::Base
3 | source_root File.expand_path("../templates", __FILE__)
4 |
5 | namespace "ember:init"
6 |
7 | def copy_initializer_file
8 | copy_file "initializer.rb", "config/initializers/ember.rb"
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require "rubygems"
2 | require "bundler/setup"
3 | require "bundler/gem_tasks"
4 | require "rspec/core/rake_task"
5 |
6 | require "webdrivers"
7 | load "webdrivers/Rakefile"
8 |
9 | task(:default).clear
10 | task default: :spec
11 |
12 | if defined? RSpec
13 | task(:spec).clear
14 | RSpec::Core::RakeTask.new(:spec) do |t|
15 | t.verbose = false
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/app/helpers/ember_rails_helper.rb:
--------------------------------------------------------------------------------
1 | require "html_page/capture"
2 |
3 | module EmberRailsHelper
4 | def render_ember_app(name, &block)
5 | EmberCli[name].build
6 |
7 | markup_capturer = HtmlPage::Capture.new(self, &block)
8 |
9 | head, body = markup_capturer.capture
10 |
11 | render html: EmberCli[name].index_html(head: head, body: body).html_safe
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gemspec
4 |
5 | rails_version = ENV.fetch("RAILS_VERSION", "7.2")
6 |
7 | if rails_version == "main"
8 | rails_constraint = { github: "rails/rails" }
9 | else
10 | rails_constraint = "~> #{rails_version}.0"
11 | end
12 |
13 | gem "rails", rails_constraint
14 | gem "high_voltage", "~> 3.0.0"
15 | gem "webdrivers", "~> 5.0"
16 | gem "webrick"
17 |
--------------------------------------------------------------------------------
/spec/support/capybara.rb:
--------------------------------------------------------------------------------
1 | require "selenium/webdriver"
2 |
3 | Capybara.register_driver :headless_chrome do |app|
4 | Capybara::Selenium::Driver.new(
5 | app,
6 | browser: :chrome,
7 | options: Selenium::WebDriver::Chrome::Options.new(
8 | args: %w[--no-sandbox --headless],
9 | ),
10 | )
11 | end
12 |
13 | Capybara.server = :webrick
14 | Capybara.javascript_driver = :headless_chrome
15 |
--------------------------------------------------------------------------------
/lib/ember_cli/configuration.rb:
--------------------------------------------------------------------------------
1 | require "singleton"
2 | require "ember_cli/app"
3 |
4 | module EmberCli
5 | class Configuration
6 | include Singleton
7 |
8 | attr_accessor :watcher
9 |
10 | def app(name, **options)
11 | app = App.new(name, **options)
12 | apps.store(name, app)
13 | end
14 |
15 | def apps
16 | @apps ||= HashWithIndifferentAccess.new
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'rake' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('rake', 'rake')
17 |
--------------------------------------------------------------------------------
/spec/lib/ember-cli-rails_spec.rb:
--------------------------------------------------------------------------------
1 | describe EmberCli do
2 | describe ".any?" do
3 | it "delegates to the collection of applications" do
4 | allow(EmberCli).to receive(:apps).and_return(
5 | with_foo: { foo: true },
6 | witout_foo: { foo: false },
7 | )
8 |
9 | any_with_foo = EmberCli.any? { |options| options.fetch(:foo) }
10 |
11 | expect(any_with_foo).to be true
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/bin/rspec:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'rspec' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('rspec-core', 'rspec')
17 |
--------------------------------------------------------------------------------
/spec/requests/assets/my-app.js_spec.rb:
--------------------------------------------------------------------------------
1 | describe "GET assets/my-app.js" do
2 | it "responds with the 'Cache-Control' header from Rails" do
3 | build_ember_cli_assets
4 |
5 | get "/assets/my-app.js"
6 |
7 | expect(headers["Cache-Control"]).to eq(cache_for_five_minutes)
8 | end
9 |
10 | def build_ember_cli_assets
11 | EmberCli["my-app"].build
12 | end
13 |
14 | def cache_for_five_minutes
15 | Dummy::Application::CACHE_CONTROL_FIVE_MINUTES
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/app/controller/ember_cli/ember_controller.rb:
--------------------------------------------------------------------------------
1 | module EmberCli
2 | class EmberController < ::ApplicationController
3 | unless ancestors.include? ActionController::Base
4 | (
5 | ActionController::Base::MODULES -
6 | ActionController::API::MODULES
7 | ).each do |controller_module|
8 | include controller_module
9 | end
10 |
11 | helper EmberRailsHelper
12 | end
13 |
14 | def index
15 | render layout: false
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/spec/lib/ember_cli_spec.rb:
--------------------------------------------------------------------------------
1 | describe EmberCli do
2 | describe ".any?" do
3 | it "delegates to the collection of applications" do
4 | stub_apps(
5 | app_with_foo: { foo: true },
6 | app_without_foo: { foo: false },
7 | )
8 |
9 | any_with_foo = EmberCli.any? { |app| app.fetch(:foo) }
10 |
11 | expect(any_with_foo).to be true
12 | end
13 | end
14 |
15 | def stub_apps(applications)
16 | allow(EmberCli).to receive(:apps).and_return(applications)
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/lib/tasks/ember-cli.rake:
--------------------------------------------------------------------------------
1 | namespace :ember do
2 | desc "Runs `ember build` for each App"
3 | task compile: :install do
4 | EmberCli.compile!
5 | end
6 |
7 | desc "Runs `ember test` for each App"
8 | task test: :environment do
9 | EmberCli.test!
10 | end
11 |
12 | desc "Installs each EmberCLI app's dependencies"
13 | task install: :environment do
14 | EmberCli.install_dependencies!
15 | end
16 | end
17 |
18 | unless EmberCli.skip?
19 | task "assets:precompile" => "ember:compile"
20 | end
21 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | echo '-- Set up Ruby dependencies via Bundler'
6 | gem install bundler --conservative
7 | bundle check || bundle install
8 |
9 | bin/rake webdrivers:chromedriver:update
10 |
11 | # Add binstubs to PATH via export PATH=".git/safe/../../bin:$PATH" in ~/.zshenv
12 | mkdir -p .git/safe
13 |
14 | if ! command -v bower > /dev/null; then
15 | npm install -g bower
16 | fi
17 |
18 | bin/setup_ember spec/dummy/my-app
19 |
20 | echo '-- Install Ember dependencies'
21 | cd spec/dummy && bundle exec rake ember:install || true
22 |
--------------------------------------------------------------------------------
/lib/generators/ember/heroku/USAGE:
--------------------------------------------------------------------------------
1 | Description:
2 | Configures a project for deploying to Heroku.
3 |
4 | Once the generator is complete, execute the following:
5 |
6 | $ heroku buildpacks:clear
7 | $ heroku buildpacks:add --index 1 heroku/nodejs
8 | $ heroku buildpacks:add --index 2 heroku/ruby
9 | $ heroku config:unset SKIP_EMBER
10 |
11 | Example:
12 | rails generate ember:heroku
13 |
14 | This will install the following gems:
15 | rails_12factor
16 |
17 | This will create:
18 | package.json
19 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 | # Security Policy
3 |
4 | ## Supported Versions
5 |
6 | Only the the latest version of this project is supported at a given time. If
7 | you find a security issue with an older version, please try updating to the
8 | latest version first.
9 |
10 | If for some reason you can't update to the latest version, please let us know
11 | your reasons so that we can have a better understanding of your situation.
12 |
13 | ## Reporting a Vulnerability
14 |
15 | For security inquiries or vulnerability reports, send email to
16 | .
17 |
--------------------------------------------------------------------------------
/RELEASING.md:
--------------------------------------------------------------------------------
1 | # Releasing
2 |
3 | 1. Update version file accordingly.
4 | 1. Update `CHANGELOG.md` to reflect the changes since last release.
5 | 1. Commit changes.
6 | There shouldn't be code changes,
7 | and thus CI doesn't need to run,
8 | you can then add "[ci skip]" to the commit message.
9 | 1. Tag the release: `git tag vVERSION`
10 | 1. Push changes: `git push --tags`
11 | 1. Build and publish:
12 |
13 | ```bash
14 | gem build ember-cli-rails.gemspec
15 | gem push ember-cli-rails-*.gem
16 | ```
17 |
18 | 1. Announce the new release,
19 | making sure to say "thank you" to the contributors
20 | who helped shape this version!
21 |
--------------------------------------------------------------------------------
/lib/ember_cli/ember_constraint.rb:
--------------------------------------------------------------------------------
1 | module EmberCli
2 | class EmberConstraint
3 | def matches?(request)
4 | html_request?(request) &&
5 | !rails_info_request?(request) &&
6 | !rails_active_storage_request?(request)
7 | end
8 |
9 | private
10 |
11 | def rails_info_request?(request)
12 | request.fullpath.start_with?("/rails/info", "/rails/mailers")
13 | end
14 |
15 | def rails_active_storage_request?(request)
16 | request.fullpath.start_with?("/rails/active_storage")
17 | end
18 |
19 | def html_request?(request)
20 | request.format.html?
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | require "codeclimate-test-reporter"
2 | CodeClimate::TestReporter.start
3 |
4 | ENV["RAILS_ENV"] = "test"
5 |
6 | require "dummy/application"
7 | require "rspec/rails"
8 |
9 | Dummy::Application.initialize!
10 |
11 | Dir["spec/support/**/*.rb"].sort.each { |file| require "./#{file}" }
12 |
13 | RSpec.configure do |config|
14 | config.expect_with :rspec do |expectations|
15 | expectations.syntax = :expect
16 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true
17 | end
18 |
19 | config.mock_with :rspec do |mocks|
20 | mocks.syntax = :expect
21 | mocks.verify_partial_doubles = true
22 | end
23 |
24 | config.infer_spec_type_from_file_location!
25 | config.order = :random
26 | end
27 |
--------------------------------------------------------------------------------
/lib/ember_cli/helpers.rb:
--------------------------------------------------------------------------------
1 | module EmberCli
2 | module Helpers
3 | extend self
4 |
5 | def which(cmd)
6 | exts = ENV.fetch("PATHEXT", ";").split(";", -1).uniq
7 |
8 | ENV.fetch("PATH").split(File::PATH_SEPARATOR).each do |path|
9 | exts.each do |ext|
10 | exe = File.join(path, "#{cmd}#{ext}")
11 | return exe if File.executable?(exe) && !File.directory?(exe)
12 | end
13 | end
14 |
15 | nil
16 | end
17 |
18 | def current_environment
19 | ENV.fetch("EMBER_ENV") { default_environment }
20 | end
21 |
22 | private
23 |
24 | def default_environment
25 | if Rails.env.match(/test|development/)
26 | Rails.env
27 | else
28 | "production"
29 | end
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/spec/dummy/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | with_options controller: "high_voltage/pages", action: "show" do |app|
3 | app.mount_ember_app(
4 | "my-app",
5 | to: "/no-block",
6 | id: "include_index",
7 | as: "include_index",
8 | )
9 |
10 | app.mount_ember_app(
11 | "my-app",
12 | to: "/empty-block",
13 | id: "include_index_empty_block",
14 | as: "include_index_empty_block",
15 | )
16 |
17 | app.mount_ember_app(
18 | "my-app",
19 | to: "/head-and-body-block",
20 | id: "include_index_head_and_body",
21 | as: "include_index_head_and_body",
22 | )
23 |
24 | app.mount_ember_app(
25 | "my-app",
26 | to: "/asset-helpers",
27 | id: "embedded",
28 | as: "embedded",
29 | )
30 | end
31 |
32 | mount_ember_app(
33 | "my-app",
34 | to: "/",
35 | as: "default",
36 | )
37 | end
38 |
--------------------------------------------------------------------------------
/bin/setup_ember:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | setup_ember() {
6 | local target="${1-spec/dummy/my-app}"
7 |
8 | if ! [ -d $target ]; then
9 | git clone -b 'v4.0.0' https://github.com/ember-cli/ember-new-output.git $target
10 |
11 | echo '-- Make router catchall routes'
12 | sed -i -e "s/'auto'/'hash'/" $target/config/environment.js
13 |
14 | echo '-- Add an image to a template'
15 | cp spec/fixtures/application.hbs $target/app/templates/application.hbs
16 |
17 | mkdir -p $target/public/assets
18 | cp spec/fixtures/logo.png $target/public/assets
19 |
20 | echo '-- Install ember-cli-rails-addon'
21 | cd $target &&
22 | npm install --save-dev ember-cli-rails-addon@rondale-sc/ember-cli-rails-addon
23 |
24 | if [ -f "$target/bower.json" ]; then
25 | echo '-- Install Bower dependencies'
26 | cd $target && bower install
27 | fi
28 |
29 | echo '-- Successfully setup Ember'
30 | fi
31 | }
32 |
33 | setup_ember
34 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **Which operating system and version is the project developed on?**
2 |
3 | **Which version of [`ruby`](https://www.ruby-lang.org/) is the project developed on?**
4 |
5 | **Which version of [`npm`](https://www.npmjs.com/) is the project developed on?**
6 |
7 | **Which version of [`ember-cli`](http://ember-cli.com/) is the project developed on?**
8 |
9 | **What is the [`rails`](https://github.com/rails/rails) version?**
10 |
11 | **What is the [`ember-cli-rails`](https://github.com/tricknotes/ember-cli-rails) version (from `Gemfile`)?**
12 |
13 | **What is the [`ember-cli-rails-addon`](https://github.com/rondale-sc/ember-cli-rails-addon/) version (from `package.json`)?**
14 |
15 | **Is your application server [multi-threaded](https://github.com/tricknotes/ember-cli-rails/commit/ef0a49546a8c2e5fb0a298ba455fba97289065a1)
16 | (such as `puma` and `unicorn`) or is it multi-process (such as thin and webrick)?**
17 |
18 | **What are the contents of `config/initializers/ember.rb`?**
19 |
20 | **What are the contents of the Rails' view that renders the Ember application?**
21 |
22 | **How are the EmberCLI-related routes defined?**
23 |
24 | **How is the application deployed?**
25 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2024 Ryunosuke Sato
2 | Copyright (c) 2015 Sean Doyle and thoughtbot, inc.
3 | Copyright (c) 2014 Pavel Pravosud
4 |
5 | MIT License
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining
8 | a copy of this software and associated documentation files (the
9 | "Software"), to deal in the Software without restriction, including
10 | without limitation the rights to use, copy, modify, merge, publish,
11 | distribute, sublicense, and/or sell copies of the Software, and to
12 | permit persons to whom the Software is furnished to do so, subject to
13 | the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be
16 | included in all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: "CI Tests"
2 |
3 | on:
4 | push:
5 | branches: "main"
6 | pull_request:
7 | branches: "*"
8 |
9 | jobs:
10 | build:
11 | runs-on: "ubuntu-latest"
12 |
13 | strategy:
14 | fail-fast: false
15 | matrix:
16 | ruby: ["3.2", "3.3"]
17 | rails: ["7.0", "7.1", "7.2"]
18 | include:
19 | - ruby: "3.3"
20 | rails: "8.0"
21 | - ruby: "3.4"
22 | rails: "8.0"
23 | - ruby: "3.4"
24 | rails: "main"
25 |
26 | env:
27 | RAILS_ENV: "test"
28 | RAILS_VERSION: "${{ matrix.rails }}"
29 |
30 | steps:
31 | - uses: "actions/checkout@v4"
32 |
33 | - name: "Install NodeJS"
34 | uses: "actions/setup-node@v4"
35 | with:
36 | node-version: "20.x"
37 |
38 | - name: "Install Ruby ${{ matrix.ruby }}"
39 | uses: "ruby/setup-ruby@v1"
40 | with:
41 | ruby-version: "${{ matrix.ruby }}"
42 | bundler-cache: true
43 |
44 | - name: "Install Webdriver"
45 | run: |
46 | sudo apt-get update
47 | sudo apt-get -yqq install chromium-browser
48 |
49 | - name: "Run Setup"
50 | run: |
51 | bin/setup
52 |
53 | - name: "Run Tests"
54 | run: |
55 | bin/rake
56 |
--------------------------------------------------------------------------------
/lib/ember_cli/route_helpers.rb:
--------------------------------------------------------------------------------
1 | require "ember_cli/ember_constraint"
2 | require "ember_cli/trailing_slash_constraint"
3 |
4 | module ActionDispatch
5 | module Routing
6 | class Mapper
7 | def mount_ember_app(app_name, to:, **options)
8 | routing_options = options.deep_merge(
9 | defaults: { ember_app: app_name },
10 | )
11 |
12 | routing_options.reverse_merge!(
13 | controller: "ember_cli/ember",
14 | action: "index",
15 | format: :html,
16 | )
17 |
18 | scope constraints: ::EmberCli::EmberConstraint.new do
19 | redirect_if_missing_trailing_slash = {
20 | constraints: EmberCli::TrailingSlashConstraint.new,
21 | to: redirect(-> (_, request) {
22 | File.join(request.path, "/?#{request.query_parameters.to_query}")
23 | }),
24 | }
25 |
26 | get(to, **redirect_if_missing_trailing_slash)
27 | get(File.join(to, "(*rest)"), **routing_options)
28 | end
29 |
30 | mount_ember_assets(app_name, to: to)
31 | end
32 |
33 | def mount_ember_assets(app_name, to: "/")
34 | app = ::EmberCli[app_name]
35 |
36 | if app.mountable?
37 | mount app.to_rack, at: to
38 | end
39 | end
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/lib/ember_cli/runner.rb:
--------------------------------------------------------------------------------
1 | require "open3"
2 |
3 | module EmberCli
4 | class Runner
5 | def initialize(out:, err:, env: {}, options: {})
6 | @env = env
7 | @output_streams = Array(out)
8 | @error_streams = Array(err)
9 | @options = options
10 | @threads = []
11 | end
12 |
13 | def run(command)
14 | Open3.popen3(env, command, options) do |stdin, stdout, stderr, process|
15 | stdin.close
16 |
17 | threads << redirect_stream_in_thread(stdout, write_to: output_streams)
18 | threads << redirect_stream_in_thread(stderr, write_to: error_streams)
19 |
20 | threads.each(&:join)
21 | process.value
22 | end
23 | end
24 |
25 | def run!(command)
26 | run(command).tap do |status|
27 | unless status.success?
28 | exit status.exitstatus
29 | end
30 | end
31 | end
32 |
33 | protected
34 |
35 | attr_reader :env, :error_streams, :options, :output_streams, :threads
36 |
37 | private
38 |
39 | def redirect_stream_in_thread(stream, write_to:)
40 | Thread.new do
41 | Thread.current.abort_on_exception = true
42 |
43 | while line = stream.gets
44 | write_to.each { |redirection_stream| redirection_stream.puts(line) }
45 | end
46 | end
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/spec/dummy/application.rb:
--------------------------------------------------------------------------------
1 | require "rails"
2 |
3 | require "action_controller/railtie"
4 | require "action_view/railtie"
5 |
6 | Bundler.require(*Rails.groups)
7 |
8 | module Dummy
9 | class Application < Rails::Application
10 | CACHE_CONTROL_FIVE_MINUTES = "public, max-age=300".freeze
11 |
12 | config.root = File.expand_path("..", __FILE__).freeze
13 | config.eager_load = false
14 |
15 | # Show full error reports and disable caching.
16 | config.consider_all_requests_local = true
17 | config.action_controller.perform_caching = false
18 |
19 | # Raise exceptions instead of rendering exception templates.
20 | config.action_dispatch.show_exceptions = false
21 |
22 | # Randomize the order test cases are executed.
23 | config.active_support.test_order = :random
24 |
25 | # Print deprecation notices to the stderr.
26 | config.active_support.deprecation = :stderr
27 |
28 | config.public_file_server.enabled = true
29 | config.public_file_server.headers = {
30 | "cache-control" => CACHE_CONTROL_FIVE_MINUTES
31 | }
32 |
33 | config.secret_token = "SECRET_TOKEN_IS_MIN_30_CHARS_LONG"
34 | config.secret_key_base = "SECRET_KEY_BASE"
35 |
36 | config.active_support.to_time_preserves_timezone = :zone
37 |
38 | def require_environment!
39 | initialize!
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/ember-cli-rails.gemspec:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | lib = File.expand_path("../lib", __FILE__)
3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4 | require "ember_cli/version"
5 |
6 | Gem::Specification.new do |spec|
7 | spec.name = "ember-cli-rails"
8 | spec.version = EmberCli::VERSION.dup
9 | spec.authors = ["Pavel Pravosud", "Jonathan Jackson", "Sean Doyle", "Ryunosuke Sato"]
10 | spec.email = ["pavel@pravosud.com", "jonathan.jackson1@me.com", "sean.p.doyle24@gmail.com", "tricknotes.rs@gmail.com"]
11 | spec.summary = "Integration between Ember CLI and Rails"
12 | spec.homepage = "https://github.com/tricknotes/ember-cli-rails"
13 | spec.license = "MIT"
14 | spec.files = Dir["README.md", "CHANGELOG.md", "LICENSE.txt", "{lib,app,config}/**/*"]
15 |
16 | spec.required_ruby_version = ">= 2.5.0"
17 |
18 | spec.add_dependency "ember-cli-rails-assets", ">= 0.6.2", "< 1.0"
19 | spec.add_dependency "railties", ">= 4.2"
20 | spec.add_dependency "rack", ">= 2.1", "< 4.0"
21 | spec.add_dependency "terrapin", "~> 0.6.0"
22 | spec.add_dependency "html_page", "~> 0.1.0"
23 |
24 | spec.add_development_dependency "generator_spec", "~> 0.9.0"
25 | spec.add_development_dependency "rspec-rails", ">= 3.6.0", "< 7.0"
26 |
27 | spec.add_development_dependency "capybara-selenium"
28 | spec.add_development_dependency "codeclimate-test-reporter", "~> 0.6.0"
29 | end
30 |
--------------------------------------------------------------------------------
/lib/generators/ember/heroku/heroku_generator.rb:
--------------------------------------------------------------------------------
1 | module EmberCli
2 | class HerokuGenerator < Rails::Generators::Base
3 | source_root File.expand_path("../templates", __FILE__)
4 |
5 | namespace "ember:heroku"
6 |
7 | def copy_package_json_file
8 | template "package.json.erb", "package.json"
9 | end
10 |
11 | def identify_as_yarn_project
12 | if EmberCli.any?(&:yarn_enabled?)
13 | template "yarn.lock.erb", "yarn.lock"
14 | end
15 | end
16 |
17 | def inject_12factor_gem
18 | gem "rails_12factor", group: [:staging, :production]
19 | end
20 |
21 | private
22 |
23 | def cache_directories
24 | all_cached_directories.map do |cached_directory|
25 | cached_directory.relative_path_from(Rails.root).to_s
26 | end
27 | end
28 |
29 | def all_cached_directories
30 | app_specific_cached_directories + project_root_cached_directories
31 | end
32 |
33 | def app_specific_cached_directories
34 | apps.flat_map(&:cached_directories)
35 | end
36 |
37 | def project_root_cached_directories
38 | [Rails.root.join("node_modules")]
39 | end
40 |
41 | def app_paths
42 | EmberCli.apps.values.map do |app|
43 | app.root_path.relative_path_from(Rails.root)
44 | end
45 | end
46 |
47 | def apps
48 | EmberCli.apps.values
49 | end
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/lib/ember_cli/command.rb:
--------------------------------------------------------------------------------
1 | require "terrapin"
2 |
3 | module EmberCli
4 | class Command
5 | def initialize(paths:, options: {})
6 | @paths = paths
7 | @options = options
8 | end
9 |
10 | def test
11 | line = Terrapin::CommandLine.new(paths.ember, "test --environment test")
12 |
13 | line.command
14 | end
15 |
16 | def build(watch: false)
17 | ember_build(watch: watch)
18 | end
19 |
20 | private
21 |
22 | attr_reader :options, :paths
23 |
24 | def process_watcher
25 | options.fetch(:watcher) { EmberCli.configuration.watcher }
26 | end
27 |
28 | def silent?
29 | options.fetch(:silent) { false }
30 | end
31 |
32 | def ember_build(watch: false)
33 | line = Terrapin::CommandLine.new(paths.ember, [
34 | "build",
35 | ("--watch" if watch),
36 | ("--watcher :watcher" if process_watcher),
37 | ("--silent" if silent?),
38 | "--environment :environment",
39 | "--output-path :output_path",
40 | ].compact.join(" "))
41 |
42 | line.command(
43 | environment: build_environment,
44 | output_path: paths.dist,
45 | watcher: process_watcher,
46 | )
47 | end
48 |
49 | def build_environment
50 | if EmberCli.env == "production"
51 | "production"
52 | else
53 | "development"
54 | end
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/lib/ember_cli.rb:
--------------------------------------------------------------------------------
1 | require "fileutils"
2 | require "ember-cli-rails-assets"
3 | require "ember_cli/engine"
4 | require "ember_cli/configuration"
5 | require "ember_cli/helpers"
6 | require "ember_cli/errors"
7 |
8 | module EmberCli
9 | extend self
10 |
11 | def configure
12 | yield configuration
13 | end
14 |
15 | def configuration
16 | Configuration.instance
17 | end
18 |
19 | def app(name)
20 | apps.fetch(name) do
21 | fail KeyError, "#{name.inspect} app is not defined"
22 | end
23 | end
24 | alias_method :[], :app
25 |
26 | def apps
27 | configuration.apps
28 | end
29 |
30 | def build(name)
31 | app(name).build
32 | end
33 |
34 | def any?(*arguments, &block)
35 | apps.values.any?(*arguments, &block)
36 | end
37 |
38 | def skip?
39 | ENV["SKIP_EMBER"].present?
40 | end
41 |
42 | def install_dependencies!
43 | each_app(&:install_dependencies)
44 | end
45 |
46 | def test!
47 | each_app(&:test)
48 | end
49 |
50 | def compile!
51 | cleanup!
52 | each_app(&:compile)
53 | end
54 |
55 | def root
56 | @root ||= Rails.root.join("tmp", "ember-cli").tap(&:mkpath)
57 | end
58 |
59 | def env
60 | @env ||= Helpers.current_environment
61 | end
62 |
63 | private
64 |
65 | def cleanup!
66 | root.children.each { |tmp_file| FileUtils.rm_rf(tmp_file) }
67 | end
68 |
69 | def each_app
70 | apps.each { |_, app| yield app }
71 | end
72 | end
73 |
--------------------------------------------------------------------------------
/spec/lib/ember_cli/deploy/file_spec.rb:
--------------------------------------------------------------------------------
1 | require "tmpdir"
2 | require "ember_cli/deploy/file"
3 |
4 | describe EmberCli::Deploy::File do
5 | describe "#index_html" do
6 | context "when the file is missing" do
7 | it "raises a BuildError" do
8 | deploy = EmberCli::Deploy::File.new(build_app)
9 |
10 | expect { deploy.index_html }.to raise_error(EmberCli::BuildError)
11 | end
12 | end
13 |
14 | it "returns the contents of the app's `index_file`" do
15 | app = build_app
16 | create_index(app.dist_path, "")
17 | deploy = EmberCli::Deploy::File.new(app)
18 |
19 | index_html = deploy.index_html
20 |
21 | expect(index_html).to eq("")
22 | end
23 | end
24 |
25 | describe "#mountable?" do
26 | it "returns true" do
27 | deploy = EmberCli::Deploy::File.new(build_app)
28 |
29 | mountable = deploy.mountable?
30 |
31 | expect(mountable).to be true
32 | end
33 | end
34 |
35 | describe "#to_rack" do
36 | it "creates a Rack::Files instance" do
37 | deploy = EmberCli::Deploy::File.new(build_app)
38 |
39 | rack_app = deploy.to_rack
40 |
41 | expect(rack_app).to respond_to(:call)
42 | end
43 | end
44 |
45 | def create_index(directory, contents)
46 | directory.join("index.html").write(contents)
47 | end
48 |
49 | def build_app
50 | tmpdir = Pathname.new(Dir.mktmpdir)
51 |
52 | double(dist_path: tmpdir, check_for_errors!: false)
53 | end
54 | end
55 |
--------------------------------------------------------------------------------
/lib/ember_cli/deploy/file.rb:
--------------------------------------------------------------------------------
1 | require "rack"
2 | require "ember_cli/errors"
3 |
4 | module EmberCli
5 | module Deploy
6 | class File
7 | def initialize(app)
8 | @app = app
9 | end
10 |
11 | def mountable?
12 | true
13 | end
14 |
15 | def to_rack
16 | Rack::Files.new(app.dist_path.to_s, rack_headers)
17 | end
18 |
19 | def index_html
20 | if index_file.exist?
21 | index_file.read
22 | else
23 | check_for_error_and_raise!
24 | end
25 | end
26 |
27 | private
28 |
29 | attr_reader :app
30 |
31 | def rack_headers
32 | config = Rails.configuration
33 |
34 | if config.respond_to?(:public_file_server) &&
35 | config.public_file_server && config.public_file_server.headers
36 | # Rails 5.
37 | config.public_file_server.headers
38 | elsif config.respond_to?(:static_cache_control)
39 | # Rails 4.2 and below.
40 | {
41 | "Cache-Control" => Rails.configuration.static_cache_control,
42 | }
43 | else
44 | # No specification.
45 | {}
46 | end
47 | end
48 |
49 | def check_for_error_and_raise!
50 | app.check_for_errors!
51 |
52 | raise BuildError.new <<-MSG
53 | EmberCLI failed to generate an `index.html` file.
54 | MSG
55 | end
56 |
57 | def index_file
58 | app.dist_path.join("index.html")
59 | end
60 | end
61 | end
62 | end
63 |
--------------------------------------------------------------------------------
/UPGRADING.md:
--------------------------------------------------------------------------------
1 | # Ruby support
2 |
3 | According to [these release notes][latest-eol], Ruby versions prior to `2.5.x`
4 | has been end-of-lifed.
5 |
6 | Additionally, this codebase makes use of [(required) keyword arguments][kwargs].
7 |
8 | From `ember-cli-rails@0.4.0` and on, we will no longer support versions of Ruby
9 | prior to `2.1.0`.
10 |
11 | `ember-cli-rails@0.8.0` adds support for Rails 5, which depends on `rack@2.0.x`,
12 | which **requires** Ruby `2.2.2` or greater.
13 |
14 | From `ember-cli-rails@0.8.0` and on, we will no longer support versions of Ruby
15 | prior to `2.2.2`.
16 |
17 | From `ember-cli-rails@0.12.0` and on, we will no longer support versions of Ruby
18 | prior to `2.5.x`.
19 |
20 | To use `ember-cli-rails` with older versions of Ruby, try the `0.3.x` series.
21 |
22 | [kwargs]: https://robots.thoughtbot.com/ruby-2-keyword-arguments
23 | [latest-eol]: https://www.ruby-lang.org/en/news/2020/04/05/support-of-ruby-2-4-has-ended/
24 |
25 | # Rails support
26 |
27 | According to the [Rails Maintenance Policy][version-policy], Rails versions
28 | prior to `5.2.x` have been end-of-lifed. Additionally, the `4.0.x` series no
29 | longer receives bug fixes of any sort.
30 |
31 | From `ember-cli-rails@0.4.0` and on, we will no longer support versions of Rails
32 | prior to `3.2.0`, nor will we support the `4.0.x` series of releases.
33 |
34 | From `ember-cli-rails@0.12.0` and on, we will no longer support versions of
35 | Rails prior to `5.2.0`.
36 |
37 | To use `ember-cli-rails` with older versions of Rails, try the `0.3.x` series.
38 |
39 | [version-policy]: http://guides.rubyonrails.org/maintenance_policy.html
40 |
--------------------------------------------------------------------------------
/spec/lib/ember_cli/helpers_spec.rb:
--------------------------------------------------------------------------------
1 | require "ember_cli/helpers"
2 |
3 | describe EmberCli::Helpers do
4 | describe ".current_environment" do
5 | context "when EMBER_ENV is set" do
6 | it "returns the value of EMBER_ENV" do
7 | stub_env("EMBER_ENV" => "staging")
8 |
9 | current_environment = EmberCli::Helpers.current_environment
10 |
11 | expect(current_environment).to eq "staging"
12 | end
13 | end
14 |
15 | context "when test" do
16 | it "returns test" do
17 | stub_rails_env("test")
18 |
19 | current_environment = EmberCli::Helpers.current_environment
20 |
21 | expect(current_environment).to eq "test"
22 | end
23 | end
24 |
25 | context "when development" do
26 | it "returns development" do
27 | stub_rails_env("development")
28 |
29 | current_environment = EmberCli::Helpers.current_environment
30 |
31 | expect(current_environment).to eq "development"
32 | end
33 | end
34 |
35 | context "when anything else" do
36 | it "returns production" do
37 | stub_rails_env("staging")
38 |
39 | current_environment = EmberCli::Helpers.current_environment
40 |
41 | expect(current_environment).to eq "production"
42 | end
43 | end
44 | end
45 |
46 | def stub_env(key_to_value)
47 | allow(ENV).
48 | to receive(:fetch).
49 | with(key_to_value.keys.first).
50 | and_return(key_to_value.values.first)
51 | end
52 |
53 | def stub_rails_env(env)
54 | allow(Rails).
55 | to receive(:env).
56 | and_return(env.to_s)
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Reporting an Issue
2 |
3 | When reporting an issue, please fill out the provided
4 | [GitHub issue template][template] to the best of your ability.
5 |
6 | This template helps this project's maintainers understand and respond to issues
7 | in a timely manner.
8 |
9 | Issues that don't attempt to answer the questions asked in the issue template
10 | will likely be closed until additional information is provided.
11 |
12 | [template]: .github/ISSUE_TEMPLATE.md
13 |
14 | # Contributing
15 |
16 | We love pull requests from everyone.
17 | By participating in this project,
18 | you agree to abide by the thoughtbot [code of conduct].
19 |
20 | [code of conduct]: https://thoughtbot.com/open-source-code-of-conduct
21 |
22 | We expect everyone to follow the code of conduct
23 | anywhere in thoughtbot's project codebases,
24 | issue trackers, chatrooms, and mailing lists.
25 |
26 | ## Setup
27 |
28 | After cloning the repository, execute the setup script:
29 |
30 | $ bin/setup
31 |
32 | Make sure the tests pass:
33 |
34 | $ bin/rake
35 |
36 | Make your change, with new passing tests. Follow the [style guide][style].
37 |
38 | [style]: https://github.com/thoughtbot/guides/tree/master/style
39 |
40 | Fork the repository and push your changes to your fork.
41 |
42 | Write a [good commit message][commit]. Submit a pull request.
43 |
44 | [commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
45 |
46 | Others will give constructive feedback.
47 | This is a time for discussion and improvements,
48 | and making the necessary changes will be required before we can
49 | merge the contribution.
50 |
--------------------------------------------------------------------------------
/spec/lib/ember_cli/ember_constraint_spec.rb:
--------------------------------------------------------------------------------
1 | require "ember_cli/ember_constraint"
2 |
3 | describe EmberCli::EmberConstraint do
4 | describe "#matches?" do
5 | context %{when the format is "html"} do
6 | context "when the request path is for a Rails active storage file" do
7 | it "returns a falsey value" do
8 | constraint = EmberCli::EmberConstraint.new
9 | request = build_html_request("/rails/active_storage")
10 |
11 | expect(constraint.matches?(request)).to be_falsey
12 | end
13 | end
14 |
15 | context "when the request path is for a Rails info page" do
16 | it "returns a falsey value" do
17 | constraint = EmberCli::EmberConstraint.new
18 | request = build_html_request("/rails/info")
19 |
20 | expect(constraint.matches?(request)).to be_falsey
21 | end
22 | end
23 |
24 | context "when the request path is not for a Rails info page" do
25 | it "returns a truthy value" do
26 | constraint = EmberCli::EmberConstraint.new
27 | request = build_html_request("/foo")
28 |
29 | expect(constraint.matches?(request)).to be_truthy
30 | end
31 | end
32 | end
33 |
34 | context %{when the format isn't "html"} do
35 | it "return false" do
36 | constraint = EmberCli::EmberConstraint.new
37 | request = build_json_request
38 |
39 | expect(constraint.matches?(request)).to be_falsey
40 | end
41 | end
42 | end
43 |
44 | def build_request(format:, fullpath: :ignored)
45 | double(format: format ? Mime::Type.new(format) : nil, fullpath: fullpath)
46 | end
47 |
48 | def build_html_request(fullpath)
49 | build_request(format: "text/html", fullpath: fullpath)
50 | end
51 |
52 | def build_json_request
53 | build_request(format: "application/json")
54 | end
55 | end
56 |
--------------------------------------------------------------------------------
/lib/ember_cli/build_monitor.rb:
--------------------------------------------------------------------------------
1 | module EmberCli
2 | class BuildMonitor
3 | def initialize(name, paths)
4 | @name = name
5 | @paths = paths
6 | end
7 |
8 | def check!
9 | if has_build_errors?
10 | raise_build_error!
11 | end
12 |
13 | true
14 | end
15 |
16 | def reset
17 | if error_file_exists?
18 | error_file.delete
19 | end
20 | end
21 |
22 | def wait!
23 | loop do
24 | check!
25 | break if complete?
26 | sleep 0.1
27 | end
28 | end
29 |
30 | private
31 |
32 | attr_reader :name, :paths
33 |
34 | def complete?
35 | !paths.lockfile.exist?
36 | end
37 |
38 | def error_file_exists?
39 | error_file.exist? && error_file.size?
40 | end
41 |
42 | def build_errors
43 | error_lines.
44 | reject { |line| is_blank_or_backtrace?(line) }.
45 | reject { |line| is_deprecation_warning?(line) }.
46 | reject { |line| is_building_notice?(line) }
47 | end
48 |
49 | def has_build_errors?
50 | build_errors.any?
51 | end
52 |
53 | def is_blank_or_backtrace?(line)
54 | line =~ /(^\s*$|^\s{4}at .+$)/
55 | end
56 |
57 | def is_deprecation_warning?(line)
58 | line =~ /^(\e[^\s]+)?DEPRECATION:/
59 | end
60 |
61 | def is_building_notice?(line)
62 | line =~ /^(\e[^\s]+)?.\s(\e[^\s]+)?Building/
63 | end
64 |
65 | def error_lines
66 | if error_file_exists?
67 | error_file.readlines
68 | else
69 | [""]
70 | end
71 | end
72 |
73 | def error_file
74 | paths.build_error_file
75 | end
76 |
77 | def raise_build_error!
78 | backtrace = build_errors.first
79 | message = "#{name.inspect} has failed to build: #{backtrace}"
80 |
81 | error = BuildError.new(message)
82 | error.set_backtrace(backtrace)
83 |
84 | fail error
85 | end
86 | end
87 | end
88 |
--------------------------------------------------------------------------------
/spec/lib/ember_cli/runner_spec.rb:
--------------------------------------------------------------------------------
1 | require "ember_cli/runner"
2 |
3 | describe EmberCli::Runner do
4 | describe "#run!" do
5 | context "when the command fails" do
6 | it "writes output to `out` streams" do
7 | stdout = StringIO.new
8 | logfile = StringIO.new
9 | runner = EmberCli::Runner.new(
10 | err: [],
11 | out: [stdout, logfile],
12 | )
13 |
14 | expect { runner.run!(command_with_error(out: "out")) }.
15 | to raise_error(SystemExit)
16 |
17 | expect(split_output_from_stream(stdout)).to eq(%w[out out])
18 | expect(split_output_from_stream(logfile)).to eq(%w[out out])
19 | end
20 |
21 | it "writes errors to `err` streams" do
22 | stderr = StringIO.new
23 | logfile = StringIO.new
24 | runner = EmberCli::Runner.new(
25 | err: [stderr, logfile],
26 | out: [],
27 | )
28 |
29 | expect { runner.run!(command_with_error(err: "err")) }.
30 | to raise_error(SystemExit)
31 |
32 | expect(split_output_from_stream(stderr)).to eq(%w[err err])
33 | expect(split_output_from_stream(logfile)).to eq(%w[err err])
34 | end
35 | end
36 |
37 | it "executes the command" do
38 | out = StringIO.new
39 | err = StringIO.new
40 | runner = EmberCli::Runner.new(err: [err], out: [out])
41 |
42 | status = runner.run!(command("out"))
43 |
44 | [err, out].each(&:rewind)
45 |
46 | expect(status).to be_success
47 | expect(split_output_from_stream(err)).to be_empty
48 | expect(split_output_from_stream(out)).to eq(%w[out])
49 | end
50 |
51 | def split_output_from_stream(stream)
52 | stream.rewind
53 |
54 | stream.read.split
55 | end
56 |
57 | def command(output)
58 | "echo '#{output}'"
59 | end
60 |
61 | def command_with_error(out: "", err: "")
62 | [
63 | "echo '#{out}'",
64 | "echo '#{err}' > /dev/stderr",
65 | "echo '#{out}'",
66 | "echo '#{err}' > /dev/stderr",
67 | "exit 1",
68 | ].join("; ")
69 | end
70 | end
71 | end
72 |
--------------------------------------------------------------------------------
/spec/features/user_views_ember_app_spec.rb:
--------------------------------------------------------------------------------
1 | feature "User views ember app", :js do
2 | scenario "using route helper" do
3 | visit default_path
4 |
5 | expect(page).to have_client_side_asset
6 | expect(page).to have_javascript_rendered_text
7 | expect(page).to have_csrf_tags
8 | end
9 |
10 | context "using custom controller" do
11 | scenario "rendering with asset helpers" do
12 | visit embedded_path
13 |
14 | expect(page).to have_client_side_asset
15 | expect(page).to have_javascript_rendered_text
16 | expect(page).to have_no_csrf_tags
17 | end
18 |
19 | scenario "rendering with index helper" do
20 | visit include_index_path
21 |
22 | expect(page).to have_javascript_rendered_text
23 | expect(page).to have_no_csrf_tags
24 |
25 | visit include_index_empty_block_path
26 |
27 | expect(page).to have_javascript_rendered_text
28 | expect(page).to have_csrf_tags
29 |
30 | visit include_index_head_and_body_path
31 |
32 | expect(page).to have_javascript_rendered_text
33 | expect(page).to have_csrf_tags
34 | expect(page).to have_rails_injected_text
35 | end
36 | end
37 |
38 | scenario "is redirected with trailing slash", js: false do
39 | expect(embedded_path).to eq("/asset-helpers")
40 |
41 | visit embedded_path
42 |
43 | expect(current_path).to eq("/asset-helpers/")
44 | end
45 |
46 | scenario "is redirected with trailing slash with query params", js: false do
47 | expect(embedded_path(query: "foo")).to eq("/asset-helpers?query=foo")
48 |
49 | visit embedded_path(query: "foo")
50 |
51 | expect(page).to have_current_path("/asset-helpers/?query=foo")
52 | end
53 |
54 | scenario "is not redirected with trailing slash with params", js: false do
55 | expect(embedded_path(query: "foo")).to eq("/asset-helpers?query=foo")
56 |
57 | visit "/asset-helpers/?query=foo"
58 |
59 | expect(page).to have_current_path("/asset-helpers/?query=foo")
60 | end
61 |
62 | def have_client_side_asset
63 | have_css %{img[src*="logo.png"]}
64 | end
65 |
66 | def have_rails_injected_text
67 | have_text "Hello from Rails"
68 | end
69 |
70 | def have_javascript_rendered_text
71 | have_text("Welcome to Ember")
72 | end
73 |
74 | def have_no_csrf_tags
75 | have_no_css("meta[name=csrf-param]", visible: false).
76 | and have_no_css("meta[name=csrf-token]", visible: false)
77 | end
78 |
79 | def have_csrf_tags
80 | have_css("meta[name=csrf-param]", visible: false).
81 | and have_css("meta[name=csrf-token]", visible: false)
82 | end
83 | end
84 |
--------------------------------------------------------------------------------
/lib/ember_cli/shell.rb:
--------------------------------------------------------------------------------
1 | require "ember_cli/command"
2 | require "ember_cli/runner"
3 |
4 | module EmberCli
5 | class Shell
6 | def initialize(paths:, env: {}, options: {})
7 | @paths = paths
8 | @env = env
9 | @ember = Command.new(
10 | paths: paths,
11 | options: options,
12 | )
13 | @on_exit ||= at_exit { stop }
14 | end
15 |
16 | def compile
17 | run! ember.build
18 | end
19 |
20 | def build_and_watch
21 | unless running?
22 | lock_buildfile
23 | self.pid = spawn ember.build(watch: true)
24 | detach
25 | end
26 | end
27 |
28 | def stop
29 | if pid.present?
30 | Process.kill(:INT, pid)
31 | self.pid = nil
32 | end
33 | end
34 |
35 | def install
36 | if paths.gemfile.exist?
37 | run! "#{paths.bundler} install"
38 | end
39 |
40 | if invalid_ember_dependencies?
41 | clean_ember_dependencies!
42 | end
43 |
44 | if paths.yarn
45 | run! "#{paths.yarn} install"
46 | else
47 | run! "#{paths.npm} prune && #{paths.npm} install"
48 | end
49 |
50 | if paths.bower_json.exist?
51 | run! "#{paths.bower} prune && #{paths.bower} install"
52 | end
53 | end
54 |
55 | def test
56 | run! ember.test
57 | end
58 |
59 | private
60 |
61 | attr_accessor :pid
62 | attr_reader :ember, :env, :options, :paths
63 |
64 | delegate :run, :run!, to: :runner
65 |
66 | def invalid_ember_dependencies?
67 | !run("#{paths.ember} version").success?
68 | rescue DependencyError
69 | false
70 | end
71 |
72 | def clean_ember_dependencies!
73 | ember_dependency_directories.flat_map(&:children).each(&:rmtree)
74 | end
75 |
76 | def ember_dependency_directories
77 | [
78 | paths.node_modules,
79 | paths.bower_components,
80 | ].select(&:exist?)
81 | end
82 |
83 | def spawn(command)
84 | Kernel.spawn(
85 | env,
86 | command,
87 | chdir: paths.root.to_s,
88 | err: paths.build_error_file.to_s,
89 | ) || exit(1)
90 | end
91 |
92 | def runner
93 | Runner.new(
94 | options: { chdir: paths.root.to_s },
95 | out: [$stdout, paths.log.open("a")],
96 | err: [$stderr],
97 | env: env,
98 | )
99 | end
100 |
101 | def running?
102 | pid.present? && Process.getpgid(pid)
103 | rescue Errno::ESRCH
104 | false
105 | end
106 |
107 | def lock_buildfile
108 | FileUtils.touch(paths.lockfile)
109 | end
110 |
111 | def detach
112 | Process.detach pid
113 | end
114 | end
115 | end
116 |
--------------------------------------------------------------------------------
/spec/lib/ember_cli/app_spec.rb:
--------------------------------------------------------------------------------
1 | require "ember-cli-rails"
2 |
3 | describe EmberCli::App do
4 | describe "#to_rack" do
5 | it "delegates to `#deploy`" do
6 | deploy = double(to_rack: :delegated)
7 | app = EmberCli["my-app"]
8 | allow(app).to receive(:deploy).and_return(deploy)
9 |
10 | to_rack = app.to_rack
11 |
12 | expect(to_rack).to be :delegated
13 | end
14 | end
15 |
16 | describe "#mountable?" do
17 | it "delegates to `#deploy`" do
18 | deploy = double(mountable?: :delegated)
19 | app = EmberCli["my-app"]
20 | allow(app).to receive(:deploy).and_return(deploy)
21 |
22 | mountable = app.mountable?
23 |
24 | expect(mountable).to be :delegated
25 | end
26 | end
27 |
28 | describe "yarn_enabled?" do
29 | context "when configured with yarn: true" do
30 | it "returns true" do
31 | app = EmberCli::App.new("with-yarn", yarn: true)
32 |
33 | yarn_enabled = app.yarn_enabled?
34 |
35 | expect(yarn_enabled).to be true
36 | end
37 | end
38 |
39 | context "when configured with yarn: false" do
40 | it "returns false" do
41 | app = EmberCli::App.new("without-yarn", yarn: false)
42 |
43 | yarn_enabled = app.yarn_enabled?
44 |
45 | expect(yarn_enabled).to be false
46 | end
47 | end
48 | end
49 |
50 | describe "#bower?" do
51 | context "when bower.json exists" do
52 | it "returns true" do
53 | bower_json_path = double("Pathname", exist?: true)
54 | stub_paths(bower_json: bower_json_path)
55 | app = EmberCli::App.new("with bower json")
56 |
57 | bower_required = app.bower?
58 |
59 | expect(bower_required).to be true
60 | end
61 | end
62 |
63 | context "when bower.json is absent" do
64 | it "returns false" do
65 | bower_json_path = double("Pathname", exist?: false)
66 | stub_paths(bower_json: bower_json_path)
67 | app = EmberCli::App.new("without bower json")
68 |
69 | bower_required = app.bower?
70 |
71 | expect(bower_required).to be false
72 | end
73 | end
74 | end
75 |
76 | describe "#compile" do
77 | it "exits with exit status of 0" do
78 | passed = EmberCli["my-app"].compile
79 |
80 | expect(passed).to be true
81 | end
82 | end
83 |
84 | describe "#test" do
85 | it "exits with exit status of 0" do
86 | passed = EmberCli["my-app"].test
87 |
88 | expect(passed).to be true
89 | end
90 | end
91 |
92 | describe "#root_path" do
93 | it "delegates to PathSet" do
94 | root_path = Pathname.new(".")
95 | stub_paths(root: root_path)
96 | app = EmberCli::App.new("foo")
97 |
98 | root_path = app.root_path
99 |
100 | expect(root_path).to eq root_path
101 | end
102 | end
103 |
104 | describe "#dist_path" do
105 | it "delegates to PathSet" do
106 | dist_path = Pathname.new(".")
107 | stub_paths(dist: dist_path)
108 | app = EmberCli::App.new("foo")
109 |
110 | dist_path = app.dist_path
111 |
112 | expect(dist_path).to eq dist_path
113 | end
114 | end
115 |
116 | def stub_paths(method_to_value)
117 | allow_any_instance_of(EmberCli::PathSet).
118 | to receive(method_to_value.keys.first).
119 | and_return(method_to_value.values.first)
120 | end
121 | end
122 |
--------------------------------------------------------------------------------
/lib/ember_cli/app.rb:
--------------------------------------------------------------------------------
1 | require "html_page/renderer"
2 | require "ember_cli/path_set"
3 | require "ember_cli/shell"
4 | require "ember_cli/build_monitor"
5 | require "ember_cli/deploy/file"
6 |
7 | module EmberCli
8 | class App
9 | attr_reader :name, :options, :paths
10 |
11 | def initialize(name, **options)
12 | @name = name.to_s
13 | @options = options
14 | @paths = PathSet.new(
15 | app: self,
16 | environment: Rails.env,
17 | rails_root: Rails.root,
18 | ember_cli_root: EmberCli.root,
19 | )
20 | @shell = Shell.new(
21 | paths: @paths,
22 | env: env_hash,
23 | options: options,
24 | )
25 | @build = BuildMonitor.new(name, @paths)
26 | end
27 |
28 | def root_path
29 | paths.root
30 | end
31 |
32 | def dist_path
33 | paths.dist
34 | end
35 |
36 | def cached_directories
37 | paths.cached_directories
38 | end
39 |
40 | def compile
41 | @compiled ||= begin
42 | prepare
43 | exit_status = @shell.compile
44 | @build.check!
45 |
46 | exit_status.success?
47 | end
48 | end
49 |
50 | def build
51 | unless EmberCli.skip?
52 | if development?
53 | build_and_watch
54 | elsif test?
55 | compile
56 | end
57 |
58 | @build.wait!
59 | end
60 | end
61 |
62 | def index_html(head:, body:)
63 | html = HtmlPage::Renderer.new(
64 | head: head,
65 | body: body,
66 | content: deploy.index_html,
67 | )
68 |
69 | html.render
70 | end
71 |
72 | def install_dependencies
73 | @shell.install
74 | end
75 |
76 | def test
77 | prepare
78 |
79 | @shell.test.success?
80 | end
81 |
82 | def check_for_errors!
83 | @build.check!
84 | end
85 |
86 | def mountable?
87 | deploy.mountable?
88 | end
89 |
90 | def yarn_enabled?
91 | options.fetch(:yarn, false)
92 | end
93 |
94 | def bower?
95 | paths.bower_json.exist?
96 | end
97 |
98 | def to_rack
99 | deploy.to_rack
100 | end
101 |
102 | private
103 |
104 | def development?
105 | env.to_s == "development"
106 | end
107 |
108 | def test?
109 | env.to_s == "test"
110 | end
111 |
112 | def deploy
113 | deploy_strategy.new(self)
114 | end
115 |
116 | def deploy_strategy
117 | strategy = options.fetch(:deploy, {})
118 |
119 | if strategy.respond_to?(:fetch)
120 | strategy.fetch(rails_env, EmberCli::Deploy::File)
121 | else
122 | strategy
123 | end
124 | end
125 |
126 | def rails_env
127 | Rails.env.to_s.to_sym
128 | end
129 |
130 | def env
131 | EmberCli.env
132 | end
133 |
134 | def build_and_watch
135 | prepare
136 | @shell.build_and_watch
137 | end
138 |
139 | def prepare
140 | @prepared ||= begin
141 | @build.reset
142 | true
143 | end
144 | end
145 |
146 | def excluded_ember_deps
147 | Array.wrap(options[:exclude_ember_deps]).join("?")
148 | end
149 |
150 | def env_hash
151 | ENV.to_h.tap do |vars|
152 | vars["RAILS_ENV"] = Rails.env
153 | vars["EXCLUDE_EMBER_ASSETS"] = excluded_ember_deps
154 | vars["BUNDLE_GEMFILE"] = paths.gemfile.to_s if paths.gemfile.exist?
155 | end
156 | end
157 | end
158 | end
159 |
--------------------------------------------------------------------------------
/spec/generators/ember/heroku/heroku_generator_spec.rb:
--------------------------------------------------------------------------------
1 | require "generator_spec"
2 | require "generators/ember/heroku/heroku_generator"
3 |
4 | describe EmberCli::HerokuGenerator, type: :generator do
5 | OUTPUT_DIRECTORY = Rails.root.join("tmp", "generator_test_output")
6 | destination OUTPUT_DIRECTORY
7 |
8 | context "without yarn enabled" do
9 | it "does not generate a root-level yarn.lock" do
10 | setup_destination
11 | configure_application(yarn: false)
12 |
13 | run_generator
14 |
15 | expect(destination_root).to have_structure {
16 | no_file "yarn.lock"
17 | }
18 | end
19 | end
20 |
21 | context "with yarn enabled" do
22 | it "generates a root-level yarn.lock" do
23 | setup_destination
24 | configure_application(yarn: true)
25 |
26 | run_generator
27 |
28 | expect(destination_root).to have_structure {
29 | file "yarn.lock"
30 | }
31 | end
32 | end
33 |
34 | describe "package.json" do
35 | it "includes the root directory node_modules" do
36 | setup_destination
37 | configure_application
38 |
39 | run_generator
40 |
41 | expect(cache_directories_from_package_json).to include("node_modules")
42 | end
43 |
44 | context "when no Ember application depends on bower" do
45 | it "does not include bower as a dependency" do
46 | setup_destination
47 | depend_on_bower(false)
48 | configure_application
49 |
50 | run_generator
51 |
52 | expect(package_json.keys).not_to include("dependencies")
53 | expect(cache_directories_from_package_json).not_to include_bower
54 | end
55 | end
56 |
57 | context "when an Ember application depends on bower" do
58 | it "includes bower as a dependency" do
59 | setup_destination
60 | depend_on_bower(true)
61 | configure_application
62 |
63 | run_generator
64 |
65 | expect(dependencies_from_package_json).to include("bower" => "*")
66 | expect(cache_directories_from_package_json).to include_bower
67 | end
68 | end
69 |
70 | def depend_on_bower(bower_enabled)
71 | allow_any_instance_of(EmberCli::App).
72 | to receive(:bower?).and_return(bower_enabled)
73 |
74 | allow_any_instance_of(EmberCli::App).
75 | to receive(:cached_directories).and_return(
76 | cached_directories(bower_enabled),
77 | )
78 | end
79 |
80 | def cached_directories(bower_enabled)
81 | if bower_enabled
82 | [OUTPUT_DIRECTORY.join("bower_components")]
83 | else
84 | []
85 | end
86 | end
87 |
88 | def include_bower
89 | include(/bower_components/)
90 | end
91 |
92 | def cache_directories_from_package_json
93 | package_json.fetch("cacheDirectories")
94 | end
95 |
96 | def dependencies_from_package_json
97 | package_json.fetch("dependencies")
98 | end
99 |
100 | def package_json
101 | JSON.parse(package_json_contents)
102 | end
103 |
104 | def package_json_contents
105 | destination_root.join("package.json").read
106 | end
107 | end
108 |
109 | def configure_application(**options)
110 | EmberCli.configure { |c| c.app("my-app", **options) }
111 | end
112 |
113 | def setup_destination
114 | prepare_destination
115 |
116 | create_empty_gemfile_for_bundler
117 | end
118 |
119 | def create_empty_gemfile_for_bundler
120 | FileUtils.touch(destination_root.join("Gemfile"))
121 | end
122 | end
123 |
--------------------------------------------------------------------------------
/spec/lib/ember_cli/command_spec.rb:
--------------------------------------------------------------------------------
1 | require "ember_cli/command"
2 |
3 | describe EmberCli::Command do
4 | describe "#test" do
5 | it "builds an `ember test` command" do
6 | paths = build_paths(ember: "path/to/ember")
7 | command = build_command(paths: paths)
8 |
9 | expect(command.test).to eq("path\/to\/ember test --environment test")
10 | end
11 | end
12 |
13 | describe "#build" do
14 | it "builds an `ember build` command" do
15 | paths = build_paths(ember: "path/to/ember")
16 | command = build_command(paths: paths)
17 |
18 | expect(command.build).to match(%r{path\/to\/ember build})
19 | end
20 |
21 | context "when building in production" do
22 | it "includes the `--environment production` flag" do
23 | paths = build_paths
24 | command = build_command(paths: paths)
25 | allow(EmberCli).to receive(:env).and_return("production")
26 |
27 | expect(command.build).to match(/--environment 'production'/)
28 | end
29 | end
30 |
31 | context "when building in any other environment" do
32 | it "includes the `--environment development` flag" do
33 | paths = build_paths
34 | command = build_command(paths: paths)
35 | allow(EmberCli).to receive(:env).and_return("test")
36 |
37 | expect(command.build).to match(/--environment 'development'/)
38 | end
39 | end
40 |
41 | it "includes the `--output-path` flag" do
42 | paths = build_paths(dist: "path/to/dist")
43 | command = build_command(paths: paths)
44 |
45 | expect(command.build).to match(%r{--output-path 'path\/to\/dist'})
46 | end
47 |
48 | context "when configured not to watch" do
49 | it "excludes the `--watch` flag" do
50 | paths = build_paths
51 | command = build_command(paths: paths)
52 |
53 | expect(command.build).not_to match(/--watch/)
54 | end
55 | end
56 |
57 | context "when configured not to be silent" do
58 | it "exludes the `--silent` flag" do
59 | paths = build_paths
60 | command = build_command(paths: paths)
61 |
62 | expect(command.build).not_to match(/--silent/)
63 |
64 | paths = build_paths
65 | command = build_command(paths: paths, options: { silent: false })
66 |
67 | expect(command.build).not_to match(/--silent/)
68 | end
69 | end
70 |
71 | context "when configured to be silent" do
72 | it "includes `--silent` flag" do
73 | paths = build_paths
74 | command = build_command(paths: paths, options: { silent: true })
75 |
76 | expect(command.build).to match(/--silent/)
77 | end
78 | end
79 |
80 | context "when configured to watch" do
81 | it "includes the `--watch` flag" do
82 | paths = build_paths
83 | command = build_command(paths: paths)
84 |
85 | expect(command.build(watch: true)).to match(/--watch/)
86 | end
87 |
88 | it "defaults to configuration for the `--watcher` flag" do
89 | paths = build_paths
90 | command = build_command(paths: paths)
91 | allow(EmberCli).
92 | to receive(:configuration).
93 | and_return(build_paths(watcher: "bar"))
94 |
95 | expect(command.build(watch: true)).to match(/--watcher 'bar'/)
96 | end
97 |
98 | context "when a watcher is configured" do
99 | it "configures the build with the value" do
100 | paths = build_paths
101 | command = build_command(paths: paths, options: { watcher: "foo" })
102 |
103 | expect(command.build(watch: true)).to match(/--watcher 'foo'/)
104 | end
105 | end
106 | end
107 | end
108 |
109 | def build_paths(**options)
110 | double(options).as_null_object
111 | end
112 |
113 | def build_command(**options)
114 | EmberCli::Command.new(**options)
115 | end
116 | end
117 |
--------------------------------------------------------------------------------
/lib/ember_cli/path_set.rb:
--------------------------------------------------------------------------------
1 | require "ember_cli/helpers"
2 |
3 | module EmberCli
4 | class PathSet
5 | def initialize(app:, rails_root:, ember_cli_root:, environment:)
6 | @app = app
7 | @rails_root = rails_root
8 | @environment = environment
9 | @ember_cli_root = ember_cli_root
10 | end
11 |
12 | def root
13 | path = app_options.fetch(:path){ default_root }
14 | pathname = Pathname.new(path)
15 | if pathname.absolute?
16 | pathname
17 | else
18 | rails_root.join(path)
19 | end
20 | end
21 |
22 | def tmp
23 | @tmp ||= root.join("tmp").tap(&:mkpath)
24 | end
25 |
26 | def log
27 | @log ||= logs.join("ember-#{app_name}.#{environment}.log")
28 | end
29 |
30 | def dist
31 | @dist ||= ember_cli_root.join("apps", app_name).tap(&:mkpath)
32 | end
33 |
34 | def gemfile
35 | @gemfile ||= root.join("Gemfile")
36 | end
37 |
38 | def bower_json
39 | root.join("bower.json")
40 | end
41 |
42 | def ember
43 | @ember ||= begin
44 | root.join("node_modules", "ember-cli", "bin", "ember").tap do |path|
45 | unless path.executable?
46 | fail DependencyError.new <<-MSG.strip_heredoc
47 | No `ember-cli` executable found for `#{app_name}`.
48 |
49 | Install it:
50 |
51 | $ cd #{root}
52 | $ #{package_manager} install
53 |
54 | MSG
55 | end
56 | end
57 | end
58 | end
59 |
60 | def lockfile
61 | @lockfile ||= tmp.join("build.lock")
62 | end
63 |
64 | def build_error_file
65 | @build_error_file ||= tmp.join("error.txt")
66 | end
67 |
68 | def bower
69 | @bower ||= begin
70 | path_for_executable("bower").tap do |bower_path|
71 | if bower_json.exist? && (bower_path.blank? || !bower_path.executable?)
72 | fail DependencyError.new <<-MSG.strip_heredoc
73 | Bower is required by EmberCLI
74 |
75 | Install it with:
76 |
77 | $ npm install -g bower
78 |
79 | MSG
80 | end
81 | end
82 | end
83 | end
84 |
85 | def bower_components
86 | @bower_components ||= root.join("bower_components")
87 | end
88 |
89 | def npm
90 | @npm ||= path_for_executable("npm")
91 | end
92 |
93 | def yarn
94 | if yarn?
95 | @yarn ||= path_for_executable("yarn").tap do |yarn|
96 | unless File.executable?(yarn.to_s)
97 | fail DependencyError.new(<<-MSG.strip_heredoc)
98 | EmberCLI has been configured to install NodeJS dependencies with Yarn, but the Yarn executable is unavailable.
99 |
100 | Install it by following the instructions at https://yarnpkg.com/lang/en/docs/install/
101 |
102 | MSG
103 | end
104 | end
105 | end
106 | end
107 |
108 | def node_modules
109 | @node_modules ||= root.join("node_modules")
110 | end
111 |
112 | def tee
113 | @tee ||= path_for_executable("tee")
114 | end
115 |
116 | def bundler
117 | @bundler ||= path_for_executable("bundler")
118 | end
119 |
120 | def cached_directories
121 | [
122 | node_modules,
123 | (bower_components if bower_json.exist?),
124 | ].compact
125 | end
126 |
127 | private
128 |
129 | attr_reader :app, :ember_cli_root, :environment, :rails_root
130 |
131 | def path_for_executable(command)
132 | path = app_options.fetch("#{command}_path") { which(command) }
133 |
134 | if path.present?
135 | Pathname.new(path)
136 | end
137 | end
138 |
139 | def package_manager
140 | if yarn?
141 | "yarn"
142 | else
143 | "npm"
144 | end
145 | end
146 |
147 | def yarn?
148 | app_options[:yarn] || app_options[:yarn_path]
149 | end
150 |
151 | def app_name
152 | app.name
153 | end
154 |
155 | def app_options
156 | app.options.with_indifferent_access
157 | end
158 |
159 | def which(executable)
160 | Helpers.which(executable)
161 | end
162 |
163 | def logs
164 | rails_root.join("log").tap(&:mkpath)
165 | end
166 |
167 | def default_root
168 | rails_root.join(app_name)
169 | end
170 | end
171 | end
172 |
--------------------------------------------------------------------------------
/spec/lib/ember_cli/build_monitor_spec.rb:
--------------------------------------------------------------------------------
1 | require "ember_cli/errors"
2 | require "ember_cli/build_monitor"
3 |
4 | describe EmberCli::BuildMonitor do
5 | BLANK_LINE = ""
6 |
7 | describe "#reset" do
8 | context "when there is a build error" do
9 | it "deletes the build file" do
10 | error_file = error_file_with_contents
11 | paths = build_paths(error_file)
12 | monitor = EmberCli::BuildMonitor.new(nil, paths)
13 |
14 | monitor.reset
15 |
16 | expect(error_file).to have_received(:delete)
17 | end
18 | end
19 |
20 | context "when there are only deprecation warnings" do
21 | it "deletes the build file" do
22 | error_file = error_file_with_contents(["DEPRECATION: A warning"])
23 | paths = build_paths(error_file)
24 | monitor = EmberCli::BuildMonitor.new(nil, paths)
25 |
26 | monitor.reset
27 |
28 | expect(error_file).to have_received(:delete)
29 | end
30 | end
31 |
32 | context "when there is not a build error" do
33 | it "does nothing" do
34 | error_file = missing_error_file
35 | paths = build_paths(error_file)
36 | monitor = EmberCli::BuildMonitor.new(nil, paths)
37 |
38 | monitor.reset
39 |
40 | expect(error_file).not_to have_received(:delete)
41 | end
42 | end
43 | end
44 |
45 | describe "#check!" do
46 | context "when the error file has content" do
47 | it "raises a BuildError" do
48 | paths = build_paths(error_file_with_contents(["first-line"]))
49 | monitor = EmberCli::BuildMonitor.new("app-name", paths)
50 |
51 | expect { monitor.check! }.
52 | to raise_error(
53 | EmberCli::BuildError,
54 | %{"app-name" has failed to build: first-line},
55 | )
56 | end
57 | end
58 |
59 | context "when the error file only contains deprecation warnings" do
60 | it "does not raise a BuildError" do
61 | error_file = error_file_with_contents(
62 | [
63 | BLANK_LINE,
64 | "DEPRECATION: A warning",
65 | " at AStackTrace",
66 | ])
67 | paths = build_paths(error_file)
68 | monitor = EmberCli::BuildMonitor.new(nil, paths)
69 |
70 | expect(monitor.check!).to be true
71 | end
72 | end
73 |
74 | context "when the error file contains a ASCII colored deprecation" do
75 | it "does not raise a BuildError" do
76 | error_file = error_file_with_contents(
77 | [
78 | BLANK_LINE,
79 | "\e[33mDEPRECATION: A warning",
80 | " at AStackTrace\e[39m",
81 | ])
82 | paths = build_paths(error_file)
83 | monitor = EmberCli::BuildMonitor.new(nil, paths)
84 |
85 | expect(monitor.check!).to be true
86 | end
87 | end
88 |
89 | context "when the error file contains an ASCII colored Building notice" do
90 | it "does not raise a BuildError" do
91 | error_file = error_file_with_contents(
92 | [
93 | "- \e[32mBuilding\e[39m"
94 | ])
95 | paths = build_paths(error_file)
96 | monitor = EmberCli::BuildMonitor.new(nil, paths)
97 |
98 | expect(monitor.check!).to be true
99 | end
100 | end
101 |
102 | context "when the error file contains both errors & deprecation warnings" do
103 | it "raises a BuildError" do
104 | error_file = error_file_with_contents(
105 | [
106 | BLANK_LINE,
107 | "DEPRECATION: A warning",
108 | " at AStackTrace",
109 | BLANK_LINE,
110 | "SyntaxError: things went wrong",
111 | ])
112 | paths = build_paths(error_file)
113 | monitor = EmberCli::BuildMonitor.new("app-name", paths)
114 |
115 | expect { monitor.check! }.
116 | to raise_error(
117 | EmberCli::BuildError,
118 | %{"app-name" has failed to build: SyntaxError: things went wrong},
119 | )
120 | end
121 | end
122 |
123 | context "when the error file exists but is empty" do
124 | it "does not raise a BuildError" do
125 | paths = build_paths(blank_error_file)
126 | monitor = EmberCli::BuildMonitor.new(nil, paths)
127 |
128 | expect(monitor.check!).to be true
129 | end
130 | end
131 |
132 | context "when the error file is missing" do
133 | it "does not raise a BuildError" do
134 | paths = build_paths(missing_error_file)
135 | monitor = EmberCli::BuildMonitor.new(nil, paths)
136 |
137 | expect(monitor.check!).to be true
138 | end
139 | end
140 | end
141 |
142 | def build_paths(error_file)
143 | double(build_error_file: error_file)
144 | end
145 |
146 | def error_file_with_contents(contents = ["foo"])
147 | build_error_file(exist?: true, size?: true, readlines: contents)
148 | end
149 |
150 | def blank_error_file
151 | build_error_file(exist?: true, size?: false)
152 | end
153 |
154 | def missing_error_file
155 | build_error_file(exist?: false)
156 | end
157 |
158 | def build_error_file(**options)
159 | double(**options).tap do |stub|
160 | allow(stub).to receive(:delete)
161 | end
162 | end
163 | end
164 |
--------------------------------------------------------------------------------
/spec/lib/ember_cli/path_set_spec.rb:
--------------------------------------------------------------------------------
1 | require "fileutils"
2 | require "ember_cli/path_set"
3 |
4 | describe EmberCli::PathSet do
5 | describe "#root" do
6 | it "depends on the app name" do
7 | app = build_app(name: "foo")
8 |
9 | path_set = build_path_set(app: app)
10 |
11 | expect(path_set.root).to eq rails_root.join("foo")
12 | end
13 |
14 | it "can be overridden" do
15 | app = build_app(name: "foo", options: { path: "not-foo" })
16 |
17 | path_set = build_path_set(app: app)
18 |
19 | expect(path_set.root).to eq rails_root.join("not-foo")
20 | end
21 | end
22 |
23 | describe "#tmp" do
24 | it "is a child of #root" do
25 | app = build_app
26 |
27 | path_set = build_path_set(app: app)
28 |
29 | expect(path_set.tmp).to exist
30 | expect(path_set.tmp).to eq rails_root.join(app.name, "tmp")
31 | end
32 | end
33 |
34 | describe "#log" do
35 | it "depends on the environment" do
36 | app = build_app(name: "foo")
37 | path_set = build_path_set(app: app, environment: "bar")
38 |
39 | expect(path_set.log).to eq rails_root.join("log", "ember-foo.bar.log")
40 | expect(rails_root.join("log")).to exist
41 | end
42 | end
43 |
44 | describe "#dist" do
45 | it "depends on the app name" do
46 | app = build_app(name: "foo")
47 |
48 | path_set = build_path_set(app: app)
49 |
50 | expect(path_set.dist).to exist
51 | expect(path_set.dist).to eq ember_cli_root.join("apps", "foo")
52 | end
53 | end
54 |
55 | describe "#gemfile" do
56 | it "is a child of #root" do
57 | app = build_app(name: "foo")
58 |
59 | path_set = build_path_set(app: app)
60 |
61 | expect(path_set.gemfile).to eq rails_root.join("foo", "Gemfile")
62 | end
63 | end
64 |
65 | describe "#lockfile" do
66 | it "is a child of #tmp" do
67 | path_set = build_path_set
68 |
69 | expect(path_set.lockfile).to eq path_set.tmp.join("build.lock")
70 | end
71 | end
72 |
73 | describe "#build_error_file" do
74 | it "is a child of #tmp" do
75 | path_set = build_path_set
76 |
77 | expect(path_set.build_error_file).to eq path_set.tmp.join("error.txt")
78 | end
79 | end
80 |
81 | describe "#ember" do
82 | it "is an executable child of #node_modules" do
83 | app = build_app
84 | path_set = build_path_set(app: app)
85 | ember_path = rails_root.join(app.name, "node_modules", "ember-cli", "bin", "ember")
86 | create_executable(ember_path)
87 |
88 | ember = path_set.ember
89 |
90 | expect(ember).to eq(ember_path).and(be_executable)
91 | end
92 |
93 | it "raises a DependencyError if the file isn't executable" do
94 | path_set = build_path_set
95 |
96 | expect { path_set.ember }.to raise_error(EmberCli::DependencyError)
97 | end
98 | end
99 |
100 | describe "#bower" do
101 | it "can be overridden" do
102 | fake_bower = create_executable(ember_cli_root.join("bower"))
103 | app = build_app(options: { bower_path: fake_bower.to_s })
104 | path_set = build_path_set(app: app)
105 |
106 | bower = path_set.bower
107 |
108 | expect(bower).to eq(fake_bower).and(be_executable)
109 | end
110 |
111 | it "can be inferred from the $PATH" do
112 | fake_bower = create_executable(ember_cli_root.join("bower"))
113 | stub_which(bower: fake_bower.to_s)
114 | path_set = build_path_set
115 |
116 | bower = path_set.bower
117 |
118 | expect(bower).to eq(fake_bower).and(be_executable)
119 | end
120 |
121 | context "when it is missing from the $PATH" do
122 | context "bower.json exists" do
123 | it "raises a helpful exception" do
124 | app = build_app
125 | create_file(app_root_for(app).join("bower.json"))
126 | stub_which(bower: nil)
127 | path_set = build_path_set
128 |
129 | expect { path_set.bower }.
130 | to raise_error(EmberCli::DependencyError, /bower is required/i)
131 | end
132 |
133 | context "bower.json is missing" do
134 | it "returns nil" do
135 | stub_which(bower: nil)
136 | path_set = build_path_set
137 |
138 | bower = path_set.bower
139 |
140 | expect(bower).to be_nil
141 | end
142 | end
143 | end
144 | end
145 | end
146 |
147 | describe "#bower_json" do
148 | it "is a child of #root" do
149 | app = build_app
150 | path_set = build_path_set(app: app)
151 |
152 | bower_json = path_set.bower_json
153 |
154 | expect(bower_json).to eq app_root_for(app).join("bower.json")
155 | end
156 | end
157 |
158 | describe "#bower_components" do
159 | it "is a child of #root" do
160 | app = build_app(name: "foo")
161 |
162 | path_set = build_path_set(app: app)
163 |
164 | expect(path_set.bower_components).
165 | to eq rails_root.join("foo", "bower_components")
166 | end
167 | end
168 |
169 | describe "#npm" do
170 | it "can be overridden" do
171 | fake_npm = create_executable(ember_cli_root.join("npm"))
172 | app = build_app(options: { npm_path: fake_npm.to_s })
173 | path_set = build_path_set(app: app)
174 |
175 | npm = path_set.npm
176 |
177 | expect(npm).to eq(fake_npm).and(be_executable)
178 | end
179 |
180 | it "can be inferred from the $PATH" do
181 | fake_npm = create_executable(ember_cli_root.join("npm"))
182 | stub_which(npm: fake_npm.to_s)
183 | path_set = build_path_set
184 |
185 | npm = path_set.npm
186 |
187 | expect(npm).to eq(fake_npm).and(be_executable)
188 | end
189 | end
190 |
191 | describe "#yarn" do
192 | it "can be overridden" do
193 | fake_yarn = create_executable(ember_cli_root.join("yarn"))
194 | app = build_app(options: { yarn_path: fake_yarn.to_s })
195 | path_set = build_path_set(app: app)
196 |
197 | yarn = path_set.yarn
198 |
199 | expect(yarn).to eq(fake_yarn).and(be_executable)
200 | end
201 |
202 | it "can be inferred from the $PATH" do
203 | fake_yarn = create_executable(ember_cli_root.join("yarn"))
204 | stub_which(yarn: fake_yarn.to_s)
205 | app = build_app(options: { yarn: true })
206 | path_set = build_path_set(app: app)
207 | create_executable(fake_yarn)
208 |
209 | yarn = path_set.yarn
210 |
211 | expect(yarn).to eq(fake_yarn).and(be_executable)
212 | end
213 |
214 | context "when the executable isn't installed on the system" do
215 | context "and yarn is requested" do
216 | it "raises a DependencyError" do
217 | stub_which(yarn: nil)
218 | app = build_app(options: { yarn: true })
219 | path_set = build_path_set(app: app)
220 |
221 | expect { path_set.yarn }.to raise_error(EmberCli::DependencyError)
222 | end
223 | end
224 |
225 | context "and yarn is not requested" do
226 | it "returns nil" do
227 | stub_which(yarn: nil)
228 | path_set = build_path_set
229 |
230 | yarn = path_set.yarn
231 |
232 | expect(yarn).to be_nil
233 | end
234 | end
235 | end
236 | end
237 |
238 | describe "#node_modules" do
239 | it "is a child of #root" do
240 | app = build_app(name: "foo")
241 |
242 | path_set = build_path_set(app: app)
243 |
244 | expect(path_set.node_modules).to eq rails_root.join("foo", "node_modules")
245 | end
246 | end
247 |
248 | describe "#tee" do
249 | it "can be overridden" do
250 | fake_tee = create_executable(rails_root.join("tee"))
251 | app = build_app(options: { tee_path: fake_tee.to_s })
252 | path_set = build_path_set(app: app)
253 |
254 | tee = path_set.tee
255 |
256 | expect(tee).to eq(fake_tee).and(be_executable)
257 | end
258 |
259 | it "can be inferred from the $PATH" do
260 | fake_tee = create_executable(rails_root.join("tee"))
261 | stub_which(tee: fake_tee.to_s)
262 | path_set = build_path_set
263 |
264 | tee = path_set.tee
265 |
266 | expect(tee).to eq(fake_tee).and(be_executable)
267 | end
268 | end
269 |
270 | describe "#bundler" do
271 | it "can be overridden" do
272 | fake_bundler = create_executable(rails_root.join("bundler"))
273 | app = build_app(options: { bundler_path: fake_bundler.to_s })
274 | path_set = build_path_set(app: app)
275 |
276 | bundler = path_set.bundler
277 |
278 | expect(bundler).to eq(fake_bundler).and(be_executable)
279 | end
280 |
281 | it "can be inferred from the $PATH" do
282 | fake_bundler = create_executable(rails_root.join("bundler"))
283 | stub_which(bundler: fake_bundler.to_s)
284 | path_set = build_path_set
285 |
286 | bundler = path_set.bundler
287 |
288 | expect(bundler).to eq(fake_bundler).and(be_executable)
289 | end
290 | end
291 |
292 | describe "#cached_directories" do
293 | it "includes the full path to the application's node_modules" do
294 | app_name = "foo"
295 | app = build_app(name: app_name)
296 | path_set = build_path_set(app: app)
297 |
298 | cached_directories = path_set.cached_directories
299 |
300 | expect(cached_directories).to include(
301 | rails_root.join(app_name, "node_modules"),
302 | )
303 | end
304 |
305 | context "when bower.json exists" do
306 | it "includes the full path to bower_components" do
307 | app_name = "foo"
308 | app = build_app(name: app_name)
309 | app_root = rails_root.join(app_name)
310 | path_set = build_path_set(app: app)
311 | create_file(app_root.join("bower.json"))
312 |
313 | cached_directories = path_set.cached_directories
314 |
315 | expect(cached_directories).to include(
316 | rails_root.join(app_name, "bower_components"),
317 | )
318 | end
319 | end
320 |
321 | context "when bower.json does not exist" do
322 | it "does not include the path to bower_components" do
323 | app_name = "foo"
324 | app = build_app(name: app_name)
325 | path_set = build_path_set(app: app)
326 |
327 | cached_directories = path_set.cached_directories
328 |
329 | expect(cached_directories).not_to include(nil)
330 | expect(cached_directories).not_to include(
331 | rails_root.join(app_name, "bower_components"),
332 | )
333 | end
334 | end
335 | end
336 |
337 | def create_file(path)
338 | path.parent.mkpath
339 | FileUtils.touch(path)
340 | path
341 | end
342 |
343 | def create_executable(path)
344 | file = File.new(create_file(path))
345 | file.chmod(0777)
346 | path
347 | end
348 |
349 | def build_app(**options)
350 | double(
351 | options.reverse_merge(
352 | name: "foo",
353 | options: {},
354 | ),
355 | )
356 | end
357 |
358 | def stub_which(program_to_path)
359 | allow(EmberCli::Helpers).
360 | to receive(:which).
361 | with(program_to_path.keys.first.to_s).
362 | and_return(program_to_path.values.last)
363 | end
364 |
365 | def build_path_set(**options)
366 | EmberCli::PathSet.new(
367 | **options.reverse_merge(
368 | app: build_app,
369 | rails_root: rails_root,
370 | ember_cli_root: ember_cli_root,
371 | environment: "test",
372 | ),
373 | )
374 | end
375 |
376 | def app_root_for(app)
377 | rails_root.join(app.name)
378 | end
379 |
380 | def ember_cli_root
381 | Rails.root.join("tmp", "ember_cli").tap(&:mkpath)
382 | end
383 |
384 | def rails_root
385 | Rails.root.join("tmp", "rails").tap(&:mkpath)
386 | end
387 |
388 | def remove_temporary_directories
389 | [rails_root, ember_cli_root].each do |dir|
390 | if dir.exist?
391 | FileUtils.rm_rf(dir)
392 | end
393 | end
394 | end
395 |
396 | before do
397 | remove_temporary_directories
398 | end
399 | end
400 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | main
2 | ------
3 |
4 | 0.12.2
5 | ------
6 |
7 | * Support Rack 3 and depend on Rack explicitly (#607)
8 |
9 | 0.12.1
10 | ------
11 |
12 | * Drop explicit dependency to rexml (#602)
13 | * Remove note for PhantomJS (#604)
14 | * Allow rspec-rails 6.x (#603)
15 | * Allow ember-cli-rails-assets < 1.0 (#599)
16 | * Update webdrivers gem (#600)
17 | * Disallow rack 3 to be compatible with capybara (#601)
18 |
19 | 0.12.0
20 | ------
21 |
22 | * Redirecting with trailing slash with query parameters
23 | * Recognize Building notice as not an error
24 | * Use keyword argument for options
25 | * Add Ruby 2.7 & 3.0 into CI matrix
26 | * Add missing gems that removed from stdlibs in Ruby 3.0.0
27 | * Fix autoload deprecation in Rails 6
28 | * Drop support for Rails versions 4.2, 5.0, 5.1, and 5.2
29 | * Drop support for End-of-Lifed Ruby versions 2.3 and 2.4
30 |
31 | 0.11.0
32 | ------
33 |
34 | * Switch from TravisCI to GitHub Actions for Continuous Integration
35 | * Redirect Ember routes with paths that don't end in `/` to corresponding paths
36 | that end in `/`.
37 | * Don't route requests to `/rails/active_storage` through the mounted Ember application.
38 | * Only support for Ruby versions >= 2.5
39 | * Only support for Rails versions >= 5.2
40 |
41 | 0.10.0
42 | ------
43 |
44 | * Remove `bin/heroku_install` to simplify Heroku setup.
45 | To upgrade, remove your project's generated `bin/heroku_install`.
46 | Next, execute `rake ember:heroku`. [#544]
47 | * Generate an empty `yarn.lock` so that Heroku understands that the
48 | application's deployment target requires `yarn`. Closes [#538]. [#540]
49 | * No longer support `rails < 4.2`. [#543]
50 | * Generate an empty `yarn.lock` so that Heroku understands that the
51 | application's deployment target requires `yarn`. Closes [#538]. [#540]
52 |
53 | [#543]: https://github.com/thoughtbot/ember-cli-rails/pull/543
54 | [#544]: https://github.com/thoughtbot/ember-cli-rails/pull/544
55 | [#538]: https://github.com/thoughtbot/ember-cli-rails/issues/538
56 | [#540]: https://github.com/thoughtbot/ember-cli-rails/pull/540
57 |
58 | 0.9.0
59 | -----
60 |
61 | * Don't require `bower` installation if `bower.json` is missing [#532]
62 |
63 | [#532]: https://github.com/thoughtbot/ember-cli-rails/pull/532
64 |
65 | 0.8.7
66 | -----
67 |
68 | * Revert [`34ff6dd`][reverted-commit] so that it can be reintroduced as a
69 | breaking change, [requiring a major version bump][#532-comment]
70 |
71 | [reverted-commit]: https://github.com/thoughtbot/ember-cli-rails/commit/34ff6dd
72 | [#532-comment]: https://github.com/thoughtbot/ember-cli-rails/pull/532#issuecomment-308141408
73 |
74 | 0.8.6
75 | -----
76 |
77 | * Don't require `bower` installation if `bower.json` is missing [#532]
78 |
79 | [#532]: https://github.com/thoughtbot/ember-cli-rails/pull/532
80 |
81 | 0.8.5
82 | -----
83 |
84 | * Ignore calls to `/rails/mailers`. [#520]
85 | * Call `render` with `html:` instead of `text:`. [#519]
86 | * Use `Mime::Type.html?` [#523]
87 |
88 | [#520]: https://github.com/thoughtbot/ember-cli-rails/pull/520
89 | [#519]: https://github.com/thoughtbot/ember-cli-rails/pull/519
90 | [#523]: https://github.com/thoughtbot/ember-cli-rails/pull/523
91 |
92 | 0.8.4
93 | -----
94 |
95 | * Execute `bin/heroku_install` through `sh` [#512]
96 | * Generate `package.json` with `bower` as a `dependencies` value.
97 |
98 | [#512]: https://github.com/thoughtbot/ember-cli-rails/pull/512
99 |
100 | 0.8.3
101 | -----
102 |
103 | * Add support for integrating with `yarn`. [#496]
104 |
105 | [#496]: https://github.com/thoughtbot/ember-cli-rails/pull/496
106 |
107 | 0.8.2.
108 | ------
109 |
110 | * Support Rails 5 static file serving configuration. [#499]
111 |
112 | [#499]: https://github.com/thoughtbot/ember-cli-rails/pull/499
113 |
114 | 0.8.1
115 | -----
116 |
117 | * Resolve issues inheriting from `ActionController::API`. [#481]
118 |
119 | [#481]: https://github.com/thoughtbot/ember-cli-rails/pull/481
120 |
121 | 0.8.0
122 | -----
123 |
124 | * `EmberCli::EmberController` no longer assumes `ApplicationController`
125 | inherits from`ActionController::Base`. [#400]
126 | * Remove support for Ruby 2.1.x. [#400]
127 | * Don't route requests to `/rails/info` through the mounted Ember application.
128 |
129 | [#400]: https://github.com/thoughtbot/ember-cli-rails/pull/400
130 |
131 | 0.7.4
132 | -----
133 |
134 | * Fix dependencies check for compile command. [#455]
135 | * Introduce the `silent` configuration value. [#445]
136 |
137 | [#455]: https://github.com/thoughtbot/ember-cli-rails/pull/455
138 | [#445]: https://github.com/thoughtbot/ember-cli-rails/pull/445
139 |
140 | 0.7.3
141 | -----
142 |
143 | * Stream output instead of waiting until subprocesses finish. [#423]
144 | * Update `ember-cli-rails-assets` dependency. [#422]
145 | * Only write errors to `STDERR`. [#421]
146 | * Remove dependency on `tee`. Fixes bug [#417]. [#420]
147 |
148 | [#423]: https://github.com/thoughtbot/ember-cli-rails/pull/423
149 | [#422]: https://github.com/thoughtbot/ember-cli-rails/pull/422
150 | [#421]: https://github.com/thoughtbot/ember-cli-rails/issues/421
151 | [#420]: https://github.com/thoughtbot/ember-cli-rails/issues/420
152 | [#417]: https://github.com/thoughtbot/ember-cli-rails/issues/417
153 |
154 | 0.7.2
155 | -----
156 |
157 | * Enhance `rake ember:install` to fully reinstall if necessary. [#396]
158 | * `EmberCli::Deploy::File` serves assets with Rails' `static_cache_control`
159 | value. [#403]
160 |
161 | [#400]: https://github.com/thoughtbot/ember-cli-rails/pull/400
162 | [#396]: https://github.com/thoughtbot/ember-cli-rails/pull/396
163 | [#403]: https://github.com/thoughtbot/ember-cli-rails/pull/403
164 |
165 | 0.7.1
166 | -----
167 |
168 | * Resolve `ember` executable with full path within `node_modules`, instead of
169 | depending on the presence of `node_modules/.bin`. [#395]
170 | * Introduce the idea of `App#mountable?` and `App#to_rack` for handling deploys
171 | that don't serve assets from the file system (Redis, for example).
172 | * Fix bug with generated `bin/heroku_install` script iterating through multiple
173 | * Don't mount route helpers at top-level. Instead, mount within the surrounding
174 | context with which they're invoked. [#381]
175 |
176 | [#395]: https://github.com/thoughtbot/ember-cli-rails/pull/395
177 | [#381]: https://github.com/thoughtbot/ember-cli-rails/pull/381
178 |
179 | 0.7.0
180 | -----
181 |
182 | * Introduce the `deploy` configuration option.
183 | * Translate Rails environments other than `test` or `development` to
184 | `production`, unless an `EMBER_ENV` is specified. [#366]
185 |
186 | [#366]: https://github.com/thoughtbot/ember-cli-rails/pull/366
187 |
188 | 0.6.1
189 | -----
190 |
191 | * Extract `include_ember_*_tags` and the associated code to the
192 | `ember-cli-rails-assets` gem. Add `ember-cli-rails-assets` as a dependency.
193 | [#363]
194 | * Introduce `mount_ember_assets` to serve Ember assets in asset-helper style
195 | projects.
196 |
197 | [#363]: https://github.com/thoughtbot/ember-cli-rails/pull/363
198 |
199 | 0.6.0
200 | -----
201 |
202 | * Use system-level `tee` to pipe `STDOUT` to both `STDOUT` and the logs. [#351]
203 | * Invoke `EmberCli[ember_app].build` from helpers to ensure everything is built
204 | before serving. [#347]
205 | * Remove dependency on `sprockets`. Serve generated files with `Rack::File`.
206 | [#336]
207 | * Rename generator namespace from `ember-cli` to `ember`. [#344]
208 | * Ensure `Rails.root.join("log")` exists when writing to logs.
209 | * Remove deprecated `include_ember_index_html` helper and deprecated
210 | `build_timeout` and `enabled` configurations. [#334]
211 | * Raise build errors for `render_ember_app` failures. [#325]
212 | * Remove `before_{action,filter}` in favor of explicit `EmberCli.build(app)`
213 | call. [#327]
214 |
215 | [#351]: https://github.com/thoughtbot/ember-cli-rails/pull/351
216 | [#347]: https://github.com/thoughtbot/ember-cli-rails/pull/347
217 | [#336]: https://github.com/thoughtbot/ember-cli-rails/pull/336
218 | [#344]: https://github.com/thoughtbot/ember-cli-rails/pull/344
219 | [#334]: https://github.com/thoughtbot/ember-cli-rails/pull/334
220 | [#327]: https://github.com/thoughtbot/ember-cli-rails/pull/327
221 | [#325]: https://github.com/thoughtbot/ember-cli-rails/pull/325
222 |
223 | 0.5.8
224 | -----
225 |
226 | * Ensure cleanup method can destroy temporary folders. [#330]
227 |
228 | [#330]: https://github.com/thoughtbot/ember-cli-rails/pull/330
229 |
230 | 0.5.7
231 | -----
232 |
233 | * Improve command failure reporting. [#324]
234 | * Use latest EmberCLI-generated asset files. [#316]
235 | * Delete previous build output on application boot instead of on process exit.
236 | [#308]
237 |
238 | [#324]: https://github.com/thoughtbot/ember-cli-rails/pull/324
239 | [#316]: https://github.com/thoughtbot/ember-cli-rails/pull/316
240 | [#308]: https://github.com/thoughtbot/ember-cli-rails/pull/308
241 |
242 | 0.5.6
243 | -----
244 |
245 | * Fallback to `before_filter` for Rails 3.2. [#306]
246 | * No longer depend on `tee` executable. Use `Kernel#{spawn,system}` with
247 | redirection options. [#299]
248 |
249 | [#306]: https://github.com/thoughtbot/ember-cli-rails/pull/306
250 | [#299]: https://github.com/thoughtbot/ember-cli-rails/pull/299
251 |
252 | 0.5.5
253 | -----
254 |
255 | * Expose `EmberCli::App#root` for Heroku generator. Fixes [#295]. [#296]
256 |
257 | [#295]: https://github.com/thoughtbot/ember-cli-rails/issues/295
258 | [#296]: https://github.com/thoughtbot/ember-cli-rails/pull/296
259 |
260 | 0.5.4
261 | -----
262 |
263 | * Escape generated CLI strings. Adds support for paths with spaces.
264 |
265 | 0.5.3
266 | -----
267 |
268 | * No longer redirect `STDERR` to `STDOUT` when executing `ember` commands. This
269 | fixes some JRuby bugs. [#288]
270 | * Don't `prune` in generated Heroku setup script. [#286]
271 |
272 | [#288]: https://github.com/thoughtbot/ember-cli-rails/pull/288
273 | [#286]: https://github.com/thoughtbot/ember-cli-rails/pull/286
274 |
275 | 0.5.2
276 | -----
277 |
278 | * Register EmberCLI app with Sprockets on application initialization
279 | * Rename `ember-cli` to `ember_cli` in Ruby.
280 |
281 | 0.5.1
282 | -----
283 |
284 | * Invoke `EmberCli::App#compile` in `test` environment, spawn `build` process in
285 | development, rely on `rake assets:precompile` in `production`-like
286 | environments.
287 |
288 | 0.5.0
289 | -----
290 |
291 | * Deprecate `include_ember_index_html` in favor of the renamed
292 | `render_ember_app`.
293 | * Always pass `--environment test` to Rails-generated `ember test` commands.
294 | [#277]
295 | * No longer check dependencies within the app. Defer to EmberCLI's `stderr`
296 | streaming. [#267]
297 | * Remove `enable` configuration in favor of using `mount_ember_app`. [#261]
298 | * Introduce `mount_ember_app` route helper [#263]
299 | * Remove support for viewing Ember tests through Rails. Instead, use `ember
300 | test` or `ember test --serve` from within the Ember directory. [#264]
301 | * Remove `build_timeout` configuration [#259]
302 | * Disable JS minification when generating Heroku setup [#238]
303 | * `BuildError#message` includes first line of backtrace. [#256]
304 | * Symlink `dist/` directly to Asset Pipeline [#250]
305 | * Merge EmberCLI-generated `manifest.json` into Sprocket's [#250]
306 | * `manifest.json`. Since we now defer to EmberCLI, we no longer need to
307 | manually resolve asset URLs. [#250]
308 |
309 | [#277]: https://github.com/thoughtbot/ember-cli-rails/pull/277
310 | [#267]: https://github.com/thoughtbot/ember-cli-rails/pull/267
311 | [#264]: https://github.com/thoughtbot/ember-cli-rails/pull/264
312 | [#263]: https://github.com/thoughtbot/ember-cli-rails/pull/263
313 | [#259]: https://github.com/thoughtbot/ember-cli-rails/pull/259
314 | [#238]: https://github.com/thoughtbot/ember-cli-rails/pull/238
315 | [#256]: https://github.com/thoughtbot/ember-cli-rails/pull/256
316 | [#250]: https://github.com/thoughtbot/ember-cli-rails/pull/250
317 | [#261]: https://github.com/thoughtbot/ember-cli-rails/pull/261
318 |
319 | 0.4.3
320 | -----
321 |
322 | * Failures in `{bundle,npm,bower} install` will now fail the host process with a
323 | non-zero exit status. [#236]
324 | * Improve error reporting:
325 | Redirect `ember build` from `$STDERR` to the build error file. [#245]
326 |
327 | [#236]: https://github.com/thoughtbot/ember-cli-rails/pull/236
328 | [#245]: https://github.com/thoughtbot/ember-cli-rails/pull/245
329 |
330 | 0.4.2
331 | -----
332 |
333 | * Use the `EmberCli` module in implementation. Ensure backward compatibility by
334 | aliasing the `EmberCli` to `EmberCLI`. [#233]
335 |
336 | [#233]: https://github.com/thoughtbot/ember-cli-rails/pull/233
337 |
338 | 0.4.1
339 | -----
340 |
341 | * `<%= head.append do %>` will now return `nil` so that accidentally using
342 | `<%= %>` variety of ERB tags won't render the contents of the capture [#231]
343 |
344 | [#231]: https://github.com/thoughtbot/ember-cli-rails/pull/231
345 |
346 | 0.4.0
347 | -----
348 |
349 | * Extend `include_ember_index_html` helper to accept a block. The contents of
350 | the block will be injected into the page [#228]
351 | * Drop support for Ruby `< 2.1.0` and Rails `4.0.0, < 3.2.0` [#227]
352 | * Introduce `rails g ember-cli:heroku` generator to configure a project for
353 | deploying to Heroku [#230]
354 | * Introduce `include_ember_index_html` helper [#226]
355 |
356 | [#226]: https://github.com/thoughtbot/ember-cli-rails/pull/226
357 | [#227]: https://github.com/thoughtbot/ember-cli-rails/pull/227
358 | [#228]: https://github.com/thoughtbot/ember-cli-rails/pull/228
359 | [#230]: https://github.com/thoughtbot/ember-cli-rails/pull/230
360 |
361 | 0.3.5
362 | -----
363 |
364 | * Update addon to 0.0.12
365 |
366 | 0.3.4
367 | -----
368 |
369 | * Add `watcher` option
370 |
371 | 0.3.3
372 | -----
373 |
374 | * Support ember-cli 1.13
375 |
376 | 0.3.2
377 | -----
378 |
379 | * Inject `RAILS_ENV` into `ember build` process [#168][https://github.com/rwz/ember-cli-rails/pull/168]
380 | * Explicitly register view helpers [#148](https://github.com/rwz/ember-cli-rails/pull/148)
381 |
382 | 0.3.1
383 | -----
384 |
385 | * Fix `assets:precompile` missing EmberCLI.compile! method
386 |
387 | 0.3.0
388 | -----
389 |
390 | * Add enable option to speficy what paths should have ember compiled [#145](https://github.com/rwz/ember-cli-rails/pull/145)
391 | * Add Runner class to monitor ember deamon failures in development [#145](https://github.com/rwz/ember-cli-rails/pull/145)
392 |
393 | 0.2.3
394 | -----
395 |
396 | * Handle Legacy Rails' lack of acronym support [#144](https://github.com/rwz/ember-cli-rails/pull/144)
397 |
398 | 0.2.2
399 | -----
400 |
401 | * Don't use frozen version string in gemspec [#142](https://github.com/rwz/ember-cli-rails/pull/142)
402 |
403 | 0.2.1
404 | -----
405 |
406 | * Fix missing App#configuration method [#141](https://github.com/rwz/ember-cli-rails/issues/141)
407 |
408 | 0.2.0
409 | -----
410 |
411 | * Rename rake namespace from ember-cli to ember [commit](https://github.com/rwz/ember-cli-rails/commit/3f5463835f05d21a34b5f8a9dfeb482b0501d8d4)
412 | * Allow helpers to take optons for ember assets [commit](https://github.com/rwz/ember-cli-rails/commit/335d117a5bf4d3520730c9c421a25aee5274c2b3)
413 | * Make EmberCLI.skip? predicate return boolean [commit](https://github.com/rwz/ember-cli-rails/commit/6f7cd58010aaf584e0810c44568008654bd1a764)
414 | * Introduce EmberCLI.env and ember\_cli\_rails\_mode config option [commit](https://github.com/rwz/ember-cli-rails/commit/4ff9ea1a1a152bee9f909e4379f6f469650891b5)
415 | * Rename EmberCLI.get\_app to .app and add .[] alias [commit](https://github.com/rwz/ember-cli-rails/commit/71b4c5cc97d9a410e2ef7acc536994e5d71175c6)
416 |
417 | 0.1.13
418 | ------
419 |
420 | * Don't Compile Assets if `SKIP_EMBER` set [#122](https://github.com/rwz/ember-cli-rails/pull/122) [@seanpdoyle](https://twitter.com/seanpdoyle)
421 |
422 | 0.1.12
423 | ------
424 |
425 | * Fix inflector initializer for older Rails [#115](https://github.com/rwz/ember-cli-rails/pull/115) [#117](https://github.com/rwz/ember-cli-rails/pull/117)
426 |
427 | 0.1.11
428 | ------
429 |
430 | * Do not include rake tasks twice [#110](https://github.com/rwz/ember-cli-rails/pull/110) [@BlakeWilliams](https://github.com/BlakeWilliams)
431 |
432 | 0.1.10
433 | ------
434 |
435 | * Support ember-cli 0.2.\* [#88](https://github.com/rwz/ember-cli-rails/issues/88)
436 |
437 | 0.1.9
438 | -----
439 |
440 | * Only set `BUNDLE_GEMFILE` to shell environment if it exists [#92](https://github.com/rwz/ember-cli-rails/issues/92) [@seanpdoyle](https://twitter.com/seanpdoyle)
441 | * Add Support for Rails 3.1 [#99](https://github.com/rwz/ember-cli-rails/pull/99) [@seanpdoyle](https://twitter.com/seanpdoyle)
442 | * Use Rails' configured asset prefix in tests [#104](https://github.com/rwz/ember-cli-rails/pull/104) [@seanpdoyle](https://twitter.com/seanpdoyle)
443 |
444 |
445 | 0.1.8
446 | -----
447 |
448 | * Include engine file into gemspec [#91](https://github.com/rwz/ember-cli-rails/pull/91) [@jesenko](https://github.com/jesenko)
449 |
450 | 0.1.7
451 | -----
452 |
453 | * Serve EmberCLI tests as mountable engine [#90](https://github.com/rwz/ember-cli-rails/pull/90) [@seanpdoyle](https://github.com/seanpdoyle)
454 |
455 | 0.1.6
456 | -----
457 |
458 | * Support Gemfile in EmberCLI app [#84](https://github.com/rwz/ember-cli-rails/commit/652cf12c0a196b4719f6517f2fea308d8d556a5f) [@sevos](https://github.com/sevos)
459 | * Allow relative path to be set via initializer [#72](https://github.com/rwz/ember-cli-rails/issues/74)
460 | * Conditionally silence build output [#82](https://github.com/rwz/ember-cli-rails/issues/82)
461 | * [DEPRECATION] Default EmberCLI application in Rails' app path [#66](https://github.com/rwz/ember-cli-rails/issues/66) [@jesenko](https://github.com/jesenko)
462 |
463 | 0.1.5
464 | -----
465 |
466 | * Compilation and dependencies Rake tasks improved [#79](https://github.com/rwz/ember-cli-rails/pull/79)
467 |
468 | 0.1.4
469 | -----
470 |
471 | * Expose `ember-cli:compile` rake task [#73](https://github.com/rwz/ember-cli-rails/pull/73)
472 |
473 | 0.1.3
474 | -----
475 |
476 | * Make sure setting optional config parameters override defaults [#70](https://github.com/rwz/ember-cli-rails/issues/70)
477 |
478 | 0.1.2
479 | -----
480 |
481 | * Bump addon version to prevent missing tmp folder error [ember-cli-rails-addon#8](https://github.com/rondale-sc/ember-cli-rails-addon/pull/8)
482 | * Add configuration to control Middleware and live recompilation [#64](https://github.com/rwz/ember-cli-rails/issues/64)
483 |
484 | 0.1.1
485 | -----
486 |
487 | * Add ember-cli:test take task [#60](https://github.com/rwz/ember-cli-rails/pull/60)
488 |
489 | 0.1.0
490 | -----
491 |
492 | * Expose rake task for `npm install` [#59](https://github.com/rwz/ember-cli-rails/pull/59)
493 | * Detect and raise EmberCLI build errors [#23](https://github.com/rwz/ember-cli-rails/pull/23)
494 |
495 | 0.0.18
496 | ------
497 |
498 | * Remove suppress jQuery feature [#49](https://github.com/rwz/ember-cli-rails/issues/49)
499 | * Add option to manually suppress Ember dependencies [#55](https://github.com/rwz/ember-cli-rails/pull/55)
500 |
501 | 0.0.17
502 | ------
503 |
504 | * Only precompile assets that start with [#53](https://github.com/rwz/ember-cli-rails/pull/53)
505 |
506 | 0.0.16
507 | ------
508 |
509 | * Use local executable for ember-cli instead of global one.
510 | [Commit](https://github.com/rwz/ember-cli-rails/commit/4aeee53f048f0445645fbc478770417fdb66cace).
511 | * Use `Dir.chdir` instead of passing `chdir` to `system`/`spawn`. Seems like
512 | JRuby doesn't yet support `chdir` option for these methods.
513 | Commits: [1](https://github.com/rwz/ember-cli-rails/commit/3bb149941f206153003726f1c18264dc62197f51),
514 | [2](https://github.com/rwz/ember-cli-rails/commit/82a39f6e523ad35ecdd595fb6e49a04cb54f9c6f).
515 |
516 | 0.0.15
517 | ------
518 |
519 | * Fix NameError when addon version doesn't match.
520 | [#47](https://github.com/rwz/ember-cli-rails/pull/47)
521 | * Fix race condition in symlink creation when run multiple workers (again).
522 | [#22](https://github.com/rwz/ember-cli-rails/pull/22)
523 |
524 | 0.0.14
525 | ------
526 |
527 | * Do not include jQuery into vendor.js when jquery-rails is available.
528 | [#32](https://github.com/rwz/ember-cli-rails/issues/32)
529 |
530 | 0.0.13
531 | ------
532 |
533 | * Fix assets:precompile in production environment.
534 | [#38](https://github.com/rwz/ember-cli-rails/issues/38)
535 |
536 | 0.0.12
537 | ------
538 |
539 | * Make sure ember-cli-dependency-checker is present.
540 | [#35](https://github.com/rwz/ember-cli-rails/issues/35)
541 |
542 | 0.0.11
543 | ------
544 |
545 | * Fix locking feature by bumping addon version to 0.0.5.
546 | [#31](https://github.com/rwz/ember-cli-rails/issues/31)
547 |
548 | 0.0.10
549 | ------
550 |
551 | * Add locking feature to prevent stale code.
552 | [#25](https://github.com/rwz/ember-cli-rails/pull/25)
553 |
554 | 0.0.9
555 | -----
556 |
557 | * Fix a bug when path provided as a string, not pathname.
558 | [#24](https://github.com/rwz/ember-cli-rails/issues/24)
559 |
560 | 0.0.8
561 | -----
562 |
563 | * Add support for including Ember stylesheet link tags.
564 | [#21](https://github.com/rwz/ember-cli-rails/pull/21)
565 |
566 | * Fix an error when the symlink already exists.
567 | [#22](https://github.com/rwz/ember-cli-rails/pull/22)
568 |
569 | 0.0.7
570 | -----
571 |
572 | * Add sprockets-rails to dependency list.
573 | [Commit](https://github.com/rwz/ember-cli-rails/commit/99a893030d6b754fe71363a396fd4515b93812b6)
574 |
575 | * Add a flag to skip ember-cli integration.
576 | [#17](https://github.com/rwz/ember-cli-rails/issues/17)
577 |
578 | 0.0.6
579 | -----
580 |
581 | * Fix compiling assets in test environment. [#15](https://github.com/rwz/ember-cli-rails/pull/15)
582 | * Use only development/production Ember environments. [#16](https://github.com/rwz/ember-cli-rails/pull/16)
583 | * Make the gem compatible with ruby 1.9.3. [#20](https://github.com/rwz/ember-cli-rails/issues/20)
584 |
585 | 0.0.5
586 | -----
587 |
588 | * Fix generator. [Commit](https://github.com/rwz/ember-cli-rails/commit/c1bb10c6a2ec5b24d55fe69b6919fdd415fd1cdc).
589 |
590 | 0.0.4
591 | -----
592 |
593 | * Add assets:precompile hook. [#11](https://github.com/rwz/ember-cli-rails/issues/11)
594 |
595 | 0.0.3
596 | -----
597 |
598 | * Make gem Ruby 2.0 compatible. [#12](https://github.com/rwz/ember-cli-rails/issues/12)
599 |
600 | 0.0.2
601 | -----
602 |
603 | * Do not assume ember-cli app name is equal to configured name. [#5](https://github.com/rwz/ember-cli-rails/issues/5)
604 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ember CLI Rails
2 |
3 | Unify your EmberCLI and Rails Workflows!
4 |
5 | EmberCLI-Rails is designed to give you the best of both worlds:
6 |
7 | * Stay up to date with the latest JavaScript technology and EmberCLI addons
8 | * Develop your Rails API and Ember front-ends from within a single process
9 | * Inject Rails-generated content into your EmberCLI application
10 | * Avoid Cross-Origin Resource Sharing gotchas by serving your EmberCLI
11 | applications and your API from a single domain
12 | * Write truly end-to-end integration tests, exercising your application's entire
13 | stack through JavaScript-enabled Capybara tests
14 | * Deploy your entire suite of applications to Heroku with a single `git push`
15 |
16 | If you're having trouble, checkout the [example project]!
17 |
18 | **EmberCLI-Rails Supports EmberCLI 1.13.13 and later.**
19 |
20 | [example project]: https://github.com/seanpdoyle/ember-cli-rails-heroku-example
21 |
22 | ## Install
23 |
24 | Add the following to your `Gemfile`:
25 |
26 | ```ruby
27 | gem "ember-cli-rails"
28 | ```
29 |
30 | Then run `bundle install`:
31 |
32 | ```bash
33 | $ bundle install
34 | ```
35 |
36 | If you haven't created an Ember application yet, generate a new one:
37 |
38 | ```bash
39 | $ ember new frontend --skip-git
40 | ```
41 |
42 | ## Setup
43 |
44 | First, generate the gem's initializer:
45 |
46 | ```bash
47 | $ rails generate ember:init
48 | ```
49 |
50 | This will create the following initializer:
51 |
52 | ```ruby
53 | # config/initializers/ember.rb
54 |
55 | EmberCli.configure do |c|
56 | c.app :frontend
57 | end
58 | ```
59 |
60 | This initializer assumes that your Ember application exists in
61 | `Rails.root.join("frontend")`.
62 |
63 | If this is not the case, you could
64 |
65 | * move your existing Ember application into `Rails.root.join("frontend")`
66 | * configure `frontend` to reference the Ember application in its current
67 | directory:
68 |
69 | ```rb
70 | c.app :frontend, path: "~/projects/my-ember-app"
71 | ```
72 |
73 | **Initializer options**
74 |
75 | - `name` - this represents the name of the Ember CLI application.
76 |
77 | - `path` - the path where your Ember CLI application is located. The default
78 | value is the name of your app in the Rails root.
79 |
80 | - `silent` - this provides `--silent` option for Ember CLI commands to control verbosity of their output.
81 |
82 | - `yarn` - enables the [yarn](https://github.com/yarnpkg/yarn) package manager when installing dependencies
83 |
84 | ```ruby
85 | EmberCli.configure do |c|
86 | c.app :adminpanel # path defaults to `Rails.root.join("adminpanel")`
87 | c.app :frontend,
88 | path: "/path/to/your/ember-cli-app/on/disk"
89 | c.app :payments, silent: true # by default it's false
90 | end
91 | ```
92 |
93 | Next, install the [ember-cli-rails-addon][addon]:
94 |
95 | ```bash
96 | $ cd path/to/frontend
97 | $ ember install ember-cli-rails-addon
98 | ```
99 |
100 | Be sure that the addon's [`MAJOR` and `MINOR` version][semver] matches the gem's
101 | `MAJOR` and `MINOR` versions.
102 |
103 | For instance, if you're using the `0.6.x` version of the gem, specify
104 | `~> 0.6.0` in your Ember app's `package.json`:
105 |
106 | ```json
107 | {
108 | "devDependencies": {
109 | "ember-cli-rails-addon": "~> 0.6.0"
110 | }
111 | }
112 | ```
113 |
114 | [addon]: https://github.com/rondale-sc/ember-cli-rails-addon/
115 | [semver]: http://semver.org/
116 |
117 | ## Mount
118 |
119 | Configure Rails to route requests to the `frontend` Ember application:
120 |
121 | ```rb
122 | # config/routes.rb
123 |
124 | Rails.application.routes.draw do
125 | mount_ember_app :frontend, to: "/"
126 | end
127 | ```
128 |
129 | **Routing options**
130 |
131 | * `to` - The path to handle as an Ember application. This will only apply to
132 | `format: :html` requests. Additionally, this will handle child routes as well.
133 | For instance, mounting `mount_ember_app :frontend, to: "/frontend"` will handle a
134 | `format: :html` request to `/frontend/posts`.
135 | *Note:* If you specify a custom path, you must also update the `rootURL` in `frontend/config/environment.js`. See [Mounting multiple Ember applications](#mounting-multiple-ember-applications) for more information.
136 | * `controller` - Defaults to `"ember_cli/ember"`
137 | * `action` - Defaults to `"index"`
138 |
139 | Finally, install your Ember application's dependencies:
140 |
141 | ```bash
142 | $ rake ember:install
143 | ```
144 |
145 | Boot your Rails application, navigate to `"/"`, and view your EmberCLI
146 | application!
147 |
148 | ## Develop
149 |
150 | EmberCLI Rails exposes several useful rake tasks.
151 |
152 | **`ember:install`**
153 |
154 | Install the Ember applications' dependencies.
155 |
156 | **`ember:compile`**
157 |
158 | Compile the Ember applications.
159 |
160 | **`ember:test`**
161 |
162 | Execute Ember's test suite.
163 |
164 | If you're using Rake to run the test suite, make sure to configure your test
165 | task to depend on `ember:test`.
166 |
167 | For example, to configure a bare `rake` command to run both RSpec and Ember test
168 | suites, configure the `default` task to depend on both `spec` and `ember:test`.
169 |
170 | ```rb
171 | task default: [:spec, "ember:test"]
172 | ```
173 |
174 | ## Deploy
175 |
176 | When Rails is running in production mode, EmberCLI-Rails stops doing runtime
177 | compilation. Instead, configured apps are built during `rake assets:precompile`.
178 | This keeps things quick for end users, and extends the normal Rails asset
179 | building process.
180 |
181 | Configuration information, including instructions for Heroku and Capistrano,
182 | can be found below.
183 |
184 | ### CDN
185 |
186 | In production environments, assets should be served over a
187 | Content Delivery Network.
188 |
189 | Configuring an `ember-cli-rails` application to serve Ember's assets over a CDN
190 | is very similar to [configuring an EmberCLI application to serve assets over a
191 | CDN][ember-cli-cdn]:
192 |
193 | [ember-cli-cdn]: http://ember-cli.com/user-guide/#fingerprinting-and-cdn-urls
194 |
195 | ```js
196 | var app = new EmberApp({
197 | fingerprint: {
198 | prepend: 'https://cdn.example.com/'
199 | }
200 | });
201 | ```
202 |
203 | If you're serving the Ember application from a path other than `"/"`, the
204 | `prepend` URL must end with the mounted path:
205 |
206 | ```js
207 | var app = new EmberApp({
208 | fingerprint: {
209 | // for an Ember application mounted to `/admin_panel/`
210 | prepend: 'https://cdn.example.com/admin_panel/',
211 | }
212 | });
213 | ```
214 |
215 | As long as your [CDN is configured to pull from your Rails application][dns-cdn]
216 | , your assets will be served over the CDN.
217 |
218 | [dns-cdn]: https://robots.thoughtbot.com/dns-cdn-origin
219 |
220 | ### Deployment Strategies
221 |
222 | By default, EmberCLI-Rails uses a file-based deployment strategy that depends on
223 | the output of `ember build`.
224 |
225 | Using this deployment strategy, Rails will serve the `index.html` file and other
226 | assets that `ember build` produces.
227 |
228 | These EmberCLI-generated assets are served with the same `Cache-Control` headers
229 | as Rails' other static files:
230 |
231 | ```rb
232 | # config/environments/production.rb
233 | Rails.application.configure do
234 | # serve static files with cache headers set to expire in 1 year
235 | config.static_cache_control = "public, max-age=31622400"
236 | end
237 | ```
238 |
239 | If you need to override this behavior (for instance, if you're using
240 | [`ember-cli-deploy`'s "Lightning Fast Deployment"][lightning] strategy in
241 | `production`), you can specify the strategy's class in the initializer:
242 |
243 | ```rb
244 | EmberCli.configure do |config|
245 | config.app :frontend, deploy: { production: EmberCli::Deploy::Redis }
246 | end
247 | ```
248 |
249 | This example configures the `frontend` Ember application to retrieve the
250 | index's HTML from an [`ember-cli-deploy-redis`][ember-cli-deploy-redis]
251 | -populated Redis entry using the
252 | [`ember-cli-rails-deploy-redis`][ember-cli-rails-deploy-redis] gem.
253 |
254 | If you're deploying HTML with a custom strategy in `development` or `test`,
255 | disable EmberCLI-Rails' build step by setting `ENV["SKIP_EMBER"] = true`.
256 |
257 | **NOTE:**
258 |
259 | Specifying a deployment strategy is only supported for applications that use the
260 | `mount_ember_app` and `render_ember_app` helpers.
261 |
262 | [ember-cli-deploy-redis]: https://github.com/ember-cli-deploy/ember-cli-deploy-redis
263 | [ember-cli-rails-deploy-redis]: https://github.com/seanpdoyle/ember-cli-rails-deploy-redis
264 | [lightning]: https://github.com/ember-cli-deploy/ember-cli-deploy-lightning-pack
265 |
266 | ### Heroku
267 |
268 | To configure your EmberCLI-Rails applications for Heroku:
269 |
270 | 1. Execute `rails generate ember:heroku`.
271 | 1. Commit the newly generated files.
272 | 1. [Add the NodeJS buildpack][buildpack] and configure NPM to include the
273 | `bower` dependency's executable file (if your build process requires
274 | `bower`).
275 |
276 | ```sh
277 | $ heroku buildpacks:clear
278 | $ heroku buildpacks:add --index 1 heroku/nodejs
279 | $ heroku buildpacks:add --index 2 heroku/ruby
280 | $ heroku config:unset SKIP_EMBER
281 | ```
282 |
283 | You are ready to deploy:
284 |
285 | ```bash
286 | $ git push heroku master
287 | ```
288 |
289 | EmberCLI compilation happens at deploy-time, triggered by the `asset:precompile` rake task.
290 |
291 | **NOTE** Run the generator each time you introduce additional EmberCLI
292 | applications into the project.
293 |
294 | [buildpack]: https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app#adding-a-buildpack
295 |
296 | #### Slug size
297 |
298 | [Heroku slug size is limited](https://devcenter.heroku.com/articles/slug-compiler#slug-size). The build process creates artifacts that are not necessary for the server to run, but are included in the deployed Heroku slug.
299 |
300 | Omitting these build assets can dramatically reduce slug size.
301 |
302 | A build-pack solution for this is discussed in [Issue #491][#491].
303 |
304 | [#491]: https://github.com/tricknotes/ember-cli-rails/issues/491
305 |
306 | ### Capistrano
307 |
308 | EmberCLI-Rails executes both `npm install` and `bower install` during EmberCLI's
309 | compilation, triggered by the `asset:precompile` rake task.
310 |
311 | The `npm` and `bower` executables are required to be defined in the deployment
312 | SSH session's `$PATH`. It is not sufficient to modify the session's `$PATH` in
313 | a `.bash_profile`.
314 |
315 | To resolve this issue, prepend the Node installation's `bin` directory to the
316 | target system's `$PATH`:
317 |
318 | ```ruby
319 | #config/deploy/production.rb
320 |
321 | set :default_env, {
322 | "PATH" => "/home/deploy/.nvm/versions/node/v4.2.1/bin:$PATH"
323 | }
324 | ```
325 |
326 | The system in this example is using `nvm` to configure the node version. If
327 | you're not using `nvm`, make sure the string you prepend to the `$PATH` variable
328 | contains the directory or directories that contain the `bower` and `npm`
329 | executables.
330 |
331 | #### For faster deployments
332 |
333 | Place the following in your `deploy/.rb`
334 |
335 | ```ruby
336 | set :linked_dirs, %w{/node_modules /bower_components}
337 | ```
338 |
339 | to avoid rebuilding all the node modules and bower components with every deploy.
340 | Replace `` with the name of your ember app (default is
341 | `frontend`).
342 |
343 | ## Override
344 |
345 | By default, routes defined by `ember_app` will be rendered with the internal
346 | `EmberCli::EmberController`.
347 |
348 | ### Overriding the view
349 |
350 | The `EmberCli::EmberController` renders the Ember application's `index.html` and
351 | injects the Rails-generated CSRF tags into the ``.
352 |
353 | To customize the view, create `app/views/ember_cli/ember/index.html.erb`:
354 |
355 | ```erb
356 | <%= render_ember_app ember_app do |head| %>
357 | <% head.append do %>
358 | <%= csrf_meta_tags %>
359 | <% end %>
360 | <% end %>
361 | ```
362 |
363 | The `ember_app` helper is available within the `EmberCli::EmberController`'s
364 | view, and refers to the name of the current EmberCLI application.
365 |
366 | To inject the EmberCLI generated `index.html`, use the `render_ember_app`
367 | helper in your view:
368 |
369 | ```erb
370 |
371 | <%= render_ember_app :frontend do |head, body| %>
372 | <% head.append do %>
373 | <%= csrf_meta_tags %>
374 | <% end %>
375 |
376 | <% body.append do %>
377 | <%= render partial: "my-analytics" %>
378 | <% end %>
379 | <% end %>
380 | ```
381 |
382 | The `body` block argument and the corresponding call to `body.append` in the
383 | example are both optional, and can be omitted.
384 |
385 | ### Serving Rails-generated CSS
386 |
387 | For more information on how to work with EmberCLI-generated stylesheets, refer
388 | to the [Stylesheets section][ember-cli-css]. EmberCLI-generated CSS will be
389 | embedded in the response's HTML document by default.
390 |
391 | To serve assets generated and served by Rails, inject them into the document's
392 | ``:
393 |
394 | ```erb
395 | <%= render_ember_app :frontend do |head| %>
396 | <% head.append do %>
397 | <%= stylesheet_link_tag "application" %>
398 | <%= csrf_meta_tags %>
399 | <% end %>
400 | <% end %>
401 | ```
402 |
403 | There are no technical limitations to sharing assets between the Ember client
404 | and the Rails server, but picking one or the other might simplify the project's
405 | organization.
406 |
407 | Sharing code during asset compilation is __not__ possible.
408 |
409 | For example, Ember's SCSS files __cannot__ use `@import` directives referencing
410 | Rails' SCSS modules.
411 |
412 | [ember-cli-css]: http://ember-cli.com/user-guide/#stylesheets
413 |
414 | ### Overriding the controller
415 |
416 | To override this behavior, you can specify [any of Rails' routing options]
417 | [route-options].
418 |
419 | [route-options]: http://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Base.html#method-i-match
420 |
421 | For the sake of this example, override the `controller` and `action` options:
422 |
423 | ```rb
424 | # config/routes.rb
425 |
426 | Rails.application.routes.draw do
427 | mount_ember_app :frontend, to: "/", controller: "application", action: "index"
428 | end
429 | ```
430 |
431 | When serving the EmberCLI generated `index.html` with the `render_ember_app`
432 | helper, make sure the controller's `layout` is disabled, as EmberCLI generates a
433 | fully-formed HTML document:
434 |
435 | ```rb
436 | # app/controllers/application.rb
437 | class ApplicationController < ActionController::Base
438 | def index
439 | render layout: false
440 | end
441 | end
442 | ```
443 |
444 | ### Rendering the EmberCLI generated JS and CSS
445 |
446 | Rendering EmberCLI applications with `render_ember_app` is the recommended,
447 | actively supported method of serving EmberCLI applications.
448 |
449 | However, for the sake of backwards compatibility, `ember-cli-rails` supports
450 | injecting the EmberCLI-generated assets into an existing Rails layout.
451 |
452 | Following the example above, configure the mounted EmberCLI application to be
453 | served by a custom controller (`ApplicationController`, in this case).
454 |
455 | In the corresponding view, use the asset helpers:
456 |
457 | ```erb
458 | <%= include_ember_script_tags :frontend %>
459 | <%= include_ember_stylesheet_tags :frontend %>
460 | ```
461 |
462 | ### Mounting multiple Ember applications
463 |
464 | Rendering Ember applications to paths other than `/` requires additional
465 | configuration.
466 |
467 | Consider a scenario where you had Ember applications named `frontend` and
468 | `admin_panel`, served from `/` and `/admin_panel` respectively.
469 |
470 | First, specify the Ember applications in the initializer:
471 |
472 | ```ruby
473 | EmberCli.configure do |c|
474 | c.app :frontend
475 | c.app :admin_panel, path: "path/to/admin_ember_app"
476 | end
477 | ```
478 |
479 | Next, mount the applications alongside the rest of Rails' routes. Note that `admin_panel` route is added before the `frontend` route because it's more specific:
480 |
481 | ```rb
482 | # /config/routes.rb
483 | Rails.application.routes.draw do
484 | mount_ember_app :admin_panel, to: "/admin_panel"
485 | mount_ember_app :frontend, to: "/"
486 | end
487 | ```
488 |
489 | Then set each Ember application's `rootURL` to the mount point:
490 |
491 | ```javascript
492 | // frontend/config/environment.js
493 |
494 | module.exports = function(environment) {
495 | var ENV = {
496 | modulePrefix: 'frontend',
497 | environment: environment,
498 | rootURL: '/',
499 | // ...
500 | }
501 | };
502 |
503 | // path/to/admin_ember_app/config/environment.js
504 |
505 | module.exports = function(environment) {
506 | var ENV = {
507 | modulePrefix: 'admin_panel',
508 | environment: environment,
509 | rootURL: '/admin_panel', // originally '/'
510 | // ...
511 | }
512 | };
513 | ```
514 |
515 | Finally, configure EmberCLI's fingerprinting to prepend the mount point to the
516 | application's assets:
517 |
518 | ```js
519 | // frontend/ember-cli-build.js
520 |
521 | module.exports = function(defaults) {
522 | var app = new EmberApp(defaults, {
523 | fingerprint: {
524 | // matches the `/` mount point
525 | prepend: 'https://cdn.example.com/',
526 | }
527 | });
528 | };
529 |
530 |
531 | // path/to/admin_ember_app/ember-cli-build.js
532 |
533 | module.exports = function(defaults) {
534 | var app = new EmberApp(defaults, {
535 | fingerprint: {
536 | // matches the `/admin_panel` mount point
537 | prepend: 'https://cdn.example.com/admin_panel/',
538 | }
539 | });
540 | };
541 | ```
542 |
543 | When injecting the EmberCLI-generated assets with the `include_ember_script_tags`
544 | and `include_ember_stylesheet_tags` helpers to a path other than `"/"`, a
545 | `` tag must also be injected with a corresponding `href` value:
546 |
547 | ```erb
548 |
549 | <%= include_ember_script_tags :frontend %>
550 | <%= include_ember_stylesheet_tags :frontend %>
551 |
552 |
553 | <%= include_ember_script_tags :admin_panel %>
554 | <%= include_ember_stylesheet_tags :admin_panel %>
555 | ```
556 |
557 | If you're using the `include_ember` style helpers with a single-page Ember
558 | application that defers routing to the Rails application, insert a call to
559 | `mount_ember_assets` at the bottom of your routes file to serve the
560 | EmberCLI-generated assets:
561 |
562 | ```rb
563 | # config/routes.rb
564 | Rails.application.routes.draw do
565 | mount_ember_assets :frontend, to: "/"
566 | end
567 | ```
568 |
569 | ## CSRF Tokens
570 |
571 | Your Rails controllers, by default, expect a valid authenticity token to
572 | be submitted along with non-`GET` requests.
573 |
574 | Without the authenticity token, requests will respond with
575 | `422 Unprocessable Entity` errors (specifically
576 | `ActionController::InvalidAuthenticityToken`).
577 |
578 | To add the necessary tokens to requests, inject the `csrf_meta_tags` into
579 | the template:
580 |
581 | ```erb
582 |
583 | <%= render_ember_app :frontend do |head| %>
584 | <% head.append do %>
585 | <%= csrf_meta_tags %>
586 | <% end %>
587 | <% end %>
588 | ```
589 |
590 | The default `EmberCli::EmberController` and the default view handle behave like
591 | this by default.
592 |
593 | If an Ember application is mounted with another controller, it should append
594 | the CSRF tags to its view's ``.
595 |
596 | [ember-cli-rails-addon][addon] configures your Ember application to make HTTP
597 | requests with the injected CSRF tokens in the `X-CSRF-TOKEN` header.
598 |
599 | ## Serving from multi-process servers in development
600 |
601 | If you're using a multi-process server ([Puma], [Unicorn], etc.) in development,
602 | make sure it's configured to run a single worker process.
603 |
604 | Without restricting the server to a single process, [it is possible for multiple
605 | EmberCLI runners to clobber each others' work][#94].
606 |
607 | [Puma]: https://github.com/puma/puma
608 | [Unicorn]: https://rubygems.org/gems/unicorn
609 | [#94]: https://github.com/tricknotes/ember-cli-rails/issues/94#issuecomment-77627453
610 |
611 | ## `SKIP_EMBER`
612 |
613 | If set on the environment, `SKIP_EMBER` will configure `ember-cli-rails` to skip
614 | the build step entirely. This is useful if you're using an alternative
615 | deployment strategy in the `test` or `development` environment. By default,
616 | `ember-cli-rails` will skip the build step in `production`-like environments.
617 |
618 | ## `EMBER_ENV`
619 |
620 | If set on the environment, the value of `EMBER_ENV` will be passed to the
621 | `ember` process as the value of the `--environment` flag.
622 |
623 | If `EMBER_ENV` is unspecified, the current Rails environment will be passed to
624 | the `ember` process, with the exception of non-standard Rails environments,
625 | which will be replaced with `production`.
626 |
627 | ## `RAILS_ENV`
628 |
629 | While being managed by EmberCLI Rails, EmberCLI process will have
630 | access to the `RAILS_ENV` environment variable. This can be helpful to detect
631 | the Rails environment from within the EmberCLI process.
632 |
633 | This can be useful to determine whether or not EmberCLI is running in its own
634 | standalone process or being managed by Rails.
635 |
636 | For example, to enable [ember-cli-mirage][ember-cli-mirage] API responses in
637 | `development` while being run outside of Rails (while run by `ember serve`),
638 | check for the absence of the `RAILS_ENV` environment variable:
639 |
640 | ```js
641 | // config/environment.js
642 | if (environment === 'development') {
643 | ENV['ember-cli-mirage'] = {
644 | enabled: typeof process.env.RAILS_ENV === 'undefined',
645 | }
646 | }
647 | ```
648 |
649 | `RAILS_ENV` will be absent in production builds.
650 |
651 | [ember-cli-mirage]: http://ember-cli-mirage.com/docs/latest/
652 |
653 | ## EmberCLI support
654 |
655 | This project supports:
656 |
657 | * EmberCLI versions `>= 1.13.13`
658 |
659 | ## Ruby and Rails support
660 |
661 | This project supports:
662 |
663 | * Ruby versions `>= 2.5.0`
664 | * Rails versions `>=5.2.x`.
665 |
666 | To learn more about supported versions and upgrades, read the [upgrading guide].
667 |
668 | [upgrading guide]: /UPGRADING.md
669 |
670 | ## Contributing
671 |
672 | See the [CONTRIBUTING] document.
673 | Thank you, [contributors]!
674 |
675 | [CONTRIBUTING]: CONTRIBUTING.md
676 | [contributors]: https://github.com/tricknotes/ember-cli-rails/graphs/contributors
677 |
678 | ## License
679 |
680 | Open source templates are Copyright (c) 2015 thoughtbot, inc.
681 | It contains free software that may be redistributed
682 | under the terms specified in the [LICENSE] file.
683 |
684 | [LICENSE]: /LICENSE.txt
685 |
686 | ## About
687 |
688 | ember-cli-rails was originally created by
689 | [Pavel Pravosud][rwz] and
690 | [Jonathan Jackson][rondale-sc].
691 |
692 | ember-cli-rails is maintained by [Sean Doyle][seanpdoyle], [Jonathan
693 | Jackson][rondale-sc] and [Ryunosuke Sato][tricknotes].
694 |
695 | [rwz]: https://github.com/rwz
696 | [rondale-sc]: https://github.com/rondale-sc
697 | [seanpdoyle]: https://github.com/seanpdoyle
698 | [tricknotes]: https://github.com/tricknotes
699 |
--------------------------------------------------------------------------------