bard 1.9.6 → 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 (157) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -2
  3. data/CLAUDE.md +1 -1
  4. data/PLUGINS.md +31 -46
  5. data/bard.gemspec +2 -1
  6. data/features/ci.feature +1 -0
  7. data/features/data.feature +1 -0
  8. data/features/deploy.feature +1 -0
  9. data/features/deploy_git_workflow.feature +1 -0
  10. data/features/run.feature +1 -0
  11. data/features/step_definitions/bard_steps.rb +1 -0
  12. data/features/support/test_server.rb +3 -3
  13. data/lib/bard/cli.rb +9 -28
  14. data/lib/bard/command.rb +9 -88
  15. data/lib/bard/config.rb +38 -177
  16. data/lib/bard/copy.rb +28 -82
  17. data/lib/bard/plugins/data.rb +56 -0
  18. data/lib/bard/{ci → plugins/deploy/ci}/github_actions.rb +2 -2
  19. data/lib/bard/{ci → plugins/deploy/ci}/jenkins.rb +1 -1
  20. data/lib/bard/{ci → plugins/deploy/ci}/local.rb +1 -1
  21. data/lib/bard/{ci → plugins/deploy/ci}/runner.rb +3 -3
  22. data/lib/bard/{ci.rb → plugins/deploy/ci.rb} +1 -1
  23. data/lib/bard/plugins/deploy/ssh_strategy.rb +27 -0
  24. data/lib/bard/{deploy_strategy.rb → plugins/deploy/strategy.rb} +1 -4
  25. data/lib/bard/plugins/deploy.rb +240 -0
  26. data/lib/bard/{git.rb → plugins/git.rb} +6 -3
  27. data/lib/bard/{github.rb → plugins/github.rb} +2 -2
  28. data/lib/bard/{deploy_strategy/github_pages.rb → plugins/github_pages/strategy.rb} +3 -4
  29. data/lib/bard/plugins/github_pages.rb +11 -15
  30. data/lib/bard/plugins/hurt.rb +12 -4
  31. data/{install_files → lib/bard/plugins/install}/.github/dependabot.yml +2 -1
  32. data/{install_files → lib/bard/plugins/install}/.github/workflows/cache-ci.yml +1 -1
  33. data/{install_files → lib/bard/plugins/install}/.github/workflows/ci.yml +2 -2
  34. data/lib/bard/plugins/install.rb +7 -3
  35. data/lib/bard/plugins/open.rb +20 -0
  36. data/lib/bard/{ping.rb → plugins/ping/check.rb} +4 -4
  37. data/lib/bard/plugins/ping/target_methods.rb +23 -0
  38. data/lib/bard/plugins/ping.rb +8 -4
  39. data/lib/bard/plugins/run.rb +19 -0
  40. data/lib/bard/plugins/setup.rb +54 -0
  41. data/lib/bard/plugins/ssh/connection.rb +75 -0
  42. data/lib/bard/plugins/ssh/copy.rb +95 -0
  43. data/lib/bard/{ssh_server.rb → plugins/ssh/server.rb} +10 -42
  44. data/lib/bard/plugins/ssh/target_methods.rb +20 -0
  45. data/lib/bard/plugins/ssh.rb +10 -0
  46. data/lib/bard/plugins/url/target_methods.rb +23 -0
  47. data/lib/bard/plugins/url.rb +1 -0
  48. data/lib/bard/plugins/vim.rb +5 -4
  49. data/lib/bard/retryable.rb +25 -0
  50. data/lib/bard/target.rb +21 -230
  51. data/lib/bard/version.rb +1 -1
  52. data/lib/bard.rb +1 -3
  53. data/spec/acceptance/docker/Dockerfile +1 -1
  54. data/spec/bard/capability_spec.rb +8 -50
  55. data/spec/bard/ci/github_actions_spec.rb +1 -1
  56. data/spec/bard/ci/jenkins_spec.rb +1 -1
  57. data/spec/bard/ci/runner_spec.rb +3 -3
  58. data/spec/bard/ci_spec.rb +1 -1
  59. data/spec/bard/cli/ci_spec.rb +4 -23
  60. data/spec/bard/cli/data_spec.rb +7 -26
  61. data/spec/bard/cli/deploy_spec.rb +43 -40
  62. data/spec/bard/cli/hurt_spec.rb +2 -8
  63. data/spec/bard/cli/install_spec.rb +4 -10
  64. data/spec/bard/cli/master_key_spec.rb +5 -19
  65. data/spec/bard/cli/open_spec.rb +17 -35
  66. data/spec/bard/cli/ping_spec.rb +10 -25
  67. data/spec/bard/cli/run_spec.rb +10 -23
  68. data/spec/bard/cli/setup_spec.rb +10 -27
  69. data/spec/bard/cli/ssh_spec.rb +10 -25
  70. data/spec/bard/cli/stage_spec.rb +17 -32
  71. data/spec/bard/cli/vim_spec.rb +5 -11
  72. data/spec/bard/command_spec.rb +1 -10
  73. data/spec/bard/config_spec.rb +68 -116
  74. data/spec/bard/copy_spec.rb +54 -18
  75. data/spec/bard/deploy_strategy/ssh_spec.rb +65 -7
  76. data/spec/bard/deploy_strategy_spec.rb +1 -1
  77. data/spec/bard/dynamic_dsl_spec.rb +18 -98
  78. data/spec/bard/git_spec.rb +9 -5
  79. data/spec/bard/github_spec.rb +1 -1
  80. data/spec/bard/ping_spec.rb +5 -5
  81. data/spec/bard/ssh_copy_spec.rb +44 -0
  82. data/spec/bard/ssh_server_spec.rb +1 -98
  83. data/spec/bard/target_spec.rb +61 -108
  84. metadata +50 -124
  85. data/lib/bard/ci/retryable.rb +0 -27
  86. data/lib/bard/cli/ci.rb +0 -73
  87. data/lib/bard/cli/command.rb +0 -26
  88. data/lib/bard/cli/data.rb +0 -45
  89. data/lib/bard/cli/deploy.rb +0 -116
  90. data/lib/bard/cli/hurt.rb +0 -15
  91. data/lib/bard/cli/install.rb +0 -11
  92. data/lib/bard/cli/master_key.rb +0 -17
  93. data/lib/bard/cli/new.rb +0 -101
  94. data/lib/bard/cli/new_rails_template.rb +0 -197
  95. data/lib/bard/cli/open.rb +0 -18
  96. data/lib/bard/cli/ping.rb +0 -12
  97. data/lib/bard/cli/provision.rb +0 -34
  98. data/lib/bard/cli/run.rb +0 -26
  99. data/lib/bard/cli/setup.rb +0 -56
  100. data/lib/bard/cli/ssh.rb +0 -14
  101. data/lib/bard/cli/stage.rb +0 -35
  102. data/lib/bard/cli/vim.rb +0 -8
  103. data/lib/bard/default_config.rb +0 -35
  104. data/lib/bard/deploy_strategy/ssh.rb +0 -19
  105. data/lib/bard/deprecation.rb +0 -19
  106. data/lib/bard/github_pages.rb +0 -134
  107. data/lib/bard/plugin.rb +0 -100
  108. data/lib/bard/plugins/backup.rb +0 -19
  109. data/lib/bard/plugins/jenkins.rb +0 -6
  110. data/lib/bard/plugins/new.rb +0 -5
  111. data/lib/bard/plugins/provision.rb +0 -5
  112. data/lib/bard/provision/app.rb +0 -10
  113. data/lib/bard/provision/apt.rb +0 -16
  114. data/lib/bard/provision/authorizedkeys.rb +0 -25
  115. data/lib/bard/provision/data.rb +0 -27
  116. data/lib/bard/provision/deploy.rb +0 -10
  117. data/lib/bard/provision/http.rb +0 -16
  118. data/lib/bard/provision/logrotation.rb +0 -30
  119. data/lib/bard/provision/masterkey.rb +0 -18
  120. data/lib/bard/provision/mysql.rb +0 -22
  121. data/lib/bard/provision/passenger.rb +0 -37
  122. data/lib/bard/provision/repo.rb +0 -72
  123. data/lib/bard/provision/rvm.rb +0 -22
  124. data/lib/bard/provision/ssh.rb +0 -79
  125. data/lib/bard/provision/swapfile.rb +0 -23
  126. data/lib/bard/provision/user.rb +0 -42
  127. data/lib/bard/provision.rb +0 -16
  128. data/lib/bard/server.rb +0 -160
  129. data/spec/bard/cli/command_spec.rb +0 -50
  130. data/spec/bard/cli/new_spec.rb +0 -73
  131. data/spec/bard/cli/provision_spec.rb +0 -42
  132. data/spec/bard/deprecation_spec.rb +0 -281
  133. data/spec/bard/github_pages_spec.rb +0 -143
  134. data/spec/bard/plugin_spec.rb +0 -79
  135. data/spec/bard/provision/app_spec.rb +0 -33
  136. data/spec/bard/provision/apt_spec.rb +0 -39
  137. data/spec/bard/provision/authorizedkeys_spec.rb +0 -40
  138. data/spec/bard/provision/data_spec.rb +0 -54
  139. data/spec/bard/provision/deploy_spec.rb +0 -33
  140. data/spec/bard/provision/http_spec.rb +0 -57
  141. data/spec/bard/provision/logrotation_spec.rb +0 -34
  142. data/spec/bard/provision/masterkey_spec.rb +0 -63
  143. data/spec/bard/provision/mysql_spec.rb +0 -55
  144. data/spec/bard/provision/passenger_spec.rb +0 -81
  145. data/spec/bard/provision/repo_spec.rb +0 -208
  146. data/spec/bard/provision/rvm_spec.rb +0 -49
  147. data/spec/bard/provision/ssh_spec.rb +0 -242
  148. data/spec/bard/provision/swapfile_spec.rb +0 -33
  149. data/spec/bard/provision/user_spec.rb +0 -103
  150. data/spec/bard/provision_spec.rb +0 -28
  151. data/spec/bard/server_spec.rb +0 -127
  152. /data/lib/bard/{ci → plugins/deploy/ci}/state.rb +0 -0
  153. /data/{install_files → lib/bard/plugins/install}/apt_dependencies.rb +0 -0
  154. /data/{install_files → lib/bard/plugins/install}/ci +0 -0
  155. /data/{install_files → lib/bard/plugins/install}/setup +0 -0
  156. /data/{install_files → lib/bard/plugins/install}/specified_bundler.rb +0 -0
  157. /data/{install_files → lib/bard/plugins/install}/specified_ruby.rb +0 -0
