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
data/features/bard_push.feature
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
Feature: bard push
|
|
2
|
-
Background:
|
|
3
|
-
Given a shared rails project
|
|
4
|
-
|
|
5
|
-
Scenario: Uploading local changes onto the remote integration branch
|
|
6
|
-
Given a commit
|
|
7
|
-
When I type "bard push"
|
|
8
|
-
And on staging, I type "bard stage"
|
|
9
|
-
Then the "integration" branch should match the "staging:integration" branch
|
|
10
|
-
|
|
11
|
-
Scenario: Uploading local changes onto a remote topic branch
|
|
12
|
-
Given a commit on the "topic" branch
|
|
13
|
-
And I am on the "topic" branch
|
|
14
|
-
When I type "bard push"
|
|
15
|
-
Then the "topic" branch should match the "origin/topic" branch
|
|
16
|
-
|
|
17
|
-
Scenario: Pushing a change that includes a migration
|
|
18
|
-
Given on staging, a staging database
|
|
19
|
-
And a commit with a new migration
|
|
20
|
-
When I type "bard push"
|
|
21
|
-
And on staging, I type "bard stage"
|
|
22
|
-
Then on staging, the staging database should include that migration
|
|
23
|
-
|
|
24
|
-
Scenario: Pushing a change that includes a gem dependency change
|
|
25
|
-
Given the test gem is not installed
|
|
26
|
-
And a commit that adds the test gem as a dependency
|
|
27
|
-
When I type "bard push"
|
|
28
|
-
And on staging, I type "bard stage"
|
|
29
|
-
Then on staging, the test gem should be installed
|
|
30
|
-
|
|
31
|
-
Scenario: Pushing a change should advance the staging HEAD and restart the staging rails server
|
|
32
|
-
Given a commit
|
|
33
|
-
When I type "bard push"
|
|
34
|
-
And on staging, I type "bard stage"
|
|
35
|
-
And the "integration" branch should match the "staging:integration" branch
|
|
36
|
-
Then on staging, passenger should have been restarted
|
|
37
|
-
|
|
38
|
-
Scenario: Pushing a change that includes a submodule addition
|
|
39
|
-
Given a commit with a new submodule
|
|
40
|
-
When I type "bard push"
|
|
41
|
-
And on staging, I type "bard stage"
|
|
42
|
-
Then on staging, there should be one new submodule
|
|
43
|
-
And the submodule branch should match the submodule origin branch
|
|
44
|
-
And on staging, the submodule working directory should be clean
|
|
45
|
-
|
|
46
|
-
Scenario: Pushing a change that includes a submodule update
|
|
47
|
-
Given a submodule
|
|
48
|
-
And a commit with a submodule update
|
|
49
|
-
When I type "bard push"
|
|
50
|
-
And on staging, I type "bard stage"
|
|
51
|
-
Then the submodule branch should match the submodule origin branch
|
|
52
|
-
Then on staging, the submodule working directory should be clean
|
|
53
|
-
|
|
54
|
-
Scenario: Pushing a change that includes a submodule url change
|
|
55
|
-
Given a submodule
|
|
56
|
-
And a commit with a submodule url change
|
|
57
|
-
When I type "bard push"
|
|
58
|
-
And on staging, I type "bard stage"
|
|
59
|
-
Then on staging, the submodule url should be changed
|
|
60
|
-
And the submodule branch should match the submodule origin branch
|
|
61
|
-
Then on staging, the submodule working directory should be clean
|
|
62
|
-
|
|
63
|
-
# TODO
|
|
64
|
-
#Scenario: Pushing a change that includes a submodule deletion
|
|
65
|
-
# Given a submodule
|
|
66
|
-
# Given I have committed a set of changes that includes a submodule deletion
|
|
67
|
-
# When I type "bard push"
|
|
68
|
-
# And on staging, I type "bard stage"
|
|
69
|
-
# Then the remote submodule should be deleted
|
|
70
|
-
|
|
71
|
-
Scenario: Trying to bard push when not in the project root
|
|
72
|
-
Given I am in a subdirectory
|
|
73
|
-
When I type "bard push"
|
|
74
|
-
Then I should see the fatal error "root directory"
|
|
75
|
-
|
|
76
|
-
Scenario: Trying to bard push when not on the integration branch
|
|
77
|
-
Given a commit on the "master" branch
|
|
78
|
-
And I am on the "master" branch
|
|
79
|
-
When I type "bard push"
|
|
80
|
-
Then I should see the fatal error "on the master branch"
|
|
81
|
-
And the "master" branch should not match the "origin/master" branch
|
|
82
|
-
|
|
83
|
-
Scenario: Trying to bard push with a dirty working directory
|
|
84
|
-
Given a commit
|
|
85
|
-
And a dirty working directory
|
|
86
|
-
When I type "bard push"
|
|
87
|
-
Then I should see the fatal error "You have uncommitted changes!"
|
|
88
|
-
And the "integration" branch should not match the "origin/integration" branch
|
|
89
|
-
|
|
90
|
-
Scenario: Trying to bard push with a non-fast-foward changeset
|
|
91
|
-
Given a commit
|
|
92
|
-
And on development_b, a commit
|
|
93
|
-
And on development_b, I type "bard push"
|
|
94
|
-
When I type "bard push"
|
|
95
|
-
Then I should see the fatal error "Someone has pushed some changes"
|
|
96
|
-
And the "integration" branch should not match the "origin/integration" branch
|
|
97
|
-
|
|
98
|
-
Scenario: Trying to bard push with an uncommitted change to a submodule
|
|
99
|
-
Given a submodule
|
|
100
|
-
And a commit
|
|
101
|
-
And the submodule working directory is dirty
|
|
102
|
-
When I type "bard push"
|
|
103
|
-
Then I should see the fatal error "Micah"
|
|
104
|
-
And the "integration" branch should not match the "origin/integration" branch
|
|
105
|
-
|
|
106
|
-
Scenario: Trying to bard push with a committed but unpushed change to a submodule
|
|
107
|
-
Given a submodule
|
|
108
|
-
And a commit to the submodule
|
|
109
|
-
And a commit
|
|
110
|
-
When I type "bard push"
|
|
111
|
-
Then I should see the fatal error "Micah"
|
|
112
|
-
And the "integration" branch should not match the "origin/integration" branch
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
@podman
|
|
2
|
-
Feature: bard run against a podman TestContainers host
|
|
3
|
-
Background:
|
|
4
|
-
Given a podman testcontainer is ready for bard
|
|
5
|
-
|
|
6
|
-
Scenario: Running ls via bard run
|
|
7
|
-
Given a remote file "test-file.txt" exists in the test container
|
|
8
|
-
When I run bard "ls" against the test container
|
|
9
|
-
Then the bard command should succeed
|
|
10
|
-
And the bard output should include "test-file.txt"
|
|
11
|
-
|
|
12
|
-
Scenario: Running commands in isolated containers
|
|
13
|
-
Given a remote file "another-file.txt" containing "content" exists in the test container
|
|
14
|
-
When I run bard "cat another-file.txt" against the test container
|
|
15
|
-
Then the bard command should succeed
|
|
16
|
-
And the bard output should include "content"
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
Then /^I should see the current version of bard$/ do
|
|
2
|
-
version = File.read("#{ROOT}/VERSION").chomp
|
|
3
|
-
@stdout.should =~ /bard\s+\(#{Regexp.escape(version)}\)/
|
|
4
|
-
end
|
|
5
|
-
|
|
6
|
-
Then /^I should see the current version of git$/ do
|
|
7
|
-
version = `git --version`[/[0-9]+\.[0-9]+\.[0-9]+/]
|
|
8
|
-
@stdout.should =~ /git\s+\(#{Regexp.escape(version)}/
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
Then /^I should see the current version of rubygems$/ do
|
|
12
|
-
version = `gem --version`.chomp
|
|
13
|
-
@stdout.should =~ /rubygems\s+\(#{Regexp.escape(version)}\)/
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
Then /^I should see the current version of ruby$/ do
|
|
17
|
-
version = `ruby --version`[/[0-9]+\.[0-9]+\.[0-9]+/]
|
|
18
|
-
@stdout.should =~ /ruby\s+\(#{Regexp.escape(version)}\)/
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
Given /^"([^\"]*)" is missing$/ do |file|
|
|
22
|
-
type "rm #{file}"
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
Given /^the database is missing$/ do
|
|
26
|
-
File.open "config/database.yml", "w" do |f|
|
|
27
|
-
f.puts <<-DB
|
|
28
|
-
development:
|
|
29
|
-
adapter: mysql
|
|
30
|
-
username: root
|
|
31
|
-
password:
|
|
32
|
-
database: bad_bad_bad
|
|
33
|
-
socket: /var/run/mysqld/mysqld.sock
|
|
34
|
-
DB
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
Given /^the submodule is missing$/ do
|
|
39
|
-
type "rm -rf submodule"
|
|
40
|
-
type "mkdir submodule"
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
Given /^the submodule has a detached head$/ do
|
|
44
|
-
Dir.chdir "submodule" do
|
|
45
|
-
type "git checkout `git rev-parse HEAD`"
|
|
46
|
-
end
|
|
47
|
-
end
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
Given /^I am on the "([^\"]+)" branch$/ do |branch|
|
|
2
|
-
if `git branch` =~ / #{branch}$/
|
|
3
|
-
type "git checkout #{branch}"
|
|
4
|
-
else
|
|
5
|
-
type "git checkout -b #{branch}"
|
|
6
|
-
end
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
Given /^there is no integration branch$/ do
|
|
10
|
-
type "git checkout master"
|
|
11
|
-
type "git branch -d integration"
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
Given /^the integration branch isnt tracking origin\/integration$/ do
|
|
15
|
-
type "git checkout master"
|
|
16
|
-
type "git branch -d integration"
|
|
17
|
-
type "git checkout -b integration"
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
Given /^a dirty working directory$/ do
|
|
21
|
-
File.open("dirty_file", "w") { |f| f.puts "dirty dirty" }
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
Given /^a commit$/ do
|
|
25
|
-
text = (rand * 100000000).round
|
|
26
|
-
type "echo '#{text}' > foobar_#{text}_file"
|
|
27
|
-
type "git add ."
|
|
28
|
-
type "git commit -am'test commit'"
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
Given /^a commit on the "([^\"]+)" branch$/ do |branch|
|
|
32
|
-
Given %(I am on the "#{branch}" branch)
|
|
33
|
-
text = (rand * 100000000).round
|
|
34
|
-
type "echo '#{text}' > #{branch}_#{text}_file"
|
|
35
|
-
type "git add ."
|
|
36
|
-
type "git commit -am 'testing #{branch} change'"
|
|
37
|
-
type "git checkout integration"
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
Then /^the directory should not be dirty$/ do
|
|
41
|
-
type("git status").should include "working directory clean"
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
Then /^I should be on the "([^\"]*)" branch$/ do |branch|
|
|
45
|
-
@repo.head.name.should == branch
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
Then /^there should not be a "([^\"]*)" branch$/ do |branch_name|
|
|
49
|
-
@repo.branches.any? { |branch| branch.name == branch_name }
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
Then /^the "([^\"]*)" branch (should|should not) match the "([^\"]*)" branch$/ do |local_branch, which, remote_branch|
|
|
53
|
-
type "git fetch origin"
|
|
54
|
-
local_env, local_branch = local_branch.split(':') if local_branch.include? ':'
|
|
55
|
-
local_env ||= "development_a"
|
|
56
|
-
remote_env, remote_branch = remote_branch.split(':') if remote_branch.include? ':'
|
|
57
|
-
remote_env ||= "development_a"
|
|
58
|
-
local_sha = @repos[local_env].commits(local_branch).first.id
|
|
59
|
-
remote_sha = @repos[remote_env].commits(remote_branch).first.id
|
|
60
|
-
which = which.gsub(/ /, '_').to_sym
|
|
61
|
-
local_sha.send(which) == remote_sha
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
Then /^the "([^\"]*)" branch should be a fast\-forward from the "([^\"]*)" branch$/ do |local_branch, remote_branch|
|
|
65
|
-
local_env, local_branch = local_branch.split(':') if local_branch.include? ':'
|
|
66
|
-
local_env ||= "development_a"
|
|
67
|
-
remote_env, remote_branch = remote_branch.split(':') if remote_branch.include? ':'
|
|
68
|
-
remote_env ||= "development_a"
|
|
69
|
-
local_sha = @repos[local_env].commits(local_branch).first.id
|
|
70
|
-
remote_sha = @repos[remote_env].commits(remote_branch).first.id
|
|
71
|
-
common_ancestor = @repos[local_env].find_common_ancestor local_sha, remote_sha
|
|
72
|
-
common_ancestor.should == remote_sha
|
|
73
|
-
end
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
Given /^a shared rails project$/ do
|
|
2
|
-
# TEARDOWN
|
|
3
|
-
Dir.foreach "#{ROOT}/tmp" do |file|
|
|
4
|
-
FileUtils.rm_rf("#{ROOT}/tmp/#{file}") unless %w(fixtures . ..).include? file
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
# SETUP
|
|
8
|
-
Dir.chdir ROOT
|
|
9
|
-
`cp -r tmp/fixtures/* tmp/`
|
|
10
|
-
|
|
11
|
-
Dir.chdir 'tmp'
|
|
12
|
-
@repos = {}
|
|
13
|
-
%w(development_a development_b staging production).each do |env|
|
|
14
|
-
@repos[env] = Grit::Repo.new env
|
|
15
|
-
end
|
|
16
|
-
Dir.chdir 'development_a'
|
|
17
|
-
@repo = @repos['development_a']
|
|
18
|
-
@env = { 'RAILS_ENV' => 'development', 'TESTING' => true }
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
Given /^I am in a subdirectory$/ do
|
|
22
|
-
FileUtils.mkdir "test_subdirectory"
|
|
23
|
-
Dir.chdir "test_subdirectory"
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
When /^I type "([^\"]*)"$/ do |command|
|
|
27
|
-
type command.sub /\b(bard)\b/, "#{ROOT}/bin/bard"
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
When /^on (\w+), (.*$)/ do |env, step|
|
|
31
|
-
old_env = @env['RAILS_ENV']
|
|
32
|
-
@env['RAILS_ENV'] = env if %w(staging production).include? env
|
|
33
|
-
Dir.chdir "#{ROOT}/tmp/#{env}" do
|
|
34
|
-
old_repo = @repo
|
|
35
|
-
@repo = @repos[env]
|
|
36
|
-
When step
|
|
37
|
-
@repo = old_repo
|
|
38
|
-
end
|
|
39
|
-
@env['RAILS_ENV'] = old_env
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
Then /^I should see the fatal error "([^\"]*)"$/ do |error_message|
|
|
43
|
-
@stderr.should include(error_message)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
Then /^I should see the warning "([^\"]*)"$/ do |warning_message|
|
|
47
|
-
@stderr.should include(warning_message)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
Then /^I should see "([^\"]*)"$/ do |message|
|
|
51
|
-
@stdout.should include(message)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
Then /^debug$/ do
|
|
55
|
-
debugger
|
|
56
|
-
end
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
Given /^a podman testcontainer is ready for bard$/ do
|
|
2
|
-
raise "Podman testcontainer failed to start" unless @podman_container && @podman_ssh_port
|
|
3
|
-
end
|
|
4
|
-
|
|
5
|
-
Given /^a remote file "([^\"]+)" exists in the test container$/ do |filename|
|
|
6
|
-
run_ssh("touch testproject/#{filename}").should be_true
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
Given /^a remote file "([^\"]+)" containing "([^\"]+)" exists in the test container$/ do |filename, content|
|
|
10
|
-
run_ssh("echo #{Shellwords.escape(content)} > testproject/#{filename}").should be_true
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
When /^I run bard "([^\"]+)" against the test container$/ do |command|
|
|
14
|
-
run_bard_against_container(command)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
Then /^the bard command should succeed$/ do
|
|
18
|
-
@status.success?.should be_true
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
Then /^the bard output should include "([^\"]+)"$/ do |expected|
|
|
22
|
-
@stdout.should include(expected)
|
|
23
|
-
end
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
Given /^a commit with a new migration$/ do
|
|
2
|
-
type "script/generate migration test_migration"
|
|
3
|
-
type "git add ."
|
|
4
|
-
type "git commit -am'added test migration.'"
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
Given /^a (\w+) database$/ do |env|
|
|
8
|
-
type "rake db:create RAILS_ENV=#{env} && rake db:migrate RAILS_ENV=#{env}"
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
Then /^the (\w+) database should include that migration$/ do |env|
|
|
12
|
-
db_version = type("rake db:version RAILS_ENV=#{env}")[/[0-9]{14}/]
|
|
13
|
-
migration_version = type("ls db/migrate/*_test_migration.rb")[/[0-9]{14}/]
|
|
14
|
-
db_version.should == migration_version
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
Given /^the test gem is not installed$/ do
|
|
18
|
-
type "gem uninstall rake-dotnet -v=0.0.1 -x"
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
Given /^a commit that adds the test gem as a dependency$/ do
|
|
22
|
-
file_inject "config/environment.rb", "
|
|
23
|
-
Rails::Initializer.run do |config|", <<-RUBY
|
|
24
|
-
config.gem "rake-dotnet", :version => "0.0.1"
|
|
25
|
-
RUBY
|
|
26
|
-
type "git add ."
|
|
27
|
-
type "git commit -am'added test gem dependency.'"
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
Then /^the test gem should be installed$/ do
|
|
31
|
-
type("gem list rake-dotnet").should include "rake-dotnet (0.0.1)"
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
Then /^passenger should have been restarted$/ do
|
|
35
|
-
File.exist?("tmp/restart.txt").should be_true
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
Given /^the "([^\"]+)" file includes "([^\"]+)"$/ do |file, contents|
|
|
39
|
-
file_append file, contents
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
Given /^the "([^\"]+)" file does not include "([^\"]+)"$/ do |file, contents|
|
|
43
|
-
gsub_file file, contents, ""
|
|
44
|
-
end
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
Given /^a submodule$/ do
|
|
2
|
-
Given 'on development_b, a commit with a new submodule'
|
|
3
|
-
Given 'on development_b, I type "bard push"'
|
|
4
|
-
Given 'I type "bard pull"'
|
|
5
|
-
@submodule_url = File.read(".gitmodules").match(/url = (.*)$/)[1]
|
|
6
|
-
@submodule_commit = type "git submodule status"
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
Given /^the submodule working directory is dirty$/ do
|
|
10
|
-
Dir.chdir "submodule" do
|
|
11
|
-
type "git checkout master"
|
|
12
|
-
type "echo 'submodule_update' > submodule_update"
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
Given /^a commit to the submodule$/ do
|
|
17
|
-
Dir.chdir "submodule" do
|
|
18
|
-
type "echo 'submodule_update' > submodule_update"
|
|
19
|
-
type "git add ."
|
|
20
|
-
type "git commit -am 'update in submodule'"
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
Given /^a commit with a new submodule$/ do
|
|
25
|
-
type "git submodule add #{ROOT}/tmp/submodule_a.git submodule"
|
|
26
|
-
type "git submodule update --init"
|
|
27
|
-
Dir.chdir "submodule" do
|
|
28
|
-
type "git checkout master"
|
|
29
|
-
end
|
|
30
|
-
type "git add ."
|
|
31
|
-
type "git commit -m 'added submodule'"
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
Given /^a commit with a submodule update$/ do
|
|
35
|
-
type "git checkout integration"
|
|
36
|
-
Dir.chdir "submodule" do
|
|
37
|
-
type "git checkout master"
|
|
38
|
-
type "echo 'submodule_update' > submodule_update"
|
|
39
|
-
type "git add ."
|
|
40
|
-
type "git commit -m 'update in submodule'"
|
|
41
|
-
type "git push origin HEAD"
|
|
42
|
-
end
|
|
43
|
-
type "git add ."
|
|
44
|
-
type "git commit -m 'updated submodule'"
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
Given /^a commit with a submodule url change$/ do
|
|
48
|
-
gsub_file ".gitmodules", "submodule_a.git", "submodule_b.git"
|
|
49
|
-
type "git add ."
|
|
50
|
-
type "git commit -m 'updated submodule url'"
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
Given /^I a commit a with a submodule deletion$/ do
|
|
54
|
-
type "rm .gitmodules"
|
|
55
|
-
type "rm -rf --cached submodule"
|
|
56
|
-
type "git add ."
|
|
57
|
-
type "git commit -am'removed submodule'"
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
Then /^there should be one new submodule$/ do
|
|
61
|
-
status = type "git submodule status"
|
|
62
|
-
status.should match /.[a-z0-9]{40} submodule/
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
Then /^the submodule branch should match the submodule origin branch$/ do
|
|
66
|
-
@submodule_url = File.read(".gitmodules").match(/url = (.*)$/)[1]
|
|
67
|
-
@submodule_commit = type "git submodule status"
|
|
68
|
-
@submodule_commit.should match %r( [a-z0-9]{40} submodule)
|
|
69
|
-
Dir.chdir "submodule" do
|
|
70
|
-
@submodule = Grit::Repo.new "."
|
|
71
|
-
branch = @submodule.head.name rescue nil
|
|
72
|
-
remote_branch = @submodule.remotes.find {|n| n.name == "origin/HEAD" }.commit.id[/\w+$/]
|
|
73
|
-
branch.should_not be_nil
|
|
74
|
-
remote_branch.should_not be_nil
|
|
75
|
-
branch.should == remote_branch
|
|
76
|
-
type("git rev-parse HEAD").should == type("git rev-parse origin/HEAD")
|
|
77
|
-
type("git name-rev --name-only HEAD").should == type("git name-rev --name-only origin/HEAD")
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
Then /^the submodule should be checked out$/ do
|
|
82
|
-
@submodule_url = File.read(".gitmodules").match(/url = (.*)$/)[1]
|
|
83
|
-
@submodule_commit = type "git submodule status"
|
|
84
|
-
@submodule_commit.should match %r( [a-z0-9]{40} submodule)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
Then /^the submodule should be updated$/ do
|
|
88
|
-
@submodule_commit[/[a-z0-9]{40}/].should_not == type("git submodule status")[/[a-z0-9]{40}/]
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
Then /^the submodule url should be changed$/ do
|
|
92
|
-
Dir.chdir "submodule" do
|
|
93
|
-
remote = type "git remote show origin"
|
|
94
|
-
remote.should_not match %r(Fetch URL: #{@submodule_url}$)
|
|
95
|
-
remote.should_not match %r(Push URL: #{@submodule_url}$)
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
Then /^the submodule should be deleted$/ do
|
|
100
|
-
Then 'the directory should not be dirty'
|
|
101
|
-
@submodule_commit = type "git submodule status"
|
|
102
|
-
@submodule_commit.should_not match /.[a-z0-9]{40} submodule/
|
|
103
|
-
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
Then /^the submodule working directory should be clean$/ do
|
|
107
|
-
Dir.chdir "submodule" do
|
|
108
|
-
type("git status").should include "working directory clean"
|
|
109
|
-
end
|
|
110
|
-
end
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
Grit::Repo.class_eval do
|
|
2
|
-
def remote_branches(remote = "origin")
|
|
3
|
-
branches = self.remotes
|
|
4
|
-
branches.reject! { |r| r.name !~ %r(^#{remote}/) }
|
|
5
|
-
branches.collect! { |r| r.name.split('/')[1] }
|
|
6
|
-
branches.reject! { |b| b == "HEAD" }
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def find_common_ancestor(head1, head2)
|
|
10
|
-
`git merge-base #{head1} #{head2}`.chomp
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
data/features/support/io.rb
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
require "open3"
|
|
2
|
-
def type(command)
|
|
3
|
-
@stdout, @stderr, @status = Open3.capture3(@env, command)
|
|
4
|
-
if ENV['DEBUG']
|
|
5
|
-
puts '-' * 20
|
|
6
|
-
puts "Executing command: #{command}"
|
|
7
|
-
puts " Status: #{@status}"
|
|
8
|
-
puts " Stdout:\n #{@stdout}"
|
|
9
|
-
puts " Stderr:\n #{@stderr}"
|
|
10
|
-
puts '-' * 20
|
|
11
|
-
end
|
|
12
|
-
@stdout || @stderr
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def file_append(file_name, contents)
|
|
16
|
-
File.open(file_name, 'ab') { |file| file.puts("\n#{contents}") }
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def file_inject(file_name, sentinel, string, before_after=:after)
|
|
20
|
-
gsub_file file_name, /(#{Regexp.escape(sentinel)})/mi do |match|
|
|
21
|
-
if before_after == :after
|
|
22
|
-
"#{match}\n#{string}"
|
|
23
|
-
else
|
|
24
|
-
"#{string}\n#{match}"
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def gsub_file(file_name, regexp, *args, &block)
|
|
30
|
-
content = File.read(file_name).gsub(regexp, *args, &block)
|
|
31
|
-
File.open(file_name, 'wb') { |file| file.write(content) }
|
|
32
|
-
end
|
data/features/support/podman.rb
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
require "fileutils"
|
|
2
|
-
require "open3"
|
|
3
|
-
require "securerandom"
|
|
4
|
-
require "shellwords"
|
|
5
|
-
require "testcontainers"
|
|
6
|
-
|
|
7
|
-
module PodmanWorld
|
|
8
|
-
class << self
|
|
9
|
-
attr_accessor :podman_available, :podman_image_built
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
class PrerequisiteError < StandardError; end
|
|
13
|
-
|
|
14
|
-
def ensure_podman_available
|
|
15
|
-
return if @podman_available || PodmanWorld.podman_available
|
|
16
|
-
|
|
17
|
-
raise PrerequisiteError, "podman is not installed or not on PATH" unless system("command -v podman >/dev/null 2>&1")
|
|
18
|
-
|
|
19
|
-
configure_podman_socket
|
|
20
|
-
ensure_bard_test_image
|
|
21
|
-
FileUtils.chmod(0o600, podman_ssh_key_path)
|
|
22
|
-
|
|
23
|
-
PodmanWorld.podman_available = true
|
|
24
|
-
@podman_available = true
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def configure_podman_socket
|
|
28
|
-
return if ENV["DOCKER_HOST"]
|
|
29
|
-
|
|
30
|
-
podman_socket = "/run/user/#{Process.uid}/podman/podman.sock"
|
|
31
|
-
unless File.exist?(podman_socket)
|
|
32
|
-
system("systemctl --user start podman.socket 2>/dev/null || podman system service --time=0 unix://#{podman_socket} &")
|
|
33
|
-
sleep 2
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
raise PrerequisiteError, "Podman socket not available at #{podman_socket}" unless File.exist?(podman_socket)
|
|
37
|
-
|
|
38
|
-
ENV["DOCKER_HOST"] = "unix://#{podman_socket}"
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def ensure_bard_test_image
|
|
42
|
-
return if @podman_image_built || PodmanWorld.podman_image_built
|
|
43
|
-
|
|
44
|
-
raise PrerequisiteError, "Unable to pull ubuntu:22.04 image" unless system("podman pull ubuntu:22.04 >/dev/null 2>&1")
|
|
45
|
-
|
|
46
|
-
docker_dir = File.join(ROOT, "spec/acceptance/docker")
|
|
47
|
-
dockerfile = File.join(docker_dir, "Dockerfile")
|
|
48
|
-
unless system("podman build -t bard-test-server -f #{dockerfile} #{docker_dir} 2>&1")
|
|
49
|
-
raise PrerequisiteError, "Failed to build bard test image"
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
PodmanWorld.podman_image_built = true
|
|
53
|
-
@podman_image_built = true
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def start_podman_container
|
|
57
|
-
ensure_podman_available
|
|
58
|
-
|
|
59
|
-
@podman_container = Testcontainers::DockerContainer
|
|
60
|
-
.new("localhost/bard-test-server:latest")
|
|
61
|
-
.with_exposed_port(22)
|
|
62
|
-
.with_name("bard-test-#{SecureRandom.hex(4)}")
|
|
63
|
-
.start
|
|
64
|
-
|
|
65
|
-
@podman_ssh_port = @podman_container.mapped_port(22)
|
|
66
|
-
wait_for_ssh
|
|
67
|
-
run_ssh("mkdir -p testproject")
|
|
68
|
-
write_bard_config
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def wait_for_ssh
|
|
72
|
-
30.times do
|
|
73
|
-
return if run_ssh("echo ready", quiet: true)
|
|
74
|
-
sleep 0.5
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
raise PrerequisiteError, "SSH in podman container did not become ready"
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def write_bard_config
|
|
81
|
-
FileUtils.mkdir_p(File.join(ROOT, "tmp"))
|
|
82
|
-
@bard_config_path = File.join(ROOT, "tmp", "test_bard_#{SecureRandom.hex(4)}.rb")
|
|
83
|
-
|
|
84
|
-
File.write(@bard_config_path, <<~RUBY)
|
|
85
|
-
server :production do
|
|
86
|
-
ssh "deploy@localhost:#{@podman_ssh_port}"
|
|
87
|
-
path "testproject"
|
|
88
|
-
ssh_key "#{podman_ssh_key_path}"
|
|
89
|
-
ping false
|
|
90
|
-
end
|
|
91
|
-
RUBY
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def run_ssh(command, quiet: false)
|
|
95
|
-
escaped = Shellwords.escape(command)
|
|
96
|
-
ssh_command = [
|
|
97
|
-
"ssh",
|
|
98
|
-
"-o", "StrictHostKeyChecking=no",
|
|
99
|
-
"-o", "ConnectTimeout=1",
|
|
100
|
-
"-p", @podman_ssh_port.to_s,
|
|
101
|
-
"-i", podman_ssh_key_path,
|
|
102
|
-
"deploy@localhost",
|
|
103
|
-
"--",
|
|
104
|
-
"bash",
|
|
105
|
-
"-lc",
|
|
106
|
-
escaped
|
|
107
|
-
].join(" ")
|
|
108
|
-
|
|
109
|
-
quiet ? system("#{ssh_command} >/dev/null 2>&1") : system(ssh_command)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def run_bard_against_container(command)
|
|
113
|
-
Dir.chdir(File.join(ROOT, "tmp")) do
|
|
114
|
-
FileUtils.cp(@bard_config_path, "bard.rb")
|
|
115
|
-
@stdout, @status = Open3.capture2e(@env || {}, "bard run #{command}")
|
|
116
|
-
@stderr = ""
|
|
117
|
-
FileUtils.rm_f("bard.rb")
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def podman_ssh_key_path
|
|
122
|
-
@podman_ssh_key_path ||= File.expand_path(File.join(ROOT, "spec/acceptance/docker/test_key"))
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def stop_podman_container
|
|
126
|
-
FileUtils.rm_f(@bard_config_path) if @bard_config_path
|
|
127
|
-
return unless @podman_container
|
|
128
|
-
|
|
129
|
-
@podman_container.stop
|
|
130
|
-
@podman_container.remove
|
|
131
|
-
rescue StandardError => e
|
|
132
|
-
warn "Failed to cleanup podman container: #{e.message}"
|
|
133
|
-
ensure
|
|
134
|
-
@podman_container = nil
|
|
135
|
-
@podman_ssh_port = nil
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
World(PodmanWorld)
|
|
140
|
-
|
|
141
|
-
Before("@podman") do
|
|
142
|
-
@env ||= {}
|
|
143
|
-
|
|
144
|
-
begin
|
|
145
|
-
start_podman_container
|
|
146
|
-
rescue PodmanWorld::PrerequisiteError => e
|
|
147
|
-
pending(e.message)
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
After("@podman") do
|
|
152
|
-
stop_podman_container
|
|
153
|
-
end
|