bard 1.4.8 → 1.4.9
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +22 -0
- data/Gemfile +4 -0
- data/bard.gemspec +3 -2
- data/lib/bard/git.rb +5 -1
- data/lib/bard/provision/repo.rb +21 -0
- data/lib/bard/provision/ssh.rb +21 -0
- data/lib/bard/server.rb +2 -2
- data/lib/bard/version.rb +1 -1
- data/spec/bard/cli/ci_spec.rb +139 -0
- data/spec/bard/cli/command_spec.rb +50 -0
- data/spec/bard/cli/data_spec.rb +77 -0
- data/spec/bard/cli/deploy_spec.rb +202 -0
- data/spec/bard/cli/hurt_spec.rb +23 -0
- data/spec/bard/cli/install_spec.rb +25 -0
- data/spec/bard/cli/master_key_spec.rb +52 -0
- data/spec/bard/cli/new_spec.rb +60 -0
- data/spec/bard/cli/open_spec.rb +67 -0
- data/spec/bard/cli/ping_spec.rb +47 -0
- data/spec/bard/cli/provision_spec.rb +42 -0
- data/spec/bard/cli/run_spec.rb +51 -0
- data/spec/bard/cli/setup_spec.rb +76 -0
- data/spec/bard/cli/ssh_spec.rb +55 -0
- data/spec/bard/cli/stage_spec.rb +77 -0
- data/spec/bard/cli/vim_spec.rb +34 -0
- data/spec/bard/command_spec.rb +37 -0
- data/spec/bard/copy_spec.rb +33 -0
- data/spec/bard/git_spec.rb +61 -0
- data/spec/bard/github_pages_spec.rb +80 -0
- data/spec/bard/github_spec.rb +45 -0
- data/spec/bard/ping_spec.rb +31 -0
- data/spec/bard/provision/app_spec.rb +33 -0
- data/spec/bard/provision/apt_spec.rb +39 -0
- data/spec/bard/provision/authorizedkeys_spec.rb +40 -0
- data/spec/bard/provision/data_spec.rb +54 -0
- data/spec/bard/provision/deploy_spec.rb +33 -0
- data/spec/bard/provision/http_spec.rb +57 -0
- data/spec/bard/provision/logrotation_spec.rb +34 -0
- data/spec/bard/provision/masterkey_spec.rb +63 -0
- data/spec/bard/provision/mysql_spec.rb +55 -0
- data/spec/bard/provision/passenger_spec.rb +81 -0
- data/spec/bard/provision/repo_spec.rb +208 -0
- data/spec/bard/provision/rvm_spec.rb +49 -0
- data/spec/bard/provision/ssh_spec.rb +229 -0
- data/spec/bard/provision/swapfile_spec.rb +32 -0
- data/spec/bard/provision/user_spec.rb +103 -0
- data/spec/bard/provision_spec.rb +28 -0
- data/spec/spec_helper.rb +6 -1
- metadata +96 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7758630b558e557b178b1d598cec7ef6c5bd3d56769673372f4133ffc488451
|
4
|
+
data.tar.gz: 86df74f01dab9bdb30690340571d10b2bd51bbff3d70f1aeca4385d399542d76
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd955ce3572ec9c071f775ea15c78ce004ef0db2125105e0d72678057b65475d534cc21e408ca0900ef57735c13f30a7d1755714bc4dd0019469f73f66ed04c2
|
7
|
+
data.tar.gz: e6b64d2cef83b325161b5f7b5f990b400a245f7b5103f7539d3a500150f7c2ab863557350954213fec8f382aa7908142f19fb98df0304a921f486be77470187d
|
@@ -0,0 +1,22 @@
|
|
1
|
+
name: CI
|
2
|
+
on: [push, pull_request]
|
3
|
+
jobs:
|
4
|
+
test:
|
5
|
+
strategy:
|
6
|
+
fail-fast: false
|
7
|
+
matrix:
|
8
|
+
ruby: [ "3.2", "3.3", "3.4" ]
|
9
|
+
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
steps:
|
12
|
+
- name: Checkout code
|
13
|
+
uses: actions/checkout@v4
|
14
|
+
|
15
|
+
- name: Set up Ruby
|
16
|
+
uses: ruby/setup-ruby@v1
|
17
|
+
with:
|
18
|
+
ruby-version: ${{ matrix.ruby }}
|
19
|
+
bundler-cache: true
|
20
|
+
|
21
|
+
- name: Run tests
|
22
|
+
run: bundle exec rake
|
data/Gemfile
CHANGED
data/bard.gemspec
CHANGED
@@ -21,8 +21,9 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_dependency "rvm"
|
22
22
|
spec.add_dependency "term-ansicolor", ">= 1.0.3"
|
23
23
|
spec.add_dependency "rbnacl"
|
24
|
+
spec.add_dependency "base64"
|
24
25
|
|
25
|
-
spec.add_development_dependency "
|
26
|
+
spec.add_development_dependency "rake"
|
26
27
|
spec.add_development_dependency "rspec"
|
27
|
-
spec.add_development_dependency "
|
28
|
+
spec.add_development_dependency "debug"
|
28
29
|
end
|
data/lib/bard/git.rb
CHANGED
@@ -21,9 +21,13 @@ module Bard
|
|
21
21
|
|
22
22
|
def sha_of ref
|
23
23
|
sha = `git rev-parse #{ref} 2>/dev/null`.chomp
|
24
|
-
return sha if
|
24
|
+
return sha if command_succeeded?
|
25
25
|
nil # Branch doesn't exist
|
26
26
|
end
|
27
|
+
|
28
|
+
def command_succeeded?
|
29
|
+
$?.success?
|
30
|
+
end
|
27
31
|
end
|
28
32
|
end
|
29
33
|
|
data/lib/bard/provision/repo.rb
CHANGED
@@ -20,6 +20,11 @@ class Bard::Provision::Repo < Bard::Provision
|
|
20
20
|
end
|
21
21
|
print " Cloning repo,"
|
22
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
|
23
28
|
end
|
24
29
|
|
25
30
|
puts " ✓"
|
@@ -47,5 +52,21 @@ class Bard::Provision::Repo < Bard::Provision
|
|
47
52
|
def project_name
|
48
53
|
server.project_name
|
49
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
|
50
71
|
end
|
51
72
|
|
data/lib/bard/provision/ssh.rb
CHANGED
@@ -5,6 +5,11 @@ class Bard::Provision::SSH < Bard::Provision
|
|
5
5
|
def call
|
6
6
|
print "SSH:"
|
7
7
|
|
8
|
+
if password_auth_enabled?
|
9
|
+
print " Disabling password authentication,"
|
10
|
+
disable_password_auth!
|
11
|
+
end
|
12
|
+
|
8
13
|
if !ssh_available?(provision_server.ssh_uri, port: target_port)
|
9
14
|
if !ssh_available?(provision_server.ssh_uri)
|
10
15
|
raise "can't find SSH on port #{target_port} or #{provision_server.ssh_uri.port || 22}"
|
@@ -48,4 +53,20 @@ class Bard::Provision::SSH < Bard::Provision
|
|
48
53
|
port ||= ssh_uri.port || 22
|
49
54
|
system "ssh-keyscan -p#{port} -H #{ssh_uri.host} >> ~/.ssh/known_hosts 2>/dev/null"
|
50
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
|
51
72
|
end
|
data/lib/bard/server.rb
CHANGED
data/lib/bard/version.rb
CHANGED
@@ -0,0 +1,139 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "bard/cli"
|
3
|
+
require "bard/cli/ci"
|
4
|
+
require "thor"
|
5
|
+
|
6
|
+
class TestCICLI < Thor
|
7
|
+
include Bard::CLI::CI
|
8
|
+
|
9
|
+
attr_reader :options
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super
|
13
|
+
@options = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def project_name
|
17
|
+
"test_project"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Bard::CLI::CI do
|
22
|
+
let(:cli) { TestCICLI.new }
|
23
|
+
let(:ci_runner) { double("ci_runner") }
|
24
|
+
|
25
|
+
before do
|
26
|
+
allow(cli).to receive(:puts)
|
27
|
+
allow(cli).to receive(:print)
|
28
|
+
allow(cli).to receive(:exit)
|
29
|
+
allow(cli).to receive(:red).and_return("")
|
30
|
+
allow($stdout).to receive(:flush)
|
31
|
+
allow(Bard::Git).to receive(:current_branch).and_return("feature-branch")
|
32
|
+
allow(Bard::CI).to receive(:new).and_return(ci_runner)
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#ci" do
|
36
|
+
it "should have a ci command" do
|
37
|
+
expect(cli).to respond_to(:ci)
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when CI exists and status option is set" do
|
41
|
+
it "prints CI status and returns early" do
|
42
|
+
allow(cli).to receive(:options).and_return({ "status" => true })
|
43
|
+
allow(ci_runner).to receive(:exists?).and_return(true)
|
44
|
+
allow(ci_runner).to receive(:status).and_return("Build #123: SUCCESS")
|
45
|
+
|
46
|
+
expect(cli).to receive(:puts).with("Build #123: SUCCESS")
|
47
|
+
expect(ci_runner).not_to receive(:run)
|
48
|
+
|
49
|
+
cli.ci
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when CI exists and running normally" do
|
54
|
+
before do
|
55
|
+
allow(cli).to receive(:options).and_return({})
|
56
|
+
allow(ci_runner).to receive(:exists?).and_return(true)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "starts CI build and handles success" do
|
60
|
+
allow(ci_runner).to receive(:run).and_yield(30, 60).and_return(true)
|
61
|
+
|
62
|
+
expect(cli).to receive(:puts).with("Continuous integration: starting build on feature-branch...")
|
63
|
+
expect(cli).to receive(:puts).with("Continuous integration: success!")
|
64
|
+
expect(cli).to receive(:puts).with("Deploying...")
|
65
|
+
|
66
|
+
cli.ci
|
67
|
+
end
|
68
|
+
|
69
|
+
it "handles CI failure" do
|
70
|
+
allow(ci_runner).to receive(:run).and_yield(30, 60).and_return(false)
|
71
|
+
allow(ci_runner).to receive(:console).and_return("Test failed: spec/model_spec.rb")
|
72
|
+
|
73
|
+
expect(cli).to receive(:puts).with("Continuous integration: starting build on feature-branch...")
|
74
|
+
expect(cli).to receive(:puts).with("Test failed: spec/model_spec.rb")
|
75
|
+
expect(cli).to receive(:puts) # The puts with newline
|
76
|
+
expect(cli).to receive(:puts) # The "Automated tests failed!" message
|
77
|
+
expect(cli).to receive(:exit).with(1)
|
78
|
+
|
79
|
+
cli.ci
|
80
|
+
end
|
81
|
+
|
82
|
+
it "displays progress with estimated completion time" do
|
83
|
+
allow(ci_runner).to receive(:run).and_yield(30, 60).and_return(true)
|
84
|
+
|
85
|
+
expect(cli).to receive(:print).with("\x08" * " Estimated completion: 50%".length)
|
86
|
+
expect(cli).to receive(:print).with(" Estimated completion: 50%")
|
87
|
+
|
88
|
+
cli.ci
|
89
|
+
end
|
90
|
+
|
91
|
+
it "displays progress without estimated completion time" do
|
92
|
+
allow(ci_runner).to receive(:run).and_yield(45, nil).and_return(true)
|
93
|
+
|
94
|
+
expect(cli).to receive(:print).with("\x08" * " No estimated completion time. Elapsed time: 45 sec".length)
|
95
|
+
expect(cli).to receive(:print).with(" No estimated completion time. Elapsed time: 45 sec")
|
96
|
+
|
97
|
+
cli.ci
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "when CI doesn't exist" do
|
102
|
+
it "shows error message and exits" do
|
103
|
+
allow(cli).to receive(:options).and_return({})
|
104
|
+
allow(ci_runner).to receive(:exists?).and_return(false)
|
105
|
+
|
106
|
+
expect(cli).to receive(:puts) # "No CI found for test_project!"
|
107
|
+
expect(cli).to receive(:puts) # "Re-run with --skip-ci to bypass CI..."
|
108
|
+
expect(cli).to receive(:exit).with(1)
|
109
|
+
|
110
|
+
cli.ci
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "with custom branch" do
|
115
|
+
it "uses the specified branch" do
|
116
|
+
allow(cli).to receive(:options).and_return({})
|
117
|
+
allow(ci_runner).to receive(:exists?).and_return(true)
|
118
|
+
allow(ci_runner).to receive(:run).and_return(true)
|
119
|
+
|
120
|
+
expect(Bard::CI).to receive(:new).with("test_project", "develop", local: nil)
|
121
|
+
expect(cli).to receive(:puts).with("Continuous integration: starting build on develop...")
|
122
|
+
|
123
|
+
cli.ci("develop")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "with local-ci option" do
|
128
|
+
it "passes local option to CI runner" do
|
129
|
+
allow(cli).to receive(:options).and_return({ "local-ci" => true })
|
130
|
+
allow(ci_runner).to receive(:exists?).and_return(true)
|
131
|
+
allow(ci_runner).to receive(:run).and_return(true)
|
132
|
+
|
133
|
+
expect(Bard::CI).to receive(:new).with("test_project", "feature-branch", local: true)
|
134
|
+
|
135
|
+
cli.ci
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,50 @@
|
|
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
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "bard/cli"
|
3
|
+
require "bard/cli/data"
|
4
|
+
|
5
|
+
require "thor"
|
6
|
+
|
7
|
+
require "term/ansicolor"
|
8
|
+
|
9
|
+
class TestCLI < Thor
|
10
|
+
include Bard::CLI::Data
|
11
|
+
include Term::ANSIColor
|
12
|
+
|
13
|
+
attr_reader :config
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@config = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def options
|
20
|
+
{}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe Bard::CLI::Data do
|
25
|
+
let(:cli) { TestCLI.new }
|
26
|
+
|
27
|
+
it "should have a data command" do
|
28
|
+
expect(cli).to respond_to(:data)
|
29
|
+
end
|
30
|
+
|
31
|
+
context "data" do
|
32
|
+
let(:from) { double("from", key: :production, run!: nil, copy_file: nil, copy_dir: nil) }
|
33
|
+
let(:to) { double("to", key: :local, run!: nil) }
|
34
|
+
|
35
|
+
let(:config) do
|
36
|
+
double("config", data: [], :[] => nil).tap do |config|
|
37
|
+
allow(config).to receive(:[]).with("production").and_return(from)
|
38
|
+
allow(config).to receive(:[]).with("local").and_return(to)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
before do
|
43
|
+
allow(cli).to receive(:config).and_return(config)
|
44
|
+
allow(cli).to receive(:options).and_return({from: "production", to: "local"})
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should run the data command" do
|
48
|
+
expect(from).to receive(:run!).with("bin/rake db:dump")
|
49
|
+
expect(from).to receive(:copy_file).with("db/data.sql.gz", to: to, verbose: true)
|
50
|
+
expect(to).to receive(:run!).with("bin/rake db:load")
|
51
|
+
cli.data
|
52
|
+
end
|
53
|
+
|
54
|
+
context "pushing to production" do
|
55
|
+
let(:to) { double("to", key: :production, ping: ["https://example.com"]) }
|
56
|
+
|
57
|
+
before do
|
58
|
+
allow(cli).to receive(:options).and_return({from: "local", to: "production"})
|
59
|
+
allow(config).to receive(:[]).with("production").and_return(to)
|
60
|
+
allow(config).to receive(:[]).with("local").and_return(from)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should prevent pushing to production if the user does not confirm" do
|
64
|
+
expect(cli).to receive(:ask).and_return("no")
|
65
|
+
expect { cli.data }.to raise_error(SystemExit)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should allow pushing to production if the user confirms" do
|
69
|
+
expect(cli).to receive(:ask).and_return("https://example.com")
|
70
|
+
expect(from).to receive(:run!).with("bin/rake db:dump")
|
71
|
+
expect(from).to receive(:copy_file).with("db/data.sql.gz", to: to, verbose: true)
|
72
|
+
expect(to).to receive(:run!).with("bin/rake db:load")
|
73
|
+
cli.data
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "bard/cli"
|
3
|
+
require "bard/cli/deploy"
|
4
|
+
require "thor"
|
5
|
+
|
6
|
+
class TestDeployCLI < Thor
|
7
|
+
include Bard::CLI::Deploy
|
8
|
+
|
9
|
+
attr_reader :config, :options
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super
|
13
|
+
@config = {}
|
14
|
+
@options = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def project_name
|
18
|
+
"test_project"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe Bard::CLI::Deploy do
|
23
|
+
let(:production_server) { double("production", run!: true, github_pages: false, path: "/var/www/test_project") }
|
24
|
+
let(:config) { { production: production_server } }
|
25
|
+
let(:cli) { TestDeployCLI.new }
|
26
|
+
|
27
|
+
before do
|
28
|
+
allow(cli).to receive(:config).and_return(config)
|
29
|
+
allow(cli).to receive(:puts)
|
30
|
+
allow(cli).to receive(:exit)
|
31
|
+
allow(cli).to receive(:run!)
|
32
|
+
allow(cli).to receive(:invoke)
|
33
|
+
allow(cli).to receive(:ping)
|
34
|
+
allow(cli).to receive(:green).and_return("")
|
35
|
+
allow(cli).to receive(:red).and_return("")
|
36
|
+
allow(cli).to receive(:yellow).and_return("")
|
37
|
+
allow(Bard::Git).to receive(:current_branch).and_return("feature-branch")
|
38
|
+
allow(Bard::Git).to receive(:up_to_date_with_remote?).and_return(true)
|
39
|
+
allow(Bard::Git).to receive(:fast_forward_merge?).and_return(true)
|
40
|
+
allow(cli).to receive(:`).and_return("")
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#deploy" do
|
44
|
+
it "should have a deploy command" do
|
45
|
+
expect(cli).to respond_to(:deploy)
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when on master branch" do
|
49
|
+
before do
|
50
|
+
allow(Bard::Git).to receive(:current_branch).and_return("master")
|
51
|
+
allow(cli).to receive(:options).and_return({})
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when up to date with remote" do
|
55
|
+
it "skips push and runs CI then deploys" do
|
56
|
+
allow(Bard::Git).to receive(:up_to_date_with_remote?).and_return(true)
|
57
|
+
|
58
|
+
expect(cli).not_to receive(:run!).with(/git push/)
|
59
|
+
expect(cli).to receive(:invoke).with(:ci, ["master"], {})
|
60
|
+
expect(production_server).to receive(:run!).with("git pull origin master && bin/setup")
|
61
|
+
expect(cli).to receive(:puts) # "Deploy Succeeded"
|
62
|
+
expect(cli).to receive(:ping).with(:production)
|
63
|
+
|
64
|
+
cli.deploy
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "when not up to date with remote" do
|
69
|
+
it "pushes master then runs CI and deploys" do
|
70
|
+
allow(Bard::Git).to receive(:up_to_date_with_remote?).and_return(false)
|
71
|
+
|
72
|
+
expect(cli).to receive(:run!).with("git push origin master:master")
|
73
|
+
expect(cli).to receive(:invoke).with(:ci, ["master"], {})
|
74
|
+
expect(production_server).to receive(:run!).with("git pull origin master && bin/setup")
|
75
|
+
|
76
|
+
cli.deploy
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "with skip-ci option" do
|
81
|
+
it "skips CI step" do
|
82
|
+
allow(cli).to receive(:options).and_return({ "skip-ci" => true })
|
83
|
+
|
84
|
+
expect(cli).not_to receive(:invoke).with(:ci, anything, anything)
|
85
|
+
expect(production_server).to receive(:run!).with("git pull origin master && bin/setup")
|
86
|
+
|
87
|
+
cli.deploy
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "when on feature branch" do
|
93
|
+
before do
|
94
|
+
allow(cli).to receive(:options).and_return({})
|
95
|
+
end
|
96
|
+
|
97
|
+
context "with fast-forward merge possible" do
|
98
|
+
it "fetches master, pushes branch, runs CI, merges to master, and deploys" do
|
99
|
+
expect(cli).to receive(:run!).with("git fetch origin master:master")
|
100
|
+
expect(cli).to receive(:run!).with("git push -f origin feature-branch:feature-branch")
|
101
|
+
expect(cli).to receive(:invoke).with(:ci, ["feature-branch"], {})
|
102
|
+
expect(cli).to receive(:run!).with("git push origin feature-branch:master")
|
103
|
+
expect(cli).to receive(:run!).with("git fetch origin master:master")
|
104
|
+
expect(production_server).to receive(:run!).with("git pull origin master && bin/setup")
|
105
|
+
|
106
|
+
cli.deploy
|
107
|
+
end
|
108
|
+
|
109
|
+
it "deletes the feature branch after successful deploy" do
|
110
|
+
expect(cli).to receive(:puts).with("Deleting branch: feature-branch")
|
111
|
+
expect(cli).to receive(:run!).with("git push --delete origin feature-branch")
|
112
|
+
expect(cli).to receive(:run!).with("git checkout master")
|
113
|
+
expect(cli).to receive(:run!).with("git branch -D feature-branch")
|
114
|
+
|
115
|
+
cli.deploy
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "when rebase is needed" do
|
120
|
+
it "attempts rebase before proceeding" do
|
121
|
+
allow(Bard::Git).to receive(:fast_forward_merge?).and_return(false)
|
122
|
+
|
123
|
+
expect(cli).to receive(:puts).with("The master branch has advanced. Attempting rebase...")
|
124
|
+
expect(cli).to receive(:run!).with("git rebase origin/master")
|
125
|
+
expect(cli).to receive(:run!).with("git push -f origin feature-branch:feature-branch")
|
126
|
+
|
127
|
+
cli.deploy
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context "with github remote" do
|
133
|
+
it "pushes to github remote" do
|
134
|
+
allow(cli).to receive(:`).with("git remote").and_return("origin\ngithub\n")
|
135
|
+
|
136
|
+
expect(cli).to receive(:run!).with("git push github")
|
137
|
+
|
138
|
+
cli.deploy
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "with clone option" do
|
143
|
+
it "clones repository and sets up application" do
|
144
|
+
allow(cli).to receive(:options).and_return({ clone: true })
|
145
|
+
|
146
|
+
expect(production_server).to receive(:run!).with("git clone git@github.com:botandrosedesign/test_project /var/www/test_project", home: true)
|
147
|
+
expect(cli).to receive(:invoke).with(:master_key, [], from: "local", to: :production)
|
148
|
+
expect(production_server).to receive(:run!).with("bin/setup && bard setup")
|
149
|
+
|
150
|
+
cli.deploy
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context "with github pages" do
|
155
|
+
it "deploys to github pages" do
|
156
|
+
allow(production_server).to receive(:github_pages).and_return(true)
|
157
|
+
github_pages = double("github_pages")
|
158
|
+
allow(Bard::GithubPages).to receive(:new).and_return(github_pages)
|
159
|
+
|
160
|
+
expect(github_pages).to receive(:deploy).with(production_server)
|
161
|
+
|
162
|
+
cli.deploy
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "with custom deployment target" do
|
167
|
+
let(:staging_server) { double("staging", run!: true, github_pages: false) }
|
168
|
+
|
169
|
+
before do
|
170
|
+
allow(config).to receive(:[]).with(:staging).and_return(staging_server)
|
171
|
+
end
|
172
|
+
|
173
|
+
it "deploys to specified target" do
|
174
|
+
expect(staging_server).to receive(:run!).with("git pull origin master && bin/setup")
|
175
|
+
expect(cli).to receive(:ping).with(:staging)
|
176
|
+
|
177
|
+
cli.deploy(:staging)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context "when command fails" do
|
182
|
+
it "handles errors gracefully" do
|
183
|
+
allow(cli).to receive(:run!).and_raise(Bard::Command::Error.new("Git push failed"))
|
184
|
+
|
185
|
+
expect(cli).to receive(:puts).with(/Running command failed/)
|
186
|
+
expect(cli).to receive(:exit).with(1)
|
187
|
+
|
188
|
+
cli.deploy
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context "with local-ci option" do
|
193
|
+
it "passes local-ci option to CI invocation" do
|
194
|
+
allow(cli).to receive(:options).and_return({ "local-ci" => true })
|
195
|
+
|
196
|
+
expect(cli).to receive(:invoke).with(:ci, ["feature-branch"], { "local-ci" => true })
|
197
|
+
|
198
|
+
cli.deploy
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "bard/cli"
|
3
|
+
require "bard/cli/hurt"
|
4
|
+
require "thor"
|
5
|
+
|
6
|
+
class TestHurtCLI < Thor
|
7
|
+
include Bard::CLI::Hurt
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Bard::CLI::Hurt do
|
11
|
+
let(:cli) { TestHurtCLI.new }
|
12
|
+
|
13
|
+
before do
|
14
|
+
allow(cli).to receive(:puts)
|
15
|
+
allow(cli).to receive(:system)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#hurt" do
|
19
|
+
it "should have a hurt command" do
|
20
|
+
expect(cli).to respond_to(:hurt)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "bard/cli"
|
3
|
+
require "bard/cli/install"
|
4
|
+
require "thor"
|
5
|
+
|
6
|
+
class TestInstallCLI < Thor
|
7
|
+
include Bard::CLI::Install
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Bard::CLI::Install do
|
11
|
+
let(:cli) { TestInstallCLI.new }
|
12
|
+
|
13
|
+
describe "#install" do
|
14
|
+
it "should have an install command" do
|
15
|
+
expect(cli).to respond_to(:install)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should copy install files to bin directory" do
|
19
|
+
expect(cli).to receive(:system).with(/cp -R .*install_files\/\* bin\//)
|
20
|
+
expect(cli).to receive(:system).with(/cp -R .*install_files\/\.github \.\//)
|
21
|
+
|
22
|
+
cli.install
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|