crazy-yard 3.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +19 -0
  3. data/README.md +438 -0
  4. data/bin/ey +9 -0
  5. data/lib/engineyard.rb +9 -0
  6. data/lib/engineyard/cli.rb +816 -0
  7. data/lib/engineyard/cli/api.rb +98 -0
  8. data/lib/engineyard/cli/recipes.rb +129 -0
  9. data/lib/engineyard/cli/ui.rb +275 -0
  10. data/lib/engineyard/cli/web.rb +85 -0
  11. data/lib/engineyard/config.rb +158 -0
  12. data/lib/engineyard/deploy_config.rb +65 -0
  13. data/lib/engineyard/deploy_config/ref.rb +56 -0
  14. data/lib/engineyard/error.rb +82 -0
  15. data/lib/engineyard/eyrc.rb +59 -0
  16. data/lib/engineyard/repo.rb +105 -0
  17. data/lib/engineyard/serverside_runner.rb +159 -0
  18. data/lib/engineyard/templates.rb +6 -0
  19. data/lib/engineyard/templates/ey.yml.erb +196 -0
  20. data/lib/engineyard/templates/ey_yml.rb +119 -0
  21. data/lib/engineyard/thor.rb +215 -0
  22. data/lib/engineyard/version.rb +4 -0
  23. data/lib/vendor/thor/Gemfile +15 -0
  24. data/lib/vendor/thor/LICENSE.md +20 -0
  25. data/lib/vendor/thor/README.md +35 -0
  26. data/lib/vendor/thor/lib/thor.rb +473 -0
  27. data/lib/vendor/thor/lib/thor/actions.rb +318 -0
  28. data/lib/vendor/thor/lib/thor/actions/create_file.rb +105 -0
  29. data/lib/vendor/thor/lib/thor/actions/create_link.rb +60 -0
  30. data/lib/vendor/thor/lib/thor/actions/directory.rb +119 -0
  31. data/lib/vendor/thor/lib/thor/actions/empty_directory.rb +137 -0
  32. data/lib/vendor/thor/lib/thor/actions/file_manipulation.rb +314 -0
  33. data/lib/vendor/thor/lib/thor/actions/inject_into_file.rb +109 -0
  34. data/lib/vendor/thor/lib/thor/base.rb +652 -0
  35. data/lib/vendor/thor/lib/thor/command.rb +136 -0
  36. data/lib/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +80 -0
  37. data/lib/vendor/thor/lib/thor/core_ext/io_binary_read.rb +12 -0
  38. data/lib/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
  39. data/lib/vendor/thor/lib/thor/error.rb +28 -0
  40. data/lib/vendor/thor/lib/thor/group.rb +282 -0
  41. data/lib/vendor/thor/lib/thor/invocation.rb +172 -0
  42. data/lib/vendor/thor/lib/thor/parser.rb +4 -0
  43. data/lib/vendor/thor/lib/thor/parser/argument.rb +74 -0
  44. data/lib/vendor/thor/lib/thor/parser/arguments.rb +171 -0
  45. data/lib/vendor/thor/lib/thor/parser/option.rb +121 -0
  46. data/lib/vendor/thor/lib/thor/parser/options.rb +218 -0
  47. data/lib/vendor/thor/lib/thor/rake_compat.rb +72 -0
  48. data/lib/vendor/thor/lib/thor/runner.rb +322 -0
  49. data/lib/vendor/thor/lib/thor/shell.rb +88 -0
  50. data/lib/vendor/thor/lib/thor/shell/basic.rb +393 -0
  51. data/lib/vendor/thor/lib/thor/shell/color.rb +148 -0
  52. data/lib/vendor/thor/lib/thor/shell/html.rb +127 -0
  53. data/lib/vendor/thor/lib/thor/util.rb +270 -0
  54. data/lib/vendor/thor/lib/thor/version.rb +3 -0
  55. data/lib/vendor/thor/thor.gemspec +24 -0
  56. data/spec/engineyard/cli/api_spec.rb +50 -0
  57. data/spec/engineyard/cli_spec.rb +28 -0
  58. data/spec/engineyard/config_spec.rb +61 -0
  59. data/spec/engineyard/deploy_config_spec.rb +194 -0
  60. data/spec/engineyard/eyrc_spec.rb +76 -0
  61. data/spec/engineyard/repo_spec.rb +83 -0
  62. data/spec/engineyard_spec.rb +7 -0
  63. data/spec/ey/console_spec.rb +57 -0
  64. data/spec/ey/deploy_spec.rb +435 -0
  65. data/spec/ey/ey_spec.rb +23 -0
  66. data/spec/ey/init_spec.rb +123 -0
  67. data/spec/ey/list_environments_spec.rb +120 -0
  68. data/spec/ey/login_spec.rb +33 -0
  69. data/spec/ey/logout_spec.rb +24 -0
  70. data/spec/ey/logs_spec.rb +36 -0
  71. data/spec/ey/rebuild_spec.rb +18 -0
  72. data/spec/ey/recipes/apply_spec.rb +29 -0
  73. data/spec/ey/recipes/download_spec.rb +43 -0
  74. data/spec/ey/recipes/upload_spec.rb +99 -0
  75. data/spec/ey/rollback_spec.rb +73 -0
  76. data/spec/ey/scp_spec.rb +176 -0
  77. data/spec/ey/servers_spec.rb +209 -0
  78. data/spec/ey/ssh_spec.rb +273 -0
  79. data/spec/ey/status_spec.rb +45 -0
  80. data/spec/ey/timeout_deploy_spec.rb +18 -0
  81. data/spec/ey/web/disable_spec.rb +21 -0
  82. data/spec/ey/web/enable_spec.rb +26 -0
  83. data/spec/ey/web/restart_spec.rb +21 -0
  84. data/spec/ey/whoami_spec.rb +30 -0
  85. data/spec/spec_helper.rb +84 -0
  86. data/spec/support/bundled_ey +7 -0
  87. data/spec/support/fixture_recipes.tgz +0 -0
  88. data/spec/support/git_repos.rb +115 -0
  89. data/spec/support/helpers.rb +330 -0
  90. data/spec/support/matchers.rb +16 -0
  91. data/spec/support/ruby_ext.rb +13 -0
  92. data/spec/support/shared_behavior.rb +278 -0
  93. metadata +411 -0
