engineyard 2.2.1 → 2.3.0

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.
@@ -1,5 +1,7 @@
1
1
  module EY
2
2
  class DeployConfig
3
+ MIGRATE = 'rake db:migrate --trace'
4
+
3
5
  def initialize(cli_opts, env_config, repo, ui)
4
6
  @cli_opts = cli_opts
5
7
  @env_config = env_config
@@ -12,13 +14,26 @@ module EY
12
14
  end
13
15
 
14
16
  def migrate
15
- decide_migrate
16
- @migrate
17
+ @migrate ||= @cli_opts.fetch('migrate') do
18
+ if in_repo?
19
+ @env_config.migrate
20
+ else
21
+ raise RefAndMigrateRequiredOutsideRepo.new(@cli_opts)
22
+ end
23
+ end
17
24
  end
18
25
 
19
26
  def migrate_command
20
- decide_migrate
21
- @migrate_command
27
+ return @command if defined? @command
28
+
29
+ if migrate
30
+ @command = migrate.respond_to?(:to_str) && migrate.to_str
31
+ @command ||= in_repo? ? @env_config.migration_command : MIGRATE
32
+ else
33
+ @command = nil
34
+ end
35
+
36
+ @command
22
37
  end
23
38
 
24
39
  def verbose
@@ -44,19 +59,7 @@ module EY
44
59
  ref_decider.when_outside_repo
45
60
  end
46
61
  end
47
-
48
- def decide_migrate
49
- return if @migrate_decider
50
- @migrate_decider = EY::DeployConfig::Migrate.new(@cli_opts, @env_config, @ui)
51
- @migrate, @migrate_command =
52
- if in_repo?
53
- @migrate_decider.when_inside_repo
54
- else
55
- @migrate_decider.when_outside_repo
56
- end
57
- end
58
62
  end
59
63
  end
60
64
 
61
- require 'engineyard/deploy_config/migrate'
62
65
  require 'engineyard/deploy_config/ref'
@@ -4,7 +4,7 @@ module EY
4
4
 
5
5
  class NoCommandError < EY::Error
6
6
  def initialize
7
- super "Must specify a command to run via ssh"
7
+ super "Specify a command to run via ssh or use --each to cycle through each server one at a time."
8
8
  end
9
9
  end
10
10
 
@@ -52,7 +52,7 @@ module EY
52
52
  EY::Serverside::Adapter.new("/usr/local/ey_resin/ruby/bin") do |args|
53
53
  args.serverside_version = serverside_version
54
54
  args.app = app.name
55
- args.repo = app.repository_uri
55
+ args.git = app.repository_uri
56
56
  args.instances = instances_data(environment.deploy_to_instances, bridge)
57
57
  args.stack = environment.app_server_stack_name
58
58
  args.framework_env = environment.framework_env
