bard 2.0.0.beta → 2.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.
Files changed (174) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +6 -1
  3. data/CLAUDE.md +76 -0
  4. data/MIGRATION_GUIDE.md +24 -9
  5. data/PLUGINS.md +99 -0
  6. data/README.md +14 -6
  7. data/Rakefile +3 -1
  8. data/bard.gemspec +2 -1
  9. data/cucumber.yml +1 -0
  10. data/features/ci.feature +63 -0
  11. data/features/data.feature +13 -0
  12. data/features/deploy.feature +14 -0
  13. data/features/deploy_git_workflow.feature +89 -0
  14. data/features/run.feature +14 -0
  15. data/features/step_definitions/bard_steps.rb +136 -0
  16. data/features/support/bard-coverage +16 -0
  17. data/features/support/env.rb +14 -39
  18. data/features/support/test_server.rb +216 -0
  19. data/lib/bard/cli.rb +14 -31
  20. data/lib/bard/command.rb +10 -69
  21. data/lib/bard/config.rb +40 -183
  22. data/lib/bard/copy.rb +28 -103
  23. data/lib/bard/plugins/data.rb +56 -0
  24. data/lib/bard/{ci → plugins/deploy/ci}/github_actions.rb +3 -4
  25. data/lib/bard/plugins/deploy/ci/jenkins.rb +176 -0
  26. data/lib/bard/{ci → plugins/deploy/ci}/local.rb +7 -7
  27. data/lib/bard/{ci → plugins/deploy/ci}/runner.rb +38 -4
  28. data/lib/bard/plugins/deploy/ci.rb +38 -0
  29. data/lib/bard/plugins/deploy/ssh_strategy.rb +27 -0
  30. data/lib/bard/{deploy_strategy.rb → plugins/deploy/strategy.rb} +1 -1
  31. data/lib/bard/plugins/deploy.rb +240 -0
  32. data/lib/bard/{git.rb → plugins/git.rb} +6 -3
  33. data/lib/bard/{github.rb → plugins/github.rb} +4 -6
  34. data/lib/bard/{deploy_strategy/github_pages.rb → plugins/github_pages/strategy.rb} +13 -6
  35. data/lib/bard/plugins/github_pages.rb +30 -0
  36. data/lib/bard/plugins/hurt.rb +13 -0
  37. data/{install_files → lib/bard/plugins/install}/.github/dependabot.yml +2 -1
  38. data/{install_files → lib/bard/plugins/install}/.github/workflows/cache-ci.yml +1 -1
  39. data/{install_files → lib/bard/plugins/install}/.github/workflows/ci.yml +2 -2
  40. data/lib/bard/plugins/install.rb +9 -0
  41. data/lib/bard/plugins/open.rb +20 -0
  42. data/lib/bard/{ping.rb → plugins/ping/check.rb} +4 -4
  43. data/lib/bard/plugins/ping/target_methods.rb +23 -0
  44. data/lib/bard/plugins/ping.rb +10 -0
  45. data/lib/bard/plugins/run.rb +19 -0
  46. data/lib/bard/plugins/setup.rb +54 -0
  47. data/lib/bard/plugins/ssh/connection.rb +75 -0
  48. data/lib/bard/plugins/ssh/copy.rb +95 -0
  49. data/lib/bard/{ssh_server.rb → plugins/ssh/server.rb} +17 -42
  50. data/lib/bard/plugins/ssh/target_methods.rb +20 -0
  51. data/lib/bard/plugins/ssh.rb +10 -0
  52. data/lib/bard/plugins/url/target_methods.rb +23 -0
  53. data/lib/bard/plugins/url.rb +1 -0
  54. data/lib/bard/plugins/vim.rb +6 -0
  55. data/lib/bard/retryable.rb +25 -0
  56. data/lib/bard/secrets.rb +10 -0
  57. data/lib/bard/target.rb +27 -185
  58. data/lib/bard/version.rb +1 -1
  59. data/lib/bard.rb +1 -3
  60. data/spec/acceptance/docker/Dockerfile +3 -2
  61. data/spec/bard/capability_spec.rb +8 -50
  62. data/spec/bard/ci/github_actions_spec.rb +117 -14
  63. data/spec/bard/ci/jenkins_spec.rb +139 -0
  64. data/spec/bard/ci/runner_spec.rb +61 -0
  65. data/spec/bard/ci_spec.rb +1 -1
  66. data/spec/bard/cli/ci_spec.rb +34 -27
  67. data/spec/bard/cli/data_spec.rb +7 -26
  68. data/spec/bard/cli/deploy_spec.rb +87 -46
  69. data/spec/bard/cli/hurt_spec.rb +3 -9
  70. data/spec/bard/cli/install_spec.rb +5 -11
  71. data/spec/bard/cli/master_key_spec.rb +5 -19
  72. data/spec/bard/cli/open_spec.rb +14 -30
  73. data/spec/bard/cli/ping_spec.rb +8 -23
  74. data/spec/bard/cli/run_spec.rb +27 -21
  75. data/spec/bard/cli/setup_spec.rb +10 -27
  76. data/spec/bard/cli/ssh_spec.rb +10 -25
  77. data/spec/bard/cli/stage_spec.rb +28 -23
  78. data/spec/bard/cli/vim_spec.rb +3 -9
  79. data/spec/bard/command_spec.rb +1 -8
  80. data/spec/bard/config_spec.rb +78 -98
  81. data/spec/bard/copy_spec.rb +54 -18
  82. data/spec/bard/deploy_strategy/ssh_spec.rb +65 -7
  83. data/spec/bard/deploy_strategy_spec.rb +1 -1
  84. data/spec/bard/dynamic_dsl_spec.rb +18 -98
  85. data/spec/bard/git_spec.rb +9 -5
  86. data/spec/bard/github_spec.rb +2 -2
  87. data/spec/bard/ping_spec.rb +5 -5
  88. data/spec/bard/ssh_copy_spec.rb +44 -0
  89. data/spec/bard/ssh_server_spec.rb +8 -101
  90. data/spec/bard/target_spec.rb +66 -109
  91. data/spec/spec_helper.rb +6 -1
  92. metadata +79 -143
  93. data/README.rdoc +0 -15
  94. data/features/bard_check.feature +0 -94
  95. data/features/bard_deploy.feature +0 -18
  96. data/features/bard_pull.feature +0 -112
  97. data/features/bard_push.feature +0 -112
  98. data/features/podman_testcontainers.feature +0 -16
  99. data/features/step_definitions/check_steps.rb +0 -47
  100. data/features/step_definitions/git_steps.rb +0 -73
  101. data/features/step_definitions/global_steps.rb +0 -56
  102. data/features/step_definitions/podman_steps.rb +0 -23
  103. data/features/step_definitions/rails_steps.rb +0 -44
  104. data/features/step_definitions/submodule_steps.rb +0 -110
  105. data/features/support/grit_ext.rb +0 -13
  106. data/features/support/io.rb +0 -32
  107. data/features/support/podman.rb +0 -153
  108. data/lib/bard/ci/jenkins.rb +0 -105
  109. data/lib/bard/ci/retryable.rb +0 -27
  110. data/lib/bard/ci.rb +0 -50
  111. data/lib/bard/cli/ci.rb +0 -66
  112. data/lib/bard/cli/command.rb +0 -26
  113. data/lib/bard/cli/data.rb +0 -45
  114. data/lib/bard/cli/deploy.rb +0 -85
  115. data/lib/bard/cli/hurt.rb +0 -20
  116. data/lib/bard/cli/install.rb +0 -16
  117. data/lib/bard/cli/master_key.rb +0 -17
  118. data/lib/bard/cli/new.rb +0 -101
  119. data/lib/bard/cli/new_rails_template.rb +0 -197
  120. data/lib/bard/cli/open.rb +0 -22
  121. data/lib/bard/cli/ping.rb +0 -18
  122. data/lib/bard/cli/provision.rb +0 -34
  123. data/lib/bard/cli/run.rb +0 -24
  124. data/lib/bard/cli/setup.rb +0 -56
  125. data/lib/bard/cli/ssh.rb +0 -14
  126. data/lib/bard/cli/stage.rb +0 -27
  127. data/lib/bard/cli/vim.rb +0 -13
  128. data/lib/bard/default_config.rb +0 -35
  129. data/lib/bard/deploy_strategy/ssh.rb +0 -19
  130. data/lib/bard/github_pages.rb +0 -134
  131. data/lib/bard/provision/app.rb +0 -10
  132. data/lib/bard/provision/apt.rb +0 -16
  133. data/lib/bard/provision/authorizedkeys.rb +0 -25
  134. data/lib/bard/provision/data.rb +0 -27
  135. data/lib/bard/provision/deploy.rb +0 -10
  136. data/lib/bard/provision/http.rb +0 -16
  137. data/lib/bard/provision/logrotation.rb +0 -30
  138. data/lib/bard/provision/masterkey.rb +0 -18
  139. data/lib/bard/provision/mysql.rb +0 -22
  140. data/lib/bard/provision/passenger.rb +0 -37
  141. data/lib/bard/provision/repo.rb +0 -72
  142. data/lib/bard/provision/rvm.rb +0 -22
  143. data/lib/bard/provision/ssh.rb +0 -72
  144. data/lib/bard/provision/swapfile.rb +0 -21
  145. data/lib/bard/provision/user.rb +0 -42
  146. data/lib/bard/provision.rb +0 -16
  147. data/lib/bard/server.rb +0 -117
  148. data/spec/bard/cli/command_spec.rb +0 -50
  149. data/spec/bard/cli/new_spec.rb +0 -73
  150. data/spec/bard/cli/provision_spec.rb +0 -42
  151. data/spec/bard/github_pages_spec.rb +0 -143
  152. data/spec/bard/provision/app_spec.rb +0 -33
  153. data/spec/bard/provision/apt_spec.rb +0 -39
  154. data/spec/bard/provision/authorizedkeys_spec.rb +0 -40
  155. data/spec/bard/provision/data_spec.rb +0 -54
  156. data/spec/bard/provision/deploy_spec.rb +0 -33
  157. data/spec/bard/provision/http_spec.rb +0 -57
  158. data/spec/bard/provision/logrotation_spec.rb +0 -34
  159. data/spec/bard/provision/masterkey_spec.rb +0 -63
  160. data/spec/bard/provision/mysql_spec.rb +0 -55
  161. data/spec/bard/provision/passenger_spec.rb +0 -81
  162. data/spec/bard/provision/repo_spec.rb +0 -208
  163. data/spec/bard/provision/rvm_spec.rb +0 -49
  164. data/spec/bard/provision/ssh_spec.rb +0 -229
  165. data/spec/bard/provision/swapfile_spec.rb +0 -32
  166. data/spec/bard/provision/user_spec.rb +0 -103
  167. data/spec/bard/provision_spec.rb +0 -28
  168. data/spec/bard/server_spec.rb +0 -127
  169. /data/lib/bard/{ci → plugins/deploy/ci}/state.rb +0 -0
  170. /data/{install_files → lib/bard/plugins/install}/apt_dependencies.rb +0 -0
  171. /data/{install_files → lib/bard/plugins/install}/ci +0 -0
  172. /data/{install_files → lib/bard/plugins/install}/setup +0 -0
  173. /data/{install_files → lib/bard/plugins/install}/specified_bundler.rb +0 -0
  174. /data/{install_files → lib/bard/plugins/install}/specified_ruby.rb +0 -0
