whiskey_disk 0.0.7 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,2 +1 @@
1
- whiskey_disk.gemspec
2
1
  pkg/
data/README CHANGED
@@ -1,39 +1,45 @@
1
1
  Whiskey Disk -- embarrassingly fast deployments.
2
2
 
3
- A very opinionated deployment tool, designed to be as fast as technologically
4
- possible. (For more background, read the WHY.txt file)
3
+ A very opinionated deployment tool, designed to be as fast as technologically possible. (For more background, read the WHY.txt file)
5
4
 
6
- Should work with any project which is git hosted, not just Ruby / Ruby on Rails projects.
7
- Allows for local deploys as well as remote.
5
+ Should work with any project which is git hosted, not just Ruby / Ruby on
6
+ Rails projects. Allows for local deploys as well as remote.
8
7
 
9
8
  Selling points:
10
9
 
11
- - If you share the same opinions there's almost no code involved, almost no dependencies,
12
- and it uses stock *nix tools (ssh, bash, rsync) to get everything done.
10
+ - If you share the same opinions there's almost no code involved, almost no
11
+ dependencies, and it uses stock *nix tools (ssh, bash, rsync) to get
12
+ everything done.
13
13
 
14
- - Written completely spec-first for 100% coverage. We even did that for the rake tasks,
15
- the init.rb and the plugin install.rb if you swing that way.
14
+ - Written completely spec-first for 100% coverage. We even did that for the
15
+ rake tasks, the init.rb and the plugin install.rb if you swing that way.
16
16
 
17
- - 1 ssh connection per rake task -- so everything needed to do a full setup is done in
18
- one shot. Everything needed to do a full deployment is done in one shot. Having 8
19
- minute deploys failing because I was on cdma wireless on a train in india where the
20
- connection won't stay up for more than 2-3 minutes is not where I want to be.
17
+ - 1 ssh connection per rake task -- so everything needed to do a full setup
18
+ is done in one shot. Everything needed to do a full deployment is done in
19
+ one shot. Having 8 minute deploys failing because I was on cdma wireless on a
20
+ train in india where the connection won't stay up for more than 2-3 minutes is
21
+ not where I want to be.
21
22
 
22
- - You can do *local* deployments, by this I mean you can use whiskey_disk to manage your
23
- local checkout with localized (aka non-production) configurations trivially. This turns
24
- out to be surprisingly handy (well, I was surprised).
23
+ - You can do *local* deployments, by this I mean you can use whiskey_disk to
24
+ deploy fully running instances of your application to the same machine
25
+ you're developing on. This turns out to be surprisingly handy (well, I was
26
+ surprised). *NOTE*: be sure to set your deploy_to to a place other than the
27
+ current local checkout.
25
28
 
26
- - You can have per-developer configurations for environments (especially useful for
27
- "local" or "development" enviroments). Use .gitignore and everyone can have their own
28
- local setup that just works.
29
+ - You can have per-developer configurations for environments (especially
30
+ useful for "local" or "development" enviroments). Use .gitignore, or
31
+ specify a config_branch and everyone can have their own local setup that just
32
+ works.
29
33
 
30
- - Deployment configuration is specified as YAML data, not as code. Operations to perform
31
- after setup or deployment are specified as rake tasks.
34
+ - Deployment configuration is specified as YAML data, not as code.
35
+ Operations to perform after setup or deployment are specified as rake
36
+ tasks.
32
37
 
33
- - There's no before_after_before_after hooks. You've got plenty of flexibility with just
34
- a handful of rake hook points to grab onto.
38
+ - There's no before_after_before_after hooks. You've got plenty of
39
+ flexibility with just a handful of rake hook points to grab onto.
35
40
 
36
- - rake deploy:setup and rake deploy:now are really all that are needed, best I can tell.
41
+ - rake deploy:setup and rake deploy:now are really all that are needed, best
42
+ I can tell.
37
43
 
38
44
 
39
45
 
@@ -63,7 +69,6 @@ Whiskey Disk -- embarrassingly fast deployments.
63
69
 
64
70
  - look in the examples/ directory for sample configuration files
65
71
  - main configuration is in <app_root>/config/deploy.yml
66
- - per-environment configurations can be stored in <app_root>/config/deploy-<environment>.yml
67
72
  - config files are YAML, with a section for each environment.
