wordpresstrano 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []