engineyard 2.2.1 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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