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 +0 -1
- data/README +152 -108
- data/TODO.txt +32 -12
- data/VERSION +1 -1
- data/bin/wd +36 -0
- data/lib/whiskey_disk/config.rb +79 -38
- data/lib/whiskey_disk/rake.rb +36 -0
- data/lib/whiskey_disk.rb +24 -11
- data/spec/wd_command_spec.rb +421 -0
- data/spec/whiskey_disk/config_spec.rb +356 -221
- data/spec/whiskey_disk/rake_spec.rb +255 -0
- data/spec/whiskey_disk_spec.rb +85 -19
- data/tasks/deploy.rake +1 -1
- data/whiskey_disk.gemspec +76 -0
- metadata +35 -15
- data/lib/tasks/deploy.rb +0 -37
- data/spec/tasks/deploy_spec.rb +0 -295
data/.gitignore
CHANGED
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
|
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
|
12
|
-
and it uses stock *nix tools (ssh, bash, rsync) to get
|
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
|
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
|
18
|
-
one shot. Everything needed to do a full deployment is done in
|
19
|
-
|
20
|
-
|
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
|
23
|
-
|
24
|
-
|
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
|
27
|
-
"local" or "development" enviroments). Use .gitignore
|
28
|
-
|
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.
|
31
|
-
after setup or deployment are specified as rake
|
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
|
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
|
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/
|
82
|
-
your project's Rakefile) will cause that task to be run at the end
|
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
|
85
|
-
your project's Rakefile) will cause that task to be run
|
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
|
-
|
90
|
-
|
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
|
-
|
98
|
-
|
99
|
-
|
100
|
-
We have a number of web applications that we manage. Usually there's a
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
the
|
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
|
-
|
206
|
-
|
207
|
-
|
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
|
-
|
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
|
-
-
|
224
|
-
|
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
|
-
-
|
2
|
-
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
15
|
+
|
16
|
+
---
|
17
|
+
|
18
|
+
- [Q] how to specify readily which projects need to be deployed? Metaconfig?:
|
14
19
|
|
15
|
-
|
16
|
-
|
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
|
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
|
data/lib/whiskey_disk/config.rb
CHANGED
@@ -4,73 +4,114 @@ class WhiskeyDisk
|
|
4
4
|
class Config
|
5
5
|
class << self
|
6
6
|
def environment_name
|
7
|
-
(ENV['to'] && ENV['to'] != '')
|
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
|
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
|
23
|
-
|
33
|
+
def base_path
|
34
|
+
return path if path
|
35
|
+
find_rakefile_from_current_path
|
24
36
|
end
|
25
37
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
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
|
32
|
-
raise "
|
33
|
-
File.
|
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
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
48
|
-
|
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 [#{
|
101
|
+
raise %Q{Error reading configuration file [#{configuration_file}]: "#{e}"}
|
51
102
|
end
|
52
103
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
-
|
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
|