bard 2.0.0.beta → 2.0.1

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} +41 -13
  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,19 +0,0 @@
1
- require "bard/deploy_strategy"
2
-
3
- module Bard
4
- class DeployStrategy
5
- class SSH < DeployStrategy
6
- def deploy
7
- # Require SSH capability
8
- target.require_capability!(:ssh)
9
-
10
- # Determine branch
11
- branch = target.instance_variable_get(:@branch) || "master"
12
-
13
- # Run git pull and setup on remote server
14
- target.run! "git pull origin #{branch}"
15
- target.run! "bin/setup"
16
- end
17
- end
18
- end
19
- end
@@ -1,134 +0,0 @@
1
- require 'delegate'
2
- require 'fileutils'
3
- require 'bard/git'
4
-
5
- module Bard
6
- class GithubPages < SimpleDelegator
7
- def deploy server
8
- @sha = Git.sha_of(Git.current_branch)
9
- @build_dir = "tmp/github-build-#{@sha}"
10
- @branch = "gh-pages"
11
- @domain = server.ping.first
12
- @domain = URI.parse(@domain).hostname if @domain
13
-
14
- puts "Starting deployment to GitHub Pages..."
15
-
16
- build_site
17
- tree_sha = create_tree_from_build
18
- new_commit = create_commit(tree_sha)
19
- commit_and_push new_commit
20
- end
21
-
22
- private
23
-
24
- def build_site
25
- with_locked_port do |port|
26
- system "rm -rf #{@build_dir.sub(@sha, "*")}"
27
- run! <<~SH
28
- set -e
29
- RAILS_ENV=production bundle exec rails s -p #{port} -d --pid tmp/pids/server.pid
30
- OUTPUT=$(bundle exec rake assets:clean assets:precompile 2>&1) || echo "$OUTPUT"
31
-
32
- # Create the output directory and enter it
33
- BUILD=#{@build_dir}
34
- rm -rf $BUILD
35
- mkdir -p $BUILD
36
- cp -R public/assets $BUILD/
37
- cd $BUILD
38
-
39
- # wait until server responds
40
- echo waiting...
41
- curl -s --retry 5 --retry-delay 2 http://localhost:#{port} >/dev/null 2>&1
42
-
43
- echo copying...
44
- # Mirror the site to the build folder, ignoring links with query params
45
- wget -nv -r -l inf --no-remove-listing -FEnH --reject-regex "(\\.*)\\?(.*)" http://localhost:#{port}/ 2>&1
46
-
47
- echo #{@domain} > CNAME
48
- SH
49
- ensure # cleanup
50
- run! <<~SH
51
- cat tmp/pids/server.pid | xargs -I {} kill {}
52
- rm -rf public/assets
53
- SH
54
- end
55
- end
56
-
57
- def with_locked_port
58
- (3000..3020).each do |port|
59
- lock_file = "/tmp/bard_github_pages_#{port}.lock"
60
- file = File.open(lock_file, File::RDWR | File::CREAT, 0644)
61
- if file.flock(File::LOCK_EX | File::LOCK_NB)
62
- begin
63
- yield port
64
- return
65
- ensure
66
- file.flock(File::LOCK_UN)
67
- file.close
68
- end
69
- else
70
- file.close
71
- end
72
- end
73
- raise "Could not find an available port for GitHub Pages deployment (checked 3000-3020)."
74
- end
75
-
76
- def create_tree_from_build
77
- # Create temporary index
78
- git_index_file = ".git/tmp-index"
79
- git = "GIT_INDEX_FILE=#{git_index_file} git"
80
- run! "#{git} read-tree --empty"
81
-
82
- # Add build files to temporary index
83
- Dir.chdir(@build_dir) do
84
- Dir.glob('**/*', File::FNM_DOTMATCH).each do |file|
85
- next if file == '.' || file == '..'
86
- if File.file?(file)
87
- run! "#{git} update-index --add --cacheinfo 100644 $(#{git} hash-object -w #{file}) #{file}"
88
- end
89
- end
90
- end
91
-
92
- # Create tree object from index
93
- tree_sha = `#{git} write-tree`.chomp
94
-
95
- # Clean up temporary index
96
- FileUtils.rm_f(git_index_file)
97
-
98
- tree_sha
99
- end
100
-
101
- def create_commit tree_sha
102
- # Get parent commit if branch exists
103
- parent = get_parent_commit
104
-
105
- # Create commit object
106
- message = "'Deploying to #{@branch} from @ #{@sha} 🚀'"
107
- args = ['commit-tree', tree_sha]
108
- args += ['-p', parent] if parent
109
- args += ['-m', message]
110
-
111
- commit_sha = `git #{args.join(' ')}`.chomp
112
-
113
- commit_sha
114
- end
115
-
116
- def get_parent_commit
117
- Git.sha_of("#{@branch}^{commit}")
118
- end
119
-
120
- def commit_and_push commit_sha
121
- if branch_exists?
122
- run! "git update-ref refs/heads/#{@branch} #{commit_sha}"
123
- else
124
- run! "git branch #{@branch} #{commit_sha}"
125
- end
126
- run! "git push -f origin #{@branch}:refs/heads/#{@branch}"
127
- end
128
-
129
- def branch_exists?
130
- system("git show-ref --verify --quiet refs/heads/#{@branch}")
131
- end
132
- end
133
- end
134
-
@@ -1,10 +0,0 @@
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
-
@@ -1,16 +0,0 @@
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
-
@@ -1,25 +0,0 @@
1
- # install public keys if missing
2
-
3
- class Bard::Provision::AuthorizedKeys < Bard::Provision
4
- def call
5
- print "Authorized Keys:"
6
-
7
- KEYS.each do |search_text, full_key|
8
- file = "~/.ssh/authorized_keys"
9
- provision_server.run! <<~SH, home: true
10
- if ! grep -F -q "#{search_text}" #{file}; then
11
- echo "#{full_key}" >> #{file}
12
- fi
13
- SH
14
- end
15
-
16
- puts " ✓"
17
- end
18
-
19
- KEYS = {
20
- "micah@haku" => "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDAH235mtpxPQucd0bIgdufo1bR3By2+a+NPHiZS1P7SpI73evN9+hY7ri+gLscPLRWeoy1ig/TbyfN1AqJmfqIaskZdYOdcEQdOum4AwDMY5L6OAq2o5NER047RqDxE6Pjm2nfRVVw2Dz38eeco+ouchCI+sY5pJL/wEZItrCpPjKvwo56uln1rL6Smd4Kh98ZBKTGL8xKs95rNmFdBCCq4eUE28JDgkJAiLDZ/4u2LNrgEr7/brkUieZjaZ4BacBi8EQvyvMWmZ0g2MoG+Ptxn/3K2nd1QqdhfINqHBVCi8UbkP08B0Msif/7Dycuxd7DU9cVZ3RgnhLtbIsQ8HaYVj5yCKB6CuX3lv3H4YKBghBC/TnJD5Nq5xcSYTW0BKKrusCb/OoOk5AUV+BGM1+R70fno8reVEBUlZDkWapHxmqgNnf1byL7Aol/L5SWgyfSLT6b5FjI6g/U+dhaecYY9T9g/GWo+JiwZktc094O0ujlQHoibMY2M0csVfvO9Oc= micah@haku",
21
- "gubs@Theia.local" => "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEApJh0E8ZlaLbMUWGvryAhEBRnnI519ZKz586vdQTuIPlDb9xhe5m3Ys8Fk9LKqJUQNxBV6qCGOXNgNdWySkk2ChmmgDnPfr7/31ZuOAASFbUY0PtaDXUsMVvs1Uu2VhtRU9gSduGonEHG7iBpAuBI23CxU4yPS6o3pv7L9xwnmULes5F9S4/nDvPig15h9byInyHOLDV0XjHFS+2OlSWO/xC8uqH5CdlxXFAmPQ0R69qmILl0rcTPyNMLJGcJGUzb/LMRJX/RDyTpZeJPjH4V+zksQ/4YQ3LWvLrlZL6QLuM285ve4mQa3vBY4WMqNlp4Ig3ZCFOpMKmpvTn7pFUmKw== gubs@Theia.local",
22
- }
23
- end
24
-
25
-
@@ -1,27 +0,0 @@
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
-
@@ -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
-