bard 2.0.0.beta → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +6 -1
- data/CLAUDE.md +76 -0
- data/MIGRATION_GUIDE.md +24 -9
- data/PLUGINS.md +99 -0
- data/README.md +14 -6
- data/Rakefile +3 -1
- data/bard.gemspec +2 -1
- data/cucumber.yml +1 -0
- data/features/ci.feature +63 -0
- data/features/data.feature +13 -0
- data/features/deploy.feature +14 -0
- data/features/deploy_git_workflow.feature +89 -0
- data/features/run.feature +14 -0
- data/features/step_definitions/bard_steps.rb +136 -0
- data/features/support/bard-coverage +16 -0
- data/features/support/env.rb +14 -39
- data/features/support/test_server.rb +216 -0
- data/lib/bard/cli.rb +14 -31
- data/lib/bard/command.rb +10 -69
- data/lib/bard/config.rb +40 -183
- data/lib/bard/copy.rb +28 -103
- data/lib/bard/plugins/data.rb +56 -0
- data/lib/bard/{ci → plugins/deploy/ci}/github_actions.rb +3 -4
- data/lib/bard/plugins/deploy/ci/jenkins.rb +176 -0
- data/lib/bard/{ci → plugins/deploy/ci}/local.rb +7 -7
- data/lib/bard/{ci → plugins/deploy/ci}/runner.rb +38 -4
- data/lib/bard/plugins/deploy/ci.rb +38 -0
- data/lib/bard/plugins/deploy/ssh_strategy.rb +27 -0
- data/lib/bard/{deploy_strategy.rb → plugins/deploy/strategy.rb} +1 -1
- data/lib/bard/plugins/deploy.rb +240 -0
- data/lib/bard/{git.rb → plugins/git.rb} +6 -3
- data/lib/bard/{github.rb → plugins/github.rb} +4 -6
- data/lib/bard/{deploy_strategy/github_pages.rb → plugins/github_pages/strategy.rb} +13 -6
- data/lib/bard/plugins/github_pages.rb +30 -0
- data/lib/bard/plugins/hurt.rb +13 -0
- data/{install_files → lib/bard/plugins/install}/.github/dependabot.yml +2 -1
- data/{install_files → lib/bard/plugins/install}/.github/workflows/cache-ci.yml +1 -1
- data/{install_files → lib/bard/plugins/install}/.github/workflows/ci.yml +2 -2
- data/lib/bard/plugins/install.rb +9 -0
- data/lib/bard/plugins/open.rb +20 -0
- data/lib/bard/{ping.rb → plugins/ping/check.rb} +4 -4
- data/lib/bard/plugins/ping/target_methods.rb +23 -0
- data/lib/bard/plugins/ping.rb +10 -0
- data/lib/bard/plugins/run.rb +19 -0
- data/lib/bard/plugins/setup.rb +54 -0
- data/lib/bard/plugins/ssh/connection.rb +75 -0
- data/lib/bard/plugins/ssh/copy.rb +95 -0
- data/lib/bard/{ssh_server.rb → plugins/ssh/server.rb} +17 -42
- data/lib/bard/plugins/ssh/target_methods.rb +20 -0
- data/lib/bard/plugins/ssh.rb +10 -0
- data/lib/bard/plugins/url/target_methods.rb +23 -0
- data/lib/bard/plugins/url.rb +1 -0
- data/lib/bard/plugins/vim.rb +6 -0
- data/lib/bard/retryable.rb +25 -0
- data/lib/bard/secrets.rb +10 -0
- data/lib/bard/target.rb +27 -185
- data/lib/bard/version.rb +1 -1
- data/lib/bard.rb +1 -3
- data/spec/acceptance/docker/Dockerfile +3 -2
- data/spec/bard/capability_spec.rb +8 -50
- data/spec/bard/ci/github_actions_spec.rb +117 -14
- data/spec/bard/ci/jenkins_spec.rb +139 -0
- data/spec/bard/ci/runner_spec.rb +61 -0
- data/spec/bard/ci_spec.rb +1 -1
- data/spec/bard/cli/ci_spec.rb +34 -27
- data/spec/bard/cli/data_spec.rb +7 -26
- data/spec/bard/cli/deploy_spec.rb +87 -46
- data/spec/bard/cli/hurt_spec.rb +3 -9
- data/spec/bard/cli/install_spec.rb +5 -11
- data/spec/bard/cli/master_key_spec.rb +5 -19
- data/spec/bard/cli/open_spec.rb +14 -30
- data/spec/bard/cli/ping_spec.rb +8 -23
- data/spec/bard/cli/run_spec.rb +27 -21
- data/spec/bard/cli/setup_spec.rb +10 -27
- data/spec/bard/cli/ssh_spec.rb +10 -25
- data/spec/bard/cli/stage_spec.rb +28 -23
- data/spec/bard/cli/vim_spec.rb +3 -9
- data/spec/bard/command_spec.rb +1 -8
- data/spec/bard/config_spec.rb +78 -98
- data/spec/bard/copy_spec.rb +54 -18
- data/spec/bard/deploy_strategy/ssh_spec.rb +65 -7
- data/spec/bard/deploy_strategy_spec.rb +1 -1
- data/spec/bard/dynamic_dsl_spec.rb +18 -98
- data/spec/bard/git_spec.rb +9 -5
- data/spec/bard/github_spec.rb +2 -2
- data/spec/bard/ping_spec.rb +5 -5
- data/spec/bard/ssh_copy_spec.rb +44 -0
- data/spec/bard/ssh_server_spec.rb +8 -101
- data/spec/bard/target_spec.rb +66 -109
- data/spec/spec_helper.rb +6 -1
- metadata +79 -143
- data/README.rdoc +0 -15
- data/features/bard_check.feature +0 -94
- data/features/bard_deploy.feature +0 -18
- data/features/bard_pull.feature +0 -112
- data/features/bard_push.feature +0 -112
- data/features/podman_testcontainers.feature +0 -16
- data/features/step_definitions/check_steps.rb +0 -47
- data/features/step_definitions/git_steps.rb +0 -73
- data/features/step_definitions/global_steps.rb +0 -56
- data/features/step_definitions/podman_steps.rb +0 -23
- data/features/step_definitions/rails_steps.rb +0 -44
- data/features/step_definitions/submodule_steps.rb +0 -110
- data/features/support/grit_ext.rb +0 -13
- data/features/support/io.rb +0 -32
- data/features/support/podman.rb +0 -153
- data/lib/bard/ci/jenkins.rb +0 -105
- data/lib/bard/ci/retryable.rb +0 -27
- data/lib/bard/ci.rb +0 -50
- data/lib/bard/cli/ci.rb +0 -66
- data/lib/bard/cli/command.rb +0 -26
- data/lib/bard/cli/data.rb +0 -45
- data/lib/bard/cli/deploy.rb +0 -85
- data/lib/bard/cli/hurt.rb +0 -20
- data/lib/bard/cli/install.rb +0 -16
- data/lib/bard/cli/master_key.rb +0 -17
- data/lib/bard/cli/new.rb +0 -101
- data/lib/bard/cli/new_rails_template.rb +0 -197
- data/lib/bard/cli/open.rb +0 -22
- data/lib/bard/cli/ping.rb +0 -18
- data/lib/bard/cli/provision.rb +0 -34
- data/lib/bard/cli/run.rb +0 -24
- data/lib/bard/cli/setup.rb +0 -56
- data/lib/bard/cli/ssh.rb +0 -14
- data/lib/bard/cli/stage.rb +0 -27
- data/lib/bard/cli/vim.rb +0 -13
- data/lib/bard/default_config.rb +0 -35
- data/lib/bard/deploy_strategy/ssh.rb +0 -19
- data/lib/bard/github_pages.rb +0 -134
- data/lib/bard/provision/app.rb +0 -10
- data/lib/bard/provision/apt.rb +0 -16
- data/lib/bard/provision/authorizedkeys.rb +0 -25
- data/lib/bard/provision/data.rb +0 -27
- data/lib/bard/provision/deploy.rb +0 -10
- data/lib/bard/provision/http.rb +0 -16
- data/lib/bard/provision/logrotation.rb +0 -30
- data/lib/bard/provision/masterkey.rb +0 -18
- data/lib/bard/provision/mysql.rb +0 -22
- data/lib/bard/provision/passenger.rb +0 -37
- data/lib/bard/provision/repo.rb +0 -72
- data/lib/bard/provision/rvm.rb +0 -22
- data/lib/bard/provision/ssh.rb +0 -72
- data/lib/bard/provision/swapfile.rb +0 -21
- data/lib/bard/provision/user.rb +0 -42
- data/lib/bard/provision.rb +0 -16
- data/lib/bard/server.rb +0 -117
- data/spec/bard/cli/command_spec.rb +0 -50
- data/spec/bard/cli/new_spec.rb +0 -73
- data/spec/bard/cli/provision_spec.rb +0 -42
- data/spec/bard/github_pages_spec.rb +0 -143
- data/spec/bard/provision/app_spec.rb +0 -33
- data/spec/bard/provision/apt_spec.rb +0 -39
- data/spec/bard/provision/authorizedkeys_spec.rb +0 -40
- data/spec/bard/provision/data_spec.rb +0 -54
- data/spec/bard/provision/deploy_spec.rb +0 -33
- data/spec/bard/provision/http_spec.rb +0 -57
- data/spec/bard/provision/logrotation_spec.rb +0 -34
- data/spec/bard/provision/masterkey_spec.rb +0 -63
- data/spec/bard/provision/mysql_spec.rb +0 -55
- data/spec/bard/provision/passenger_spec.rb +0 -81
- data/spec/bard/provision/repo_spec.rb +0 -208
- data/spec/bard/provision/rvm_spec.rb +0 -49
- data/spec/bard/provision/ssh_spec.rb +0 -229
- data/spec/bard/provision/swapfile_spec.rb +0 -32
- data/spec/bard/provision/user_spec.rb +0 -103
- data/spec/bard/provision_spec.rb +0 -28
- data/spec/bard/server_spec.rb +0 -127
- /data/lib/bard/{ci → plugins/deploy/ci}/state.rb +0 -0
- /data/{install_files → lib/bard/plugins/install}/apt_dependencies.rb +0 -0
- /data/{install_files → lib/bard/plugins/install}/ci +0 -0
- /data/{install_files → lib/bard/plugins/install}/setup +0 -0
- /data/{install_files → lib/bard/plugins/install}/specified_bundler.rb +0 -0
- /data/{install_files → lib/bard/plugins/install}/specified_ruby.rb +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
root = File.expand_path("../../..", __FILE__)
|
|
3
|
+
|
|
4
|
+
require "simplecov"
|
|
5
|
+
SimpleCov.root(root)
|
|
6
|
+
SimpleCov.start do
|
|
7
|
+
command_name "Cucumber (subprocess #{$$})"
|
|
8
|
+
track_files "lib/**/*.rb"
|
|
9
|
+
add_filter "spec/"
|
|
10
|
+
add_filter "features/"
|
|
11
|
+
coverage_dir "#{root}/coverage"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
$LOAD_PATH.unshift("#{root}/lib")
|
|
15
|
+
require "bard/cli"
|
|
16
|
+
Bard::CLI.start ARGV
|
data/features/support/env.rb
CHANGED
|
@@ -1,47 +1,22 @@
|
|
|
1
|
+
require "simplecov"
|
|
2
|
+
SimpleCov.start do
|
|
3
|
+
command_name "Cucumber"
|
|
4
|
+
track_files "lib/**/*.rb"
|
|
5
|
+
add_filter "spec/"
|
|
6
|
+
add_filter "features/"
|
|
7
|
+
end
|
|
8
|
+
|
|
1
9
|
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
|
|
2
|
-
require
|
|
3
|
-
require '
|
|
4
|
-
require '
|
|
5
|
-
gem 'sqlite3-ruby'
|
|
10
|
+
require "bard"
|
|
11
|
+
require 'rspec/expectations'
|
|
12
|
+
require 'fileutils'
|
|
6
13
|
|
|
7
|
-
ENV["PATH"]
|
|
14
|
+
ENV["PATH"] = "#{File.dirname(File.expand_path(__FILE__))}:#{ENV['PATH']}"
|
|
8
15
|
ENV["GIT_DIR"] = nil
|
|
9
16
|
ENV["GIT_WORK_TREE"] = nil
|
|
10
17
|
ENV["GIT_INDEX_FILE"] = nil
|
|
11
18
|
|
|
12
19
|
ROOT = File.expand_path(File.dirname(__FILE__) + '/../..')
|
|
13
20
|
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
FileUtils.rm_rf "tmp"
|
|
17
|
-
tmp_dir = "/dev/shm/bard_testing_tmp"
|
|
18
|
-
FileUtils.rm_rf tmp_dir
|
|
19
|
-
FileUtils.mkdir tmp_dir
|
|
20
|
-
`ln -s #{tmp_dir} tmp`
|
|
21
|
-
else
|
|
22
|
-
FileUtils.rm_rf "tmp"
|
|
23
|
-
FileUtils.mkdir "tmp"
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
Dir.chdir 'tmp' do
|
|
27
|
-
`git clone --mirror --recursive #{ROOT}/fixtures/repo origin.git`
|
|
28
|
-
|
|
29
|
-
`git clone --bare --recursive origin.git submodule_a.git`
|
|
30
|
-
`git clone --bare --recursive origin.git submodule_b.git`
|
|
31
|
-
%w(development_a development_b staging production).each do |env|
|
|
32
|
-
`git clone --recursive origin.git #{env}`
|
|
33
|
-
Dir.chdir env do
|
|
34
|
-
FileUtils.cp "config/database.sample.yml", "config/database.yml"
|
|
35
|
-
`grb track master`
|
|
36
|
-
`git checkout master`
|
|
37
|
-
unless env == "production"
|
|
38
|
-
`grb track integration`
|
|
39
|
-
`git checkout integration`
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
FileUtils.mkdir "fixtures"
|
|
44
|
-
Dir.foreach "." do |file|
|
|
45
|
-
FileUtils.mv(file, "fixtures/") unless %w(fixtures . ..).include? file
|
|
46
|
-
end
|
|
47
|
-
end
|
|
21
|
+
# Ensure tmp directory exists
|
|
22
|
+
FileUtils.mkdir_p(File.join(ROOT, "tmp"))
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
require "fileutils"
|
|
2
|
+
require "open3"
|
|
3
|
+
require "tmpdir"
|
|
4
|
+
require "docker-api"
|
|
5
|
+
|
|
6
|
+
module TestServerWorld
|
|
7
|
+
class << self
|
|
8
|
+
attr_accessor :server_available, :image_built
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class PrerequisiteError < StandardError; end
|
|
12
|
+
|
|
13
|
+
def ensure_server_available
|
|
14
|
+
return if TestServerWorld.server_available
|
|
15
|
+
|
|
16
|
+
unless system("command -v podman >/dev/null 2>&1")
|
|
17
|
+
raise PrerequisiteError, "podman is not installed"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
configure_container_socket
|
|
21
|
+
build_test_image
|
|
22
|
+
FileUtils.chmod(0o600, ssh_key_path)
|
|
23
|
+
|
|
24
|
+
TestServerWorld.server_available = true
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def configure_container_socket
|
|
28
|
+
if ENV["DOCKER_HOST"]
|
|
29
|
+
Docker.url = ENV["DOCKER_HOST"]
|
|
30
|
+
return
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
socket_path = "/run/user/#{Process.uid}/podman/podman.sock"
|
|
34
|
+
unless File.exist?(socket_path)
|
|
35
|
+
system("systemctl --user start podman.socket 2>/dev/null")
|
|
36
|
+
sleep 2
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
unless File.exist?(socket_path)
|
|
40
|
+
raise PrerequisiteError, "Podman socket not available"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
ENV["DOCKER_HOST"] = "unix://#{socket_path}"
|
|
44
|
+
Docker.url = ENV["DOCKER_HOST"]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def build_test_image
|
|
48
|
+
return if TestServerWorld.image_built
|
|
49
|
+
|
|
50
|
+
# Check if image already exists (e.g., pre-built in CI)
|
|
51
|
+
if image_exists?("bard-test-server")
|
|
52
|
+
TestServerWorld.image_built = true
|
|
53
|
+
return
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
system("podman pull ubuntu:24.04 >/dev/null 2>&1")
|
|
57
|
+
|
|
58
|
+
docker_dir = File.join(ROOT, "spec/acceptance/docker")
|
|
59
|
+
unless system("podman build -t bard-test-server -f #{docker_dir}/Dockerfile #{docker_dir} 2>&1")
|
|
60
|
+
raise PrerequisiteError, "Failed to build test image"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
TestServerWorld.image_built = true
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def image_exists?(name)
|
|
67
|
+
Docker::Image.get(name)
|
|
68
|
+
true
|
|
69
|
+
rescue Docker::Error::NotFoundError
|
|
70
|
+
false
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def start_test_server
|
|
74
|
+
ensure_server_available
|
|
75
|
+
|
|
76
|
+
@container = Docker::Container.create(
|
|
77
|
+
"Image" => "localhost/bard-test-server:latest",
|
|
78
|
+
"ExposedPorts" => { "22/tcp" => {} },
|
|
79
|
+
"HostConfig" => {
|
|
80
|
+
"PortBindings" => { "22/tcp" => [{ "HostPort" => "" }] },
|
|
81
|
+
"PublishAllPorts" => true
|
|
82
|
+
}
|
|
83
|
+
)
|
|
84
|
+
@container.start
|
|
85
|
+
@container.refresh!
|
|
86
|
+
|
|
87
|
+
@ssh_port = @container.info["NetworkSettings"]["Ports"]["22/tcp"].first["HostPort"].to_i
|
|
88
|
+
|
|
89
|
+
wait_for_ssh
|
|
90
|
+
setup_test_directory
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def wait_for_ssh
|
|
94
|
+
30.times do
|
|
95
|
+
return if system(
|
|
96
|
+
"ssh", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null",
|
|
97
|
+
"-o", "ConnectTimeout=1", "-p", @ssh_port.to_s, "-i", ssh_key_path,
|
|
98
|
+
"deploy@localhost", "true",
|
|
99
|
+
out: File::NULL, err: File::NULL
|
|
100
|
+
)
|
|
101
|
+
sleep 0.5
|
|
102
|
+
end
|
|
103
|
+
raise PrerequisiteError, "SSH not ready"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def setup_test_directory
|
|
107
|
+
# Set up git repos on the remote container
|
|
108
|
+
run_ssh "git config --global user.email 'test@example.com'"
|
|
109
|
+
run_ssh "git config --global user.name 'Test User'"
|
|
110
|
+
run_ssh "git config --global init.defaultBranch master"
|
|
111
|
+
run_ssh "mkdir -p ~/repos/testproject.git"
|
|
112
|
+
run_ssh "cd ~/repos/testproject.git && git init --bare"
|
|
113
|
+
run_ssh "git clone ~/repos/testproject.git ~/testproject"
|
|
114
|
+
run_ssh "mkdir -p ~/testproject/bin ~/testproject/db"
|
|
115
|
+
|
|
116
|
+
# bin/setup script
|
|
117
|
+
run_ssh "echo '#!/bin/bash' > ~/testproject/bin/setup"
|
|
118
|
+
run_ssh "echo 'echo Setup complete' >> ~/testproject/bin/setup"
|
|
119
|
+
run_ssh "chmod +x ~/testproject/bin/setup"
|
|
120
|
+
|
|
121
|
+
# bin/rake script for db:dump and db:load
|
|
122
|
+
run_ssh <<~'SETUP'
|
|
123
|
+
cat > ~/testproject/bin/rake << 'SCRIPT'
|
|
124
|
+
#!/bin/bash
|
|
125
|
+
case "$1" in
|
|
126
|
+
db:dump)
|
|
127
|
+
echo "production data" | gzip > db/data.sql.gz
|
|
128
|
+
;;
|
|
129
|
+
db:load)
|
|
130
|
+
gunzip -c db/data.sql.gz > /dev/null
|
|
131
|
+
echo "Data loaded"
|
|
132
|
+
;;
|
|
133
|
+
esac
|
|
134
|
+
SCRIPT
|
|
135
|
+
SETUP
|
|
136
|
+
run_ssh "chmod +x ~/testproject/bin/rake"
|
|
137
|
+
run_ssh "cd ~/testproject && git add . && git commit -m 'Initial commit'"
|
|
138
|
+
run_ssh "cd ~/testproject && git push origin master"
|
|
139
|
+
|
|
140
|
+
# Set up local git repo in isolated temp directory
|
|
141
|
+
setup_local_git_repo
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def setup_local_git_repo
|
|
145
|
+
@test_dir = Dir.mktmpdir("bard_test")
|
|
146
|
+
@ssh_command = "ssh -i #{ssh_key_path} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
|
|
147
|
+
|
|
148
|
+
Dir.chdir(@test_dir) do
|
|
149
|
+
# Clone directly into the temp directory (pass SSH command via env, not global ENV)
|
|
150
|
+
ssh_url = "ssh://deploy@localhost:#{@ssh_port}/home/deploy/repos/testproject.git"
|
|
151
|
+
system({ "GIT_SSH_COMMAND" => @ssh_command }, "git clone #{ssh_url} .", out: File::NULL, err: File::NULL)
|
|
152
|
+
|
|
153
|
+
# Configure git settings locally in this repo only
|
|
154
|
+
system("git config user.email 'test@example.com'", out: File::NULL, err: File::NULL)
|
|
155
|
+
system("git config user.name 'Test User'", out: File::NULL, err: File::NULL)
|
|
156
|
+
system("git config core.sshCommand '#{@ssh_command}'", out: File::NULL, err: File::NULL)
|
|
157
|
+
|
|
158
|
+
# Ensure db directory exists locally
|
|
159
|
+
FileUtils.mkdir_p("db")
|
|
160
|
+
|
|
161
|
+
# Write bard config in the test directory
|
|
162
|
+
File.write("bard.rb", <<~RUBY)
|
|
163
|
+
target :production do
|
|
164
|
+
ssh "deploy@localhost:#{@ssh_port}",
|
|
165
|
+
path: "testproject",
|
|
166
|
+
ssh_key: "#{ssh_key_path}"
|
|
167
|
+
ping false
|
|
168
|
+
end
|
|
169
|
+
RUBY
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def run_ssh(command)
|
|
174
|
+
stdout, status = Open3.capture2e(
|
|
175
|
+
"ssh", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null",
|
|
176
|
+
"-p", @ssh_port.to_s, "-i", ssh_key_path,
|
|
177
|
+
"deploy@localhost", command
|
|
178
|
+
)
|
|
179
|
+
unless status.success?
|
|
180
|
+
raise PrerequisiteError, "SSH command failed: #{command}\nOutput: #{stdout}"
|
|
181
|
+
end
|
|
182
|
+
true
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def run_bard(command)
|
|
186
|
+
Dir.chdir(@test_dir) do
|
|
187
|
+
bard_coverage = File.join(ROOT, "features/support/bard-coverage")
|
|
188
|
+
@stdout, @status = Open3.capture2e("#{bard_coverage} #{command}")
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def ssh_key_path
|
|
193
|
+
File.join(ROOT, "spec/acceptance/docker/test_key")
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def stop_test_server
|
|
197
|
+
return unless @container
|
|
198
|
+
@container.stop rescue nil
|
|
199
|
+
@container.delete(force: true) rescue nil
|
|
200
|
+
ensure
|
|
201
|
+
@container = nil
|
|
202
|
+
@ssh_port = nil
|
|
203
|
+
FileUtils.rm_rf(@test_dir) if @test_dir
|
|
204
|
+
@test_dir = nil
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
World(TestServerWorld)
|
|
209
|
+
|
|
210
|
+
Before("@server") do
|
|
211
|
+
start_test_server
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
After("@server") do
|
|
215
|
+
stop_test_server
|
|
216
|
+
end
|
data/lib/bard/cli.rb
CHANGED
|
@@ -1,46 +1,27 @@
|
|
|
1
1
|
# this file gets loaded in the CLI context, not the Rails boot context
|
|
2
2
|
|
|
3
3
|
require "thor"
|
|
4
|
+
require "bard/version"
|
|
4
5
|
require "bard/config"
|
|
5
6
|
require "bard/command"
|
|
6
|
-
require "term/ansicolor"
|
|
7
7
|
|
|
8
8
|
module Bard
|
|
9
9
|
class CLI < Thor
|
|
10
|
-
include Term::ANSIColor
|
|
11
|
-
|
|
12
10
|
class_option :verbose, type: :boolean, aliases: :v
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
ci: "CI",
|
|
19
|
-
master_key: "MasterKey",
|
|
20
|
-
setup: "Setup",
|
|
21
|
-
run: "Run",
|
|
22
|
-
open: "Open",
|
|
23
|
-
ssh: "SSH",
|
|
24
|
-
install: "Install",
|
|
25
|
-
ping: "Ping",
|
|
26
|
-
hurt: "Hurt",
|
|
27
|
-
vim: "Vim",
|
|
28
|
-
}.each do |command, klass|
|
|
29
|
-
require "bard/cli/#{command}"
|
|
30
|
-
include const_get(klass)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
{
|
|
34
|
-
provision: "Provision",
|
|
35
|
-
new: "New",
|
|
36
|
-
}.each do |command, klass|
|
|
37
|
-
require "bard/cli/#{command}"
|
|
38
|
-
const_get(klass).setup(self)
|
|
12
|
+
map "--version" => :version
|
|
13
|
+
desc "version", "Display version"
|
|
14
|
+
def version
|
|
15
|
+
puts Bard::VERSION
|
|
39
16
|
end
|
|
40
17
|
|
|
41
18
|
def self.exit_on_failure? = true
|
|
42
19
|
|
|
43
20
|
no_commands do
|
|
21
|
+
def red(text) = "\e[31m#{text}\e[0m"
|
|
22
|
+
def yellow(text) = "\e[33m#{text}\e[0m"
|
|
23
|
+
def green(text) = "\e[32m#{text}\e[0m"
|
|
24
|
+
|
|
44
25
|
def run!(...)
|
|
45
26
|
Bard::Command.run!(...)
|
|
46
27
|
rescue Bard::Command::Error => e
|
|
@@ -49,13 +30,15 @@ module Bard
|
|
|
49
30
|
end
|
|
50
31
|
|
|
51
32
|
def config
|
|
52
|
-
@config ||= Bard::Config.
|
|
33
|
+
@config ||= Bard::Config.current
|
|
53
34
|
end
|
|
54
35
|
|
|
55
36
|
def project_name
|
|
56
|
-
|
|
37
|
+
config.project_name
|
|
57
38
|
end
|
|
58
39
|
end
|
|
40
|
+
|
|
41
|
+
# load plugins from bard and other gems
|
|
42
|
+
Gem.find_files("bard/plugins/*.rb").sort.each { |path| require path }
|
|
59
43
|
end
|
|
60
44
|
end
|
|
61
|
-
|
data/lib/bard/command.rb
CHANGED
|
@@ -1,42 +1,20 @@
|
|
|
1
1
|
require "open3"
|
|
2
2
|
|
|
3
3
|
module Bard
|
|
4
|
-
|
|
4
|
+
module Command
|
|
5
5
|
class Error < RuntimeError; end
|
|
6
6
|
|
|
7
|
-
def self.run!
|
|
8
|
-
|
|
7
|
+
def self.run!(command, verbose: false, quiet: false)
|
|
8
|
+
result = run(command, verbose:, quiet:)
|
|
9
|
+
raise Error.new(command) unless result
|
|
10
|
+
result
|
|
9
11
|
end
|
|
10
12
|
|
|
11
|
-
def self.run
|
|
12
|
-
new(command, on, home).run verbose:, quiet:
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def self.exec! command, on: :local, home: false
|
|
16
|
-
new(command, on, home).exec!
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def run! verbose: false, quiet: false
|
|
20
|
-
if !run(verbose:, quiet:)
|
|
21
|
-
raise Error.new(full_command)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def run verbose: false, quiet: false
|
|
26
|
-
# no-op if server doesn't really exist
|
|
27
|
-
if on.to_sym != :local
|
|
28
|
-
# Check for new Target architecture
|
|
29
|
-
if on.respond_to?(:server) && on.server.nil?
|
|
30
|
-
return true
|
|
31
|
-
# Check for old Server architecture
|
|
32
|
-
elsif on.respond_to?(:ssh) && on.ssh == false
|
|
33
|
-
return true
|
|
34
|
-
end
|
|
35
|
-
end
|
|
13
|
+
def self.run(command, verbose: false, quiet: false)
|
|
36
14
|
if verbose
|
|
37
|
-
system
|
|
15
|
+
system command
|
|
38
16
|
else
|
|
39
|
-
stdout, stderr, status = Open3.capture3(
|
|
17
|
+
stdout, stderr, status = Open3.capture3(command)
|
|
40
18
|
failed = status.to_i.nonzero?
|
|
41
19
|
if failed && !quiet
|
|
42
20
|
$stdout.puts stdout
|
|
@@ -46,45 +24,8 @@ module Bard
|
|
|
46
24
|
end
|
|
47
25
|
end
|
|
48
26
|
|
|
49
|
-
def exec!
|
|
50
|
-
exec
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
private
|
|
54
|
-
|
|
55
|
-
def full_command quiet: false
|
|
56
|
-
if on.to_sym == :local
|
|
57
|
-
command
|
|
58
|
-
else
|
|
59
|
-
remote_command quiet: false
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def remote_command quiet: false
|
|
64
|
-
# Support both new Target (with server attribute) and old Server architecture
|
|
65
|
-
ssh_server = on.respond_to?(:server) ? on.server : on
|
|
66
|
-
|
|
67
|
-
cmd = command
|
|
68
|
-
if ssh_server.env
|
|
69
|
-
cmd = "#{ssh_server.env} #{command}"
|
|
70
|
-
end
|
|
71
|
-
unless home
|
|
72
|
-
path = on.respond_to?(:path) ? on.path : ssh_server.path
|
|
73
|
-
cmd = "cd #{path} && #{cmd}" if path
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
ssh_key = ssh_server.ssh_key ? "-i #{ssh_server.ssh_key} " : ""
|
|
77
|
-
ssh_uri = ssh_server.respond_to?(:ssh_uri) ? ssh_server.ssh_uri : ssh_server.ssh_uri(:ssh)
|
|
78
|
-
|
|
79
|
-
cmd = "ssh -tt #{ssh_key} #{ssh_uri} '#{cmd}'"
|
|
80
|
-
|
|
81
|
-
if ssh_server.gateway
|
|
82
|
-
gateway_uri = ssh_server.respond_to?(:ssh_uri) ? ssh_server.gateway : ssh_server.ssh_uri(:gateway)
|
|
83
|
-
cmd = "ssh -tt #{gateway_uri} \"#{cmd}\""
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
cmd += " 2>&1" if quiet
|
|
87
|
-
cmd
|
|
27
|
+
def self.exec!(command)
|
|
28
|
+
Kernel.exec command
|
|
88
29
|
end
|
|
89
30
|
end
|
|
90
31
|
end
|