@@ -1,10 +0,0 @@
1
- # run bard deploy
2
-
3
- class Bard::Provision::Deploy < Bard::Provision
4
- def call
5
- print "Deploy:"
6
- provision_server.run! "bin/setup"
7
- puts " ✓"
8
- end
9
- end
10
-
@@ -1,16 +0,0 @@
1
- require "uri"
2
-
3
- # test for existence
4
-
5
- class Bard::Provision::HTTP < Bard::Provision
6
- def call
7
- print "HTTP:"
8
- target_host = URI.parse(server.ping.first).host
9
- 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"
10
- puts " ✓"
11
- else
12
- puts " !!! not serving a rails app from #{provision_server.ssh_uri.host}"
13
- end
14
- end
15
- end
16
-
@@ -1,30 +0,0 @@
1
- # install log rotation if missing
2
-
3
- class Bard::Provision::LogRotation < Bard::Provision
4
- def call
5
- print "Log Rotation:"
6
-
7
- provision_server.run! <<~SH, quiet: true
8
- file=/etc/logrotate.d/#{server.project_name}
9
- if [ ! -f $file ]; then
10
- sudo tee $file > /dev/null <<EOF
11
- $(pwd)/log/*.log {
12
- weekly
13
- size 100M
14
- missingok
15
- rotate 52
16
- delaycompress
17
- notifempty
18
- copytruncate
19
- create 664 www www
20
- }
21
- EOF
22
- fi
23
- SH
24
-
25
- puts " ✓"
26
- end
27
- end
28
-
29
-
30
-
@@ -1,18 +0,0 @@
1
- require "bard/copy"
2
-
3
- # copy master key if missing
4
-
5
- class Bard::Provision::MasterKey < Bard::Provision
6
- def call
7
- print "Master Key:"
8
- if File.exist?("config/master.key")
9
- if !provision_server.run "[ -f config/master.key ]", quiet: true
10
- print " Uploading config/master.key,"
11
- Bard::Copy.new("config/master.key").scp_using_local(:to, provision_server)
12
- end
13
- end
14
-
15
- puts " ✓"
16
- end
17
- end
18
-
@@ -1,22 +0,0 @@
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
- %(mysql -uroot -e "UPDATE mysql.user SET password_lifetime = NULL WHERE user = \\"'\\"root\\"'\\" AND host = \\"'\\"localhost\\"'\\";"),
12
- ].join("; "), home: true
13
- end
14
-
15
- puts " ✓"
16
- end
17
-
18
- def mysql_responding?
19
- provision_server.run "sudo systemctl is-active --quiet mysql", home: true, quiet: true
20
- end
21
- end
22
-
@@ -1,37 +0,0 @@
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
- %(grep -qxF "RAILS_ENV=production" /etc/environment || echo "RAILS_ENV=production" | sudo tee -a /etc/environment),
10
- %(grep -qxF "EDITOR=vim" /etc/environment || echo "EDITOR=vim" | sudo tee -a /etc/environment),
11
- "sudo apt-get install -y vim dirmngr gnupg apt-transport-https ca-certificates",
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",
13
- %(echo "deb https://oss-binaries.phusionpassenger.com/apt/passenger jammy main" | sudo tee /etc/apt/sources.list.d/passenger.list),
14
- "sudo apt-get update -y",
15
- "sudo apt-get install -y nginx libnginx-mod-http-passenger",
16
- "sudo rm /etc/nginx/sites-enabled/default",
17
- ].join("; "), home: true
18
- end
19
-
20
- if !app_configured?
21
- print " Creating nginx config for app,"
22
- provision_server.run! "bard setup"
23
- end
24
-
25
- puts " ✓"
26
- end
27
-
28
- def http_responding?
29
- system "nc -zv #{provision_server.ssh_uri.host} 80 2>/dev/null"
30
- end
31
-
32
- def app_configured?
33
- provision_server.run "[ -f /etc/nginx/sites-enabled/#{server.project_name} ]", quiet: true
34
- end
35
- end
36
-
37
-
@@ -1,72 +0,0 @@
1
- require "bard/github"
2
-
3
- # generate and install ssh public key into deploy keys
4
- # add repo to known hosts
5
- # clone repo
6
-
7
- class Bard::Provision::Repo < Bard::Provision
8
- def call
9
- print "Repo:"
10
- if !already_cloned?
11
- if !can_clone_project?
12
- if !ssh_keypair?
13
- print " Generating keypair in ~/.ssh,"
14
- provision_server.run! "ssh-keygen -t rsa -b 2048 -f ~/.ssh/id_rsa -q -N \"\"", home: true
15
- end
16
- print " Add public key to GitHub repo deploy keys,"
17
- title = "#{server.ssh_uri.user}@#{server.ssh_uri.host}"
18
- key = provision_server.run "cat ~/.ssh/id_rsa.pub", home: true
19
- Bard::Github.new(server.project_name).add_deploy_key title:, key:
20
- end
21
- print " Cloning repo,"
22
- provision_server.run! "git clone git@github.com:botandrosedesign/#{project_name}", home: true
23
- else
24
- if !on_latest_master?
25
- print " Updating to latest master,"
26
- update_to_latest_master!
27
- end
28
- end
29
-
30
- puts " ✓"
31
- end
32
-
33
- private
34
-
35
- def ssh_keypair?
36
- provision_server.run "[ -f ~/.ssh/id_rsa.pub ]", home: true, quiet: true
37
- end
38
-
39
- def already_cloned?
40
- provision_server.run "[ -d ~/#{project_name}/.git ]", home: true, quiet: true
41
- end
42
-
43
- def can_clone_project?
44
- github_url = "git@github.com:botandrosedesign/#{project_name}"
45
- provision_server.run [
46
- "needle=$(ssh-keyscan -t ed25519 github.com 2>/dev/null | cut -d \" \" -f 2-3)",
47
- "grep -q \"$needle\" ~/.ssh/known_hosts || ssh-keyscan -H github.com >> ~/.ssh/known_hosts 2>/dev/null",
48
- "git ls-remote #{github_url}",
49
- ].join("; "), home: true, quiet: true
50
- end
51
-
52
- def project_name
53
- server.project_name
54
- end
55
-
56
- def on_latest_master?
57
- provision_server.run [
58
- "cd ~/#{project_name}",
59
- "git fetch origin",
60
- "[ $(git rev-parse HEAD) = $(git rev-parse origin/master) ]"
61
- ].join(" && "), home: true, quiet: true
62
- end
63
-
64
- def update_to_latest_master!
65
- provision_server.run! [
66
- "cd ~/#{project_name}",
67
- "git checkout master",
68
- "git reset --hard origin/master"
69
- ].join(" && "), home: true
70
- end
71
- end
72
-
@@ -1,22 +0,0 @@
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
- version = File.read(".ruby-version").chomp
14
- print " Installing Ruby #{version},"
15
- provision_server.run! "rvm install #{version}"
16
- end
17
-
18
- puts " ✓"
19
- end
20
- end
21
-
22
-
@@ -1,72 +0,0 @@
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 password_auth_enabled?
9
- print " Disabling password authentication,"
10
- disable_password_auth!
11
- end
12
-
13
- if !ssh_available?(provision_server.ssh_uri, port: target_port)
14
- if !ssh_available?(provision_server.ssh_uri)
15
- raise "can't find SSH on port #{target_port} or #{provision_server.ssh_uri.port || 22}"
16
- end
17
- if !ssh_known_host?(provision_server.ssh_uri)
18
- print " Adding known host,"
19
- add_ssh_known_host!(provision_server.ssh_uri)
20
- end
21
- print " Reconfiguring port to #{target_port},"
22
- provision_server.run! %(echo "Port #{target_port}" | sudo tee /etc/ssh/sshd_config.d/port_#{target_port}.conf; sudo service ssh restart), home: true
23
- end
24
-
25
- if !ssh_known_host?(provision_server.ssh_uri)
26
- print " Adding known host,"
27
- add_ssh_known_host!(provision_server.ssh_uri)
28
- end
29
-
30
- # provision with new target port from now on
31
- ssh_url.gsub!(/:\d+$/, "")
32
- ssh_url << ":#{target_port}"
33
- puts " ✓"
34
- end
35
-
36
- private
37
-
38
- def target_port
39
- server.ssh_uri.port || 22
40
- end
41
-
42
- def ssh_available? ssh_uri, port: nil
43
- port ||= ssh_uri.port || 22
44
- system "nc -zv #{ssh_uri.host} #{port} 2>/dev/null"
45
- end
46
-
47
- def ssh_known_host? ssh_uri
48
- port ||= ssh_uri.port || 22
49
- system "grep -q \"$(ssh-keyscan -t ed25519 -p#{port} #{ssh_uri.host} 2>/dev/null | cut -d ' ' -f 2-3)\" ~/.ssh/known_hosts"
50
- end
51
-
52
- def add_ssh_known_host! ssh_uri
53
- port ||= ssh_uri.port || 22
54
- system "ssh-keyscan -p#{port} -H #{ssh_uri.host} >> ~/.ssh/known_hosts 2>/dev/null"
55
- end
56
-
57
- def password_auth_enabled?
58
- result = provision_server.run!(
59
- %q{grep -E '^\s*PasswordAuthentication\s+yes' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null || true},
60
- home: true,
61
- capture: true
62
- )
63
- !!(result && !result.strip.empty?)
64
- end
65
-
66
- def disable_password_auth!
67
- provision_server.run!(
68
- %q{echo "PasswordAuthentication no" | sudo tee /etc/ssh/sshd_config.d/disable_password_auth.conf; sudo service ssh restart},
69
- home: true
70
- )
71
- end
72
- end
@@ -1,21 +0,0 @@
1
- # setup swapfile
2
-
3
- class Bard::Provision::Swapfile < Bard::Provision
4
- def call
5
- print "Swapfile:"
6
-
7
- provision_server.run! <<~SH
8
- if [ ! -f /swapfile ]; then
9
- sudo fallocate -l $(grep MemTotal /proc/meminfo | awk '{print $2}')K /swapfile
10
- fi
11
- sudo chmod 600 /swapfile
12
- sudo swapon --show | grep -q '/swapfile' || sudo mkswap /swapfile
13
- sudo swapon --show | grep -q '/swapfile' || sudo swapon /swapfile
14
- grep -q '/swapfile none swap sw 0 0' /etc/fstab || echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
15
- SH
16
-
17
- puts " ✓"
18
- end
19
- end
20
-
21
-
@@ -1,42 +0,0 @@
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
- "sudo chmod +rx ~#{new_user}", # so nginx and passenger can read it
20
- ].join("; "), home: true
21
- end
22
-
23
- # provision with new user from now on
24
- ssh_url.gsub!("#{old_user}@", "#{new_user}@")
25
- puts " ✓"
26
- end
27
-
28
- private
29
-
30
- def new_user
31
- server.ssh_uri.user
32
- end
33
-
34
- def old_user
35
- provision_server.ssh_uri.user
36
- end
37
-
38
- def ssh_with_user? ssh_uri, user: ssh_uri.user
39
- system "ssh -o ConnectTimeout=2 -p#{ssh_uri.port || 22} #{user}@#{ssh_uri.host} : >/dev/null 2>&1"
40
- end
41
- end
42
-
@@ -1,16 +0,0 @@
1
- module Bard
2
- class Provision < Struct.new(:config, :ssh_url)
3
- def self.call(...) = new(...).call
4
-
5
- private
6
-
7
- def server
8
- config[:production]
9
- end
10
-
11
- def provision_server
12
- server.with(ssh: ssh_url)
13
- end
14
- end
15
- end
16
-
data/lib/bard/server.rb DELETED
@@ -1,117 +0,0 @@
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, :github_pages)
7
- def self.define project_name, key, &block
8
- new(project_name, key).tap do |server|
9
- server.instance_eval &block
10
- end
11
- end
12
-
13
- def self.setting *fields
14
- fields.each do |field|
15
- define_method field do |*args|
16
- if args.length == 1
17
- send :"#{field}=", args.first
18
- elsif args.length == 0
19
- super()
20
- else
21
- raise ArgumentError
22
- end
23
- end
24
- end
25
- end
26
-
27
- setting :ssh, :path, :ping, :gateway, :ssh_key, :env, :github_pages
28
-
29
- def ping(*args)
30
- if args.length == 0
31
- (super() || [nil]).map(&method(:normalize_ping)).flatten
32
- else
33
- self.ping = args
34
- end
35
- end
36
-
37
- private def normalize_ping value
38
- return [] if value == false
39
- normalized = "https://#{ssh_uri.host}" # default if none specified
40
- if value =~ %r{^/}
41
- normalized += value
42
- elsif value.to_s.length > 0
43
- normalized = value
44
- end
45
- if normalized !~ /^http/
46
- normalized = "https://#{normalized}"
47
- end
48
- normalized
49
- end
50
-
51
- def path(*args)
52
- if args.length == 1
53
- self.path = args.first
54
- elsif args.length == 0
55
- super() || project_name
56
- else
57
- raise ArgumentError
58
- end
59
- end
60
-
61
- def ssh_uri which=:ssh
62
- value = send(which)
63
- URI("ssh://#{value}")
64
- end
65
-
66
- def scp_uri file_path=nil
67
- ssh_uri.dup.tap do |uri|
68
- uri.scheme = "scp"
69
- uri.path = "/#{path}"
70
- uri.path += "/#{file_path}" if file_path
71
- end
72
- end
73
-
74
- def rsync_uri file_path=nil
75
- str = ssh_uri.dup.tap do |uri|
76
- uri.send :set_scheme, nil
77
- uri.send :set_port, nil
78
- end.to_s[2..]
79
- str += ":#{path}"
80
- str += "/#{file_path}" if file_path
81
- str
82
- end
83
-
84
- def with(attrs)
85
- dup.tap do |s|
86
- attrs.each do |key, value|
87
- s.send key, value
88
- end
89
- end
90
- end
91
-
92
- def to_sym
93
- key
94
- end
95
-
96
- def run! command, home: false, verbose: false, quiet: false
97
- Bard::Command.run! command, on: self, home:, verbose:, quiet:
98
- end
99
-
100
- def run command, home: false, verbose: false, quiet: false
101
- Bard::Command.run command, on: self, home:, verbose:, quiet:
102
- end
103
-
104
- def exec! command, home: false
105
- Bard::Command.exec! command, on: self, home:
106
- end
107
-
108
- def copy_file path, to:, verbose: false
109
- Bard::Copy.file path, from: self, to:, verbose:
110
- end
111
-
112
- def copy_dir path, to:, verbose: false
113
- Bard::Copy.dir path, from: self, to:, verbose:
114
- end
115
- end
116
- end
117
-
@@ -1,50 +0,0 @@
1
- require "spec_helper"
2
- require "bard/cli"
3
- require "bard/cli/command"
4
-
5
- class TestCommand < Bard::CLI::Command
6
- desc "test_command", "test command description"
7
- option :verbose, type: :boolean
8
-
9
- def test_command
10
- "executed"
11
- end
12
- end
13
-
14
- describe Bard::CLI::Command do
15
- let(:cli_mock) { double("cli") }
16
- let(:command) { TestCommand.new(cli_mock) }
17
-
18
- describe ".desc" do
19
- it "sets command and description" do
20
- expect(TestCommand.instance_variable_get(:@command)).to eq("test_command")
21
- expect(TestCommand.instance_variable_get(:@description)).to eq("test command description")
22
- end
23
- end
24
-
25
- describe ".option" do
26
- it "sets option arguments" do
27
- expect(TestCommand.instance_variable_get(:@option_args)).to eq([:verbose])
28
- expect(TestCommand.instance_variable_get(:@option_kwargs)).to eq({type: :boolean})
29
- end
30
- end
31
-
32
- describe ".setup" do
33
- let(:cli_double) { double("cli") }
34
-
35
- it "sets up the command on the CLI class" do
36
- expect(cli_double).to receive(:desc).with("test_command", "test command description")
37
- expect(cli_double).to receive(:option).with(:verbose, type: :boolean)
38
- expect(cli_double).to receive(:define_method)
39
-
40
- TestCommand.setup(cli_double)
41
- end
42
- end
43
-
44
- describe "delegation" do
45
- it "should delegate to the wrapped object" do
46
- allow(cli_mock).to receive(:some_method).and_return("delegated")
47
- expect(command.some_method).to eq("delegated")
48
- end
49
- end
50
- end
@@ -1,73 +0,0 @@
1
- require "spec_helper"
2
- require "bard/cli"
3
- require "bard/cli/new"
4
-
5
- describe Bard::CLI::New do
6
- let(:new_cli) { Bard::CLI::New.new(double("cli")) }
7
-
8
- before do
9
- allow(new_cli).to receive(:puts)
10
- allow(new_cli).to receive(:exit)
11
- allow(new_cli).to receive(:run!)
12
- allow(new_cli).to receive(:green).and_return("")
13
- allow(new_cli).to receive(:red).and_return("")
14
- allow(new_cli).to receive(:yellow).and_return("")
15
- allow(File).to receive(:read).and_return("master_key_content")
16
- end
17
-
18
- describe "#new" do
19
- context "with invalid project name" do
20
- before do
21
- allow(new_cli).to receive(:create_project)
22
- allow(new_cli).to receive(:push_to_github)
23
- allow(new_cli).to receive(:stage)
24
- end
25
-
26
- it "should reject names starting with uppercase" do
27
- expect(new_cli).to receive(:puts).with(/Invalid project name/)
28
- expect(new_cli).to receive(:exit).with(1)
29
-
30
- new_cli.new("InvalidProject")
31
- end
32
-
33
- it "should reject names with special characters" do
34
- expect(new_cli).to receive(:puts).with(/Invalid project name/)
35
- expect(new_cli).to receive(:exit).with(1)
36
-
37
- new_cli.new("invalid-project")
38
- end
39
-
40
- it "should reject names starting with numbers" do
41
- expect(new_cli).to receive(:puts).with(/Invalid project name/)
42
- expect(new_cli).to receive(:exit).with(1)
43
-
44
- new_cli.new("1invalidproject")
45
- end
46
- end
47
- end
48
-
49
- describe "#ruby_version" do
50
- it "returns the ruby version" do
51
- expect(new_cli.send(:ruby_version)).to eq("ruby-3.4.2")
52
- end
53
- end
54
-
55
- describe "#template_path" do
56
- it "returns the path to the rails template" do
57
- expect(new_cli.send(:template_path)).to match(/new_rails_template\.rb$/)
58
- end
59
- end
60
-
61
- describe "#install_and_extract_version" do
62
- it "correctly installs a gem and extracts its version", skip: !!ENV["CI"] do
63
- cmd = new_cli.send :build_bash_env do
64
- <<~SH
65
- #{new_cli.send(:build_gem_install, "bundler", "~> 2.0")}
66
- echo ${GEM_VERSION}
67
- SH
68
- end
69
- result = `#{cmd}`.strip
70
- expect(result).to match(/^2\.\d+\.\d+/)
71
- end
72
- end
73
- end
@@ -1,42 +0,0 @@
1
- require "spec_helper"
2
- require "bard/cli"
3
- require "bard/cli/provision"
4
-
5
- describe Bard::CLI::Provision do
6
- let(:config) { { production: double("production", ssh: "user@example.com") } }
7
- let(:provision_cli) { Bard::CLI::Provision.new(double("cli")) }
8
-
9
- before do
10
- allow(provision_cli).to receive(:config).and_return(config)
11
- allow(provision_cli).to receive(:options).and_return({ steps: ["SSH", "User"] })
12
- end
13
-
14
- describe "STEPS constant" do
15
- it "defines the provisioning steps" do
16
- expect(Bard::CLI::Provision::STEPS).to include("SSH", "User", "Apt", "MySQL", "Deploy")
17
- expect(Bard::CLI::Provision::STEPS).to be_a(Array)
18
- end
19
- end
20
-
21
- describe "#provision" do
22
- it "should run provision steps" do
23
- expect(Bard::Provision).to receive(:const_get).with("SSH").and_return(double("ssh_step", call: true))
24
- expect(Bard::Provision).to receive(:const_get).with("User").and_return(double("user_step", call: true))
25
-
26
- provision_cli.provision
27
- end
28
-
29
- it "should use production ssh by default" do
30
- allow(Bard::Provision).to receive(:const_get).and_return(double("step", call: true))
31
-
32
- provision_cli.provision
33
- end
34
-
35
- it "should accept custom ssh_url" do
36
- custom_ssh = "root@newserver.com"
37
- allow(Bard::Provision).to receive(:const_get).and_return(double("step", call: true))
38
-
39
- provision_cli.provision(custom_ssh)
40
- end
41
- end
42
- end