bard 1.0.0 → 1.0.2
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 +4 -4
- data/Rakefile +5 -0
- data/features/bard_check.feature +1 -1
- data/features/bard_push.feature +1 -1
- data/features/step_definitions/global_steps.rb +4 -4
- data/features/support/env.rb +1 -1
- data/features/support/io.rb +1 -1
- data/lib/bard/ci/github_actions.rb +3 -6
- data/lib/bard/ci/local.rb +0 -2
- data/lib/bard/ci.rb +10 -12
- data/lib/bard/cli/ci.rb +51 -0
- data/lib/bard/cli/data.rb +45 -0
- data/lib/bard/cli/deploy.rb +64 -0
- data/lib/bard/cli/hurt.rb +20 -0
- data/lib/bard/cli/install.rb +16 -0
- data/lib/bard/cli/master_key.rb +17 -0
- data/lib/bard/cli/open.rb +13 -0
- data/lib/bard/cli/ping.rb +18 -0
- data/lib/bard/cli/provision.rb +15 -0
- data/lib/bard/cli/run.rb +24 -0
- data/lib/bard/cli/setup.rb +45 -0
- data/lib/bard/cli/ssh.rb +14 -0
- data/lib/bard/cli/stage.rb +27 -0
- data/lib/bard/cli/vim.rb +13 -0
- data/lib/bard/cli.rb +21 -246
- data/lib/bard/command.rb +8 -6
- data/lib/bard/config.rb +2 -11
- data/lib/bard/copy.rb +15 -40
- data/lib/bard/git.rb +2 -4
- data/lib/bard/ping.rb +0 -1
- data/lib/bard/provision/apt.rb +16 -0
- data/lib/bard/provision/http.rb +1 -15
- data/lib/bard/provision/mysql.rb +0 -2
- data/lib/bard/provision/passenger.rb +2 -4
- data/lib/bard/provision/repo.rb +2 -2
- data/lib/bard/provision/rvm.rb +3 -2
- data/lib/bard/provision/ssh.rb +17 -10
- data/lib/bard/provision/user.rb +1 -0
- data/lib/bard/provision.rb +4 -21
- data/lib/bard/server.rb +29 -7
- data/lib/bard/version.rb +1 -1
- data/spec/bard/ci_spec.rb +10 -0
- data/spec/bard/config_spec.rb +83 -0
- data/spec/bard/server_spec.rb +127 -0
- metadata +24 -3
- /data/lib/bard/provision/{master_key.rb → masterkey.rb} +0 -0
data/lib/bard/cli.rb
CHANGED
@@ -1,17 +1,9 @@
|
|
1
1
|
# this file gets loaded in the CLI context, not the Rails boot context
|
2
2
|
|
3
3
|
require "thor"
|
4
|
-
require "bard/git"
|
5
|
-
require "bard/ci"
|
6
|
-
require "bard/copy"
|
7
|
-
require "bard/github"
|
8
|
-
require "bard/ping"
|
9
4
|
require "bard/config"
|
10
5
|
require "bard/command"
|
11
|
-
require "bard/provision"
|
12
6
|
require "term/ansicolor"
|
13
|
-
require "open3"
|
14
|
-
require "uri"
|
15
7
|
|
16
8
|
module Bard
|
17
9
|
class CLI < Thor
|
@@ -19,244 +11,24 @@ module Bard
|
|
19
11
|
|
20
12
|
class_option :verbose, type: :boolean, aliases: :v
|
21
13
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
from.run! "bin/rake db:dump"
|
41
|
-
|
42
|
-
puts "Transfering file from #{from.key} to #{to.key}..."
|
43
|
-
from.copy_file "db/data.sql.gz", to: to, verbose: true
|
44
|
-
|
45
|
-
puts "Loading file into #{to.key} database..."
|
46
|
-
to.run! "bin/rake db:load"
|
47
|
-
|
48
|
-
config.data.each do |path|
|
49
|
-
puts "Synchronizing files in #{path}..."
|
50
|
-
from.copy_dir path, to: to, verbose: true
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
desc "master_key --from=production --to=local", "copy master key from from to to"
|
55
|
-
option :from, default: "production"
|
56
|
-
option :to, default: "local"
|
57
|
-
def master_key
|
58
|
-
from = config[options[:from]]
|
59
|
-
to = config[options[:to]]
|
60
|
-
from.copy_file "config/master.key", to:
|
61
|
-
end
|
62
|
-
|
63
|
-
desc "stage [branch=HEAD]", "pushes current branch, and stages it"
|
64
|
-
def stage branch=Git.current_branch
|
65
|
-
unless config.servers.key?(:production)
|
66
|
-
raise Thor::Error.new("`bard stage` is disabled until a production server is defined. Until then, please use `bard deploy` to deploy to the staging server.")
|
67
|
-
end
|
68
|
-
|
69
|
-
run! "git push -u origin #{branch}", verbose: true
|
70
|
-
config[:staging].run! "git fetch && git checkout -f origin/#{branch} && bin/setup"
|
71
|
-
puts green("Stage Succeeded")
|
72
|
-
|
73
|
-
ping :staging
|
74
|
-
end
|
75
|
-
|
76
|
-
option :"skip-ci", type: :boolean
|
77
|
-
option :"local-ci", type: :boolean
|
78
|
-
desc "deploy [TO=production]", "checks that current branch is a ff with master, checks with ci, merges into master, deploys to target, and then deletes branch."
|
79
|
-
def deploy to=:production
|
80
|
-
branch = Git.current_branch
|
81
|
-
|
82
|
-
if branch == "master"
|
83
|
-
if !Git.up_to_date_with_remote?(branch)
|
84
|
-
run! "git push origin #{branch}:#{branch}"
|
85
|
-
end
|
86
|
-
invoke :ci, [branch], options.slice("local-ci") unless options["skip-ci"]
|
87
|
-
|
88
|
-
else
|
89
|
-
run! "git fetch origin master:master"
|
90
|
-
|
91
|
-
unless Git.fast_forward_merge?("origin/master", branch)
|
92
|
-
puts "The master branch has advanced. Attempting rebase..."
|
93
|
-
run! "git rebase origin/master"
|
94
|
-
end
|
95
|
-
|
96
|
-
run! "git push -f origin #{branch}:#{branch}"
|
97
|
-
|
98
|
-
invoke :ci, [branch], options.slice("local-ci") unless options["skip-ci"]
|
99
|
-
|
100
|
-
run! "git push origin #{branch}:master"
|
101
|
-
run! "git fetch origin master:master"
|
102
|
-
end
|
103
|
-
|
104
|
-
if `git remote` =~ /\bgithub\b/
|
105
|
-
run! "git push github"
|
106
|
-
end
|
107
|
-
|
108
|
-
config[to].run! "git pull origin master && bin/setup"
|
109
|
-
|
110
|
-
puts green("Deploy Succeeded")
|
111
|
-
|
112
|
-
if branch != "master"
|
113
|
-
puts "Deleting branch: #{branch}"
|
114
|
-
run! "git push --delete origin #{branch}"
|
115
|
-
|
116
|
-
if branch == Git.current_branch
|
117
|
-
run! "git checkout master"
|
118
|
-
end
|
119
|
-
|
120
|
-
run! "git branch -D #{branch}"
|
121
|
-
end
|
122
|
-
|
123
|
-
ping to
|
124
|
-
end
|
125
|
-
|
126
|
-
option :"local-ci", type: :boolean
|
127
|
-
option :status, type: :boolean
|
128
|
-
desc "ci [branch=HEAD]", "runs ci against BRANCH"
|
129
|
-
def ci branch=Git.current_branch
|
130
|
-
ci = CI.new(project_name, branch, local: options["local-ci"])
|
131
|
-
if ci.exists?
|
132
|
-
return puts ci.status if options["status"]
|
133
|
-
|
134
|
-
puts "Continuous integration: starting build on #{branch}..."
|
135
|
-
|
136
|
-
success = ci.run do |elapsed_time, last_time|
|
137
|
-
if last_time
|
138
|
-
percentage = (elapsed_time.to_f / last_time.to_f * 100).to_i
|
139
|
-
output = " Estimated completion: #{percentage}%"
|
140
|
-
else
|
141
|
-
output = " No estimated completion time. Elapsed time: #{elapsed_time} sec"
|
142
|
-
end
|
143
|
-
print "\x08" * output.length
|
144
|
-
print output
|
145
|
-
$stdout.flush
|
146
|
-
end
|
147
|
-
|
148
|
-
if success
|
149
|
-
puts
|
150
|
-
puts "Continuous integration: success!"
|
151
|
-
puts "Deploying..."
|
152
|
-
else
|
153
|
-
puts
|
154
|
-
puts ci.last_response
|
155
|
-
puts ci.console
|
156
|
-
puts red("Automated tests failed!")
|
157
|
-
exit 1
|
158
|
-
end
|
159
|
-
|
160
|
-
else
|
161
|
-
puts red("No CI found for #{project_name}!")
|
162
|
-
puts "Re-run with --skip-ci to bypass CI, if you absolutely must, and know what you're doing."
|
163
|
-
exit 1
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
desc "open [server=production]", "opens the url in the web browser."
|
168
|
-
def open server=:production
|
169
|
-
exec "xdg-open #{config[server].ping.first}"
|
170
|
-
end
|
171
|
-
|
172
|
-
option :home, type: :boolean
|
173
|
-
desc "ssh [to=production]", "logs into the specified server via SSH"
|
174
|
-
def ssh to=:production
|
175
|
-
config[to].exec! "exec $SHELL -l", home: options[:home]
|
176
|
-
end
|
177
|
-
|
178
|
-
desc "install", "copies bin/setup and bin/ci scripts into current project."
|
179
|
-
def install
|
180
|
-
install_files_path = File.expand_path(File.join(__dir__, "../../install_files/*"))
|
181
|
-
system "cp -R #{install_files_path} bin/"
|
182
|
-
github_files_path = File.expand_path(File.join(__dir__, "../../install_files/.github"))
|
183
|
-
system "cp -R #{github_files_path} ./"
|
184
|
-
end
|
185
|
-
|
186
|
-
desc "provision [ssh_url]", "takes an ssh url to a raw ubuntu 22.04 install, and readies it in the shape of :production"
|
187
|
-
def provision ssh_url
|
188
|
-
Provision.call(config, ssh_url.dup) # dup unfreezes the string for later mutation
|
189
|
-
end
|
190
|
-
|
191
|
-
desc "setup", "installs app in nginx"
|
192
|
-
def setup
|
193
|
-
path = "/etc/nginx/sites-available/#{project_name}"
|
194
|
-
dest_path = path.sub("sites-available", "sites-enabled")
|
195
|
-
server_name = case ENV["RAILS_ENV"]
|
196
|
-
when "production"
|
197
|
-
(config[:production].ping.map do |str|
|
198
|
-
"*.#{URI.parse(str).host}"
|
199
|
-
end + ["_"]).join(" ")
|
200
|
-
when "staging" then "#{project_name}.botandrose.com"
|
201
|
-
else "#{project_name}.localhost"
|
202
|
-
end
|
203
|
-
|
204
|
-
system "sudo tee #{path} >/dev/null <<-EOF
|
205
|
-
server {
|
206
|
-
listen 80;
|
207
|
-
server_name #{server_name};
|
208
|
-
|
209
|
-
root #{Dir.pwd}/public;
|
210
|
-
passenger_enabled on;
|
211
|
-
|
212
|
-
location ~* \\.(ico|css|js|gif|jp?g|png|webp) {
|
213
|
-
access_log off;
|
214
|
-
if (\\$request_filename ~ \"-[0-9a-f]{32}\\.\") {
|
215
|
-
expires max;
|
216
|
-
add_header Cache-Control public;
|
217
|
-
}
|
218
|
-
}
|
219
|
-
gzip_static on;
|
220
|
-
}
|
221
|
-
EOF"
|
222
|
-
system "sudo ln -sf #{path} #{dest_path}" if !File.exist?(dest_path)
|
223
|
-
system "sudo service nginx restart"
|
224
|
-
end
|
225
|
-
|
226
|
-
desc "ping [server=production]", "hits the server over http to verify that its up."
|
227
|
-
def ping server=:production
|
228
|
-
server = config[server]
|
229
|
-
down_urls = Bard::Ping.call(config[server])
|
230
|
-
down_urls.each { |url| puts "#{url} is down!" }
|
231
|
-
exit 1 if down_urls.any?
|
232
|
-
end
|
233
|
-
|
234
|
-
# HACK: we don't use Thor::Base#run, so its okay to stomp on it here
|
235
|
-
original_verbose, $VERBOSE = $VERBOSE, nil
|
236
|
-
Thor::THOR_RESERVED_WORDS -= ["run"]
|
237
|
-
$VERBOSE = original_verbose
|
238
|
-
|
239
|
-
desc "run <command>", "run the given command on production"
|
240
|
-
def run *args
|
241
|
-
server = config[:production]
|
242
|
-
server.run! *args, verbose: true
|
243
|
-
end
|
244
|
-
|
245
|
-
desc "hurt <command>", "reruns a command until it fails"
|
246
|
-
def hurt *args
|
247
|
-
1.upto(Float::INFINITY) do |count|
|
248
|
-
puts "Running attempt #{count}"
|
249
|
-
system *args
|
250
|
-
unless $?.success?
|
251
|
-
puts "Ran #{count-1} times before failing"
|
252
|
-
break
|
253
|
-
end
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
desc "vim [branch=master]", "open all files that have changed since master"
|
258
|
-
def vim branch="master"
|
259
|
-
exec "vim -p `git diff #{branch} --name-only | grep -v sass$ | tac`"
|
14
|
+
{
|
15
|
+
data: "Data",
|
16
|
+
stage: "Stage",
|
17
|
+
deploy: "Deploy",
|
18
|
+
ci: "CI",
|
19
|
+
master_key: "MasterKey",
|
20
|
+
setup: "Setup",
|
21
|
+
run: "Run",
|
22
|
+
open: "Open",
|
23
|
+
ssh: "SSH",
|
24
|
+
install: "Install",
|
25
|
+
provision: "Provision",
|
26
|
+
ping: "Ping",
|
27
|
+
hurt: "Hurt",
|
28
|
+
vim: "Vim",
|
29
|
+
}.each do |command, klass|
|
30
|
+
require "bard/cli/#{command}"
|
31
|
+
include const_get(klass)
|
260
32
|
end
|
261
33
|
|
262
34
|
def self.exit_on_failure? = true
|
@@ -273,6 +45,9 @@ EOF"
|
|
273
45
|
|
274
46
|
def run!(...)
|
275
47
|
Bard::Command.run!(...)
|
48
|
+
rescue Bard::Command::Error => e
|
49
|
+
puts red("!!! ") + "Running command failed: #{yellow(e.message)}"
|
50
|
+
exit 1
|
276
51
|
end
|
277
52
|
end
|
278
53
|
end
|
data/lib/bard/command.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
require "open3"
|
2
|
+
|
1
3
|
module Bard
|
2
4
|
class Command < Struct.new(:command, :on, :home)
|
5
|
+
class Error < RuntimeError; end
|
6
|
+
|
3
7
|
def self.run! command, on: :local, home: false, verbose: false, quiet: false
|
4
8
|
new(command, on, home).run! verbose:, quiet:
|
5
9
|
end
|
@@ -14,9 +18,7 @@ module Bard
|
|
14
18
|
|
15
19
|
def run! verbose: false, quiet: false
|
16
20
|
if !run(verbose:, quiet:)
|
17
|
-
raise
|
18
|
-
# puts red("!!! ") + "Running command failed: #{yellow(command)}"
|
19
|
-
# exit 1
|
21
|
+
raise Error.new(full_command)
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
@@ -49,7 +51,6 @@ module Bard
|
|
49
51
|
end
|
50
52
|
|
51
53
|
def remote_command quiet: false
|
52
|
-
uri = on.ssh_uri
|
53
54
|
ssh_key = on.ssh_key ? "-i #{on.ssh_key} " : ""
|
54
55
|
cmd = command
|
55
56
|
if on.env
|
@@ -58,10 +59,11 @@ module Bard
|
|
58
59
|
unless home
|
59
60
|
cmd = "cd #{on.path} && #{cmd}"
|
60
61
|
end
|
61
|
-
|
62
|
+
uri = on.ssh_uri
|
63
|
+
cmd = "ssh -tt #{ssh_key} -p#{uri.port} #{uri.user}@#{uri.host} '#{cmd}'"
|
62
64
|
if on.gateway
|
63
65
|
uri = on.ssh_uri(:gateway)
|
64
|
-
cmd = "ssh -tt
|
66
|
+
cmd = "ssh -tt -p#{uri.port} #{uri.user}@#{uri.host} \"#{cmd}\""
|
65
67
|
end
|
66
68
|
cmd += " 2>&1" if quiet
|
67
69
|
cmd
|
data/lib/bard/config.rb
CHANGED
@@ -12,13 +12,6 @@ module Bard
|
|
12
12
|
"./",
|
13
13
|
false,
|
14
14
|
),
|
15
|
-
theia: Server.new(
|
16
|
-
project_name,
|
17
|
-
:theia,
|
18
|
-
"gubito@gubs.pagekite.me",
|
19
|
-
"Sites/#{project_name}",
|
20
|
-
false,
|
21
|
-
),
|
22
15
|
gubs: Server.new(
|
23
16
|
project_name,
|
24
17
|
:gubs,
|
@@ -40,7 +33,7 @@ module Bard
|
|
40
33
|
),
|
41
34
|
}
|
42
35
|
if path && File.exist?(path)
|
43
|
-
source = File.read(
|
36
|
+
source = File.read(path)
|
44
37
|
end
|
45
38
|
if source
|
46
39
|
instance_eval source
|
@@ -51,9 +44,7 @@ module Bard
|
|
51
44
|
|
52
45
|
def server key, &block
|
53
46
|
key = key.to_sym
|
54
|
-
@servers[key]
|
55
|
-
@servers[key].instance_eval &block if block_given?
|
56
|
-
@servers[key]
|
47
|
+
@servers[key] = Server.define(project_name, key, &block)
|
57
48
|
end
|
58
49
|
|
59
50
|
def [] key
|
data/lib/bard/copy.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require "uri"
|
2
|
+
require "bard/command"
|
3
|
+
|
1
4
|
module Bard
|
2
5
|
class Copy < Struct.new(:path, :from, :to, :verbose)
|
3
6
|
def self.file path, from:, to:, verbose: false
|
@@ -19,33 +22,20 @@ module Bard
|
|
19
22
|
end
|
20
23
|
|
21
24
|
def scp_using_local direction, server
|
22
|
-
|
23
|
-
port = uri.port ? "-p#{uri.port}" : ""
|
24
|
-
gateway = server.gateway ? "-oProxyCommand='ssh #{port} #{uri.user}@#{uri.host} -W %h:%p'" : ""
|
25
|
+
gateway = server.gateway ? "-oProxyCommand='ssh #{server.ssh_uri(:gateway)} -W %h:%p'" : ""
|
25
26
|
|
26
27
|
ssh_key = server.ssh_key ? "-i #{server.ssh_key}" : ""
|
27
28
|
|
28
|
-
|
29
|
-
port = uri.port ? "-P#{uri.port}" : ""
|
30
|
-
from_and_to = [path, "#{uri.user}@#{uri.host}:#{server.path}/#{path}"]
|
31
|
-
|
29
|
+
from_and_to = [path, server.scp_uri(path)]
|
32
30
|
from_and_to.reverse! if direction == :from
|
33
|
-
command = "scp #{gateway} #{ssh_key} #{port} #{from_and_to.join(" ")}"
|
34
31
|
|
32
|
+
command = ["scp", gateway, ssh_key, *from_and_to].join(" ")
|
35
33
|
Bard::Command.run! command, verbose: verbose
|
36
34
|
end
|
37
35
|
|
38
36
|
def scp_as_mediator
|
39
37
|
raise NotImplementedError if from.gateway || to.gateway || from.ssh_key || to.ssh_key
|
40
|
-
|
41
|
-
from_uri = URI.parse("ssh://#{from.ssh}")
|
42
|
-
from_str = "scp://#{from_uri.user}@#{from_uri.host}:#{from_uri.port || 22}/#{from.path}/#{path}"
|
43
|
-
|
44
|
-
to_uri = URI.parse("ssh://#{to.ssh}")
|
45
|
-
to_str = "scp://#{to_uri.user}@#{to_uri.host}:#{to_uri.port || 22}/#{to.path}/#{path}"
|
46
|
-
|
47
|
-
command = "scp -o ForwardAgent=yes #{from_str} #{to_str}"
|
48
|
-
|
38
|
+
command = "scp -o ForwardAgent=yes #{from.scp_uri(path)} #{to.scp_uri(path)}"
|
49
39
|
Bard::Command.run! command, verbose: verbose
|
50
40
|
end
|
51
41
|
|
@@ -55,46 +45,31 @@ module Bard
|
|
55
45
|
elsif to.key == :local
|
56
46
|
rsync_using_local :from, from
|
57
47
|
else
|
58
|
-
rsync_as_mediator
|
48
|
+
rsync_as_mediator
|
59
49
|
end
|
60
50
|
end
|
61
51
|
|
62
52
|
def rsync_using_local direction, server
|
63
|
-
|
64
|
-
port = uri.port ? "-p#{uri.port}" : ""
|
65
|
-
gateway = server.gateway ? "-oProxyCommand=\"ssh #{port} #{uri.user}@#{uri.host} -W %h:%p\"" : ""
|
53
|
+
gateway = server.gateway ? "-oProxyCommand=\"ssh #{server.ssh_uri(:gateway)} -W %h:%p\"" : ""
|
66
54
|
|
67
55
|
ssh_key = server.ssh_key ? "-i #{server.ssh_key}" : ""
|
68
|
-
|
69
|
-
port = uri.port ? "-p#{uri.port}" : ""
|
70
|
-
ssh = "-e'ssh #{ssh_key} #{port} #{gateway}'"
|
56
|
+
ssh = "-e'ssh #{gateway} -p#{server.ssh_uri.port || 22}'"
|
71
57
|
|
72
|
-
|
73
|
-
dest_path = "./#{dest_path}"
|
74
|
-
from_and_to = [dest_path, "#{uri.user}@#{uri.host}:#{server.path}/#{path}"]
|
58
|
+
from_and_to = ["./#{path}", server.rsync_uri(path)]
|
75
59
|
from_and_to.reverse! if direction == :from
|
76
60
|
from_and_to[-1].sub! %r(/[^/]+$), '/'
|
77
61
|
|
78
62
|
command = "rsync #{ssh} --delete --info=progress2 -az #{from_and_to.join(" ")}"
|
79
|
-
|
80
63
|
Bard::Command.run! command, verbose: verbose
|
81
64
|
end
|
82
65
|
|
83
|
-
def rsync_as_mediator
|
66
|
+
def rsync_as_mediator
|
84
67
|
raise NotImplementedError if from.gateway || to.gateway || from.ssh_key || to.ssh_key
|
85
68
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
from_uri = URI.parse("ssh://#{from.ssh}")
|
90
|
-
from_str = "-p#{from_uri.port || 22} #{from_uri.user}@#{from_uri.host}"
|
91
|
-
|
92
|
-
to_uri = URI.parse("ssh://#{to.ssh}")
|
93
|
-
to_str = "#{to_uri.user}@#{to_uri.host}:#{to.path}/#{path}"
|
94
|
-
to_str.sub! %r(/[^/]+$), '/'
|
95
|
-
|
96
|
-
command = %(ssh -A #{from_str} 'rsync -e \"ssh -A -p#{to_uri.port || 22} -o StrictHostKeyChecking=no\" --delete --info=progress2 -az #{from.path}/#{path} #{to_str}')
|
69
|
+
from_str = "-p#{from.ssh_uri.port || 22} #{from.ssh_uri.user}@#{from.ssh_uri.host}"
|
70
|
+
to_str = to.rsync_uri(path).sub(%r(/[^/]+$), '/')
|
97
71
|
|
72
|
+
command = %(ssh -A #{from_str} 'rsync -e \"ssh -A -p#{to.ssh_uri.port || 22} -o StrictHostKeyChecking=no\" --delete --info=progress2 -az #{from.path}/#{path} #{to_str}')
|
98
73
|
Bard::Command.run! command, verbose: verbose
|
99
74
|
end
|
100
75
|
end
|
data/lib/bard/git.rb
CHANGED
@@ -8,10 +8,6 @@ module Bard
|
|
8
8
|
ref.sub(/refs\/heads\//, '') # refs/heads/master ... we want "master"
|
9
9
|
end
|
10
10
|
|
11
|
-
def current_sha
|
12
|
-
sha_of("HEAD")
|
13
|
-
end
|
14
|
-
|
15
11
|
def fast_forward_merge?(root, branch)
|
16
12
|
root_head = sha_of(root)
|
17
13
|
branch_head = sha_of(branch)
|
@@ -23,6 +19,8 @@ module Bard
|
|
23
19
|
sha_of(branch) == sha_of("origin/#{branch}")
|
24
20
|
end
|
25
21
|
|
22
|
+
private
|
23
|
+
|
26
24
|
def sha_of ref
|
27
25
|
`git rev-parse #{ref}`.chomp
|
28
26
|
end
|
data/lib/bard/ping.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
# apt sanity
|
2
|
+
|
3
|
+
class Bard::Provision::Apt < Bard::Provision
|
4
|
+
def call
|
5
|
+
print "Apt:"
|
6
|
+
provision_server.run! [
|
7
|
+
%(echo "\\$nrconf{restart} = \\"a\\";" | sudo tee /etc/needrestart/conf.d/90-autorestart.conf),
|
8
|
+
"sudo apt-get update -y",
|
9
|
+
"sudo apt-get upgrade -y",
|
10
|
+
"sudo apt-get install -y curl",
|
11
|
+
].join("; "), home: true
|
12
|
+
|
13
|
+
puts " ✓"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
data/lib/bard/provision/http.rb
CHANGED
@@ -4,25 +4,11 @@ class Bard::Provision::HTTP < Bard::Provision
|
|
4
4
|
def call
|
5
5
|
print "HTTP:"
|
6
6
|
target_host = URI.parse(server.ping.first).host
|
7
|
-
if system "curl -s --resolve #{target_host}:80:#{provision_server.ssh_uri.host} http://#{target_host} -I | grep -i \"x-powered-by: phusion passenger\""
|
7
|
+
if system "curl -s --resolve #{target_host}:80:#{provision_server.ssh_uri.host} http://#{target_host} -I | grep -i \"x-powered-by: phusion passenger\" >/dev/null 2>&1"
|
8
8
|
puts " ✓"
|
9
9
|
else
|
10
10
|
puts " !!! not serving a rails app from #{provision_server.ssh_uri.host}"
|
11
11
|
end
|
12
12
|
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def ssh_available? ssh_uri, port: ssh_uri.port
|
17
|
-
system "nc -zv #{ssh_uri.host} #{port} 2>/dev/null"
|
18
|
-
end
|
19
|
-
|
20
|
-
def ssh_known_host? ssh_uri
|
21
|
-
system "grep -q \"$(ssh-keyscan -t ed25519 -p#{ssh_uri.port || 22} #{ssh_uri.host} 2>/dev/null | cut -d ' ' -f 2-3)\" ~/.ssh/known_hosts"
|
22
|
-
end
|
23
|
-
|
24
|
-
def add_ssh_known_host! ssh_uri
|
25
|
-
system "ssh-keyscan -p#{ssh_uri.port || 22} -H #{ssh_uri.host} >> ~/.ssh/known_hosts"
|
26
|
-
end
|
27
13
|
end
|
28
14
|
|
data/lib/bard/provision/mysql.rb
CHANGED
@@ -6,16 +6,14 @@ class Bard::Provision::Passenger < Bard::Provision
|
|
6
6
|
if !http_responding?
|
7
7
|
print " Installing nginx & Passenger,"
|
8
8
|
provision_server.run! [
|
9
|
-
%(echo "\\$nrconf{restart} = \\"a\\";" | sudo tee /etc/needrestart/conf.d/90-autorestart.conf),
|
10
9
|
%(grep -qxF "RAILS_ENV=production" /etc/environment || echo "RAILS_ENV=production" | sudo tee -a /etc/environment),
|
11
10
|
%(grep -qxF "EDITOR=vim" /etc/environment || echo "EDITOR=vim" | sudo tee -a /etc/environment),
|
12
|
-
"sudo apt-get
|
13
|
-
"sudo apt-get upgrade -y",
|
14
|
-
"sudo apt-get install -y vim dirmngr gnupg apt-transport-https ca-certificates curl",
|
11
|
+
"sudo apt-get install -y vim dirmngr gnupg apt-transport-https ca-certificates",
|
15
12
|
"curl https://oss-binaries.phusionpassenger.com/auto-software-signing-gpg-key.txt | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/phusion.gpg >/dev/null",
|
16
13
|
%(echo "deb https://oss-binaries.phusionpassenger.com/apt/passenger jammy main" | sudo tee /etc/apt/sources.list.d/passenger.list),
|
17
14
|
"sudo apt-get update -y",
|
18
15
|
"sudo apt-get install -y nginx libnginx-mod-http-passenger",
|
16
|
+
"sudo rm /etc/nginx/sites-enabled/default",
|
19
17
|
].join("; "), home: true
|
20
18
|
end
|
21
19
|
|
data/lib/bard/provision/repo.rb
CHANGED
@@ -37,9 +37,9 @@ class Bard::Provision::Repo < Bard::Provision
|
|
37
37
|
github_url = "git@github.com:botandrosedesign/#{project_name}"
|
38
38
|
provision_server.run [
|
39
39
|
"needle=$(ssh-keyscan -t ed25519 github.com 2>/dev/null | cut -d \" \" -f 2-3)",
|
40
|
-
"grep -q \"$needle\" ~/.ssh/known_hosts || ssh-keyscan -H github.com >> ~/.ssh/known_hosts",
|
40
|
+
"grep -q \"$needle\" ~/.ssh/known_hosts || ssh-keyscan -H github.com >> ~/.ssh/known_hosts 2>/dev/null",
|
41
41
|
"git ls-remote #{github_url}",
|
42
|
-
].join("; "), home: true
|
42
|
+
].join("; "), home: true, quiet: true
|
43
43
|
end
|
44
44
|
|
45
45
|
def project_name
|
data/lib/bard/provision/rvm.rb
CHANGED
@@ -10,8 +10,9 @@ class Bard::Provision::RVM < Bard::Provision
|
|
10
10
|
"gpg --keyserver keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB",
|
11
11
|
"curl -sSL https://get.rvm.io | bash -s stable",
|
12
12
|
].join("; ")
|
13
|
-
|
14
|
-
|
13
|
+
version = File.read(".ruby-version").chomp
|
14
|
+
print " Installing Ruby #{version},"
|
15
|
+
provision_server.run! "rvm install #{version}"
|
15
16
|
end
|
16
17
|
|
17
18
|
puts " ✓"
|
data/lib/bard/provision/ssh.rb
CHANGED
@@ -5,16 +5,16 @@ class Bard::Provision::SSH < Bard::Provision
|
|
5
5
|
def call
|
6
6
|
print "SSH:"
|
7
7
|
|
8
|
-
if !ssh_available?(provision_server.ssh_uri, port:
|
8
|
+
if !ssh_available?(provision_server.ssh_uri, port: target_port)
|
9
9
|
if !ssh_available?(provision_server.ssh_uri)
|
10
|
-
raise "can't find SSH on port #{
|
10
|
+
raise "can't find SSH on port #{target_port} or #{provision_server.ssh_uri.port || 22}"
|
11
11
|
end
|
12
12
|
if !ssh_known_host?(provision_server.ssh_uri)
|
13
13
|
print " Adding known host,"
|
14
14
|
add_ssh_known_host!(provision_server.ssh_uri)
|
15
15
|
end
|
16
|
-
print " Reconfiguring port to #{
|
17
|
-
|
16
|
+
print " Reconfiguring port to #{target_port},"
|
17
|
+
provision_server.run! %(echo "Port #{target_port}" | sudo tee /etc/ssh/sshd_config.d/port_#{target_port}.conf; sudo service ssh restart), home: true
|
18
18
|
end
|
19
19
|
|
20
20
|
if !ssh_known_host?(provision_server.ssh_uri)
|
@@ -22,23 +22,30 @@ class Bard::Provision::SSH < Bard::Provision
|
|
22
22
|
add_ssh_known_host!(provision_server.ssh_uri)
|
23
23
|
end
|
24
24
|
|
25
|
-
# provision with new port from now on
|
25
|
+
# provision with new target port from now on
|
26
26
|
ssh_url.gsub!(/:\d+$/, "")
|
27
|
-
ssh_url << ":#{
|
27
|
+
ssh_url << ":#{target_port}"
|
28
28
|
puts " ✓"
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
private
|
32
32
|
|
33
|
-
def
|
33
|
+
def target_port
|
34
|
+
server.ssh_uri.port || 22
|
35
|
+
end
|
36
|
+
|
37
|
+
def ssh_available? ssh_uri, port: nil
|
38
|
+
port ||= ssh_uri.port || 22
|
34
39
|
system "nc -zv #{ssh_uri.host} #{port} 2>/dev/null"
|
35
40
|
end
|
36
41
|
|
37
42
|
def ssh_known_host? ssh_uri
|
38
|
-
|
43
|
+
port ||= ssh_uri.port || 22
|
44
|
+
system "grep -q \"$(ssh-keyscan -t ed25519 -p#{port} #{ssh_uri.host} 2>/dev/null | cut -d ' ' -f 2-3)\" ~/.ssh/known_hosts"
|
39
45
|
end
|
40
46
|
|
41
47
|
def add_ssh_known_host! ssh_uri
|
42
|
-
|
48
|
+
port ||= ssh_uri.port || 22
|
49
|
+
system "ssh-keyscan -p#{port} -H #{ssh_uri.host} >> ~/.ssh/known_hosts 2>/dev/null"
|
43
50
|
end
|
44
51
|
end
|
data/lib/bard/provision/user.rb
CHANGED
@@ -16,6 +16,7 @@ class Bard::Provision::User < Bard::Provision
|
|
16
16
|
"sudo mkdir -p ~#{new_user}/.ssh",
|
17
17
|
"sudo cp ~/.ssh/authorized_keys ~#{new_user}/.ssh/authorized_keys",
|
18
18
|
"sudo chown -R #{new_user}:#{new_user} ~#{new_user}/.ssh",
|
19
|
+
"sudo chmod +rx ~#{new_user}", # so nginx and passenger can read it
|
19
20
|
].join("; "), home: true
|
20
21
|
end
|
21
22
|
|