bard-new 0.1.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 (62) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +42 -0
  3. data/.gitignore +4 -0
  4. data/CLAUDE.md +55 -0
  5. data/Gemfile +10 -0
  6. data/Gemfile.lock +179 -0
  7. data/README.md +107 -0
  8. data/Rakefile +8 -0
  9. data/bard-new.gemspec +25 -0
  10. data/features/new.feature +12 -0
  11. data/features/provision.feature +10 -0
  12. data/features/step_definitions/bard_new_steps.rb +64 -0
  13. data/features/support/bard-coverage +16 -0
  14. data/features/support/env.rb +22 -0
  15. data/features/support/new_server.rb +136 -0
  16. data/features/support/provision_server.rb +282 -0
  17. data/lib/bard/new/cli/new.rb +102 -0
  18. data/lib/bard/new/cli/provision.rb +32 -0
  19. data/lib/bard/new/provision/app.rb +9 -0
  20. data/lib/bard/new/provision/apt.rb +15 -0
  21. data/lib/bard/new/provision/authorizedkeys.rb +23 -0
  22. data/lib/bard/new/provision/base.rb +17 -0
  23. data/lib/bard/new/provision/data.rb +23 -0
  24. data/lib/bard/new/provision/deploy.rb +9 -0
  25. data/lib/bard/new/provision/http.rb +15 -0
  26. data/lib/bard/new/provision/logrotation.rb +27 -0
  27. data/lib/bard/new/provision/masterkey.rb +17 -0
  28. data/lib/bard/new/provision/mysql.rb +21 -0
  29. data/lib/bard/new/provision/nginx.rb +31 -0
  30. data/lib/bard/new/provision/repo.rb +71 -0
  31. data/lib/bard/new/provision/rvm.rb +20 -0
  32. data/lib/bard/new/provision/ssh.rb +79 -0
  33. data/lib/bard/new/provision/swapfile.rb +21 -0
  34. data/lib/bard/new/provision/user.rb +43 -0
  35. data/lib/bard/new/rails_template.rb +213 -0
  36. data/lib/bard/new/version.rb +5 -0
  37. data/lib/bard/plugins/new.rb +2 -0
  38. data/spec/acceptance/docker/Dockerfile.new +68 -0
  39. data/spec/acceptance/docker/Dockerfile.provision +41 -0
  40. data/spec/acceptance/docker/entrypoint-new.sh +3 -0
  41. data/spec/acceptance/docker/test_key +27 -0
  42. data/spec/acceptance/docker/test_key.pub +1 -0
  43. data/spec/bard/new/cli/new_spec.rb +85 -0
  44. data/spec/bard/new/cli/provision_spec.rb +40 -0
  45. data/spec/bard/new/provision/app_spec.rb +33 -0
  46. data/spec/bard/new/provision/apt_spec.rb +39 -0
  47. data/spec/bard/new/provision/authorizedkeys_spec.rb +40 -0
  48. data/spec/bard/new/provision/base_spec.rb +34 -0
  49. data/spec/bard/new/provision/data_spec.rb +54 -0
  50. data/spec/bard/new/provision/deploy_spec.rb +33 -0
  51. data/spec/bard/new/provision/http_spec.rb +57 -0
  52. data/spec/bard/new/provision/logrotation_spec.rb +34 -0
  53. data/spec/bard/new/provision/masterkey_spec.rb +62 -0
  54. data/spec/bard/new/provision/mysql_spec.rb +55 -0
  55. data/spec/bard/new/provision/nginx_spec.rb +81 -0
  56. data/spec/bard/new/provision/repo_spec.rb +208 -0
  57. data/spec/bard/new/provision/rvm_spec.rb +49 -0
  58. data/spec/bard/new/provision/ssh_spec.rb +242 -0
  59. data/spec/bard/new/provision/swapfile_spec.rb +33 -0
  60. data/spec/bard/new/provision/user_spec.rb +103 -0
  61. data/spec/spec_helper.rb +19 -0
  62. metadata +214 -0
@@ -0,0 +1,27 @@
1
+ -----BEGIN OPENSSH PRIVATE KEY-----
2
+ b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
3
+ NhAAAAAwEAAQAAAQEAuvnrkoVh6AISBhqUOtmvTf6TMoq/Do6i/ayn1aqs9YmbN57tNVnY
4
+ XEKBQ15HL5bquY0A4Fcf5mO73LyrHGdUODrJS6vZo4J8wcoyEyKxOC2UYV5ssCUntq13de
5
+ E4WVHfSykMEo9z3U7bxFSwtwU8ECYQHKLb4OBmQb4hp/nDvx4EM554laBUByGm8fgSKOlY
6
+ GEdWE0KAFVsKfkRW8AiR2RtQ5C1hIT/zCmHo01WTtHMpuyZk4cxpBlS3xz6wsD61f6SgMh
7
+ M0X575jfV/MxhbDd3FGkxIk8kM24DtLfLW9idYWDD25dfQuXK3eQZDJ3vcoKa+2W73XfHd
8
+ fBrAGrvjaQAAA8jQXv0u0F79LgAAAAdzc2gtcnNhAAABAQC6+euShWHoAhIGGpQ62a9N/p
9
+ Myir8OjqL9rKfVqqz1iZs3nu01WdhcQoFDXkcvluq5jQDgVx/mY7vcvKscZ1Q4OslLq9mj
10
+ gnzByjITIrE4LZRhXmywJSe2rXd14ThZUd9LKQwSj3PdTtvEVLC3BTwQJhAcotvg4GZBvi
11
+ Gn+cO/HgQznniVoFQHIabx+BIo6VgYR1YTQoAVWwp+RFbwCJHZG1DkLWEhP/MKYejTVZO0
12
+ cym7JmThzGkGVLfHPrCwPrV/pKAyEzRfnvmN9X8zGFsN3cUaTEiTyQzbgO0t8tb2J1hYMP
13
+ bl19C5crd5BkMne9ygpr7Zbvdd8d18GsAau+NpAAAAAwEAAQAAAQACxR+WkYfNtbQkfNcm
14
+ gmGXZ0wGeGmUCAxwSNMetlMu0GL+jAn0cPg52660ZmHpxFOwu971Xo0QLyOSGwXHm1ydza
15
+ R8TMI3atWO0xWdVMr+gPxdBJavIF8ff3U7h5fmXjEPmRQpn+WbSScL2FEFkRwJRYsWZYTv
16
+ kVt/zKw3zm/g4Fo7ieeM51heWDOVbNdCk0dcy2YK0L7Kb0FO+zvu3vxXrvWAqKmuRjxefc
17
+ FiumkkgaTn78ZIHdfYZa26PmZPIUxVNxRkauvHxYo921t634O0Ji1gwbT5hK8Y7JoGRIp0
18
+ alwgjjdbE80ZPuTspmeHQ7OKephb+c8qvoJu/LC8hQiBAAAAgCFGqbOsY9AcIfXY4hlADt
19
+ 94P5ySq5q3FbXeriy/CEklDPVER/w4iZaSRwMUqd7V36iZaLwHZyFQSNgIwiN1ysBPbcsq
20
+ c642pv4XuAyNTMtD+y8CxcH1LgL7EOEn6if8cgTJ7ayTGT4qIDaUgzf6Ot8z4wDGNKyCpE
21
+ lgPfdb8LKiAAAAgQDbrXnetOikB9+p+vf8M59UlfMYx7X9qLDsj0CUn1S0RyxgPWiJDBQl
22
+ fZg7WyYOQwRYF0b0s8JlpGLkhLDM6nhBzT1M+nrN0axTAvYkBZV5MJPNg31F/iHxEtt+/V
23
+ fMkH6VhmscVyiwEJkDP212dTAaDW3UremlRk77NIZ1PpPKKQAAAIEA2eRCJwNOvdsHYoJ6
24
+ k6mEpwISzglbs+y6tTeIwiI7AVGEzvVuKVTCV3n9ljofmnh0UChczIOyywEKSqJi2pos/B
25
+ kJoOmCxYMecB9lCxf61MUKdbpWaKF52+GvqT34Ne+VrYGuUp/0+asSTczVudJWRSzcdCji
26
+ NEMB0tV88Vro90EAAAANYmFyZC10ZXN0LWtleQECAwQFBg==
27
+ -----END OPENSSH PRIVATE KEY-----
@@ -0,0 +1 @@
1
+ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6+euShWHoAhIGGpQ62a9N/pMyir8OjqL9rKfVqqz1iZs3nu01WdhcQoFDXkcvluq5jQDgVx/mY7vcvKscZ1Q4OslLq9mjgnzByjITIrE4LZRhXmywJSe2rXd14ThZUd9LKQwSj3PdTtvEVLC3BTwQJhAcotvg4GZBviGn+cO/HgQznniVoFQHIabx+BIo6VgYR1YTQoAVWwp+RFbwCJHZG1DkLWEhP/MKYejTVZO0cym7JmThzGkGVLfHPrCwPrV/pKAyEzRfnvmN9X8zGFsN3cUaTEiTyQzbgO0t8tb2J1hYMPbl19C5crd5BkMne9ygpr7Zbvdd8d18GsAau+Np bard-test-key
@@ -0,0 +1,85 @@
1
+ require "spec_helper"
2
+
3
+ describe "bard new" do
4
+ let(:cli) { Bard::CLI.new }
5
+
6
+ before do
7
+ allow(cli).to receive(:puts)
8
+ allow(cli).to receive(:exit)
9
+ allow(cli).to receive(:run!)
10
+ allow(cli).to receive(:green).and_return("")
11
+ allow(cli).to receive(:red).and_return("")
12
+ allow(cli).to receive(:yellow).and_return("")
13
+ allow(File).to receive(:read).and_return("master_key_content")
14
+ end
15
+
16
+ describe "#new" do
17
+ context "with --skip-github and --skip-stage" do
18
+ let(:cli) { Bard::CLI.new([], skip_github: true, skip_stage: true) }
19
+
20
+ before do
21
+ allow(cli).to receive(:new_create_project)
22
+ end
23
+
24
+ it "skips github and stage steps" do
25
+ expect(cli).not_to receive(:new_push_to_github)
26
+ expect(cli).not_to receive(:new_stage)
27
+ cli.new("testproject")
28
+ end
29
+ end
30
+
31
+ context "with invalid project name" do
32
+ before do
33
+ allow(cli).to receive(:new_create_project)
34
+ allow(cli).to receive(:new_push_to_github)
35
+ allow(cli).to receive(:new_stage)
36
+ end
37
+
38
+ it "should reject names starting with uppercase" do
39
+ expect(cli).to receive(:puts).with(/Invalid project name/)
40
+ expect(cli).to receive(:exit).with(1)
41
+
42
+ cli.new("InvalidProject")
43
+ end
44
+
45
+ it "should reject names with special characters" do
46
+ expect(cli).to receive(:puts).with(/Invalid project name/)
47
+ expect(cli).to receive(:exit).with(1)
48
+
49
+ cli.new("invalid-project")
50
+ end
51
+
52
+ it "should reject names starting with numbers" do
53
+ expect(cli).to receive(:puts).with(/Invalid project name/)
54
+ expect(cli).to receive(:exit).with(1)
55
+
56
+ cli.new("1invalidproject")
57
+ end
58
+ end
59
+ end
60
+
61
+ describe "#new_ruby_version" do
62
+ it "returns the ruby version" do
63
+ expect(cli.send(:new_ruby_version)).to eq("ruby-4.0.2")
64
+ end
65
+ end
66
+
67
+ describe "#new_template_path" do
68
+ it "returns the path to the rails template" do
69
+ expect(cli.send(:new_template_path)).to match(/rails_template\.rb$/)
70
+ end
71
+ end
72
+
73
+ describe "#install_and_extract_version" do
74
+ it "correctly installs a gem and extracts its version", skip: !!ENV["CI"] do
75
+ cmd = cli.send :new_build_bash_env do
76
+ <<~SH
77
+ #{cli.send(:new_build_gem_install, "bundler", "~> 2.0")}
78
+ echo ${GEM_VERSION}
79
+ SH
80
+ end
81
+ result = `#{cmd}`.strip
82
+ expect(result).to match(/^2\.\d+\.\d+/)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+
3
+ describe "bard provision" do
4
+ let(:config) { { production: double("production", ssh: "user@example.com") } }
5
+ let(:cli) { Bard::CLI.new }
6
+
7
+ before do
8
+ allow(cli).to receive(:config).and_return(config)
9
+ allow(cli).to receive(:options).and_return({ steps: ["SSH", "User"] })
10
+ end
11
+
12
+ describe "PROVISION_STEPS constant" do
13
+ it "defines the provisioning steps" do
14
+ expect(Bard::CLI::PROVISION_STEPS).to include("SSH", "User", "Apt", "MySQL", "Deploy")
15
+ expect(Bard::CLI::PROVISION_STEPS).to be_a(Array)
16
+ end
17
+ end
18
+
19
+ describe "#provision" do
20
+ it "should run provision steps" do
21
+ expect(Bard::Provision).to receive(:const_get).with("SSH").and_return(double("ssh_step", call: true))
22
+ expect(Bard::Provision).to receive(:const_get).with("User").and_return(double("user_step", call: true))
23
+
24
+ cli.provision
25
+ end
26
+
27
+ it "should use production ssh by default" do
28
+ allow(Bard::Provision).to receive(:const_get).and_return(double("step", call: true))
29
+
30
+ cli.provision
31
+ end
32
+
33
+ it "should accept custom ssh_url" do
34
+ custom_ssh = "root@newserver.com"
35
+ allow(Bard::Provision).to receive(:const_get).and_return(double("step", call: true))
36
+
37
+ cli.provision(custom_ssh)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,33 @@
1
+ require "spec_helper"
2
+ require "bard/new/provision/base"
3
+ require "bard/new/provision/app"
4
+
5
+ describe Bard::Provision::App do
6
+ let(:config) { { production: double("production") } }
7
+ let(:ssh_url) { "user@example.com" }
8
+ let(:provision_server) { double("provision_server") }
9
+ let(:app) { Bard::Provision::App.new(config, ssh_url) }
10
+
11
+ before do
12
+ allow(app).to receive(:provision_server).and_return(provision_server)
13
+ allow(app).to receive(:print)
14
+ allow(app).to receive(:puts)
15
+ end
16
+
17
+ describe "#call" do
18
+ it "runs bin/setup on the server" do
19
+ expect(provision_server).to receive(:run!).with("bin/setup")
20
+
21
+ app.call
22
+ end
23
+
24
+ it "prints status messages" do
25
+ allow(provision_server).to receive(:run!)
26
+
27
+ expect(app).to receive(:print).with("App:")
28
+ expect(app).to receive(:puts).with(" ✓")
29
+
30
+ app.call
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ require "spec_helper"
2
+ require "bard/new/provision/base"
3
+ require "bard/new/provision/apt"
4
+
5
+ describe Bard::Provision::Apt do
6
+ let(:config) { { production: double("production") } }
7
+ let(:ssh_url) { "user@example.com" }
8
+ let(:provision_server) { double("provision_server") }
9
+ let(:apt) { Bard::Provision::Apt.new(config, ssh_url) }
10
+
11
+ before do
12
+ allow(apt).to receive(:provision_server).and_return(provision_server)
13
+ allow(apt).to receive(:print)
14
+ allow(apt).to receive(:puts)
15
+ end
16
+
17
+ describe "#call" do
18
+ it "updates and installs packages on the server" do
19
+ expected_commands = [
20
+ %(echo "\\$nrconf{restart} = \\"a\\";" | sudo tee /etc/needrestart/conf.d/90-autorestart.conf),
21
+ "sudo apt-get update -y",
22
+ "sudo apt-get upgrade -y",
23
+ "sudo apt-get install -y curl build-essential libsodium-dev"
24
+ ].join("; ")
25
+
26
+ expect(provision_server).to receive(:run!).with(expected_commands, home: true)
27
+
28
+ apt.call
29
+ end
30
+
31
+ it "prints status messages" do
32
+ allow(provision_server).to receive(:run!)
33
+ expect(apt).to receive(:print).with("Apt:")
34
+ expect(apt).to receive(:puts).with(" ✓")
35
+
36
+ apt.call
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+ require "bard/new/provision/base"
3
+ require "bard/new/provision/authorizedkeys"
4
+
5
+ describe Bard::Provision::AuthorizedKeys do
6
+ let(:config) { { production: double("production") } }
7
+ let(:ssh_url) { "user@example.com" }
8
+ let(:provision_server) { double("provision_server") }
9
+ let(:authorized_keys) { Bard::Provision::AuthorizedKeys.new(config, ssh_url) }
10
+
11
+ before do
12
+ allow(authorized_keys).to receive(:provision_server).and_return(provision_server)
13
+ allow(authorized_keys).to receive(:print)
14
+ allow(authorized_keys).to receive(:puts)
15
+ end
16
+
17
+ describe "#call" do
18
+ it "adds authorized keys to the server" do
19
+ expect(provision_server).to receive(:run!).at_least(:once).with(/grep -F -q/, home: true)
20
+
21
+ authorized_keys.call
22
+ end
23
+
24
+ it "prints status messages" do
25
+ allow(provision_server).to receive(:run!)
26
+ expect(authorized_keys).to receive(:print).with("Authorized Keys:")
27
+ expect(authorized_keys).to receive(:puts).with(" ✓")
28
+
29
+ authorized_keys.call
30
+ end
31
+ end
32
+
33
+ describe "KEYS constant" do
34
+ it "should have predefined SSH keys" do
35
+ expect(Bard::Provision::AuthorizedKeys::KEYS).to be_a(Hash)
36
+ expect(Bard::Provision::AuthorizedKeys::KEYS).not_to be_empty
37
+ expect(Bard::Provision::AuthorizedKeys::KEYS.keys.first).to match(/@/)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,34 @@
1
+ require "spec_helper"
2
+ require "bard/new/provision/base"
3
+
4
+ describe Bard::Provision do
5
+ let(:config) { { production: double("production", key: :production) } }
6
+ let(:ssh_url) { "user@example.com" }
7
+ let(:provision) { Bard::Provision.new(config, ssh_url) }
8
+
9
+ describe ".call" do
10
+ it "creates a new instance and calls it" do
11
+ expect_any_instance_of(Bard::Provision).to receive(:call)
12
+ Bard::Provision.call(config, ssh_url)
13
+ end
14
+ end
15
+
16
+ describe "#target" do
17
+ it "returns the production target from config" do
18
+ expect(provision.send(:target)).to eq(config[:production])
19
+ end
20
+ end
21
+
22
+ describe "#provision_server" do
23
+ it "returns a target with the provision ssh_url" do
24
+ target = config[:production]
25
+ allow(target).to receive(:ssh).and_return(nil)
26
+ duped = double("duped_target")
27
+ allow(target).to receive(:dup).and_return(duped)
28
+ allow(duped).to receive(:ssh)
29
+
30
+ result = provision.send(:provision_server)
31
+ expect(result).to eq(duped)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,54 @@
1
+ require "spec_helper"
2
+ require "bard/new/provision/base"
3
+ require "bard/new/provision/data"
4
+
5
+ describe Bard::Provision::Data do
6
+ let(:target) { double("target", key: :production) }
7
+ let(:config) { double("config", data: ["uploads", "assets"]) }
8
+ let(:ssh_url) { "user@example.com" }
9
+ let(:provision_server) { double("provision_server") }
10
+ let(:data_provisioner) { Bard::Provision::Data.new(config, ssh_url) }
11
+
12
+ before do
13
+ allow(data_provisioner).to receive(:target).and_return(target)
14
+ allow(data_provisioner).to receive(:config).and_return(config)
15
+ allow(data_provisioner).to receive(:provision_server).and_return(provision_server)
16
+ allow(data_provisioner).to receive(:print)
17
+ allow(data_provisioner).to receive(:puts)
18
+ end
19
+
20
+ describe "#call" do
21
+ it "dumps, transfers, and loads database data" do
22
+ expect(target).to receive(:run!).with("bin/rake db:dump")
23
+ expect(target).to receive(:copy_file).with("db/data.sql.gz", to: provision_server, verbose: false)
24
+ expect(provision_server).to receive(:run!).with("bin/rake db:load")
25
+
26
+ allow(target).to receive(:copy_dir)
27
+
28
+ data_provisioner.call
29
+ end
30
+
31
+ it "synchronizes configured data directories" do
32
+ allow(target).to receive(:run!)
33
+ allow(target).to receive(:copy_file)
34
+ allow(provision_server).to receive(:run!)
35
+
36
+ expect(target).to receive(:copy_dir).with("uploads", to: provision_server, verbose: false)
37
+ expect(target).to receive(:copy_dir).with("assets", to: provision_server, verbose: false)
38
+
39
+ data_provisioner.call
40
+ end
41
+
42
+ it "prints status messages" do
43
+ allow(target).to receive(:run!)
44
+ allow(target).to receive(:copy_file)
45
+ allow(target).to receive(:copy_dir)
46
+ allow(provision_server).to receive(:run!)
47
+
48
+ expect(data_provisioner).to receive(:print).with("Data:")
49
+ expect(data_provisioner).to receive(:puts).with(" ✓")
50
+
51
+ data_provisioner.call
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,33 @@
1
+ require "spec_helper"
2
+ require "bard/new/provision/base"
3
+ require "bard/new/provision/deploy"
4
+
5
+ describe Bard::Provision::Deploy do
6
+ let(:config) { { production: double("production") } }
7
+ let(:ssh_url) { "user@example.com" }
8
+ let(:provision_server) { double("provision_server") }
9
+ let(:deploy) { Bard::Provision::Deploy.new(config, ssh_url) }
10
+
11
+ before do
12
+ allow(deploy).to receive(:provision_server).and_return(provision_server)
13
+ allow(deploy).to receive(:print)
14
+ allow(deploy).to receive(:puts)
15
+ end
16
+
17
+ describe "#call" do
18
+ it "runs bin/setup on the server" do
19
+ expect(provision_server).to receive(:run!).with("bin/setup")
20
+
21
+ deploy.call
22
+ end
23
+
24
+ it "prints status messages" do
25
+ allow(provision_server).to receive(:run!)
26
+
27
+ expect(deploy).to receive(:print).with("Deploy:")
28
+ expect(deploy).to receive(:puts).with(" ✓")
29
+
30
+ deploy.call
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,57 @@
1
+ require "spec_helper"
2
+ require "bard/new/provision/base"
3
+ require "bard/new/provision/http"
4
+
5
+ describe Bard::Provision::HTTP do
6
+ let(:target) { double("target", url: "https://example.com") }
7
+ let(:config) { { production: target } }
8
+ let(:ssh_url) { "user@example.com" }
9
+ let(:provision_server) { double("provision_server") }
10
+ let(:http) { Bard::Provision::HTTP.new(config, ssh_url) }
11
+
12
+ before do
13
+ allow(http).to receive(:target).and_return(target)
14
+ allow(http).to receive(:provision_server).and_return(provision_server)
15
+ allow(provision_server).to receive_message_chain(:ssh_uri, :host).and_return("192.168.1.100")
16
+ allow(http).to receive(:print)
17
+ allow(http).to receive(:puts)
18
+ allow(http).to receive(:system)
19
+ end
20
+
21
+ describe "#call" do
22
+ context "when HTTP test passes" do
23
+ it "shows success message" do
24
+ allow(http).to receive(:system).and_return(true)
25
+
26
+ expect(http).to receive(:puts).with(" ✓")
27
+
28
+ http.call
29
+ end
30
+ end
31
+
32
+ context "when HTTP test fails" do
33
+ it "shows failure message" do
34
+ allow(http).to receive(:system).and_return(false)
35
+
36
+ expect(http).to receive(:puts).with(" !!! not serving a rails app from 192.168.1.100")
37
+
38
+ http.call
39
+ end
40
+ end
41
+
42
+ it "prints status header" do
43
+ allow(http).to receive(:system).and_return(true)
44
+
45
+ expect(http).to receive(:print).with("HTTP:")
46
+
47
+ http.call
48
+ end
49
+
50
+ it "tests the correct URL" do
51
+ expected_command = /curl -sf --resolve example\.com:80:192\.168\.1\.100 http:\/\/example\.com -o \/dev\/null/
52
+ expect(http).to receive(:system).with(expected_command)
53
+
54
+ http.call
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,34 @@
1
+ require "spec_helper"
2
+ require "bard/new/provision/base"
3
+ require "bard/new/provision/logrotation"
4
+
5
+ describe Bard::Provision::LogRotation do
6
+ let(:target) { double("target", project_name: "test_app") }
7
+ let(:config) { double("config", project_name: "test_app", :[] => target) }
8
+ let(:ssh_url) { "user@example.com" }
9
+ let(:provision_server) { double("provision_server") }
10
+ let(:logrotation) { Bard::Provision::LogRotation.new(config, ssh_url) }
11
+
12
+ before do
13
+ allow(logrotation).to receive(:target).and_return(target)
14
+ allow(logrotation).to receive(:provision_server).and_return(provision_server)
15
+ allow(logrotation).to receive(:print)
16
+ allow(logrotation).to receive(:puts)
17
+ end
18
+
19
+ describe "#call" do
20
+ it "sets up log rotation config on the target" do
21
+ expect(provision_server).to receive(:run!).with(/file=\/etc\/logrotate\.d\/test_app/, quiet: true)
22
+
23
+ logrotation.call
24
+ end
25
+
26
+ it "prints status messages" do
27
+ allow(provision_server).to receive(:run!)
28
+ expect(logrotation).to receive(:print).with("Log Rotation:")
29
+ expect(logrotation).to receive(:puts).with(" ✓")
30
+
31
+ logrotation.call
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,62 @@
1
+ require "spec_helper"
2
+ require "bard/new/provision/base"
3
+ require "bard/new/provision/masterkey"
4
+
5
+ describe Bard::Provision::MasterKey do
6
+ let(:local) { double("local") }
7
+ let(:config) { { production: double("production"), local: local } }
8
+ let(:ssh_url) { "user@example.com" }
9
+ let(:provision_server) { double("provision_server") }
10
+ let(:master_key) { Bard::Provision::MasterKey.new(config, ssh_url) }
11
+
12
+ before do
13
+ allow(master_key).to receive(:provision_server).and_return(provision_server)
14
+ allow(master_key).to receive(:print)
15
+ allow(master_key).to receive(:puts)
16
+ end
17
+
18
+ describe "#call" do
19
+ context "when master.key exists locally" do
20
+ before do
21
+ allow(File).to receive(:exist?).with("config/master.key").and_return(true)
22
+ end
23
+
24
+ it "uploads master.key if not present on server" do
25
+ allow(provision_server).to receive(:run).with("[ -f config/master.key ]", quiet: true).and_return(false)
26
+
27
+ expect(Bard::Copy).to receive(:file).with("config/master.key", from: local, to: provision_server)
28
+
29
+ master_key.call
30
+ end
31
+
32
+ it "skips upload if master.key already exists on server" do
33
+ allow(provision_server).to receive(:run).with("[ -f config/master.key ]", quiet: true).and_return(true)
34
+
35
+ expect(Bard::Copy).not_to receive(:file)
36
+
37
+ master_key.call
38
+ end
39
+ end
40
+
41
+ context "when master.key doesn't exist locally" do
42
+ before do
43
+ allow(File).to receive(:exist?).with("config/master.key").and_return(false)
44
+ end
45
+
46
+ it "skips the upload" do
47
+ expect(Bard::Copy).not_to receive(:file)
48
+
49
+ master_key.call
50
+ end
51
+ end
52
+
53
+ it "prints status messages" do
54
+ allow(File).to receive(:exist?).and_return(false)
55
+
56
+ expect(master_key).to receive(:print).with("Master Key:")
57
+ expect(master_key).to receive(:puts).with(" ✓")
58
+
59
+ master_key.call
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,55 @@
1
+ require "spec_helper"
2
+ require "bard/new/provision/base"
3
+ require "bard/new/provision/mysql"
4
+
5
+ describe Bard::Provision::MySQL do
6
+ let(:config) { { production: double("production") } }
7
+ let(:ssh_url) { "user@example.com" }
8
+ let(:provision_server) { double("provision_server") }
9
+ let(:mysql) { Bard::Provision::MySQL.new(config, ssh_url) }
10
+
11
+ before do
12
+ allow(mysql).to receive(:provision_server).and_return(provision_server)
13
+ allow(mysql).to receive(:print)
14
+ allow(mysql).to receive(:puts)
15
+ end
16
+
17
+ describe "#call" do
18
+ context "when MySQL is not responding" do
19
+ it "installs MySQL" do
20
+ allow(mysql).to receive(:mysql_responding?).and_return(false)
21
+
22
+ expect(provision_server).to receive(:run!).with(/DEBIAN_FRONTEND=noninteractive.*apt-get install -y mysql-server/, home: true)
23
+
24
+ mysql.call
25
+ end
26
+ end
27
+
28
+ context "when MySQL is already responding" do
29
+ it "skips installation" do
30
+ allow(mysql).to receive(:mysql_responding?).and_return(true)
31
+
32
+ expect(provision_server).not_to receive(:run!)
33
+
34
+ mysql.call
35
+ end
36
+ end
37
+
38
+ it "prints status messages" do
39
+ allow(mysql).to receive(:mysql_responding?).and_return(true)
40
+
41
+ expect(mysql).to receive(:print).with("MySQL:")
42
+ expect(mysql).to receive(:puts).with(" ✓")
43
+
44
+ mysql.call
45
+ end
46
+ end
47
+
48
+ describe "#mysql_responding?" do
49
+ it "checks if MySQL service is active" do
50
+ expect(provision_server).to receive(:run).with("sudo systemctl is-active --quiet mysql", home: true, quiet: true)
51
+
52
+ mysql.mysql_responding?
53
+ end
54
+ end
55
+ end