@@ -0,0 +1,6 @@
1
+ module EY
2
+ module Templates
3
+ end
4
+ end
5
+
6
+ require 'engineyard/templates/ey_yml'
@@ -0,0 +1,193 @@
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, set this to true.
42
+ #
43
+ # For more control over assets, set precompile_assets: false and
44
+ # run your precompile task in the deploy/before_compile_assets.rb deploy hook.
45
+ #
46
+ <%= option 'precompile_assets' %>
47
+
48
+ # Override the assets:precompile rake task. This option will be used instead
49
+ # of <%= defaults['precompile_assets_task'] %> in the `rake <%= defaults['precompile_assets_task'] %>` command.
50
+ #
51
+ <%= option_unless_default 'precompile_assets_task' %>
52
+
53
+ # Asset strategies affect the way assets are stored on the server.
54
+ #
55
+ # * private
56
+ # Store assets directly in public/assets for each deployment.
57
+ # Previous assets are symlinked for continuity.
58
+ # When assets are reused, they are copied using rsync.
59
+ #
60
+ # * shifting
61
+ # Assets are kept in a shared directory on each server.
62
+ # When new assets are compiled, old assets are shifted to a shared
63
+ # last_assets directory. This has always been the default behavior.
64
+ #
65
+ # * shared
66
+ # Assets are kept in a shared directory on each server.
67
+ # When new assets are compiled, the same directory is used.
68
+ # Assets will accumulate in this mode if a cleaning script is not run.
69
+ # Use this strategy if you want to write your own asset cleaning script.
70
+ #
71
+ # * cleaning
72
+ # Like shared, but a cleaning script is run before each new compile.
73
+ # The script attempts to remove all files not mentioned by the old
74
+ # manifest.yml, before it is replaced by the new manifest (leaving 2
75
+ # deployments worth of assets in the directory)
76
+ #
77
+ # "private" is recommended because it is the least error prone.
78
+ # If you prefer faster compilation, "shared" can be quicker, but will require
79
+ # custom scripting and will cause problems when rollbacks are used.
80
+ # "shifting" is the default behavior.
81
+ #
82
+ <% if config['asset_strategy'] != defaults['asset_strategy'] %>
83
+ <%= option 'asset_strategy' %>
84
+ <% else %>
85
+ #asset_strategy: private
86
+ <% end %>
87
+
88
+ # This list of repository relative paths is checked for chenges during
89
+ # each deployment (when change detection is not disabled). If `git diff`
90
+ # detects changes since the last deployment, fresh assets will be compiled.
91
+ #
92
+ # This option overrides the default list, so include the following
93
+ # defaults if you need them.
94
+ #
95
+ <% if config['asset_dependencies'] %>
96
+ <%= option 'asset_dependencies' %>
97
+ <% else %><%# better default format than the normal yaml dump %>
98
+ #asset_dependencies:
99
+ #- app/assets # default
100
+ #- lib/assets # default
101
+ #- vendor/assets # default
102
+ #- Gemfile.lock # default
103
+ #- config/application.rb # default
104
+ #- config/routes.rb # default
105
+ #- config/requirejs.yml # example of a custom asset dependency
106
+ <% end %>
107
+
108
+ # When true, precompiles assets even if no changes would be detected by
109
+ # running git diff with the asset_dependencies above.
110
+ #
111
+ # Default is false (always check git diff before asset compilation)
112
+ #
113
+ <%= option_unless_default 'precompile_unchanged_assets' %>
114
+
115
+ # Choose which servers should compile assets.
116
+ #
117
+ # Default behavior is to exclude util instances.
118
+ # Specify :all to compile on all servers including util servers.
119
+ #
120
+ <% if config['asset_roles'] %>
121
+ <%= option 'asset_roles' %>
122
+ <% else %>
123
+ #asset_roles: :all
124
+ <% end %>
125
+
126
+ # Bundle without different bundler groups:
127
+ # Ex: bundle install --without '[bundle_without]'
128
+ #
129
+ # Default is "<%= defaults['bundle_without'] %>".
130
+ # Leave blank to remove --without from the bundle install command.
131
+ #
132
+ <%= option_unless_default 'bundle_without' %>
133
+
134
+ # Add extra options to the bundle install command line.
135
+ # Does not override bundle_without, if specified.
136
+ #
137
+ # If the application's gems are vendored in the
138
+ # repository, setting --local can speed up bundle.
139
+ #
140
+ <%= option_unless_default 'bundle_options' %>
141
+
142
+ # Enable maintenance page during migrate action (default)
143
+ # Setting this to false, disables maintenance page during migrations.
144
+ #
145
+ # CAUTION! No-downtime migrations requires careful migration
146
+ # planning. Migrations must be non-destructive. The *previous*
147
+ # deployment might serve pages during a partially migrated state.
148
+ # For example, if you rename a column, all traffic served during
149
+ # that migration will be broken until the new code is deployed.
150
+ #
151
+ <%= option_unless_default 'maintenance_on_migrate' %>
152
+
153
+ # Enable maintanence page during every deploy.
154
+ # Unicorn and Passenger support no-downtime deploys, so the default
155
+ # for these servers is false. Mongrel and some other servers default
156
+ # to true to avoid downtime during server restarting.
157
+ #
158
+ <%= option_unless_default 'maintenance_on_restart' %>
159
+
160
+ # If true, always run deployments in verbose mode.
161
+ #
162
+ <%= option_unless_default 'verbose' %>
163
+
164
+ # Hide the warning shown when the Gemfile does not contain a recognized
165
+ # database adapter (mongodb for example)
166
+ #
167
+ # This warning is here to help new customers that accidentally have no adapter.
168
+ # You may safely set this to true if you aren't using a common database.
169
+ #
170
+ <%= option_unless_default 'ignore_database_adapter_warning' %>
171
+
172
+ # You can add custom keys that will be available in your deploy hooks.
173
+ # Custom keys will be available using config.key or config[:key]
174
+ #
175
+ #your_own_custom_key: custom info
176
+
177
+ <%= extra_root_options %>
178
+
179
+ ####################################################################
180
+ # Environment specific options.
181
+ #
182
+ # The options you specify here will only apply to a single environment
183
+ # that exactly matches the environment name key.
184
+ #
185
+ # Environment options will override the default options above.
186
+ #
187
+ environments:
188
+
189
+ # These options will only apply to the EXAMPLE_ENVIRONMENT environment.
190
+ #EXAMPLE_ENVIRONMENT:
191
+ #precompile_unchanged_assets: true
192
+
193
+ <%= environment_options %>
@@ -0,0 +1,119 @@
1
+ require 'erb'
2
+
3
+ module EY
4
+ module Templates
5
+ class EyYml
6
+ PATH = Pathname.new(__FILE__).dirname.join('ey.yml.erb').freeze
7
+
8
+ attr_reader :existing_config, :existing, :config, :template
9
+
10
+ def initialize(existing, template=PATH)
11
+ @template = template
12
+
13
+ @existing = existing.dup
14
+ @environments = @existing.delete('environments') || {}
15
+ @existing_config = @existing.delete('defaults') || {}
16
+ @config = defaults.merge(@existing_config)
17
+
18
+ fix_config!
19
+ end
20
+
21
+ def to_str
22
+ ERB.new(template.read, 0, "<>").result(binding)
23
+ end
24
+ alias to_s to_str
25
+
26
+ def write(dest)
27
+ dest = Pathname.new(dest)
28
+ dir = dest.dirname
29
+ temp = dir.join("ey.yml.tmp")
30
+
31
+ # generate first so we don't overwrite with a failed generation
32
+ output = to_str
33
+ temp.open('w') { |f| f << output }
34
+
35
+ FileUtils.mv(dest, dir.join("ey.yml.backup")) if dest.exist?
36
+ FileUtils.mv(temp, dest)
37
+ end
38
+
39
+ protected
40
+
41
+ def fix_config!
42
+ if config['migrate'] == nil && existing_config['migration_command']
43
+ config['migrate'] = true
44
+ end
45
+ end
46
+
47
+ def defaults
48
+ {
49
+ "migrate" => Pathname.new('db/migrate').exist?,
50
+ "migration_command" => "rake db:migrate --trace",
51
+ "precompile_assets" => Pathname.new('app/assets').exist?,
52
+ "precompile_assets_task" => "assets:precompile",
53
+ "asset_dependencies" => nil, # %w[app/assets lib/assets vendor/assets Gemfile.lock config/application.rb config/routes.rb],
54
+ "asset_strategy" => "shifting",
55
+ "precompile_unchanged_assets" => false,
56
+ "bundle_without" => nil,
57
+ "bundle_options" => nil,
58
+ "maintenance_on_migrate" => true,
59
+ "maintenance_on_restart" => nil,
60
+ "verbose" => false,
61
+ "ignore_database_adapter_warning" => false,
62
+ }
63
+ end
64
+
65
+ def option_unless_default(key)
66
+ value = config[key]
67
+ if value != nil && value != defaults[key]
68
+ option(key, value)
69
+ else
70
+ commented_option key
71
+ end
72
+ end
73
+
74
+ def option(key, value = nil)
75
+ value ||= config[key]
76
+ dump_indented_yaml key => value
77
+ end
78
+
79
+ def commented_option(key)
80
+ data = {key => defaults[key]}
81
+ " ##{dump_indented_yaml(data, 0)}"
82
+ end
83
+
84
+ def extra_root_options
85
+ out = ""
86
+
87
+ extra_defaults = config.reject { |k,v| defaults.key?(k) }
88
+ extra_defaults.each do |key,val|
89
+ out << option(key, val) << "\n"
90
+ end
91
+
92
+ unless existing.empty?
93
+ out << dump_indented_yaml(existing, 0)
94
+ end
95
+
96
+ out
97
+ end
98
+
99
+ def environment_options
100
+ if @environments && !@environments.empty?
101
+ dump_indented_yaml(@environments)
102
+ end
103
+ end
104
+
105
+ def dump_indented_yaml(data, indent=2)
106
+ YAML.dump(data).sub(/^---/, '').lstrip.gsub(/^/,' '*indent)
107
+ end
108
+
109
+ def string_to_boolean(str)
110
+ case str
111
+ when "true" then true
112
+ when "false" then false
113
+ else str
114
+ end
115
+ end
116
+
117
+ end
118
+ end
119
+ end
@@ -1,4 +1,4 @@
1
1
  module EY
