bard 0.69.2 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f673fe1fe69ab05d32b5ea9eabd725d406d95e647aa50840154a31f5ea9c452d
4
- data.tar.gz: 1162fc60862ed9f342ba6360e301040c313d5ba71d6c7f785f54ecb832a83ab9
3
+ metadata.gz: ecbadd22fc4903fa9e779a515d0a7c9448392ac4fe2396ae2272bab7daeb4018
4
+ data.tar.gz: '068143adee00988e0506bb8e834ad5a15ebf65caf9e824d7a7f8e3923b9dbf18'
5
5
  SHA512:
6
- metadata.gz: 3b40b9fe3f5088079e33d33d8bb511b75a86d1991667a67e876f3f31adc11ec147ea7b0c995e01b8635fc0d6a7d07e70825c5ecb1e0e8ea4f088893dacf827b2
7
- data.tar.gz: 79b91cae3d507aee13592c1e303fd37bc0ae1988b7842f16d58966d095af7e478b325a238ba565f88b998ec342838198d074c78fc6f56916cf6ca26d1d3fd457
6
+ metadata.gz: b12423bf86e5978f48a4864c0572585aa583af33d1b1d6cdcdfb3e466b511d00e7e887908720346b6b13e7f09baa4948e511d717dbea34f72883a27385f58d6b
7
+ data.tar.gz: 73451d824a62f1f8953f83d89055e87355018aebbf0b92d05741e17391db204be01d594afcedd113bbb347f065a3e42ed3dffc387ebcb94118670e9ce08f0316
data/lib/bard/cli.rb CHANGED
@@ -8,6 +8,7 @@ require "bard/github"
8
8
  require "bard/ping"
9
9
  require "bard/config"
10
10
  require "bard/command"
11
+ require "bard/provision"
11
12
  require "term/ansicolor"
12
13
  require "open3"
13
14
  require "uri"
@@ -50,6 +51,15 @@ module Bard
50
51
  end
51
52
  end
52
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
+
53
63
  desc "stage [branch=HEAD]", "pushes current branch, and stages it"
54
64
  def stage branch=Git.current_branch
55
65
  unless config.servers.key?(:production)
@@ -159,18 +169,6 @@ module Bard
159
169
  exec "xdg-open #{config[server].ping.first}"
160
170
  end
161
171
 
162
- desc "hurt <command>", "reruns a command until it fails"
163
- def hurt *args
164
- 1.upto(Float::INFINITY) do |count|
165
- puts "Running attempt #{count}"
166
- system *args
167
- unless $?.success?
168
- puts "Ran #{count-1} times before failing"
169
- break
170
- end
171
- end
172
- end
173
-
174
172
  option :home, type: :boolean
175
173
  desc "ssh [to=production]", "logs into the specified server via SSH"
176
174
  def ssh to=:production
@@ -185,11 +183,23 @@ module Bard
185
183
  system "cp -R #{github_files_path} ./"
186
184
  end
187
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
+
188
191
  desc "setup", "installs app in nginx"
189
192
  def setup
190
193
  path = "/etc/nginx/sites-available/#{project_name}"
191
194
  dest_path = path.sub("sites-available", "sites-enabled")
192
- server_name = "#{project_name}.localhost"
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
193
203
 
194
204
  system "sudo tee #{path} >/dev/null <<-EOF
