wordpresstrano 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5436061cb8fc9afe6050e4f86f69595e9259c791
4
+ data.tar.gz: 1513416e7fed88eaa04554fd21f9711dc60d0667
5
+ SHA512:
6
+ metadata.gz: 3719edf22d551b9ff9d8dac8691b77123d2b3e3ecbf237742ed040d331f8ee81975d3bd3304edfc4122bcab4ec9869deeda8f51a81a1849fd481f1a88a9a5800
7
+ data.tar.gz: 644b5f81e4007e13770fce41c8cfb18f4b3a9f66320a99d0ff8364e1de837e7ab05928b7b34b075489e12adf303db08f378118b9dcfba91cc4b3171c284d9fd2
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Nialto Services
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # WordPresstrano
2
+
3
+ This gem is currently in beta.
4
+
5
+ Documentation coming soon!
@@ -0,0 +1,22 @@
1
+ class Fixnum
2
+ # Get the ordinal string of the integer value
3
+ def ordinal
4
+ abs_number = self.to_i.abs
5
+
6
+ if (11..13).include?(abs_number % 100)
7
+ "th"
8
+ else
9
+ case abs_number % 10
10
+ when 1; "st"
11
+ when 2; "nd"
12
+ when 3; "rd"
13
+ else "th"
14
+ end
15
+ end
16
+ end
17
+
18
+ # Get the ordinal string prefixed with the integer value
19
+ def ordinalize
20
+ "#{self}#{self.ordinal}"
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ class Hash
2
+ # Check to see if we contain all the specified keys
3
+ def has_keys?(*keys)
4
+ keys.each do |key|
5
+ return false unless self.has_key? key
6
+ end
7
+
8
+ true
9
+ end
10
+ end
@@ -0,0 +1,95 @@
1
+ # Check binaries before performing tasks
2
+ before "db:backup", "binaries:check"
3
+ before "db:create", "binaries:check"
4
+ before "db:list_backups", "binaries:check"
5
+ before "db:pull", "binaries:check"
6
+ before "db:push", "binaries:check"
7
+ before "db:reset", "binaries:check"
8
+ before "db:restore", "binaries:check"
9
+ before "deploy", "binaries:check"
10
+ before "htaccess:pull", "binaries:check"
11
+ before "htaccess:push", "binaries:check"
12
+ before "uploads:pull", "binaries:check"
13
+ before "uploads:push", "binaries:check"
14
+ before "uploads:setperms", "binaries:check"
15
+ before "wp:core:download", "binaries:check"
16
+ before "wp:core:remove", "binaries:check"
17
+
18
+ # Check directories before performing tasks
19
+ before "config:generate", "deploy:check:directories"
20
+ before "db:backup", "deploy:check:directories"
21
+ before "db:create", "deploy:check:directories"
22
+ before "db:list_backups", "deploy:check:directories"
23
+ before "db:pull", "deploy:check:directories"
24
+ before "db:push", "deploy:check:directories"
25
+ before "db:reset", "deploy:check:directories"
26
+ before "db:restore", "deploy:check:directories"
27
+ before "deploy:shared_configs", "deploy:check:directories"
28
+ before "htaccess:pull", "deploy:check:directories"
29
+ before "htaccess:push", "deploy:check:directories"
30
+ before "robots:generate", "deploy:check:directories"
31
+ before "uploads:pull", "deploy:check:directories"
32
+ before "uploads:push", "deploy:check:directories"
33
+
34
+ # Check if maintenance mode should be enabled before pushing the database
35
+ before "db:push", "db:check_maintenance_enable"
36
+
37
+ # Create the MySQL database before pushing content to it
38
+ before "db:push", "db:create"
39
+
40
+ # Backup the database before pushing
41
+ before "db:push", "db:backup"
42
+
43
+ # Check if maintenance mode should be enabled before restoring the database
44
+ before "db:restore", "db:check_maintenance_enable"
45
+
46
+ # Create the database before restoring
47
+ before "db:restore", "db:create"
48
+
49
+ # Deploy shared configuration files before deploying
50
+ before "deploy", "deploy:shared_configs"
51
+
52
+ # Move the database backup from the release we rolled away from
53
+ # into the release's root before it's archived
54
+ before "deploy:cleanup_rollback", "db:cleanup_rollback_database"
55
+
56
+ # Load the local WordPress version so that when downloading the
57
+ # WordPress core on a remote server, the version matches the local installation.
58
+ before "deploy:updated", "wp:core:load_local_version"
59
+
60
+ # Remove the existing WordPress core before downloading a new one
61
+ before "wp:core:download", "wp:core:remove"
62
+
63
+ # Download the WordPress core files before finishing deploy:updated
64
+ before "deploy:updated", "wp:core:download"
65
+
66
+ # Link the release into the website root
67
+ after "deploy:finished", "webroot:symlink"
68
+
69
+ # Touch the release directory after deploying
70
+ # This is required as after the first deployment, we enable
71
+ # maintenance mode for every subsequent deployment. This causes
72
+ # the previous release directory to have a newer timestamp than
73
+ # the new release directory which leads to issues with the rollback
74
+ # feature as the releases directory is sorted by modification time
75
+ # when capistrano looks for the release to rollback to.
76
+ after "deploy:finishing", "deploy:touch_release"
77
+
78
+ # Set permissions on the resources after deploying them
79
+ after "config:generate", "config:setperms"
80
+ after "htaccess:push", "htaccess:setperms"
81
+ after "robots:generate", "robots:setperms"
82
+ after "uploads:push", "uploads:setperms"
83
+ after "deploy:finished", "webroot:setperms"
84
+
85
+ # Check if maintenance mode should be disabled after pushing the database
86
+ after "db:push", "db:check_maintenance_disable"
87
+
88
+ # Check if maintenance mode should be disabled after restoring the database
89
+ after "db:restore", "db:check_maintenance_disable"
90
+
91
+ # Push the local resources after finishing deploy:updated
92
+ after "deploy:reverted", "db:rollback"
93
+ after "deploy:updated", "htaccess:push"
94
+ after "deploy:updated", "uploads:push"
95
+ after "deploy:updated", "db:push" # We want this to happen last so leave it here :)
@@ -0,0 +1,35 @@
1
+ namespace :binaries do
2
+ desc "Check that all required binaries are installed"
3
+ task :check do
4
+ next if true == fetch(:checked_binaries)
5
+
6
+ required_binaries = {
7
+ local: [:php, :rm, :rsync, :wp],
8
+ remote: {
9
+ :all => [:chmod, :find, :rm, :wp],
10
+ :app => [:ln, :readlink, :rsync],
11
+ :db => [:du, :grep, :mysqlshow]
12
+ }
13
+ }
14
+
15
+ run_locally do
16
+ required_binaries[:local].each do |binary|
17
+ unless test :which, binary
18
+ abort "The binary '#{binary}' is missing from the local system"
19
+ end
20
+ end
21
+ end
22
+
23
+ required_binaries[:remote].each do |role, binaries|
24
+ on roles(role) do |server|
25
+ binaries.each do |binary|
26
+ unless test :which, binary
27
+ abort "The binary '#{binary}' is missing from #{server.user}@#{server.hostname}"
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ set :checked_binaries, true
34
+ end
35
+ end
@@ -0,0 +1,85 @@
1
+ namespace :config do
2
+ desc "Generate a wp-config.php file"
3
+ task :generate do
4
+ file = "wp-config.php"
5
+
6
+ local_path = File.join(Dir.pwd, file)
7
+ remote_path = File.join(shared_path, file)
8
+
9
+ template_path = File.join("config", "templates", "#{file}.erb")
10
+ template_content = File.read(template_path)
11
+
12
+ run_locally do
13
+ database_config = fetch(:local_database_config)
14
+
15
+ unless database_config.has_keys? :hostname, :username, :database, :password
16
+ abort "The local database configuration is invalid"
17
+ end
18
+
19
+ database_hostname = database_config[:hostname]
20
+ database_username = database_config[:username]
21
+ database_name = database_config[:database]
22
+ database_password = database_config[:password]
23
+
24
+ secret_keys = Net::HTTP.get URI("https://api.wordpress.org/secret-key/1.1/salt")
25
+
26
+ if secret_keys.nil? or secret_keys.empty?
27
+ abort "Unable to fetch secret keys using the WordPress API"
28
+ end
29
+
30
+ configuration = ERB.new(template_content).result(binding)
31
+
32
+ if test("[ -f #{local_path} ]")
33
+ execute :rm, "-f", local_path
34
+ end
35
+
36
+ info "Writing local #{file} file"
37
+
38
+ File.write(local_path, configuration)
39
+ end
40
+
41
+ database_config = fetch(:database_config)
42
+
43
+ unless database_config.has_keys? :hostname, :username, :database, :password
44
+ abort "The #{fetch(:stage)} database configuration is invalid"
45
+ end
46
+
47
+ database_hostname = database_config[:hostname]
48
+ database_username = database_config[:username]
49
+ database_name = database_config[:database]
50
+ database_password = database_config[:password]
51
+
52
+ secret_keys = Net::HTTP.get URI("https://api.wordpress.org/secret-key/1.1/salt")
53
+
54
+ if secret_keys.nil? or secret_keys.empty?
55
+ abort "Unable to fetch secret keys using the WordPress API"
56
+ end
57
+
58
+ configuration = ERB.new(template_content).result(binding)
59
+
60
+ on roles(:app) do |server|
61
+ if test("[ -f #{remote_path} ]")
62
+ execute :rm, "-f", remote_path
63
+ end
64
+
65
+ upload! StringIO.new(configuration), remote_path
66
+ end
67
+ end
68
+
69
+ desc "Set permissions on the wp-config.php file"
70
+ task :setperms do
71
+ on roles(:app) do |server|
72
+ file = "wp-config.php"
73
+
74
+ remote_path = File.join(shared_path, file)
75
+
76
+ unless test("[ -f #{remote_path} ]")
77
+ error "A #{file} file does not exist on #{server.user}@#{server.hostname}"
78
+ end
79
+
80
+ info "Setting permissions for #{file} on #{server.user}@#{server.hostname}"
81
+
82
+ execute :chmod, 644, remote_path
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,355 @@
1
+ namespace :db do
2
+ desc "Pull down the WordPress database"
3
+ task :pull do
4
+ file = "#{SecureRandom.hex(8)}.sql"
5
+
6
+ local_path = File.join(Dir.pwd, file)
7
+ remote_path = File.join(fetch(:tmp_dir), file)
8
+
9
+ next if 0 == roles(:db).count
10
+
11
+ if 1 < roles(:db).count
12
+ run_locally do
13
+ info "Found #{roles(:db).count} database servers"
14
+
15
+ roles(:db).each_with_index do |server, index|
16
+ info "#{index + 1}) #{server.user}@#{server.hostname} (Port #{server.port or 22})"
17
+ end
18
+
19
+ set :database_pull_server, ask("the number of the server to pull the database from", "1")
20
+ end
21
+ else
22
+ set :database_pull_server, "1"
23
+ end
24
+
25
+ database_pull_server = fetch(:database_pull_server).to_i
26
+
27
+ if 1 > database_pull_server or roles(:db).count < database_pull_server
28
+ run_locally do
29
+ error "Unable to locate a server with an id '#{database_pull_server}'"
30
+ end
31
+
32
+ next
33
+ end
34
+
35
+ database_pull_server = roles(:db)[database_pull_server - 1]
36
+
37
+ on roles(:db) do |server|
38
+ next unless server.matches? database_pull_server
39
+
40
+ info "Pulling WordPress database from #{server.user}@#{server.hostname}"
41
+
42
+ within release_path do
43
+ execute :wp, "db", "export", remote_path
44
+ end
45
+
46
+ download! remote_path, local_path
47
+
48
+ execute :rm, "-f", remote_path
49
+
50
+ run_locally do
51
+ execute :wp, "db", "import", local_path
52
+ execute :rm, "-f", local_path
53
+
54
+ if fetch(:local_site_url) and fetch(:site_url)
55
+ execute :wp, "search-replace", fetch(:site_url), fetch(:local_site_url)
56
+ end
57
+ end
58
+ end
59
+
60
+ set :database_pull_server, nil
61
+ end
62
+
63
+ desc "Push up the WordPress database"
64
+ task :push do
65
+ file = "#{SecureRandom.hex(8)}.sql"
66
+
67
+ local_path = File.join(Dir.pwd, file)
68
+ remote_path = File.join(fetch(:tmp_dir), file)
69
+
70
+ on roles(:db) do |server|
71
+ info "Pushing WordPress database to #{server.user}@#{server.hostname}"
72
+
73
+ run_locally do
74
+ execute :wp, "db", "export", local_path
75
+ end
76
+
77
+ upload! local_path, remote_path
78
+
79
+ run_locally do
80
+ execute :rm, "-f", local_path
81
+ end
82
+
83
+ within release_path do
84
+ execute :wp, "db", "import", remote_path
85
+ execute :rm, "-f", remote_path
86
+
87
+ if fetch(:local_site_url) and fetch(:site_url)
88
+ execute :wp, "search-replace", fetch(:local_site_url), fetch(:site_url)
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ desc "Create the MySQL database"
95
+ task :create do
96
+ database_config = fetch(:database_config)
97
+
98
+ unless database_config.has_keys? :hostname, :username, :database, :password
99
+ abort "The #{fetch(:stage)} database configuration is invalid"
100
+ end
101
+
102
+ database_name = database_config[:database]
103
+ database_hostname = database_config[:hostname]
104
+ database_username = database_config[:username]
105
+ database_password = database_config[:password]
106
+
107
+ on roles(:db) do |server|
108
+ within release_path do
109
+ if test("[ \"#{database_name}\" == $(mysqlshow --user=\"#{database_username}\" --password=\"#{database_password}\" #{database_name} | grep -v Wildcard | grep -o #{database_name}) ]")
110
+ info "The MySQL database already exists on #{server.user}@#{server.hostname}"
111
+
112
+ next
113
+ end
114
+
115
+ info "Creating MySQL database on #{server.user}@#{server.hostname}"
116
+
117
+ execute :wp, "db", "create"
118
+ end
119
+ end
120
+ end
121
+
122
+ desc "Drop the MySQL database"
123
+ task :drop do
124
+ database_config = fetch(:database_config)
125
+
126
+ unless database_config.has_keys? :hostname, :username, :database, :password
127
+ abort "The #{fetch(:stage)} database configuration is invalid"
128
+ end
129
+
130
+ database_name = database_config[:database]
131
+ database_hostname = database_config[:hostname]
132
+ database_username = database_config[:username]
133
+ database_password = database_config[:password]
134
+
135
+ on roles(:db) do |server|
136
+ within release_path do
137
+ unless test("[ \"#{database_name}\" == $(mysqlshow --user=\"#{database_username}\" --password=\"#{database_password}\" #{database_name} | grep -v Wildcard | grep -o #{database_name}) ]")
138
+ info "The MySQL database does not exist on #{server.user}@#{server.hostname}"
139
+
140
+ next
141
+ end
142
+
143
+ info "Deleting MySQL database on #{server.user}@#{server.hostname}"
144
+
145
+ execute :wp, "db", "drop", "--yes"
146
+ end
147
+ end
148
+ end
149
+
150
+ desc "Reset the MySQL database"
151
+ task :reset do
152
+ on roles(:db) do |server|
153
+ within release_path do
154
+ unless test :wp, "core", "is-installed"
155
+ info "The WordPress database does not appear to be installed on #{server.user}@#{server.hostname}"
156
+
157
+ next
158
+ end
159
+
160
+ info "Resetting the WordPress database on #{server.user}@#{server.hostname}"
161
+
162
+ execute :wp, "db", "reset", "--yes"
163
+ end
164
+ end
165
+ end
166
+
167
+ desc "Create a backup of the WordPress database"
168
+ task :backup do
169
+ backups_directory = File.join(fetch(:deploy_to), "backups", "database")
170
+
171
+ on roles(:db) do |server|
172
+ next unless test("[ -d #{current_path} ]")
173
+
174
+ actual_current_path = capture("readlink -f #{current_path}").strip
175
+
176
+ file = File.basename(actual_current_path)
177
+ file = "#{file}.sql"
178
+
179
+ remote_path = File.join(backups_directory, file)
180
+
181
+ info "Backing up WordPress database on #{server.user}@#{server.hostname}"
182
+
183
+ execute :mkdir, "-p", backups_directory
184
+
185
+ if test("[ -f #{remote_path} ]")
186
+ execute :rm, "-f", remote_path
187
+ end
188
+
189
+ within release_path do
190
+ execute :wp, "db", "export", remote_path
191
+ end
192
+ end
193
+ end
194
+
195
+ desc "Restore a backup of the WordPress database"
196
+ task :restore do
197
+ backups_directory = File.join(fetch(:deploy_to), "backups", "database")
198
+
199
+ backup_id = fetch(:rollback_timestamp, ENV["id"])
200
+
201
+ unless backup_id
202
+ run_locally do
203
+ info "No backup id provided to restore database backup"
204
+ end
205
+
206
+ next
207
+ end
208
+
209
+ on roles(:db) do |server|
210
+ file = "#{backup_id}.sql"
211
+
212
+ remote_path = File.join(backups_directory, file)
213
+
214
+ unless test("[ -f #{remote_path} ]")
215
+ info "Could not find database backup #{backup_id} on #{server.user}@#{server.hostname}"
216
+
217
+ next
218
+ end
219
+
220
+ info "Restoring WordPress database #{backup_id} on #{server.user}@#{server.hostname}"
221
+
222
+ within release_path do
223
+ execute :wp, "db", "import", remote_path
224
+ end
225
+ end
226
+ end
227
+
228
+ desc "List all WordPress database backups"
229
+ task :list_backups do
230
+ on roles(:db) do |server|
231
+ next unless server.matches? roles(:db).first # Hack to make sure we run only once
232
+
233
+ backups_directory = File.join(fetch(:deploy_to), "backups", "database")
234
+
235
+ unless test("[ -d #{backups_directory} ]")
236
+ info "No database backups found"
237
+
238
+ next
239
+ end
240
+
241
+ backup_paths = capture("find #{backups_directory} -name '*.sql' -maxdepth 1")
242
+
243
+ if backup_paths.nil? or backup_paths.empty?
244
+ info "No database backups found"
245
+
246
+ next
247
+ end
248
+
249
+ if 1 == backup_paths.lines.count
250
+ info "Found 1 database backup"
251
+ else
252
+ info "Found #{backup_paths.lines.count} database backups"
253
+ end
254
+
255
+ backup_paths.each_line do |backup_path|
256
+ backup_path = backup_path.strip
257
+
258
+ backup_basename = File.basename(backup_path).gsub(".sql", "").strip
259
+
260
+ backup_time = Time.parse(backup_basename)
261
+ backup_time = backup_time.strftime("%A #{backup_time.day.ordinalize} %B %Y at %H:%M:%S")
262
+
263
+ backup_size = capture("du -h #{backup_path} | awk '{ print \$1 }'")
264
+
265
+ info "#{backup_time} - #{backup_size} (ID: #{backup_basename})"
266
+ end
267
+ end
268
+ end
269
+
270
+ # Rollback the WordPress database
271
+ # This is only useful when called during a deploy:rollback task
272
+ task :rollback do
273
+ actual_current_path = nil
274
+ actual_release_path = nil
275
+
276
+ on roles(:db) do |server|
277
+ next unless server.matches? roles(:db).first # Hack to make sure we run only once
278
+
279
+ actual_current_path = capture("readlink -f #{current_path}").strip
280
+ actual_release_path = capture("readlink -f #{release_path}").strip
281
+ end
282
+
283
+ if actual_current_path == actual_release_path
284
+ run_locally do
285
+ error "This task is only useful when called during a deploy:rollback task!"
286
+ end
287
+
288
+ next
289
+ end
290
+
291
+ invoke 'db:backup'
292
+ invoke 'db:restore'
293
+
294
+ set :rollback_from_timestamp, File.basename(actual_current_path)
295
+ end
296
+
297
+ # Move the database backup from the release we rolled away from
298
+ # into the release's root before it's archived
299
+ task :cleanup_rollback_database do
300
+ rollback_from_timestamp = fetch(:rollback_from_timestamp)
301
+
302
+ unless :rollback_from_timestamp
303
+ run_locally do
304
+ error "No timestamp set for the release we rolled away from"
305
+ end
306
+
307
+ next
308
+ end
309
+
310
+ file = "#{rollback_from_timestamp}.sql"
311
+
312
+ backups_directory = File.join(fetch(:deploy_to), "backups", "database")
313
+
314
+ source_path = File.join(backups_directory, file)
315
+ destination_path = File.join(releases_path, rollback_from_timestamp, file)
316
+
317
+ on roles(:db) do |server|
318
+ unless test("[ -f #{source_path} ]")
319
+ error "The database backup file does not exist on #{server.user}@#{server.hostname}"
320
+
321
+ next
322
+ end
323
+
324
+ info "Moving database backup #{rollback_from_timestamp} into release on #{server.user}@#{server.hostname}"
325
+
326
+ execute :mv, source_path, destination_path
327
+ end
328
+ end
329
+
330
+ # Enable maintenance mode if WordPress is already installed (used by db:push)
331
+ task :check_maintenance_enable do
332
+ maintenance_path = File.join(current_path, ".maintenance")
333
+
334
+ on roles(:db) do
335
+ next unless test("[ -d #{current_path} ]")
336
+ next if test("[ -f #{maintenance_path} ]")
337
+ next if true == fetch(:db_enabled_maintenance_mode)
338
+
339
+ within current_path do
340
+ if test :wp, "core", "is-installed"
341
+ set :db_enabled_maintenance_mode, true
342
+
343
+ invoke 'maintenance:enable'
344
+ end
345
+ end
346
+ end
347
+ end
348
+
349
+ # Disable maintenance mode if it was enabled by check_maintenance_enable
350
+ task :check_maintenance_disable do
351
+ next unless true == fetch(:db_enabled_maintenance_mode)
352
+
353
+ invoke 'maintenance:disable'
354
+ end
355
+ end
@@ -0,0 +1,24 @@
1
+ namespace :deploy do
2
+ task :shared_configs do
3
+ config_path = File.join(shared_path, "wp-config.php")
4
+ robots_path = File.join(shared_path, "robots.txt")
5
+
6
+ on roles(:app) do
7
+ unless test("[ -f #{config_path} ]")
8
+ invoke "config:generate"
9
+ end
10
+
11
+ unless test("[ -f #{robots_path} ]")
12
+ invoke "robots:generate"
13
+ end
14
+ end
15
+ end
16
+
17
+ task :touch_release do
18
+ on roles(:app) do |server|
19
+ info "Touching release directory on #{server.user}@#{server.hostname}"
20
+
21
+ execute :touch, release_path
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,132 @@
1
+ namespace :htaccess do
2
+ desc "Pull down the .htaccess file"
3
+ task :pull do
4
+ file = ".htaccess"
5
+
6
+ remote_file = File.join(release_path, file)
7
+
8
+ next if 0 == roles(:app).count
9
+
10
+ if 1 < roles(:app).count
11
+ run_locally do
12
+ info "Found #{roles(:app).count} application servers"
13
+
14
+ roles(:app).each_with_index do |server, index|
15
+ info "#{index + 1}) #{server.user}@#{server.hostname} (Port #{server.port or 22})"
16
+ end
17
+
18
+ set :htaccess_pull_server, ask("the number of the server to pull the #{file} file from", "1")
19
+ end
20
+ else
21
+ set :htaccess_pull_server, "1"
22
+ end
23
+
24
+ htaccess_pull_server = fetch(:htaccess_pull_server).to_i
25
+
26
+ if 1 > htaccess_pull_server or roles(:app).count < htaccess_pull_server
27
+ run_locally do
28
+ error "Unable to locate a server with an id '#{htaccess_pull_server}'"
29
+ end
30
+
31
+ next
32
+ end
33
+
34
+ htaccess_pull_server = roles(:app)[htaccess_pull_server - 1]
35
+
36
+ on roles(:app) do |server|
37
+ next unless server.matches? htaccess_pull_server
38
+
39
+ unless test("[ -f #{remote_file} ]")
40
+ error "There isn't a #{file} file on #{server.user}@#{server.hostname}"
41
+
42
+ next
43
+ end
44
+
45
+ if File.file? file
46
+ local_sha256sum = Digest::SHA256.hexdigest(File.read(file))
47
+ remote_sha256sum = capture("sha256sum #{remote_file}").split(' ').first
48
+
49
+ if local_sha256sum == remote_sha256sum
50
+ info "No changes detected in #{file} file on #{server.user}@#{server.hostname}"
51
+
52
+ next
53
+ end
54
+
55
+ unless fetch(:confirm_pull_htaccess)
56
+ set :confirm_pull_htaccess, ask("confirmation for local #{file} file overwrite", "Y/n")
57
+ end
58
+
59
+ next unless [true, "y", "yes"].include? fetch(:confirm_pull_htaccess).downcase
60
+ end
61
+
62
+ info "Pulling #{file} file from #{server.user}@#{server.hostname}"
63
+
64
+ download! remote_file, file
65
+
66
+ break
67
+ end
68
+
69
+ set :htaccess_pull_server, nil
70
+ end
71
+
72
+ desc "Push up the .htaccess file"
73
+ task :push do
74
+ file = ".htaccess"
75
+
76
+ local_path = File.join(Dir.pwd, file)
77
+ remote_path = File.join(release_path, file)
78
+
79
+ unless File.file? file
80
+ run_locally do
81
+ htaccess = "# BEGIN WordPress\n"
82
+ htaccess << "<IfModule mod_rewrite.c>\n"
83
+ htaccess << "RewriteEngine On\n"
84
+ htaccess << "RewriteBase /\n"
85
+ htaccess << "RewriteRule ^index\.php$ - [L]\n"
86
+ htaccess << "RewriteCond %{REQUEST_FILENAME} !-f\n"
87
+ htaccess << "RewriteCond %{REQUEST_FILENAME} !-d\n"
88
+ htaccess << "RewriteRule . /index.php [L]\n"
89
+ htaccess << "</IfModule>\n"
90
+ htaccess << "# END WordPress\n"
91
+
92
+ File.write(local_path, htaccess)
93
+ end
94
+ end
95
+
96
+ on roles(:app) do |server|
97
+ if test("[ -f #{remote_path} ]")
98
+ local_sha256sum = Digest::SHA256.hexdigest(File.read(local_path))
99
+ remote_sha256sum = capture("sha256sum #{remote_path}").split(' ').first
100
+
101
+ if local_sha256sum == remote_sha256sum
102
+ info "No changes detected in #{file} on #{server.user}@#{server.hostname}"
103
+
104
+ next
105
+ end
106
+ end
107
+
108
+ info "Pushing #{file} file to #{server.user}@#{server.hostname}"
109
+
110
+ upload! local_path, remote_path
111
+ end
112
+ end
113
+
114
+ desc "Set permissions on the .htaccess file"
115
+ task :setperms do
116
+ file = ".htaccess"
117
+
118
+ remote_path = File.join(release_path, file)
119
+
120
+ on roles(:app) do |server|
121
+ unless test("[ -f #{remote_path} ]")
122
+ info "No #{file} file found on #{server.user}@#{server.hostname}"
123
+
124
+ next
125
+ end
126
+
127
+ info "Setting permissions for #{file} on #{server.user}@#{server.hostname}"
128
+
129
+ execute :chmod, 644, remote_path
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,68 @@
1
+ namespace :maintenance do
2
+ desc "Enable maintenance mode on the WordPress site"
3
+ task :enable do
4
+ file = ".maintenance"
5
+
6
+ on roles(:app) do |server|
7
+ actual_current_path = capture("readlink -f #{current_path}").strip
8
+
9
+ remote_path = File.join(actual_current_path, file)
10
+
11
+ if test("[ -f #{remote_path} ]")
12
+ info "Maintenance mode is already enabled on #{server.user}@#{server.hostname}"
13
+
14
+ next
15
+ end
16
+
17
+ maintenance_info = fetch(:maintenance_info, {
18
+ title: "Maintenance",
19
+ header: "This site is currently undergoing maintenance.",
20
+ body: "Please check back in a moment."
21
+ })
22
+
23
+ file_content = "<?php header('HTTP/1.1 503 Service Unavailable'); ?>\n"
24
+ file_content << "<?php header('Content-Type: text/html'); ?>\n"
25
+ file_content << "<!DOCTYPE html>\n"
26
+ file_content << "<html>\n"
27
+ file_content << " <head>\n"
28
+ file_content << " <meta charset=\"utf-8\">\n"
29
+ file_content << " <meta name=\"viewport\" content=\"initial-scale=1.0\">\n"
30
+ file_content << " <title>#{maintenance_info[:title]}</title>\n" if maintenance_info.has_key? :title
31
+ file_content << " </head>\n"
32
+ file_content << " <body class=\"body\">\n"
33
+ file_content << " <h1>#{maintenance_info[:header]}</h1>\n" if maintenance_info.has_key? :header
34
+ file_content << " <h3>#{maintenance_info[:subheader]}</h3>\n" if maintenance_info.has_key? :subheader
35
+ file_content << " <p>#{maintenance_info[:body]}</p>\n" if maintenance_info.has_key? :body
36
+ file_content << " </body>\n"
37
+ file_content << "</html>\n"
38
+ file_content << "<?php exit; ?>\n"
39
+
40
+ info "Enabling WordPress maintenance mode on #{server.user}@#{server.hostname}"
41
+
42
+ upload! StringIO.new(file_content), remote_path
43
+
44
+ execute :chmod, 644, remote_path
45
+ end
46
+ end
47
+
48
+ desc "Disable maintenance mode on the WordPress site"
49
+ task :disable do
50
+ file = ".maintenance"
51
+
52
+ on roles(:app) do |server|
53
+ actual_current_path = capture("readlink -f #{current_path}").strip
54
+
55
+ remote_path = File.join(actual_current_path, file)
56
+
57
+ unless test("[ -f #{remote_path} ]")
58
+ info "Maintenance mode is not enabled on #{server.user}@#{server.hostname}"
59
+
60
+ next
61
+ end
62
+
63
+ info "Disabling WordPress maintenance mode on #{server.user}@#{server.hostname}"
64
+
65
+ execute :rm, "-f", remote_path
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,37 @@
1
+ namespace :robots do
2
+ desc "Generate a robots.txt file"
3
+ task :generate do
4
+ file = "robots.txt"
5
+
6
+ remote_path = File.join(shared_path, file)
7
+
8
+ on roles(:app) do |server|
9
+ info "Generating a #{file} file on #{server.user}@#{server.hostname}"
10
+
11
+ if :production != fetch(:stage)
12
+ debug "Disallowing all user agents in #{file} on #{server.user}@#{server.hostname}"
13
+
14
+ upload! StringIO.new("User-agent: *\nDisallow: /"), remote_path
15
+ else
16
+ upload! StringIO.new, remote_path
17
+ end
18
+ end
19
+ end
20
+
21
+ desc "Set permissions on the robots.txt file"
22
+ task :setperms do
23
+ file = "robots.txt"
24
+
25
+ remote_path = File.join(shared_path, file)
26
+
27
+ on roles(:app) do |server|
28
+ unless test("[ -f #{remote_path} ]")
29
+ error "A #{file} file does not exist on #{server.user}@#{server.hostname}"
30
+ end
31
+
32
+ info "Setting permissions for #{file} on #{server.user}@#{server.hostname}"
33
+
34
+ execute :chmod, 644, remote_path
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,122 @@
1
+ namespace :uploads do
2
+ desc "Pull down the uploads directory"
3
+ task :pull do
4
+ directory = File.join("wp-content", "uploads")
5
+
6
+ local_path = File.join(Dir.pwd, directory)
7
+ remote_path = File.join(release_path, directory)
8
+
9
+ next if 0 == roles(:app).count
10
+
11
+ if 1 < roles(:app).count
12
+ run_locally do
13
+ info "Found #{roles(:app).count} application servers"
14
+
15
+ roles(:app).each_with_index do |server, index|
16
+ info "#{index + 1}) #{server.user}@#{server.hostname} (Port #{server.port or 22})"
17
+ end
18
+
19
+ set :uploads_pull_server, ask("the number of the server to pull the #{directory} directory from", "1")
20
+ end
21
+ else
22
+ set :uploads_pull_server, "1"
23
+ end
24
+
25
+ uploads_pull_server = fetch(:uploads_pull_server).to_i
26
+
27
+ if 1 > uploads_pull_server or roles(:app).count < uploads_pull_server
28
+ run_locally do
29
+ error "Unable to locate a server with an id '#{uploads_pull_server}'"
30
+ end
31
+
32
+ next
33
+ end
34
+
35
+ uploads_pull_server = roles(:app)[uploads_pull_server - 1]
36
+
37
+ on roles(:app) do |server|
38
+ next unless server.matches? uploads_pull_server
39
+
40
+ unless test("[ -d #{remote_path} ]")
41
+ error "There isn't a #{directory} directory on #{server.user}@#{server.hostname}"
42
+
43
+ next
44
+ end
45
+
46
+ run_locally do
47
+ execute :mkdir, "-p", local_path
48
+ end
49
+
50
+ info "Pulling #{directory} directory from #{server.user}@#{server.hostname}"
51
+
52
+ # Fix for rsync
53
+ remote_path += "/"
54
+
55
+ run_locally do
56
+ execute :rsync, "-lrtvzO", "--delete-before", (server.port ? "-e 'ssh -p #{server.port}'" : nil), "#{server.user}@#{server.hostname}:#{remote_path}", local_path
57
+ end
58
+ end
59
+
60
+ set :uploads_pull_server, nil
61
+ end
62
+
63
+ desc "Push up the uploads directory"
64
+ task :push do
65
+ directory = File.join("wp-content", "uploads")
66
+
67
+ local_path = File.join(Dir.pwd, directory)
68
+ remote_path = File.join(release_path, directory)
69
+
70
+ unless File.directory? local_path
71
+ error "No local uploads directory exists"
72
+
73
+ next
74
+ end
75
+
76
+ on roles(:app) do |server|
77
+ if test("[ -d #{current_path} ]") and (ENV["clone_uploads"].nil? or ENV["clone_uploads"].empty? or [true, "true", "yes", "y"].include? ENV["clone_uploads"].downcase)
78
+ actual_current_path = capture("readlink -f #{current_path}").strip
79
+ actual_release_path = capture("readlink -f #{release_path}").strip
80
+
81
+ previous_remote_path = File.join(actual_current_path, directory)
82
+
83
+ if actual_current_path != actual_release_path and test("[ -d #{previous_remote_path} ]")
84
+ debug "Cloning uploads directory from current release on #{server.user}@#{server.hostname}"
85
+
86
+ execute :cp, "-R", "--preserve=timestamps", previous_remote_path, remote_path
87
+ end
88
+ end
89
+
90
+ execute :mkdir, "-p", remote_path
91
+
92
+ info "Pushing #{directory} directory to #{server.user}@#{server.hostname}"
93
+
94
+ # Fix for rsync
95
+ local_path += "/"
96
+
97
+ run_locally do
98
+ execute :rsync, "-lrtvzO", "--delete-before", (server.port ? "-e 'ssh -p #{server.port}'" : nil), local_path, "#{server.user}@#{server.hostname}:#{remote_path}"
99
+ end
100
+ end
101
+ end
102
+
103
+ desc "Set permissions on the uploads directory"
104
+ task :setperms do
105
+ directory = File.join("wp-content", "uploads")
106
+
107
+ remote_path = File.join(release_path, directory)
108
+
109
+ on roles(:app) do |server|
110
+ unless test("[ -d #{remote_path} ]")
111
+ error "No uploads directory exists on #{server.user}@#{server.hostname}"
112
+
113
+ next
114
+ end
115
+
116
+ info "Setting permissions for the uploads directory on #{server.user}@#{server.hostname}"
117
+
118
+ execute :find, remote_path, "-type d", "-exec", :chmod, 755, "{}", "\\;"
119
+ execute :find, remote_path, "-type f", "-exec", :chmod, 644, "{}", "\\;"
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,38 @@
1
+ namespace :webroot do
2
+ desc "Symlink the current release into the website root"
3
+ task :symlink do
4
+ remote_path = fetch(:website_root)
5
+
6
+ next unless remote_path
7
+
8
+ on roles(:app) do |server|
9
+ if test("[ -d #{remote_path} ]")
10
+ execute :rm, "-rf", remote_path
11
+ end
12
+
13
+ info "Symlinking the current release into the website root on #{server.user}@#{server.hostname}"
14
+
15
+ execute :ln, "-nfs", release_path, remote_path
16
+ end
17
+ end
18
+
19
+ desc "Set permissions on the uploads directory"
20
+ task :setperms do
21
+ remote_path = fetch(:website_root)
22
+
23
+ next unless remote_path
24
+
25
+ on roles(:app) do |server|
26
+ unless test("[ -d #{remote_path} ]")
27
+ error "No website root directory exists on #{server.user}@#{server.hostname}"
28
+
29
+ next
30
+ end
31
+
32
+ info "Setting permissions for the website root directory on #{server.user}@#{server.hostname}"
33
+
34
+ execute :find, remote_path, "-type d", "-exec", :chmod, 755, "{}", "\\;"
35
+ execute :find, remote_path, "-type f", "-exec", :chmod, 644, "{}", "\\;"
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,89 @@
1
+ namespace :wp do
2
+ namespace :core do
3
+ # Load the local version (for use with wp:core:deploy)
4
+ task :load_local_version do
5
+ run_locally do
6
+ version_script_path = File.join(Dir.pwd, "wp-includes", "version.php")
7
+
8
+ unless File.file? version_script_path
9
+ abort "No valid WordPress installation could be found locally"
10
+ end
11
+
12
+ set :wp_version, capture("php -r \"include '#{version_script_path}'; echo \\$wp_version;\"")
13
+ end
14
+ end
15
+
16
+ desc "Download the WordPress core files into the release"
17
+ task :download do
18
+ on roles(:app) do |server|
19
+ version = fetch(:wp_version, ENV["version"])
20
+
21
+ info "Downloading WordPress Core" + (version ? " (Version #{version})" : "")
22
+
23
+ tmp_dir = File.join(fetch(:tmp_dir), SecureRandom.hex(8))
24
+
25
+ execute :mkdir, "-p", tmp_dir
26
+
27
+ within tmp_dir do
28
+ execute :wp, "core", "download", (version ? "--version=#{version}" : "")
29
+
30
+ excludes = [".", "license.txt", "readme.html", "wp-config-sample.php", "wp-content"]
31
+ excludes = excludes.map { |e| "! -name '#{e}' " }.join(" ").squeeze(" ").strip
32
+
33
+ paths = capture :find, ".", "-maxdepth 1", excludes
34
+ paths = paths.split("\n")
35
+ paths.each do |path|
36
+ execute :cp, "-R", path, release_path
37
+ end
38
+ end
39
+
40
+ execute :rm, "-rf", tmp_dir
41
+ end
42
+ end
43
+
44
+ desc "Remove the WordPress core files from the release"
45
+ task :remove do
46
+ on roles(:app) do
47
+ within release_path do
48
+ paths = []
49
+
50
+ excludes = [".", "wp-config.php", "wp-content"]
51
+ excludes = excludes.map { |e| "! -name '#{e}' " }.join(" ").squeeze(" ").strip
52
+
53
+ ["index.php", "wp-*", "xmlrpc.php"].each do |glob|
54
+ find_output = capture :find, ".", "-maxdepth 1", "-name '#{glob}'", excludes
55
+
56
+ paths.concat(find_output.split("\n"))
57
+ end
58
+
59
+ next if 1 > paths.length
60
+
61
+ info "Removing #{paths.length} WordPress core file(s)"
62
+
63
+ paths.each do |path|
64
+ execute :rm, "-rf", path
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ desc "Execute a WordPress CLI command"
72
+ task :exec do
73
+ set :wp_exec_command, ask("The WordPress CLI command to execute", "help")
74
+
75
+ unless fetch(:wp_exec_command)
76
+ abort "You didn't enter a command to execute"
77
+ end
78
+
79
+ on roles(:all) do |server|
80
+ next if ENV["role"] and !server.roles.map { |role| role.to_s }.include? ENV["role"]
81
+
82
+ within release_path do
83
+ puts capture :wp, fetch(:wp_exec_command)
84
+ end
85
+ end
86
+
87
+ set :wp_exec_command, nil
88
+ end
89
+ end
@@ -0,0 +1,13 @@
1
+ require "net/http"
2
+ require "securerandom"
3
+ require "time"
4
+
5
+ # Load all helpers and capistrano tasks
6
+ ["wordpress/helpers/**/*.rb", "wordpress/tasks/**/*.rake", "wordpress/hooks.rb"].each do |glob|
7
+ Dir.glob(File.expand_path(File.join('..', glob), __FILE__)).each do |file_path|
8
+ load file_path
9
+ end
10
+ end
11
+
12
+ # Tell capistrano about files we want linked into releases
13
+ set :linked_files, fetch(:linked_files, []).push("robots.txt", "wp-config.php")
@@ -0,0 +1 @@
1
+ require 'capistrano/wordpress'
@@ -0,0 +1,16 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'wordpresstrano'
3
+ s.version = '0.2.0'
4
+ s.date = '2015-08-09'
5
+ s.authors = ['Nialto Services']
6
+ s.email = 'support@nialtoservices.co.uk'
7
+ s.summary = 'Deploy WordPress sites to web servers using Capistrano'
8
+ s.description = 'Deploy your WordPress sites to web servers like cPanel using the Capistrano deployment tool'
9
+ s.homepage = 'http://rubygems.org/gems/wordpresstrano'
10
+ s.files = `git ls-files`.split($/)
11
+ s.require_paths = ['lib']
12
+ s.license = 'MIT'
13
+
14
+ s.required_ruby_version = '>= 2.0.0'
15
+ s.add_dependency 'capistrano', '~> 3.0', '>= 3.4.0'
16
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wordpresstrano
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Nialto Services
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: capistrano
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 3.4.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 3.4.0
33
+ description: Deploy your WordPress sites to web servers like cPanel using the Capistrano
34
+ deployment tool
35
+ email: support@nialtoservices.co.uk
36
+ executables: []
37
+ extensions: []
38
+ extra_rdoc_files: []
39
+ files:
40
+ - LICENSE
41
+ - README.md
42
+ - lib/capistrano/wordpress.rb
43
+ - lib/capistrano/wordpress/helpers/fixnum.rb
44
+ - lib/capistrano/wordpress/helpers/hash.rb
45
+ - lib/capistrano/wordpress/hooks.rb
46
+ - lib/capistrano/wordpress/tasks/binaries.rake
47
+ - lib/capistrano/wordpress/tasks/config.rake
48
+ - lib/capistrano/wordpress/tasks/database.rake
49
+ - lib/capistrano/wordpress/tasks/deploy.rake
50
+ - lib/capistrano/wordpress/tasks/htaccess.rake
51
+ - lib/capistrano/wordpress/tasks/maintenance.rake
52
+ - lib/capistrano/wordpress/tasks/robots.rake
53
+ - lib/capistrano/wordpress/tasks/uploads.rake
54
+ - lib/capistrano/wordpress/tasks/webroot.rake
55
+ - lib/capistrano/wordpress/tasks/wordpress.rake
56
+ - lib/wordpresstrano.rb
57
+ - wordpresstrano.gemspec
58
+ homepage: http://rubygems.org/gems/wordpresstrano
59
+ licenses:
60
+ - MIT
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: 2.0.0
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 2.4.8
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: Deploy WordPress sites to web servers using Capistrano
82
+ test_files: []