68
73
 
69
74
  Known config file settings (if you're familiar with capistrano and vlad these
@@ -72,94 +77,136 @@ Whiskey Disk -- embarrassingly fast deployments.
72
77
  - domain: host on which to deploy (this is an ssh connect string)
73
78
  - deploy_to: path to which to deploy main application
74
79
  - repository: git repo path for main application
75
- - branch: git branch to deploy from main application git repo
80
+ - branch: git branch to deploy from main application git repo (default: master)
76
81
  - deploy_config_to: where to deploy the configuration repository
77
82
  - config_repository: git repository for configuration files
83
+ - config_branch: git branch to deploy from configuration git repo (default: master)
78
84
  - project: project name (used to compute path in configuration checkout)
79
85
  - rake_env: hash of environment variables to set when running post_setup and post_deploy rake tasks
80
86
 
81
- - defining a deploy:<environment>:post_setup rake task (e.g., in lib/tasks/ or in
82
- your project's Rakefile) will cause that task to be run at the end of deploy:setup
87
+ - defining a deploy:<environment>:post_setup rake task (e.g., in lib/tasks/
88
+ or in your project's Rakefile) will cause that task to be run at the end
89
+ of deploy:setup
83
90
 
84
- - defining a deploy:<environment>:post_deploy rake task (e.g., in lib/tasks/ or in
85
- your project's Rakefile) will cause that task to be run at the end of deploy:now
91
+ - defining a deploy:<environment>:post_deploy rake task (e.g., in
92
+ lib/tasks/ or in your project's Rakefile) will cause that task to be run
93
+ at the end of deploy:now
86
94
 
87
- Running:
88
95
 
89
- - rake deploy:setup to=<environment> (e.g., "staging", "production", etc.)
90
- - rake deploy:now to=<environment>
96
+ Running via rake:
97
+
98
+ ... in your Rakefile:
99
+
100
+ require 'whiskey_disk/rake'
101
+
102
+ Then, from the command-line:
103
+
104
+ % rake deploy:setup to=<target> (e.g., "staging", "production", etc.)
105
+ % rake deploy:now to=<target>
106
+
107
+ or, specifying the project name:
108
+
109
+ % rake deploy:setup to=<project>:<target> (e.g., "foo:staging", "bar:production", etc.)
110
+ % rake deploy:now to=<project>:<target>
111
+
112
+
113
+ Running from the command-line:
114
+
115
+ % wd setup --to=<target>
116
+ % wd setup --to=<project>:<target>
117
+ % wd setup --to=foo:staging --path=/etc/whiskey_disk/deploy.yml
118
+
119
+ % wd deploy --to=<target>
120
+ % wd deploy --to=<project>:<target>
121
+ % wd deploy --to=foo:staging --path=/etc/whiskey_disk/deploy.yml
122
+
123
+
124
+ Note that the wd command (unlike rake, which requires a Rakefile in the current directory) can be run from anywhere, so you can deploy any project, working from any path, and can even specify where to find the deployment YAML configuration file.
125
+
126
+ The --path argument can take either a file or a directory. When given a file it will use that file as the configuration file. When given a directory it will look in that directory for deploy/<project>/<target>.yml, then deploy/<project>.yml, then deploy/<target>.yml, then <target>.yml, and finally, deploy.yml.
127
+
128
+ All this means you can manage a large number of project deployments (local or remote) and have a single scripted deployment manager that keeps them up to date. Configurations can live in a centralized location, and developers don't have to be actively involved in ensuring code gets shipped up to a server. Win.
91
129
 
92
130
 
93
131
  Configuration Repository
94
132
 
95
133
  What's all this about a second repository for configuration stuff?
96
134
 
97
- Well, we're going to make it optional probably in another release, but we really
98
- are digging this, so maybe you should try it. Basically it goes like this...
99
-
100
- We have a number of web applications that we manage. Usually there's a customer,
101
- there might be third-party developers, or the customer might have access to the git
102
- repo, or their designer might, etc. We also tend to run a few instances of any given
103
- app, for any given customer. So, we'll run a "production" site, which is the public-
104
- facing, world-accessible main site. We'll usually also run a "staging" site, which is
105
- roughly the same code, maybe the same data, running on a different URL, which the customer
106
- can look at to see if the functionality there is suitable for deploying out to production.
107
- We sometimes run a "development" site which is even less likely to be the same code as
108
- production, etc., but gives visibility into what might end up in production one day soon.
109
-
110
- So we'll store the code for all of these versions of a site in the same git repo, typically
111
- using a different remote branch for each environment ("production", "staging", "development").
112
-
113
- One thing that comes up pretty quickly is that there are various files associated with
114
- the application which have more to do with configuration of a running instance than they
115
- have to do with the application in general. In the rails world these files are probably
116
- in config, or config/initializers/. Think database connection information, search engine
117
- settings, exception notification plugin data, email configuration, Amazon S3 credentials,
118
- e-commerce back-end configuration, etc.
119
-
120
- We don't want the production site using the same database as the development site. We don't
121
- want staging using (and re-indexing, re-starting, etc.) production's search engine server.
122
- We don't want any site other than production to send account reset emails, or to push orders
123
- out to fulfillment, etc.
124
-
125
- For some reason, the answer to this with cap and/or vlad has been to have recipes which
126
- reference various files up in a shared area on the server, do copying or symlinking, etc.
127
- Where did those files come from? How did they get there? How are they managed over time?
128
- If they got there via a configuration tool, why (a) are they not in the right place, or
129
- (b) do we have to do work to get them into the right place?
130
-
131
- So, we decided that we'd change how we deal with the issue. Instead of moving files around
132
- or symlinking every time we deploy, we will manage the configuration data just like we
133
- manage other files required by our projects -- with git.
134
-
135
- So, each project we deploy is associated with a config repo in our git repository. Usually
136
- many projects are in the same repo, because we're the only people to see the data and
137
- there's no confidentiality issue. But, if a customer has access to their git information
138
- then we'll make a separate config repo for all that customers' projects. (This is easier
139
- to manage than it sounds if you're using gitosis, btw.)
140
-
141
- Anyway, a config repo is just a git repo. In it are directories for every project
142
- whose configuration information is managed in that repo. For example, there's a "larry"
143
- directory in our main config repo, because we're deploying the larry project
144
- (http://github.com/rick/larry) to manage our high-level configuration data.
145
-
146
- Note, if you set the 'project' setting in deploy.yml, that determines the name of the
147
- top-level project directory whiskey_disk will hunt for in your config repo. If you don't
148
- it uses the 'repository' setting (i.e., the git URL) to try to guess what the project
149
- name might be. So if the URL ends in foo/bar.git, or foo:bar.git, or /bar, or :bar,
150
- whiskey_disk is going to guess "bar". If it's all bitched up, just set 'project' manually
151
- in deploy.yml.
152
-
153
- Inside the project directory is a directory named for each environment we might
154
- deploy to. Frankly, we've been using "production", "staging", "development", and "local"
155
- on just about everything.
156
-
157
- Inside the environment directory is a tree of files. So, e.g., there's config/, which
158
- has initializers/ and database.yml in it.
159
-
160
- Long story short, load up whatever configuration files you're using into the repo
161
- as described, and come deployment time exactly those files will be overlaid on top of
162
- the most recent checkout of the project. Snap.
135
+ This is completely optional, but we really are digging this, so maybe
136
+ you should try it. Basically it goes like this...
137
+
138
+ We have a number of web applications that we manage. Usually there's a
139
+ customer, there might be third-party developers, or the customer might have
140
+ access to the git repo, or their designer might, etc. We also tend to run a
141
+ few instances of any given app, for any given customer. So, we'll run a
142
+ "production" site, which is the public- facing, world-accessible main site.
143
+ We'll usually also run a "staging" site, which is roughly the same code, maybe
144
+ the same data, running on a different URL, which the customer can look at to
145
+ see if the functionality there is suitable for deploying out to production. We
146
+ sometimes run a "development" site which is even less likely to be the same
147
+ code as production, etc., but gives visibility into what might end up in
148
+ production one day soon.
149
+
150
+ So we'll store the code for all of these versions of a site in the same git
151
+ repo, typically using a different remote branch for each environment
152
+ ("production", "staging", "development").
153
+
154
+ One thing that comes up pretty quickly is that there are various files
155
+ associated with the application which have more to do with configuration of a
156
+ running instance than they have to do with the application in general. In the
157
+ rails world these files are probably in config, or config/initializers/. Think
158
+ database connection information, search engine settings, exception notification
159
+ plugin data, email configuration, Amazon S3 credentials, e-commerce back-end
160
+ configuration, etc.
161
+
162
+ We don't want the production site using the same database as the
163
+ development site. We don't want staging using (and re-indexing, re-starting,
164
+ etc.) production's search engine server. We don't want any site other than
165
+ production to send account reset emails, or to push orders out to fulfillment,
166
+ etc.
167
+
168
+ For some reason, the answer to this with cap and/or vlad has been to have
169
+ recipes which reference various files up in a shared area on the server, do
170
+ copying or symlinking, etc. Where did those files come from? How did they get
171
+ there? How are they managed over time? If they got there via a configuration
172
+ tool, why (a) are they not in the right place, or (b) do we have to do work to
173
+ get them into the right place?
174
+
175
+ So, we decided that we'd change how we deal with the issue. Instead of
176
+ moving files around or symlinking every time we deploy, we will manage the
177
+ configuration data just like we manage other files required by our projects --
178
+ with git.
179
+
180
+ So, each project we deploy is associated with a config repo in our git
181
+ repository. Usually many projects are in the same repo, because we're the only
182
+ people to see the data and there's no confidentiality issue. But, if a
183
+ customer has access to their git information then we'll make a separate config
184
+ repo for all that customers' projects. (This is easier to manage than it
185
+ sounds if you're using gitosis, btw.)
186
+
187
+ Anyway, a config repo is just a git repo. In it are directories for every
188
+ project whose configuration information is managed in that repo. For example,
189
+ there's a "larry" directory in our main config repo, because we're deploying
190
+ the larry project (http://github.com/rick/larry) to manage our high-level
191
+ configuration data.
192
+
193
+ Note, if you set the 'project' setting in deploy.yml, that determines the
194
+ name of the top-level project directory whiskey_disk will hunt for in your
195
+ config repo. If you don't it uses the 'repository' setting (i.e., the git URL)
196
+ to try to guess what the project name might be. So if the URL ends in
197
+ foo/bar.git, or foo:bar.git, or /bar, or :bar, whiskey_disk is going to guess
198
+ "bar". If it's all bitched up, just set 'project' manually in deploy.yml.
199
+
200
+ Inside the project directory is a directory named for each environment we
201
+ might deploy to. Frankly, we've been using "production", "staging",
202
+ "development", and "local" on just about everything.
203
+
204
+ Inside the environment directory is a tree of files. So, e.g., there's
205
+ config/, which has initializers/ and database.yml in it.
206
+
207
+ Long story short, load up whatever configuration files you're using into
208
+ the repo as described, and come deployment time exactly those files will be
209
+ overlaid on top of the most recent checkout of the project. Snap.
163
210
 
164
211
  project-config/
165
212
  |
@@ -201,28 +248,25 @@ Whiskey Disk -- embarrassingly fast deployments.
201
248
  http://github.com/rick/larry/blob/master/config/deploy.yml
202
249
  http://github.com/rick/larry/blob/master/lib/tasks/deploy.rake
203
250
 
204
- Note that you can also provide per-environment config settings,
205
- outside of deploy.yml. This is most useful for handling per-developer
206
- local deployments, though you could use it to override some settings
207
- if that makes sense in some context. Here's a simple example of that:
251
+ Note that you can also provide per-environment config settings, outside of
252
+ deploy.yml. This is most useful for handling per-developer local deployments,
253
+ though you could use it to override some settings if that makes sense in some
254
+ context. Here's a simple example of that:
208
255
 
209
256
  http://github.com/rick/larry/blob/master/config/deploy-local.yml.example
210
257
 
211
258
 
212
259
  - We are using it on a private project with lots of config files, but here's
213
260
  a gist showing a bit more interesting deploy.rake file for post_setup and
214
- post_deploy work:
261
+ post_deploy work:
215
262
 
216
263
  https://gist.github.com/47e23f2980943531beeb
217
264
 
218
-
219
-
220
265
  On the radar for an upcoming release are:
221
266
 
222
267
  - common post_* recipes being specifiable by symbol names in deploy.yml ?
223
- - making the config repo stuff optional if you don't need that at all
224
- - bringing in a very simplified version of mislav/git-deploy post-{receive,reset}
225
- hooks, and a little sugar so you can say:
268
+ - bringing in a very simplified version of mislav/git-deploy
269
+ post-{receive,reset} hooks, and a little sugar so you can say:
226
270
 
227
271
  task :post_deploy do
228
272
  if has_changes?('db/migrate') or has_changes?('config/database.yml')
data/TODO.txt CHANGED
@@ -1,16 +1,36 @@
1
- - common post-deploy tasks (including db:migrate, server bounce)
2
- - some sort of simple API for hooks to check which files have changed (either via git rev differences or rsync output), so then the rake task would just do something like:
1
+ - would be nice to have the ability to say if a project is out of date (meaning that, based upon this config file, either the checked out project repo or the checked out config repo is older than the upstream) so we can do some sort of automated / conditional deployments. We could implement this as a config file option (check for out of date before deploying), but questions about how to "force" if necessary. Could also be done as a flag.
2
+
3
+ - do git-deploy style change detection: get the current branch ref, then do the fetch/reset, get the current branch ref; find the differences, make them available to the rake task(s)
4
+ - some sort of simple API to access the detected changes
5
+ require 'whiskey_disk/rake'
3
6
 
4
- require 'whiskey_disk/rake'
5
-
6
- namespace :deploy do
7
- task :post_deploy do
8
- if changed_in?('db/migrate') or changed?('config/database.yml')
9
- Rake::Task['db:migrate'].invoke
7
+ namespace :deploy do
8
+ task :post_deploy do
9
+ if changed_in?('db/migrate') or changed?('config/database.yml')
10
+ Rake::Task['db:migrate'].invoke
11
+ end
12
+ # etc. ...
10
13
  end
11
- # etc. ...
12
14
  end
13
- end
15
+
16
+ ---
17
+
18
+ - [Q] how to specify readily which projects need to be deployed? Metaconfig?:
14
19
 
15
- - install hooks (look at maybe git-deploy for good examples)
16
- - make sure the config repo stuff is optional
20
+ ---
21
+ - config: /path/to/config
22
+ project: larry
23
+ target: staging
24
+ - config: /path/to/config
25
+ project: larry
26
+ target: production
27
+
28
+ - [Q] what about per-environment rake tasks, do we just store these in the config repo? does this work?
29
+
30
+ - [Q] ditto, maintenance pages(?) (i.e., a pre-deploy hook)
31
+
32
+ - [Q] do we want a mechanism to manage the config repo? (add a repo, add a project, add an environment, put a file into the config repo for an environment?)
33
+
34
+ - [Q] do we need actual support for "rollbacks"?
35
+
36
+ - [Q] do we want to support multi-system deployments (i.e., deploy and rollback on 4 simultaneous app servers, other bullshit running on the db server, etc.)? If we get into this, we have the original :role problem that cap faced -- i.e., we only want to run the database operations on certain hosts.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.7
1
+ 0.3.0
data/bin/wd ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'whiskey_disk/rake'
5
+
6
+ $0 = "#{$0} setup|deploy" # jesus, this is a hack.
7
+
8
+ options = {}
9
+ op = OptionParser.new do |opts|
10
+ opts.on('-t=TARGET', '--to=TARGET', "deployment target") do |target|
11
+ options[:target] = target
12
+ end
13
+
14
+ opts.on('-p=TARGET', '--path=TARGET', "configuration path") do |path|
15
+ options[:path] = path
16
+ end
17
+
18
+ opts.on_tail('-h', '--help', 'show this message') do
19
+ raise opts.to_s
20
+ end
21
+ end
22
+
23
+ rest = op.parse(ARGV)
24
+ raise op.to_s unless options[:target]
25
+ raise op.to_s unless rest and rest.size == 1
26
+ command = rest.first
27
+ raise op.to_s unless ['deploy', 'setup'].include?(command)
28
+
29
+ ENV['to'] = options[:target]
30
+ ENV['path'] = options[:path]
31
+
32
+ if command == 'deploy'
33
+ Rake::Task['deploy:now'].invoke
34
+ else
35
+ Rake::Task['deploy:setup'].invoke
36
+ end
@@ -4,73 +4,114 @@ class WhiskeyDisk
4
4
  class Config
5
5
  class << self
6
6
  def environment_name
7
- (ENV['to'] && ENV['to'] != '') ? ENV['to'] : false
7
+ return false unless (ENV['to'] && ENV['to'] != '')
8
+ return ENV['to'] unless ENV['to'] =~ /:/
9
+ ENV['to'].split(/:/)[1]
10
+ end
11
+
12
+ def specified_project_name
13
+ return false unless (ENV['to'] && ENV['to'] =~ /:/)
14
+ ENV['to'].split(/:/).first
15
+ end
16
+
17
+ def path
18
+ (ENV['path'] && ENV['path'] != '') ? ENV['path'] : false
8
19
  end
9
20
 
10
21
  def contains_rakefile?(path)
11
22
  File.exists?(File.expand_path(File.join(path, 'Rakefile')))
12
23
  end
13
24
 
14
- def base_path
25
+ def find_rakefile_from_current_path
15
26
  while (!contains_rakefile?(Dir.pwd))
16
27
  raise "Could not find Rakefile in the current directory tree!" if Dir.pwd == '/'
17
28
  Dir.chdir('..')
18
29
  end
19
- Dir.pwd
30
+ File.join(Dir.pwd, 'config')
20
31
  end
21
32
 
22
- def main_configuration_file
23
- File.expand_path(File.join(base_path, 'config', 'deploy.yml'))
33
+ def base_path
34
+ return path if path
35
+ find_rakefile_from_current_path
24
36
  end
25
37
 
26
- def main_configuration_data
27
- raise "Main configuration file [#{main_configuration_file}] not found!" unless File.exists?(main_configuration_file)
28
- File.read(main_configuration_file)
38
+ def configuration_file
39
+ return path if path and File.file?(path)
40
+
41
+ files = []
42
+
43
+ files += [
44
+ File.join(base_path, 'deploy', specified_project_name, "#{environment_name}.yml"), # /deploy/foo/staging.yml
45
+ File.join(base_path, 'deploy', "#{specified_project_name}.yml") # /deploy/foo.yml
46
+ ] if specified_project_name
47
+
48
+ files += [
49
+ File.join(base_path, 'deploy', "#{environment_name}.yml"), # /deploy/staging.yml
50
+ File.join(base_path, "#{environment_name}.yml"), # /staging.yml
51
+ File.join(base_path, 'deploy.yml') # /deploy.yml
52
+ ]
53
+
54
+ files.each { |file| return file if File.exists?(file) }
55
+
56
+ raise "Could not locate configuration file in path [#{base_path}]"
29
57
  end
30
58
 
31
- def environment_configuration_file
32
- raise "Cannot determine current environment -- try rake ... to=staging, for example." unless environment_name
33
- File.expand_path(File.join(base_path, 'config', "deploy-#{environment_name}.yml"))
59
+ def configuration_data
60
+ raise "Configuration file [#{configuration_file}] not found!" unless File.exists?(configuration_file)
61
+ File.read(configuration_file)
34
62
  end
35
63
 
36
- def environment_configuration_data
37
- File.exists?(environment_configuration_file) ? File.read(environment_configuration_file) : nil
38
- rescue Exception => e
39
- raise %Q{Could not read configuration file [#{environment_configuration_file}] for environment [#{environment_name}]: "#{e}"}
64
+ def project_name
65
+ specified_project_name || 'unnamed_project'
66
+ end
67
+
68
+ def repository_depth(data, depth = 0)
69
+ raise 'no repository found' unless data.respond_to?(:has_key?)
70
+ return depth if data.has_key?('repository')
71
+ repository_depth(data.values.first, depth + 1)
40
72
  end
41
73
 
42
- def project_name(config)
43
- return '' unless config['repository'] and config['repository'] != ''
44
- config['repository'].sub(%r{^.*[/:]}, '').sub(%r{\.git$}, '')
74
+ # is this data hash a bottom-level data hash without an environment name?
75
+ def needs_environment_scoping?(data)
76
+ repository_depth(data) == 0
45
77
  end
46
78
 
47
- def load_main_data
48
- YAML.load(main_configuration_data)
79
+ # is this data hash an environment data hash without a project name?
80
+ def needs_project_scoping?(data)
81
+ repository_depth(data) == 1
82
+ end
83
+
84
+ def add_environment_scoping(data)
85
+ return data unless needs_environment_scoping?(data)
86
+ { environment_name => data }
87
+ end
88
+
89
+ def add_project_scoping(data)
90
+ return data unless needs_project_scoping?(data)
91
+ { project_name => data }
92
+ end
93
+
94
+ def normalize_data(data)
95
+ add_project_scoping(add_environment_scoping(data.clone))
96
+ end
97
+
98
+ def load_data
99
+ normalize_data(YAML.load(configuration_data))
49
100
  rescue Exception => e
50
- raise %Q{Error reading configuration file [#{main_configuration_file}]: "#{e}"}
101
+ raise %Q{Error reading configuration file [#{configuration_file}]: "#{e}"}
51
102
  end
52
103
 
53
- def load_environment_data
54
- begin
55
- env = environment_configuration_data ? YAML.load(environment_configuration_data) : nil
56
- rescue Exception => e
57
- raise %Q{Error reading configuration file [#{environment_configuration_file}]: "#{e}"}
58
- end
59
- raise "Configuration file [#{environment_configuration_file}] does not define data for environment [#{environment_name}]" if env and !env[environment_name]
60
- env || {}
104
+ def filter_data(data)
105
+ raise "No configuration file defined data for environment [#{environment_name}]" unless data[project_name][environment_name]
106
+ data[project_name][environment_name].merge({
107
+ 'environment' => environment_name,
108
+ 'project' => project_name
109
+ })
61
110
  end
62
111
 
63
112
  def fetch
64
113
  raise "Cannot determine current environment -- try rake ... to=staging, for example." unless environment_name
65
- main, env = load_main_data, load_environment_data
66
- raise "No configuration file defined data for environment [#{environment_name}]" unless main[environment_name] or env[environment_name]
67
- config = (main[environment_name] || {}).merge(env[environment_name] || {}).merge({'environment' => environment_name})
68
- { 'project' => project_name(config) }.merge(config)
69
- end
70
-
71
- def filenames
72
- raise "Cannot determine current environment -- try rake ... to=staging, for example." unless environment_name
73
- [ main_configuration_file, environment_configuration_file ]
114
+ filter_data(load_data)
74
115
  end
75
116
  end
76
117
  end
@@ -0,0 +1,36 @@
1
+ require 'rake'
2
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'whiskey_disk'))
3
+
4
+ namespace :deploy do
5
+ desc "Perform initial setup for deployment"
6
+ task :setup do
7
+ WhiskeyDisk.ensure_main_parent_path_is_present
8
+ WhiskeyDisk.ensure_config_parent_path_is_present if WhiskeyDisk.has_config_repo?
9
+ WhiskeyDisk.checkout_main_repository
10
+ WhiskeyDisk.checkout_configuration_repository if WhiskeyDisk.has_config_repo?
11
+ WhiskeyDisk.update_main_repository_checkout
12
+ WhiskeyDisk.update_configuration_repository_checkout if WhiskeyDisk.has_config_repo?
13
+ WhiskeyDisk.refresh_configuration if WhiskeyDisk.has_config_repo?
14
+ WhiskeyDisk.run_post_setup_hooks
15
+ WhiskeyDisk.flush
16
+ end
17
+
18
+ desc "Deploy now."
19
+ task :now do
20
+ WhiskeyDisk.update_main_repository_checkout
21
+ WhiskeyDisk.update_configuration_repository_checkout if WhiskeyDisk.has_config_repo?
22
+ WhiskeyDisk.refresh_configuration if WhiskeyDisk.has_config_repo?
23
+ WhiskeyDisk.run_post_deploy_hooks
24
+ WhiskeyDisk.flush
25
+ end
26
+
27
+ task :post_setup do
28
+ env = WhiskeyDisk[:environment]
29
+ Rake::Task["deploy:#{env}:post_setup"].invoke if Rake::Task.task_defined? "deploy:#{env}:post_setup"
30
+ end
31
+
32
+ task :post_deploy do
33
+ env = WhiskeyDisk[:environment]
34
+ Rake::Task["deploy:#{env}:post_deploy"].invoke if Rake::Task.task_defined? "deploy:#{env}:post_deploy"
35
+ end
36
+ end