195
205
  server {
@@ -221,20 +231,27 @@ EOF"
221
231
  exit 1 if down_urls.any?
222
232
  end
223
233
 
224
- option :on, default: "production"
225
- desc "command <command> --on=production", "run the given command on the remote server"
226
- def command command
227
- server = config[options[:on]]
228
- server.run! remote_command, verbose: true
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
229
243
  end
230
244
 
231
- desc "master_key --from=production --to=local", "copy master key from from to to"
232
- option :from, default: "production"
233
- option :to, default: "local"
234
- def master_key
235
- from = config[options[:from]]
236
- to = config[options[:to]]
237
- from.copy_file "config/master.key", to:
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
238
255
  end
239
256
 
240
257
  desc "vim [branch=master]", "open all files that have changed since master"
data/lib/bard/command.rb CHANGED
@@ -1,31 +1,36 @@
1
1
  module Bard
2
2
  class Command < Struct.new(:command, :on, :home)
3
- def self.run! command, on: :local, home: false, verbose: false
4
- new(command, on, home).run! verbose: verbose
3
+ def self.run! command, on: :local, home: false, verbose: false, quiet: false
4
+ new(command, on, home).run! verbose:, quiet:
5
+ end
6
+
7
+ def self.run command, on: :local, home: false, verbose: false, quiet: false
8
+ new(command, on, home).run verbose:, quiet:
5
9
  end
6
10
 
7
11
  def self.exec! command, on: :local, home: false
8
12
  new(command, on, home).exec!
9
13
  end
10
14
 
11
- def run! verbose: false
12
- failed = false
15
+ def run! verbose: false, quiet: false
16
+ if !run(verbose:, quiet:)
17
+ raise "Running command failed: #{full_command}"
18
+ # puts red("!!! ") + "Running command failed: #{yellow(command)}"
19
+ # exit 1
20
+ end
21
+ end
13
22
 
23
+ def run verbose: false, quiet: false
14
24
  if verbose
15
- failed = !(system full_command)
25
+ system full_command(quiet: quiet)
16
26
  else
17
27
  stdout, stderr, status = Open3.capture3(full_command)
18
28
  failed = status.to_i.nonzero?
19
- if failed
29
+ if failed && !quiet
20
30
  $stdout.puts stdout
21
31
  $stderr.puts stderr
22
32
  end
23
- end
24
-
25
- if failed
26
- raise "Running command failed: #{full_command}"
27
- # puts red("!!! ") + "Running command failed: #{yellow(command)}"
28
- # exit 1
33
+ !failed && stdout
29
34
  end
30
35
  end
31
36
 
@@ -35,16 +40,16 @@ module Bard
35
40
 
36
41
  private
37
42
 
38
- def full_command
43
+ def full_command quiet: false
39
44
  if on.to_sym == :local
40
45
  command
41
46
  else
42
- remote_command
47
+ remote_command quiet: false
43
48
  end
44
49
  end
45
50
 
46
- def remote_command
47
- uri = URI.parse("ssh://#{on.ssh}")
51
+ def remote_command quiet: false
52
+ uri = on.ssh_uri
48
53
  ssh_key = on.ssh_key ? "-i #{on.ssh_key} " : ""
49
54
  cmd = command
50
55
  if on.env
@@ -55,9 +60,10 @@ module Bard
55
60
  end
56
61
  cmd = "ssh -tt #{ssh_key}#{"-p#{uri.port} " if uri.port}#{uri.user}@#{uri.host} '#{cmd}'"
57
62
  if on.gateway
58
- uri = URI.parse("ssh://#{on.gateway}")
63
+ uri = on.ssh_uri(:gateway)
59
64
  cmd = "ssh -tt #{" -p#{uri.port} " if uri.port}#{uri.user}@#{uri.host} \"#{cmd}\""
60
65
  end
66
+ cmd += " 2>&1" if quiet
61
67
  cmd
62
68
  end
63
69
  end
data/lib/bard/config.rb CHANGED
@@ -1,6 +1,4 @@
1
- require "uri"
2
- require "bard/command"
3
- require "bard/copy"
1
+ require "bard/server"
4
2
 
5
3
  module Bard
6
4
  class Config
@@ -84,78 +82,5 @@ module Bard
84
82
  raise ArgumentError
85
83
  end
86
84
  end
87
-
88
- private
89
-
90
- class Server < Struct.new(:project_name, :key, :ssh, :path, :ping, :gateway, :ssh_key, :env)
91
- def self.setting *fields
92
- fields.each do |field|
93
- define_method field do |*args|
94
- if args.length == 1
95
- send :"#{field}=", args.first
96
- elsif args.length == 0
97
- super()
98
- else
99
- raise ArgumentError
100
- end
101
- end
102
- end
103
- end
104
-
105
- setting :ssh, :path, :ping, :gateway, :ssh_key, :env
106
-
107
- def ping(*args)
108
- if args.length == 0
109
- (super() || [nil]).map(&method(:normalize_ping))
110
- else
111
- self.ping = args
112
- end
113
- end
114
-
115
- private def normalize_ping value
116
- return value if value == false
117
- uri = URI.parse("ssh://#{ssh}")
118
- normalized = "https://#{uri.host}" # default if none specified
119
- if value =~ %r{^/}
120
- normalized += value
121
- elsif value.to_s.length > 0
122
- normalized = value
123
- end
124
- if normalized !~ /^http/
125
- normalized = "https://#{normalized}"
126
- end
127
- normalized
128
- end
129
-
130
- def path(*args)
131
- if args.length == 1
132
- self.path = args.first
133
- elsif args.length == 0
134
- super() || project_name
135
- else
136
- raise ArgumentError
137
- end
138
- end
139
-
140
- def to_sym
141
- key
142
- end
143
-
144
- def run! command, home: false, verbose: false
145
- Bard::Command.run! command, on: self, home:, verbose:
146
- end
147
-
148
- def exec! command, home: false
149
- Bard::Command.exec! command, on: self, home:
150
- end
151
-
152
- def copy_file path, to:, verbose: false
153
- Bard::Copy.file path, from: self, to:, verbose:
154
- end
155
-
156
- def copy_dir
157
- Bard::Copy.dir path, from: self, to:, verbose:
158
- end
159
- end
160
85
  end
161
86
  end
data/lib/bard/github.rb CHANGED
@@ -24,6 +24,10 @@ module Bard
24
24
  Base64.decode64(metadata["content"])
25
25
  end
26
26
 
27
+ def add_deploy_key title:, key:
28
+ post("keys", title:, key:)
29
+ end
30
+
27
31
  private
28
32
 
29
33
  def github_apikey
@@ -0,0 +1,10 @@
1
+ # run bin/setup
2
+
3
+ class Bard::Provision::App < Bard::Provision
4
+ def call
5
+ print "App:"
6
+ provision_server.run! "bin/setup"
7
+ puts " ✓"
8
+ end
9
+ end
10
+
@@ -0,0 +1,27 @@
1
+ # copy data from production
2
+
3
+ class Bard::Provision::Data < Bard::Provision
4
+ def call
5
+ print "Data:"
6
+
7
+ # print " Dumping #{server.key} database to file"
8
+ # server.run! "bin/rake db:dump"
9
+
10
+ # print " Transfering file from #{server.key},"
11
+ # server.copy_file "db/data.sql.gz", to: provision_server, verbose: false
12
+
13
+ # print " Loading file into database,"
14
+ # provision_server.run! "bin/rake db:load"
15
+
16
+ config.data.each do |path|
17
+ print " Synchronizing files in #{path},"
18
+ server.copy_dir path, to: provision_server, verbose: false
19
+ end
20
+
21
+ puts " ✓"
22
+ end
23
+ end
24
+
25
+
26
+
27
+
@@ -0,0 +1,28 @@
1
+ # test for existence
2
+
3
+ class Bard::Provision::HTTP < Bard::Provision
4
+ def call
5
+ print "HTTP:"
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\""
8
+ puts " ✓"
9
+ else
10
+ puts " !!! not serving a rails app from #{provision_server.ssh_uri.host}"
11
+ end
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
+ end
28
+
@@ -0,0 +1,16 @@
1
+ # copy master key if missing
2
+
3
+ class Bard::Provision::MasterKey < Bard::Provision
4
+ def call
5
+ print "Master Key:"
6
+ if File.exist?("config/master.key")
7
+ if !provision_server.run "[ -f config/master.key ]", quiet: true
8
+ print " Uploading config/master.key,"
9
+ Bard::Copy.new("config/master.key").scp_using_local(:to, provision_server)
10
+ end
11
+ end
12
+
13
+ puts " ✓"
14
+ end
15
+ end
16
+
@@ -0,0 +1,23 @@
1
+ # install mysql
2
+
3
+ class Bard::Provision::MySQL < Bard::Provision
4
+ def call
5
+ print "MySQL:"
6
+ if !mysql_responding?
7
+ print " Installing,"
8
+ provision_server.run! [
9
+ "sudo apt-get install -y mysql-server",
10
+ %(sudo mysql -uroot -e "ALTER USER \\"'\\"root\\"'\\"@\\"'\\"localhost\\"'\\" IDENTIFIED WITH mysql_native_password BY \\"'\\"\\"'\\", \\"'\\"root\\"'\\"@\\"'\\"localhost\\"'\\" PASSWORD EXPIRE NEVER; FLUSH PRIVILEGES;"),
11
+ ].join("; "), home: true
12
+ end
13
+
14
+ puts " ✓"
15
+ end
16
+
17
+ def mysql_responding?
18
+ provision_server.run "sudo service mysql status | cat", quiet: true
19
+ end
20
+ end
21
+
22
+
23
+
@@ -0,0 +1,39 @@
1
+ # install nginx & passenger
2
+
3
+ class Bard::Provision::Passenger < Bard::Provision
4
+ def call
5
+ print "Passenger:"
6
+ if !http_responding?
7
+ print " Installing nginx & Passenger,"
8
+ provision_server.run! [
9
+ %(echo "\\$nrconf{restart} = \\"a\\";" | sudo tee /etc/needrestart/conf.d/90-autorestart.conf),
10
+ %(grep -qxF "RAILS_ENV=production" /etc/environment || echo "RAILS_ENV=production" | sudo tee -a /etc/environment),
11
+ %(grep -qxF "EDITOR=vim" /etc/environment || echo "EDITOR=vim" | sudo tee -a /etc/environment),
12
+ "sudo apt-get update -y",
13
+ "sudo apt-get upgrade -y",
14
+ "sudo apt-get install -y vim dirmngr gnupg apt-transport-https ca-certificates curl",
15
+ "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
+ %(echo "deb https://oss-binaries.phusionpassenger.com/apt/passenger jammy main" | sudo tee /etc/apt/sources.list.d/passenger.list),
17
+ "sudo apt-get update -y",
18
+ "sudo apt-get install -y nginx libnginx-mod-http-passenger",
19
+ ].join("; "), home: true
20
+ end
21
+
22
+ if !app_configured?
23
+ print " Creating nginx config for app,"
24
+ provision_server.run! "bard setup"
25
+ end
26
+
27
+ puts " ✓"
28
+ end
29
+
30
+ def http_responding?
31
+ system "nc -zv #{provision_server.ssh_uri.host} 80 2>/dev/null"
32
+ end
33
+
34
+ def app_configured?
35
+ provision_server.run "[ -f /etc/nginx/sites-enabled/#{server.project_name} ]", quiet: true
36
+ end
37
+ end
38
+
39
+
@@ -0,0 +1,49 @@
1
+ # generate and install ssh public key into deploy keys
2
+ # add repo to known hosts
3
+ # clone repo
4
+
5
+ class Bard::Provision::Repo < Bard::Provision
6
+ def call
7
+ print "Repo:"
8
+ if !already_cloned?
9
+ if !can_clone_project?
10
+ if !ssh_keypair?
11
+ print " Generating keypair in ~/.ssh,"
12
+ provision_server.run! "ssh-keygen -t rsa -b 2048 -f ~/.ssh/id_rsa -q -N \"\"", home: true
13
+ end
14
+ print " Add public key to GitHub repo deploy keys,"
15
+ title = "#{server.ssh_uri.user}@#{server.ssh_uri.host}"
16
+ key = provision_server.run "cat ~/.ssh/id_rsa.pub", home: true
17
+ Bard::Github.new(server.project_name).add_deploy_key title:, key:
18
+ end
19
+ print " Cloning repo,"
20
+ provision_server.run! "git clone git@github.com:botandrosedesign/#{project_name}", home: true
21
+ end
22
+
23
+ puts " ✓"
24
+ end
25
+
26
+ private
27
+
28
+ def ssh_keypair?
29
+ provision_server.run "[ -f ~/.ssh/id_rsa.pub ]", home: true, quiet: true
30
+ end
31
+
32
+ def already_cloned?
33
+ provision_server.run "[ -d ~/#{project_name}/.git ]", home: true, quiet: true
34
+ end
35
+
36
+ def can_clone_project?
37
+ github_url = "git@github.com:botandrosedesign/#{project_name}"
38
+ provision_server.run [
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",
41
+ "git ls-remote #{github_url}",
42
+ ].join("; "), home: true
43
+ end
44
+
45
+ def project_name
46
+ server.project_name
47
+ end
48
+ end
49
+
@@ -0,0 +1,21 @@
1
+ # install rvm if missing
2
+
3
+ class Bard::Provision::RVM < Bard::Provision
4
+ def call
5
+ print "RVM:"
6
+ if !provision_server.run "[ -d ~/.rvm ]", quiet: true
7
+ print " Installing RVM,"
8
+ provision_server.run! [
9
+ %(sed -i "1i[[ -s \\"$HOME/.rvm/scripts/rvm\\" ]] && source \\"$HOME/.rvm/scripts/rvm\\" # Load RVM into a shell session *as a function*" ~/.bashrc),
10
+ "gpg --keyserver keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB",
11
+ "curl -sSL https://get.rvm.io | bash -s stable",
12
+ ].join("; ")
13
+ print " Installing Ruby #{File.read(".ruby-version")},"
14
+ provision_server.run! "rvm install ."
15
+ end
16
+
17
+ puts " ✓"
18
+ end
19
+ end
20
+
21
+
@@ -0,0 +1,44 @@
1
+ # move ssh port
2
+ # add to known hosts
3
+
4
+ class Bard::Provision::SSH < Bard::Provision
5
+ def call
6
+ print "SSH:"
7
+
8
+ if !ssh_available?(provision_server.ssh_uri, port: server.ssh_uri.port)
9
+ if !ssh_available?(provision_server.ssh_uri)
10
+ raise "can't find SSH on port #{server.ssh_uri.port} or #{provision_server.ssh_uri.port}"
11
+ end
12
+ if !ssh_known_host?(provision_server.ssh_uri)
13
+ print " Adding known host,"
14
+ add_ssh_known_host!(provision_server.ssh_uri)
15
+ end
16
+ print " Reconfiguring port to #{server.ssh_uri.port},"
17
+ provision.server.run! %(echo "Port #{server.ssh_uri.port}" | sudo tee /etc/ssh/sshd_config.d/port_22022.conf; sudo service ssh restart), home: true
18
+ end
19
+
20
+ if !ssh_known_host?(provision_server.ssh_uri)
21
+ print " Adding known host,"
22
+ add_ssh_known_host!(provision_server.ssh_uri)
23
+ end
24
+
25
+ # provision with new port from now on
26
+ ssh_url.gsub!(/:\d+$/, "")
27
+ ssh_url << ":#{server.ssh_uri.port}"
28
+ puts " ✓"
29
+ end
30
+
31
+ private
32
+
33
+ def ssh_available? ssh_uri, port: ssh_uri.port
34
+ system "nc -zv #{ssh_uri.host} #{port} 2>/dev/null"
35
+ end
36
+
37
+ def ssh_known_host? ssh_uri
38
+ 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"
39
+ end
40
+
41
+ def add_ssh_known_host! ssh_uri
42
+ system "ssh-keyscan -p#{ssh_uri.port || 22} -H #{ssh_uri.host} >> ~/.ssh/known_hosts"
43
+ end
44
+ end
@@ -0,0 +1,41 @@
1
+ # rename user
2
+
3
+ class Bard::Provision::User < Bard::Provision
4
+ def call
5
+ print "User:"
6
+
7
+ if !ssh_with_user?(provision_server.ssh_uri, user: new_user)
8
+ if !ssh_with_user?(provision_server.ssh_uri)
9
+ raise "can't ssh in with user #{new_user} or #{old_user}"
10
+ end
11
+ print " Adding user #{new_user},"
12
+ provision_server.run! [
13
+ "sudo useradd -m -s /bin/bash #{new_user}",
14
+ "sudo usermod -aG sudo #{new_user}",
15
+ "echo \"#{new_user} ALL=(ALL) NOPASSWD:ALL\" | sudo tee -a /etc/sudoers",
16
+ "sudo mkdir -p ~#{new_user}/.ssh",
17
+ "sudo cp ~/.ssh/authorized_keys ~#{new_user}/.ssh/authorized_keys",
18
+ "sudo chown -R #{new_user}:#{new_user} ~#{new_user}/.ssh",
19
+ ].join("; "), home: true
20
+ end
21
+
22
+ # provision with new user from now on
23
+ ssh_url.gsub!("#{old_user}@", "#{new_user}@")
24
+ puts " ✓"
25
+ end
26
+
27
+ private
28
+
29
+ def new_user
30
+ server.ssh_uri.user
31
+ end
32
+
33
+ def old_user
34
+ provision_server.ssh_uri.user
35
+ end
36
+
37
+ def ssh_with_user? ssh_uri, user: ssh_uri.user
38
+ system "ssh -o ConnectTimeout=2 -p#{ssh_uri.port || 22} #{user}@#{ssh_uri.host} exit >/dev/null 2>&1"
39
+ end
40
+ end
41
+
@@ -0,0 +1,40 @@
1
+ module Bard
2
+ class Provision < Struct.new(:config, :ssh_url)
3
+ def self.call(...) = new(...).call
4
+
5
+ def call
6
+ SSH.call(*values)
7
+ User.call(*values)
8
+ MySQL.call(*values)
9
+ Repo.call(*values)
10
+ MasterKey.call(*values)
11
+ RVM.call(*values)
12
+ App.call(*values)
13
+ Passenger.call(*values)
14
+ Data.call(*values)
15
+ HTTP.call(*values)
16
+ end
17
+
18
+ private
19
+
20
+ def server
21
+ config[:production]
22
+ end
23
+
24
+ def provision_server
25
+ server.with(ssh: ssh_url)
26
+ end
27
+ end
28
+ end
29
+
30
+ require "bard/provision/ssh"
31
+ require "bard/provision/user"
32
+ require "bard/provision/mysql"
33
+ require "bard/provision/passenger"
34
+ require "bard/provision/repo"
35
+ require "bard/provision/master_key"
36
+ require "bard/provision/rvm"
37
+ require "bard/provision/app"
38
+ require "bard/provision/data"
39
+ require "bard/provision/http"
40
+
@@ -0,0 +1,94 @@
1
+ require "uri"
2
+ require "bard/command"
3
+ require "bard/copy"
4
+
5
+ module Bard
6
+ class Server < Struct.new(:project_name, :key, :ssh, :path, :ping, :gateway, :ssh_key, :env, :provision)
7
+ def self.setting *fields
8
+ fields.each do |field|
9
+ define_method field do |*args|
10
+ if args.length == 1
11
+ send :"#{field}=", args.first
12
+ elsif args.length == 0
13
+ super()
14
+ else
15
+ raise ArgumentError
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ setting :ssh, :path, :ping, :gateway, :ssh_key, :env, :provision
22
+
23
+ def ping(*args)
24
+ if args.length == 0
25
+ (super() || [nil]).map(&method(:normalize_ping))
26
+ else
27
+ self.ping = args
28
+ end
29
+ end
30
+
31
+ private def normalize_ping value
32
+ return value if value == false
33
+ uri = URI.parse("ssh://#{ssh}")
34
+ normalized = "https://#{uri.host}" # default if none specified
35
+ if value =~ %r{^/}
36
+ normalized += value
37
+ elsif value.to_s.length > 0
38
+ normalized = value
39
+ end
40
+ if normalized !~ /^http/
41
+ normalized = "https://#{normalized}"
42
+ end
43
+ normalized
44
+ end
45
+
46
+ def path(*args)
47
+ if args.length == 1
48
+ self.path = args.first
49
+ elsif args.length == 0
50
+ super() || project_name
51
+ else
52
+ raise ArgumentError
53
+ end
54
+ end
55
+
56
+ def ssh_uri which=:ssh
57
+ value = send(which)
58
+ URI.parse("ssh://#{value}")
59
+ end
60
+
61
+ def with(attrs)
62
+ dup.tap do |s|
63
+ attrs.each do |key, value|
64
+ s.send key, value
65
+ end
66
+ end
67
+ end
68
+
69
+ def to_sym
70
+ key
71
+ end
72
+
73
+ def run! command, home: false, verbose: false, quiet: false
74
+ Bard::Command.run! command, on: self, home:, verbose:, quiet:
75
+ end
76
+
77
+ def run command, home: false, verbose: false, quiet: false
78
+ Bard::Command.run command, on: self, home:, verbose:, quiet:
79
+ end
80
+
81
+ def exec! command, home: false
82
+ Bard::Command.exec! command, on: self, home:
83
+ end
84
+
85
+ def copy_file path, to:, verbose: false
86
+ Bard::Copy.file path, from: self, to:, verbose:
87
+ end
88
+
89
+ def copy_dir path, to:, verbose: false
90
+ Bard::Copy.dir path, from: self, to:, verbose:
91
+ end
92
+ end
93
+ end
94
+
data/lib/bard/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Bard
2
- VERSION = "0.69.2"
2
+ VERSION = "1.0.0"
3
3
  end
4
4
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.69.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Micah Geisel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-19 00:00:00.000000000 Z
11
+ date: 2024-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -144,6 +144,18 @@ files:
144
144
  - lib/bard/git.rb
145
145
  - lib/bard/github.rb
146
146
  - lib/bard/ping.rb
147
+ - lib/bard/provision.rb
148
+ - lib/bard/provision/app.rb
149
+ - lib/bard/provision/data.rb
150
+ - lib/bard/provision/http.rb
151
+ - lib/bard/provision/master_key.rb
152
+ - lib/bard/provision/mysql.rb
153
+ - lib/bard/provision/passenger.rb
154
+ - lib/bard/provision/repo.rb
155
+ - lib/bard/provision/rvm.rb
156
+ - lib/bard/provision/ssh.rb
157
+ - lib/bard/provision/user.rb
158
+ - lib/bard/server.rb
147
159
  - lib/bard/version.rb
148
160
  - spec/bard/ci/github_actions_spec.rb
149
161
  - spec/bard_spec.rb