2
- VERSION = '2.2.1'
3
- ENGINEYARD_SERVERSIDE_VERSION = ENV['ENGINEYARD_SERVERSIDE_VERSION'] || '2.2.1'
2
+ VERSION = '2.3.0'
3
+ ENGINEYARD_SERVERSIDE_VERSION = ENV['ENGINEYARD_SERVERSIDE_VERSION'] || '2.3.1'
4
4
  end
@@ -1,72 +1,38 @@
1
1
  require 'spec_helper'
2
2
  require 'tempfile'
3
3
 
4
- describe EY::DeployConfig::Migrate do
5
- before do
6
- @tempfile = Tempfile.new('ey.yml')
7
- @parent = EY::Config.new(@tempfile.path)
8
- @ui = EY::CLI::UI.new
9
- EY::CLI::UI::Prompter.enable_mock!
10
- @repo = double('repo')
11
- end
4
+ describe EY::DeployConfig do
5
+ let(:tempfile) { @tempfile = Tempfile.new('ey.yml') }
6
+ let(:parent) { EY::Config.new(tempfile.path) }
7
+ let(:ui) { EY::CLI::UI.new }
8
+ let(:repo) { double('repo') }
9
+ let(:env) { env_config(nil) }
12
10
 
13
- after do
14
- @tempfile.unlink
15
- end
11
+ after { @tempfile.unlink if @tempfile }
16
12
 