@@ -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
-
data/lib/bard/plugin.rb DELETED
@@ -1,100 +0,0 @@
1
- module Bard
2
- class Plugin
3
- @registry = {}
4
-
5
- class << self
6
- attr_reader :registry
7
-
8
- def register(name, &block)
9
- plugin = new(name)
10
- plugin.instance_eval(&block) if block
11
- @registry[name.to_sym] = plugin
12
- end
13
-
14
- def [](name)
15
- @registry[name.to_sym]
16
- end
17
-
18
- def all
19
- @registry.values
20
- end
21
-
22
- def load_all!
23
- Dir[File.join(__dir__, "plugins", "*.rb")].sort.each { |f| require f }
24
- Dir[File.join(Dir.pwd, "lib", "bard", "plugins", "*.rb")].sort.each { |f| require f }
25
- all.each(&:apply!)
26
- end
27
-
28
- def reset!
29
- @registry = {}
30
- end
31
- end
32
-
33
- attr_reader :name, :cli_modules
34
-
35
- def initialize(name)
36
- @name = name.to_sym
37
- @cli_modules = []
38
- @cli_requires = []
39
- @target_methods = {}
40
- @config_methods = {}
41
- @requires = []
42
- end
43
-
44
- # DSL methods for defining plugins
45
-
46
- def require_file(path)
47
- @requires << path
48
- end
49
-
50
- def cli(mod, require: nil)
51
- @cli_requires << require if require
52
- @cli_modules << mod
53
- end
54
-
55
- def target_method(name, &block)
56
- @target_methods[name] = block
57
- end
58
-
59
- def config_method(name, &block)
60
- @config_methods[name] = block
61
- end
62
-
63
- # Apply plugin to the system (non-CLI parts)
64
- def apply!
65
- @requires.each { |path| require path }
66
- apply_target_methods!
67
- apply_config_methods!
68
- end
69
-
70
- def apply_to_cli(cli_class)
71
- @cli_requires.each { |path| require path }
72
- @cli_modules.each do |mod|
73
- mod = resolve_constant(mod) if mod.is_a?(String)
74
- mod.setup(cli_class)
75
- end
76
- end
77
-
78
- private
79
-
80
- def apply_target_methods!
81
- return if @target_methods.empty?
82
- require "bard/target"
83
- @target_methods.each do |method_name, block|
84
- Target.define_method(method_name, &block)
85
- end
86
- end
87
-
88
- def apply_config_methods!
89
- return if @config_methods.empty?
90
- require "bard/config"
91
- @config_methods.each do |method_name, block|
92
- Config.define_method(method_name, &block)
93
- end
94
- end
95
-
96
- def resolve_constant(name)
97
- name.split("::").reduce(Object) { |mod, const| mod.const_get(const) }
98
- end
99
- end
100
- end
@@ -1,19 +0,0 @@
1
- require "bard/plugin"
2
-
3
- Bard::Plugin.register :backup do
4
- config_method :backup do |value = nil, &block|
5
- if block
6
- @backup = Bard::BackupConfig.new(&block)
7
- elsif value == false
8
- @backup = Bard::BackupConfig.new { disabled }
9
- elsif value.nil? # Getter
10
- @backup ||= Bard::BackupConfig.new { bard }
11
- else
12
- raise ArgumentError, "backup accepts false or a block"
13
- end
14
- end
15
-
16
- config_method :backup_enabled? do
17
- backup == true
18
- end
19
- end
@@ -1,6 +0,0 @@
1
- require "bard/plugin"
2
-
3
- Bard::Plugin.register :jenkins do
4
- # Jenkins CI runner - auto-registers via inherited hook when loaded
5
- require_file "bard/ci/jenkins"
6
- end
@@ -1,5 +0,0 @@
1
- require "bard/plugin"
2
-
3
- Bard::Plugin.register :new do
4
- cli "Bard::CLI::New", require: "bard/cli/new"
5
- end
@@ -1,5 +0,0 @@
1
- require "bard/plugin"
2
-
3
- Bard::Plugin.register :provision do
4
- cli "Bard::CLI::Provision", require: "bard/cli/provision"
5
- end
@@ -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 build-essential",
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/#{config.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 '' 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-2025.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/#{config.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(config.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
- config.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,79 +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
- 5.times do
24
- sleep 1
25
- break if ssh_available?(provision_server.ssh_uri, port: target_port)
26
- end
27
- if !ssh_available?(provision_server.ssh_uri, port: target_port)
28
- raise "reconfigured SSH to port #{target_port} but it's not responding — check firewall and sshd_config Include directive"
29
- end
30
- end
31
-
32
- if !ssh_known_host?(provision_server.ssh_uri)
33
- print " Adding known host,"
34
- add_ssh_known_host!(provision_server.ssh_uri)
35
- end
36
-
37
- # provision with new target port from now on
38
- ssh_url.gsub!(/:\d+$/, "")
39
- ssh_url << ":#{target_port}"
40
- puts " ✓"
41
- end
42
-
43
- private
44
-
45
- def target_port
46
- server.ssh_uri.port || 22
47
- end
48
-
49
- def ssh_available? ssh_uri, port: nil
50
- port ||= ssh_uri.port || 22
51
- system "nc -zv #{ssh_uri.host} #{port} 2>/dev/null"
52
- end
53
-
54
- def ssh_known_host? ssh_uri
55
- port ||= ssh_uri.port || 22
56
- system "grep -q \"$(ssh-keyscan -t ed25519 -p#{port} #{ssh_uri.host} 2>/dev/null | cut -d ' ' -f 2-3)\" ~/.ssh/known_hosts"
57
- end
58
-
59
- def add_ssh_known_host! ssh_uri
60
- port ||= ssh_uri.port || 22
61
- system "ssh-keyscan -p#{port} -H #{ssh_uri.host} >> ~/.ssh/known_hosts 2>/dev/null"
62
- end
63
-
64
- def password_auth_enabled?
65
- result = provision_server.run!(
66
- %q{grep -E '^\s*PasswordAuthentication\s+yes' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null || true},
67
- home: true,
68
- capture: true
69
- )
70
- !!(result && !result.strip.empty?)
71
- end
72
-
73
- def disable_password_auth!
74
- provision_server.run!(
75
- %q{echo "PasswordAuthentication no" | sudo tee /etc/ssh/sshd_config.d/disable_password_auth.conf && sudo service ssh restart},
76
- home: true
77
- )
78
- end
79
- end