bard 0.69.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e77aaa3b46702d144f1ed078868c7992c7283d5a97cc74113eb47de070a9ecc
4
- data.tar.gz: e3f5210ab5741c06f5ee6a9010b885718895eec302b69cdb75c1f53b2a5d573f
3
+ metadata.gz: ecbadd22fc4903fa9e779a515d0a7c9448392ac4fe2396ae2272bab7daeb4018
4
+ data.tar.gz: '068143adee00988e0506bb8e834ad5a15ebf65caf9e824d7a7f8e3923b9dbf18'
5
5
  SHA512:
6
- metadata.gz: f162644185e01bb6ee64adc4e4973868195a27fcc5c1e7fafdf40cab8f2b45bc8bd43b5f3210086549de543f01eec3f88487525bc1cc7f40f5034208731cedfb
7
- data.tar.gz: b8ce44b788f1ccb4f057498ed61049a66d4f6e1019d44f97fac272933ee7aa1aba3198ca80e6256d8da7a3cb090793bfd4a35046d7cce1905d97dea3db14b02c
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
@@ -44,7 +42,9 @@ module Bard
44
42
  if path && File.exist?(path)
45
43
  source = File.read(File.expand_path(path))
46
44
  end
47
- instance_eval source
45
+ if source
46
+ instance_eval source
47
+ end
48
48
  end
49
49
 
50
50
  attr_reader :project_name, :servers
@@ -82,78 +82,5 @@ module Bard
82
82
  raise ArgumentError
83
83
  end
84
84
  end
85
-
86
- private
87
-
88
- class Server < Struct.new(:project_name, :key, :ssh, :path, :ping, :gateway, :ssh_key, :env)
89
- def self.setting *fields
90
- fields.each do |field|
91
- define_method field do |*args|
92
- if args.length == 1
93
- send :"#{field}=", args.first
94
- elsif args.length == 0
95
- super()
96
- else
97
- raise ArgumentError
98
- end
99
- end
100
- end
101
- end
102
-
103
- setting :ssh, :path, :ping, :gateway, :ssh_key, :env
104
-
105
- def ping(*args)
106
- if args.length == 0
107
- (super() || [nil]).map(&method(:normalize_ping))
108
- else
109
- self.ping = args
110
- end
111
- end
112
-
113
- private def normalize_ping value
114
- return value if value == false
115
- uri = URI.parse("ssh://#{ssh}")
116
- normalized = "https://#{uri.host}" # default if none specified
117
- if value =~ %r{^/}
118
- normalized += value
119
- elsif value.to_s.length > 0
120
- normalized = value
121
- end
122
- if normalized !~ /^http/
123
- normalized = "https://#{normalized}"
124
- end
125
- normalized
126
- end
127
-
128
- def path(*args)
129
- if args.length == 1
130
- self.path = args.first
131
- elsif args.length == 0
132
- super() || project_name
133
- else
134
- raise ArgumentError
135
- end
136
- end
137
-
138
- def to_sym
139
- key
140
- end
141
-
142
- def run! command, home: false, verbose: false
143
- Bard::Command.run! command, on: self, home:, verbose:
144
- end
145
-
146
- def exec! command, home: false
147
- Bard::Command.exec! command, on: self, home:
148
- end
149
-
150
- def copy_file path, to:, verbose: false
151
- Bard::Copy.file path, from: self, to:, verbose:
152
- end
153
-
154
- def copy_dir
155
- Bard::Copy.dir path, from: self, to:, verbose:
156
- end
157
- end
158
85
  end
159
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.1"
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.1
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