@@ -0,0 +1,59 @@
1
+ module EY
2
+ class EYRC
3
+ attr_reader :path
4
+
5
+ DEFAULT_PATH = "~/.eyrc"
6
+
7
+ def self.load
8
+ new(ENV['EYRC'] || DEFAULT_PATH)
9
+ end
10
+
11
+ def initialize(path)
12
+ @path = Pathname.new(path).expand_path
13
+ end
14
+
15
+ def exist?
16
+ path.exist?
17
+ end
18
+
19
+ def delete_api_token
20
+ delete('api_token')
21
+ end
22
+
23
+ def api_token
24
+ self['api_token']
25
+ end
26
+
27
+ def api_token=(token)
28
+ self['api_token'] = token
29
+ end
30
+
31
+ private
32
+
33
+ def [](key)
34
+ read_data[key.to_s]
35
+ end
36
+
37
+ def []=(key,val)
38
+ new_data = read_data.merge(key.to_s => val)
39
+ write_data new_data
40
+ val
41
+ end
42
+
43
+ def delete(key)
44
+ data = read_data.dup
45
+ res = data.delete(key)
46
+ write_data data
47
+ res
48
+ end
49
+
50
+ def read_data
51
+ exist? && YAML.load(path.read) || {}
52
+ end
53
+
54
+ def write_data(new_data)
55
+ path.open("w") {|f| YAML.dump(new_data, f) }
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,105 @@
1
+ require 'engineyard/error'
2
+ require 'pathname'
3
+
4
+ module EY
5
+ class Repo
6
+ class NotAGitRepository < EY::Error
7
+ attr_reader :dir
8
+ def initialize(output)
9
+ @dir = File.expand_path(ENV['GIT_DIR'] || ENV['GIT_WORK_TREE'] || '.')
10
+ super("#{output} (#{@dir})")
11
+ end
12
+ end
13
+
14
+ class NoRemotesError < EY::Error
15
+ def initialize(path)
16
+ super "fatal: No git remotes found in #{path}"
17
+ end
18
+ end
19
+
20
+ def self.exist?
21
+ `git rev-parse --git-dir 2>&1`
22
+ $?.success?
23
+ end
24
+
25
+ attr_reader :root
26
+
27
+ # $GIT_DIR is what git uses to override the location of the .git dir.
28
+ # $GIT_WORK_TREE is the working tree for git, which we'll use after $GIT_DIR.
29
+ #
30
+ # We use this to specify which repo we should look at, since it would also
31
+ # specify where any git commands are directed, thus fooling commands we
32
+ # run anyway.
33
+ def initialize
34
+ end
35
+
36
+ def root
37
+ @root ||= begin
38
+ out = `git rev-parse --show-toplevel 2>&1`.strip
39
+
40
+ if $?.success? && !out.empty?
41
+ Pathname.new(out)
42
+ else
43
+ raise EY::Repo::NotAGitRepository.new(out)
44
+ end
45
+ end
46
+ end
47
+
48
+ def ensure_repository!
49
+ root
50
+ end
51
+
52
+ def has_committed_file?(file)
53
+ ensure_repository!
54
+ `git ls-files --full-name #{file}`.strip == file && $?.success?
55
+ end
56
+
57
+ def has_file?(file)
58
+ ensure_repository!
59
+ has_committed_file?(file) || root.join(file).exist?
60
+ end
61
+
62
+ # Read the committed version at HEAD (or ref) of a file using the git working tree relative filename.
63
+ # If the file is not committed, but does exist, a warning will be displayed
64
+ # and the file will be read anyway.
65
+ # If the file does not exist, returns nil.
66
+ #
67
+ # Example:
68
+ #
69
+ # read_file('config/ey.yml') # will read $GIT_WORK_TREE/config/ey.yml
70
+ #
71
+ def read_file(file, ref = 'HEAD')
72
+ ensure_repository!
73
+ if has_committed_file?(file)
74
+ # TODO warn if there are unstaged changes.
75
+ `git show #{ref}:#{file}`
76
+ else
77
+ EY.ui.warn <<-WARN
78
+ Warn: #{file} is not committed to this git repository:
79
+ \t#{root}
80
+ This can prevent ey deploy from loading this file for certain server side
81
+ deploy-time operations. Commit this file to fix this warning.
82
+ WARN
83
+ root.join(file).read
84
+ end
85
+ end
86
+
87
+ def current_branch
88
+ ensure_repository!
89
+ branch = `git symbolic-ref -q HEAD`.chomp.gsub("refs/heads/", "")
90
+ branch.empty? ? nil : branch
91
+ end
92
+
93
+ def remotes
94
+ ensure_repository!
95
+ @remotes ||= `git remote -v`.scan(/\t[^\s]+\s/).map { |c| c.strip }.uniq
96
+ end
97
+
98
+ def fail_on_no_remotes!
99
+ if remotes.empty?
100
+ raise EY::Repo::NoRemotesError.new(root)
101
+ end
102
+ end
103
+
104
+ end # Repo
105
+ end # EY
@@ -0,0 +1,159 @@
1
+ require 'escape'
2
+ require 'net/ssh'
3
+ require 'engineyard-serverside-adapter'
4
+
5
+ module EY
6
+ class ServersideRunner
7
+ def initialize(options)
8
+ @verbose = options[:verbose] || !!ENV['DEBUG']
9
+ @hostname = options[:bridge]
10
+ env = options[:environment]
11
+ @adapter = load_adapter(@hostname, options[:app], env, @verbose, options[:serverside_version])
12
+ @username = env.username
13
+ @hierarchy_name = env.hierarchy_name
14
+ @command = nil
15
+ end
16
+
17
+ def deploy(&block)
18
+ @command = @adapter.deploy(&block)
19
+ self
20
+ end
21
+
22
+ def rollback(&block)
23
+ @command = @adapter.rollback(&block)
24
+ self
25
+ end
26
+
27
+ def restart(&block)
28
+ @command = @adapter.restart(&block)
29
+ self
30
+ end
31
+
32
+ def put_up_maintenance_page(&block)
33
+ @command = @adapter.enable_maintenance(&block)
34
+ self
35
+ end
36
+
37
+ def take_down_maintenance_page(&block)
38
+ @command = @adapter.disable_maintenance(&block)
39
+ self
40
+ end
41
+
42
+ def call(out, err)
43
+ raise "No command!" unless @command
44
+ @command.call do |cmd|
45
+ run cmd, out, err
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def load_adapter(bridge, app, environment, verbose, serverside_version)
52
+ EY::Serverside::Adapter.new("/usr/local/ey_resin/ruby/bin") do |args|
53
+ args.serverside_version = serverside_version
54
+ args.app = app.name
55
+ args.git = app.repository_uri
56
+ args.instances = instances_data(environment.deploy_to_instances, bridge)
57
+ args.stack = environment.app_server_stack_name
58
+ args.framework_env = environment.framework_env
59
+ args.environment_name = environment.name
60
+ args.account_name = app.account.name
61
+ args.verbose = verbose
62
+ end
63
+ end
64
+
65
+ # If we tell engineyard-serverside to use 'localhost', it'll run
66
+ # commands on the instance directly (#system). If we give it the
67
+ # instance's actual hostname, it'll SSH to itself.
68
+ #
69
+ # Using 'localhost' instead of its EC2 hostname speeds up
70
+ # deploys on solos and single-app-server clusters significantly.
71
+ def instances_data(instances, bridge)
72
+ instances.map do |i|
73
+ {
74
+ hostname: i.hostname == bridge ? 'localhost' : i.hostname,
75
+ roles: [i.role],
76
+ name: i.name,
77
+ }
78
+ end
79
+ end
80
+
81
+ def run(remote_command, out, err)
82
+ cmd = Escape.shell_command(['bash', '-lc', remote_command])
83
+
84
+ if cmd.respond_to?(:encoding) && cmd.respond_to?(:force_encoding)
85
+ out << "Encoding: #{cmd.encoding.name}" if @verbose
86
+ cmd.force_encoding('binary')
87
+ out << " => #{cmd.encoding.name}; __ENCODING__: #{__ENCODING__.name}; LANG: #{ENV['LANG']}; LC_CTYPE: #{ENV['LC_CTYPE']}\n" if @verbose
88
+ end
89
+
90
+ out << "Running command on #{@username}@#{@hostname}.\n"
91
+ out << cmd << "\n" if @verbose || ENV['PRINT_CMD']
92
+
93
+ if ENV["NO_SSH"]
94
+ out << "NO_SSH is set. No output.\n"
95
+ true
96
+ else
97
+ begin
98
+ ssh(cmd, @hostname, @username, out, err)
99
+ rescue Net::SSH::AuthenticationFailed
100
+ raise EY::Error, <<-ERROR
101
+ Authentication Failed. Things to fix:
102
+ 1. Add your SSH key to your local SSH agent with `ssh-add path/to/key`.
103
+ 2. Add your SSH key to #{@hierarchy_name} on Engine Yard Cloud and apply the changes.
104
+ (https://support.cloud.engineyard.com/entries/20996846-set-up-ssh-keys)
105
+ ERROR
106
+ end
107
+ end
108
+ end
109
+
110
+ def net_ssh_options
111
+ level = :fatal # default in Net::SSH
112
+ if debug = ENV["DEBUG"]
113
+ level = :info
114
+ if %w[debug info warn error fatal].include?(debug.downcase)
115
+ level = debug.downcase.to_sym
116
+ end
117
+ end
118
+
119
+ {paranoid: false, verbose: level, keepalive: true, keepalive_interval: 60}
120
+ end
121
+
122
+ def ssh(cmd, hostname, username, out, err)
123
+ exit_code = 1
124
+ Net::SSH.start(hostname, username, net_ssh_options) do |net_ssh|
125
+ net_ssh.open_channel do |channel|
126
+ channel.exec cmd do |_, success|
127
+ unless success
128
+ err << "Remote command execution failed"
129
+ return false
130
+ end
131
+
132
+ channel.on_data do |_, data|
133
+ out << data
134
+ end
135
+
136
+ channel.on_extended_data do |_, _, data|
137
+ err << data
138
+ end
139
+
140
+ channel.on_request("exit-status") do |_, data|
141
+ exit_code = data.read_long
142
+ end
143
+
144
+ channel.on_request("exit-signal") do |_, data|
145
+ exit_code = 255
146
+ end
147
+
148
+ # sending eof declares no more data coming from this end (close stdin)
149
+ channel.eof!
150
+ end
151
+ end
152
+
153
+ net_ssh.loop
154
+ end
155
+ exit_code.zero?
156
+ end
157
+
158
+ end
159
+ end
@@ -0,0 +1,6 @@
1
+ module EY
2
+ module Templates
3
+ end
4
+ end
5
+
6
+ require 'engineyard/templates/ey_yml'
@@ -0,0 +1,196 @@
1
+ # Engine Yard Cloud Deploy Options
2
+ #
3
+ ####################################################################
4
+ # IMPORTANT
5
+ # Commit this file into your git repository.
6
+ # These options are loaded on the server during deploy.
7
+ ####################################################################
8
+ #
9
+ # Valid locations:
10
+ # * REPOSITORY_ROOT/config/ey.yml.
11
+ # * REPOSITORY_ROOT/ey.yml
12
+ #
13
+ # Further information available here:
14
+ # https://support.cloud.engineyard.com/entries/20996661-customize-your-deployment-on-engine-yard-cloud
15
+ #
16
+ # For advanced usage, see the source that loads this configuration:
17
+ # https://github.com/engineyard/engineyard-serverside/blob/master/lib/engineyard-serverside/configuration.rb
18
+ #
19
+ defaults:
20
+ # Run migrations during deploy by default.
21
+ #
22
+ # When set to true, runs the migration_command (below) during deploy.
23
+ #
24
+ # This setting can be overridden for individual deployments using
25
+ # the command line options --migrate or --no-migrate.
26
+ #
27
+ <%= option 'migrate' %>
28
+
29
+ # Default migration command to run when migrations are enabled.
30
+ #
31
+ <% if existing_config['migration_command'] || config['migrate'] %>
32
+ <%= option 'migration_command' %>
33
+ <% else %>
34
+ <%= commented_option 'migration_command' %>
35
+ <% end %>
36
+
37
+ # Enables rails assets precompilation always and halts when the task fails.
38
+ #
39
+ # By default, assets are detected using app/assets and config/application.rb.
40
+ #
41
+ # If you use rails assets and you want Engine Yard to compile your assets
42
+ # during deploy, set this to true. If you want to compile assets locally
43
+ # before deploy, set this to false. Make sure you add `public/assets` to
44
+ # `.gitignore` if you want Engine Yard to precompile your assets.
45
+ #
46
+ # For more control over assets, set precompile_assets: false and
47
+ # run your precompile task in the deploy/before_compile_assets.rb deploy hook.
48
+ #
49
+ <%= option 'precompile_assets' %>
50
+
51
+ # Override the assets:precompile rake task. This option will be used instead
52
+ # of <%= defaults['precompile_assets_task'] %> in the `rake <%= defaults['precompile_assets_task'] %>` command.
53
+ #
54
+ <%= option_unless_default 'precompile_assets_task' %>
55
+
56
+ # Asset strategies affect the way assets are stored on the server.
57
+ #
58
+ # * private
59
+ # Store assets directly in public/assets for each deployment.
60
+ # Previous assets are symlinked for continuity.
61
+ # When assets are reused, they are copied using rsync.
62
+ #
63
+ # * shifting
64
+ # Assets are kept in a shared directory on each server.
65
+ # When new assets are compiled, old assets are shifted to a shared
66
+ # last_assets directory. This has always been the default behavior.
67
+ #
68
+ # * shared
69
+ # Assets are kept in a shared directory on each server.
70
+ # When new assets are compiled, the same directory is used.
71
+ # Assets will accumulate in this mode if a cleaning script is not run.
72
+ # Use this strategy if you want to write your own asset cleaning script.
73
+ #
74
+ # * cleaning
75
+ # Like shared, but a cleaning script is run before each new compile.
76
+ # The script attempts to remove all files not mentioned by the old
77
+ # manifest.yml, before it is replaced by the new manifest (leaving 2
78
+ # deployments worth of assets in the directory)
79
+ #
80
+ # "private" is recommended because it is the least error prone.
81
+ # If you prefer faster compilation, "shared" can be quicker, but will require
82
+ # custom scripting and will cause problems when rollbacks are used.
83
+ # "shifting" is the default behavior.
84
+ #
85
+ <% if config['asset_strategy'] != defaults['asset_strategy'] %>
86
+ <%= option 'asset_strategy' %>
87
+ <% else %>
88
+ #asset_strategy: private
89
+ <% end %>
90
+
91
+ # This list of repository relative paths is checked for changes during
92
+ # each deployment (when change detection is not disabled). If `git diff`
93
+ # detects changes since the last deployment, fresh assets will be compiled.
94
+ #
95
+ # This option overrides the default list, so include the following
96
+ # defaults if you need them.
97
+ #
98
+ <% if config['asset_dependencies'] %>
99
+ <%= option 'asset_dependencies' %>
100
+ <% else %><%# better default format than the normal yaml dump %>
101
+ #asset_dependencies:
102
+ #- app/assets # default
103
+ #- lib/assets # default
104
+ #- vendor/assets # default
105
+ #- Gemfile.lock # default
106
+ #- config/application.rb # default
107
+ #- config/routes.rb # default
108
+ #- config/requirejs.yml # example of a custom asset dependency
109
+ <% end %>
110
+
111
+ # When true, precompiles assets even if no changes would be detected by
112
+ # running git diff with the asset_dependencies above.
113
+ #
114
+ # Default is false (always check git diff before asset compilation)
115
+ #
116
+ <%= option_unless_default 'precompile_unchanged_assets' %>
117
+
118
+ # Choose which servers should compile assets.
119
+ #
120
+ # Default behavior is to exclude util instances.
121
+ # Specify :all to compile on all servers including util servers.
122
+ #
123
+ <% if config['asset_roles'] %>
124
+ <%= option 'asset_roles' %>
125
+ <% else %>
126
+ #asset_roles: :all
127
+ <% end %>
128
+
129
+ # Bundle without different bundler groups:
130
+ # Ex: bundle install --without '[bundle_without]'
131
+ #
132
+ # Default is "<%= defaults['bundle_without'] %>".
133
+ # Leave blank to remove --without from the bundle install command.
134
+ #
135
+ <%= option_unless_default 'bundle_without' %>
136
+
137
+ # Add extra options to the bundle install command line.
138
+ # Does not override bundle_without, if specified.
139
+ #
140
+ # If the application's gems are vendored in the
141
+ # repository, setting --local can speed up bundle.
142
+ #
143
+ <%= option_unless_default 'bundle_options' %>
144
+
145
+ # Enable maintenance page during migrate action (default)
146
+ # Setting this to false, disables maintenance page during migrations.
147
+ #
148
+ # CAUTION! No-downtime migrations requires careful migration
149
+ # planning. Migrations must be non-destructive. The *previous*
150
+ # deployment might serve pages during a partially migrated state.
151
+ # For example, if you rename a column, all traffic served during
152
+ # that migration will be broken until the new code is deployed.
153
+ #
154
+ <%= option_unless_default 'maintenance_on_migrate' %>
155
+
156
+ # Enable maintanence page during every deploy.
157
+ # Unicorn and Passenger support no-downtime deploys, so the default
158
+ # for these servers is false. Mongrel and some other servers default
159
+ # to true to avoid downtime during server restarting.
160
+ #
161
+ <%= option_unless_default 'maintenance_on_restart' %>
162
+
163
+ # If true, always run deployments in verbose mode.
164
+ #
165
+ <%= option_unless_default 'verbose' %>
166
+
167
+ # Hide the warning shown when the Gemfile does not contain a recognized
168
+ # database adapter (mongodb for example)
169
+ #
170
+ # This warning is here to help new customers that accidentally have no adapter.
171
+ # You may safely set this to true if you aren't using a common database.
172
+ #
173
+ <%= option_unless_default 'ignore_database_adapter_warning' %>
174
+
175
+ # You can add custom keys that will be available in your deploy hooks.
176
+ # Custom keys will be available using config.key or config[:key]
177
+ #
178
+ #your_own_custom_key: custom info
179
+
180
+ <%= extra_root_options %>
181
+
182
+ ####################################################################
183
+ # Environment specific options.
184
+ #
185
+ # The options you specify here will only apply to a single environment
186
+ # that exactly matches the environment name key.
187
+ #
188
+ # Environment options will override the default options above.
189
+ #
190
+ environments:
191
+
192
+ # These options will only apply to the EXAMPLE_ENVIRONMENT environment.
193
+ #EXAMPLE_ENVIRONMENT:
194
+ #precompile_unchanged_assets: true
195
+
196
+ <%= environment_options %>