17
- def env_config(opts=nil)
18
- @env_config ||= EY::Config::EnvironmentConfig.new(opts, 'envname', @parent)
13
+ def env_config(opts, config = parent)
14
+ EY::Config::EnvironmentConfig.new(opts, 'envname', config)
19
15
  end
20
16
 
21
- def deploy_config(cli_options)
22
- EY::DeployConfig.new(cli_options, env_config, @repo, @ui)
17
+ def deploy_config(cli_opts, ec = env)
18
+ EY::DeployConfig.new(cli_opts, ec, repo, ui)
23
19
  end
24
20
 
25
21
  context "inside a repository" do
26
- context "no migrate options set (interactive)" do
27
- it "prompts migrate and command and adds to defaults section" do
28
- EY::CLI::UI::Prompter.add_answer "" # default
29
- EY::CLI::UI::Prompter.add_answer ""
30
- @parent.should_receive(:set_default_option).with('migrate', true)
31
- @parent.should_receive(:set_default_option).with('migration_command', 'rake db:migrate')
32
- dc = deploy_config({})
33
- out = capture_stdout do
34
- dc.migrate.should be_true
35
- dc.migrate_command.should == 'rake db:migrate'
36
- end
37
- out.should =~ /#{@tempfile.path}: migrate settings saved for envname/
38
- out.should =~ /You can override this default with --migrate or --no-migrate/
39
- out.should =~ /Please git commit #{@tempfile.path} with these new changes./
40
- end
41
-
42
- it "prompts migration_command if first answer is yes" do
43
- EY::CLI::UI::Prompter.add_answer "yes" # default
44
- EY::CLI::UI::Prompter.add_answer "ruby script/migrate"
45
- @parent.should_receive(:set_default_option).with('migrate', true)
46
- @parent.should_receive(:set_default_option).with('migration_command', 'ruby script/migrate')
47
- dc = deploy_config({})
48
- capture_stdout do
49
- dc.migrate.should be_true
50
- dc.migrate_command.should == 'ruby script/migrate'
51
- end
52
- end
22
+ context "with no ey.yml file" do
23
+ let(:env) { env_config(nil, EY::Config.new('noexisto.yml')) }
53
24
 
54
- it "doesn't prompt migration_command if first answer is no" do
55
- EY::CLI::UI::Prompter.add_answer "no" # default
56
- @parent.should_receive(:set_default_option).with('migrate', false)
57
- dc = deploy_config({})
58
- capture_stdout do
59
- dc.migrate.should be_false
60
- dc.migrate_command.should be_nil
61
- end
25
+ it "tells you to initialize a new repository with ey init" do
26
+ dc = deploy_config({}, env)
27
+ expect { dc.migrate }.to raise_error(EY::Error, /Please initialize this application with the following command:/)
62
28
  end
63
29
  end
64
30
 
65
31
  context "with the migrate cli option" do
66
- it "returns the default migration command when is true" do
32
+ it "returns default command when true" do
67
33
  dc = deploy_config({'migrate' => true})
68
34
  dc.migrate.should be_true
69
- dc.migrate_command.should == 'rake db:migrate'
35
+ expect { dc.migrate_command }.to raise_error(EY::Error, /'migration_command' not found/)
70
36
  end
71
37
 
72
38
  it "returns false when nil" do
@@ -83,30 +49,30 @@ describe EY::DeployConfig::Migrate do
83
49
  end
84
50
 
85
51
  context "with the migrate option in the global configuration" do
86
- it "return the default migration command when the option is true" do
87
- env_config('migrate' => true, 'migration_command' => 'bar migrate')
88
- dc = deploy_config({})
52
+ it "return the migration command when the option is true" do
53
+ env = env_config('migrate' => true, 'migration_command' => 'bar migrate')
54
+ dc = deploy_config({}, env)
89
55
  dc.migrate.should be_true
90
56
  dc.migrate_command.should == 'bar migrate'
91
57
  end
92
58
 
93
59
  it "return the false when migrate is false" do
94
- env_config('migrate' => false, 'migration_command' => 'bar migrate')
95
- dc = deploy_config({})
60
+ env = env_config('migrate' => false, 'migration_command' => 'bar migrate')
61
+ dc = deploy_config({}, env)
96
62
  dc.migrate.should be_false
97
63
  dc.migrate_command.should be_nil
98
64
  end
99
65
 
100
- it "return the default migration command when the option is true" do
101
- env_config('migrate' => true)
102
- dc = deploy_config({})
103
- dc.migrate.should be_true
104
- dc.migrate_command.should == 'rake db:migrate'
66
+ it "tells you to run ey init" do
67
+ env = env_config('migrate' => true)
68
+ dc = deploy_config({}, env)
69
+ expect(dc.migrate).to be_true
70
+ expect { dc.migrate_command }.to raise_error(EY::Error, /'migration_command' not found/)
105
71
  end
106
72
 
107
73
  it "return the ey.yml migration_command when command line option --migrate is passed" do
108
- env_config('migrate' => false, 'migration_command' => 'bar migrate')
109
- dc = deploy_config({'migrate' => true})
74
+ env = env_config('migrate' => false, 'migration_command' => 'bar migrate')
75
+ dc = deploy_config({'migrate' => true}, env)
110
76
  dc.migrate.should be_true
111
77
  dc.migrate_command.should == 'bar migrate'
112
78
  end
@@ -130,7 +96,7 @@ describe EY::DeployConfig::Migrate do
130
96
  end
131
97
 
132
98
  context "with a default branch" do
133
- before { env_config('branch' => 'default') }
99
+ let(:env) { env_config('branch' => 'default') }
134
100
 
135
101
  it "uses the configured default if ref is not passed" do
136
102
  out = capture_stdout do
@@ -164,7 +130,7 @@ describe EY::DeployConfig::Migrate do
164
130
 
165
131
  context "no options, no default" do
166
132
  it "uses the repo's current branch" do
167
- @repo.should_receive(:current_branch).and_return('current')
133
+ repo.should_receive(:current_branch).and_return('current')
168
134
  out = capture_stdout do
169
135
  deploy_config({}).ref.should == 'current'
170
136
  end
@@ -179,7 +145,7 @@ describe EY::DeployConfig::Migrate do
179
145
  it "returns the default migration command when migrate is true" do
180
146
  dc = deploy_config({'app' => 'app', 'migrate' => true})
181
147
  dc.migrate.should be_true
182
- dc.migrate_command.should == 'rake db:migrate'
148
+ dc.migrate_command.should == 'rake db:migrate --trace'
183
149
  end
184
150
 
185
151
  it "returns false when nil" do