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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 24a9ee78c591a6446ac1bb749225497c75470e12e4fe822d96e975870ac88152
|
|
4
|
+
data.tar.gz: 2b8ae0acbf1237b3312957128130f399a516a3a19d52d45f63c7b0677952e4f2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 55a1a4f6fcf3bf12201105974a619be5178c3c9c6367d8dccf2eef1e7e504880a869a6291dfb5024930e025f63d8cf2f22c8925cf5fc24f9e83d2aa85ed047ed
|
|
7
|
+
data.tar.gz: 5da5d707ceed5ca663e4a68cd4a2ba2afbb232052e4a0542a4e41a1badc0161ba4eda410195b717d21f8fdaea299af771afa6a19310d93b66915996e8579b5fa
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -5,7 +5,7 @@ jobs:
|
|
|
5
5
|
strategy:
|
|
6
6
|
fail-fast: false
|
|
7
7
|
matrix:
|
|
8
|
-
ruby: [ "3.
|
|
8
|
+
ruby: [ "3.3", "3.4", "4.0" ]
|
|
9
9
|
|
|
10
10
|
runs-on: ubuntu-latest
|
|
11
11
|
steps:
|
|
@@ -34,5 +34,10 @@ jobs:
|
|
|
34
34
|
done
|
|
35
35
|
echo "DOCKER_HOST=tcp://127.0.0.1:8080" >> $GITHUB_ENV
|
|
36
36
|
|
|
37
|
+
- name: Build test container image
|
|
38
|
+
run: |
|
|
39
|
+
sudo podman pull ubuntu:24.04
|
|
40
|
+
sudo podman build -t bard-test-server -f spec/acceptance/docker/Dockerfile spec/acceptance/docker
|
|
41
|
+
|
|
37
42
|
- name: Run tests
|
|
38
43
|
run: bundle exec rake
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## What is Bard?
|
|
6
|
+
|
|
7
|
+
Bard is a modular deployment CLI tool for Ruby applications. It provides:
|
|
8
|
+
- SSH-based deployment via git pull
|
|
9
|
+
- GitHub Pages static site deployment
|
|
10
|
+
- Custom pluggable deployment strategies
|
|
11
|
+
- Data syncing (database dumps and file rsync)
|
|
12
|
+
- CI integration (GitHub Actions/Jenkins)
|
|
13
|
+
- Server provisioning
|
|
14
|
+
|
|
15
|
+
## Development Commands
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Install dependencies
|
|
19
|
+
bundle install
|
|
20
|
+
|
|
21
|
+
# Run all tests (RSpec + Cucumber)
|
|
22
|
+
bundle exec rake
|
|
23
|
+
|
|
24
|
+
# Run only RSpec tests
|
|
25
|
+
bundle exec rspec
|
|
26
|
+
|
|
27
|
+
# Run a single spec file
|
|
28
|
+
bundle exec rspec spec/bard/target_spec.rb
|
|
29
|
+
|
|
30
|
+
# Run a specific test by line number
|
|
31
|
+
bundle exec rspec spec/bard/target_spec.rb:42
|
|
32
|
+
|
|
33
|
+
# Run Cucumber features (slow - avoid full suite)
|
|
34
|
+
bundle exec cucumber features/deploy.feature
|
|
35
|
+
|
|
36
|
+
# Run bard from source
|
|
37
|
+
bundle exec bin/bard
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Architecture
|
|
41
|
+
|
|
42
|
+
### Core Classes
|
|
43
|
+
|
|
44
|
+
- **`Bard::CLI`** (`lib/bard/cli.rb`) - Thor-based command dispatcher. Commands are modules in `lib/bard/cli/` included into CLI.
|
|
45
|
+
- **`Bard::Config`** (`lib/bard/config.rb`) - DSL parser for `bard.rb` files. Manages targets and settings.
|
|
46
|
+
- **`Bard::Target`** (`lib/bard/target.rb`) - Deployment destination with capabilities (ssh, ping, data). Supports dynamic strategy DSL via `method_missing`.
|
|
47
|
+
- **`Bard::SSHServer`** (`lib/bard/ssh_server.rb`) - SSH connection details (user, host, port, gateway, ssh_key, env).
|
|
48
|
+
- **`Bard::DeployStrategy`** (`lib/bard/deploy_strategy.rb`) - Base class for deployment strategies. Subclasses auto-register via Ruby's `inherited` hook.
|
|
49
|
+
|
|
50
|
+
### Capability System
|
|
51
|
+
|
|
52
|
+
Targets track enabled capabilities (`:ssh`, `:ping`, `:github_pages`, etc.). Commands call `require_capability!` to ensure the target supports the operation.
|
|
53
|
+
|
|
54
|
+
### Strategy Auto-Registration
|
|
55
|
+
|
|
56
|
+
Custom strategies subclass `DeployStrategy` and are automatically registered by class name:
|
|
57
|
+
```ruby
|
|
58
|
+
class Bard::DeployStrategy::Jets < DeployStrategy # registers as :jets
|
|
59
|
+
def deploy; ...; end
|
|
60
|
+
end
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### File Organization
|
|
64
|
+
|
|
65
|
+
- `lib/bard/cli/*.rb` - CLI command modules (deploy, data, ssh, etc.)
|
|
66
|
+
- `lib/bard/ci/*.rb` - CI system integrations (github_actions, jenkins, local)
|
|
67
|
+
- `lib/bard/deploy_strategy/*.rb` - Built-in strategies (ssh, github_pages)
|
|
68
|
+
- `lib/bard/provision/*.rb` - Server provisioning modules
|
|
69
|
+
- `spec/` - RSpec unit tests
|
|
70
|
+
- `features/` - Cucumber integration tests
|
|
71
|
+
|
|
72
|
+
## Testing Notes
|
|
73
|
+
|
|
74
|
+
- Use `focus: true` in RSpec to run specific tests
|
|
75
|
+
- Cucumber tests use testcontainers and are slow - run specific feature files only
|
|
76
|
+
- SimpleCov tracks coverage across both RSpec and Cucumber runs
|
data/MIGRATION_GUIDE.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
This guide will help you migrate your Bard configuration from v1.x to v2.0.
|
|
4
4
|
|
|
5
|
+
> **Note:** Bard v1.8.0 is a transitional release that supports both v1.x and v2.0 APIs. When using deprecated v1.x patterns, you'll see deprecation warnings indicating what to change. This gives you time to migrate at your own pace while keeping your deployments working.
|
|
6
|
+
|
|
5
7
|
## Overview of Changes
|
|
6
8
|
|
|
7
9
|
Bard v2.0 introduces a cleaner, more modular architecture:
|
|
@@ -477,22 +479,35 @@ mv bard.rb.backup bard.rb
|
|
|
477
479
|
- Check [CUSTOM_STRATEGIES.md](CUSTOM_STRATEGIES.md) for strategy creation
|
|
478
480
|
- Open an issue at https://github.com/botandrose/bard/issues
|
|
479
481
|
|
|
480
|
-
## Transitional Release (v1.
|
|
482
|
+
## Transitional Release (v1.8.0)
|
|
481
483
|
|
|
482
|
-
|
|
484
|
+
Bard v1.8.0 is a transitional release that supports both v1.x and v2.0 APIs simultaneously with deprecation warnings. This allows gradual migration.
|
|
483
485
|
|
|
484
|
-
**Using v1.
|
|
486
|
+
**Using v1.8.0:**
|
|
485
487
|
```bash
|
|
486
488
|
# Gemfile
|
|
487
|
-
gem 'bard', '~> 1.
|
|
489
|
+
gem 'bard', '~> 1.8'
|
|
488
490
|
|
|
489
491
|
bundle update bard
|
|
490
492
|
```
|
|
491
493
|
|
|
492
|
-
v1.
|
|
493
|
-
- Accept both `server` and `target` (with deprecation warning)
|
|
494
|
-
- Accept both old and new SSH configuration styles
|
|
495
|
-
-
|
|
496
|
-
-
|
|
494
|
+
v1.8.0 will:
|
|
495
|
+
- Accept both `server` and `target` (with deprecation warning for `server`)
|
|
496
|
+
- Accept both old and new SSH configuration styles (with deprecation warnings for separate options)
|
|
497
|
+
- Accept both old `strategy`/`option` calls and new direct strategy methods (with deprecation warnings)
|
|
498
|
+
- Show deprecation warnings for all deprecated v1.x API usage
|
|
499
|
+
- Support full v2.0 API
|
|
497
500
|
|
|
498
501
|
This gives you time to migrate at your own pace while keeping your deployments working.
|
|
502
|
+
|
|
503
|
+
### Deprecation Warnings
|
|
504
|
+
|
|
505
|
+
When using deprecated patterns, you'll see warnings like:
|
|
506
|
+
|
|
507
|
+
```
|
|
508
|
+
[DEPRECATION] `server` is deprecated; use `target` instead (will be removed in v2.0) (called from bard.rb:3)
|
|
509
|
+
[DEPRECATION] Separate SSH options are deprecated; pass as keyword arguments to `ssh` instead (will be removed in v2.0) (called from bard.rb:5)
|
|
510
|
+
[DEPRECATION] `strategy` is deprecated; use the strategy method directly (will be removed in v2.0) (called from bard.rb:10)
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
These warnings help you identify what needs to change before upgrading to v2.0.
|
data/PLUGINS.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Plugin Development
|
|
2
|
+
|
|
3
|
+
Bard uses a plugin system to extend functionality. Plugins can add CLI commands, target methods, and config DSL methods.
|
|
4
|
+
|
|
5
|
+
## Plugin Structure
|
|
6
|
+
|
|
7
|
+
Plugins live in `lib/bard/plugins/` and are auto-loaded. Command classes auto-register when they subclass `Bard::Plugin::Command`:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
# lib/bard/plugins/my_plugin.rb
|
|
11
|
+
require "bard/plugin"
|
|
12
|
+
|
|
13
|
+
class Bard::CLI::MyPlugin < Bard::Plugin::Command
|
|
14
|
+
desc "mycommand", "Description of my command"
|
|
15
|
+
option :verbose, type: :boolean
|
|
16
|
+
def mycommand
|
|
17
|
+
puts "Hello from my plugin!"
|
|
18
|
+
puts config[:production].url
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
That's it — no registration block needed. The `Command` base class provides:
|
|
24
|
+
- Automatic registration via Ruby's `inherited` hook
|
|
25
|
+
- `desc` and `option` class methods for Thor integration
|
|
26
|
+
- Delegation to the CLI instance (access to `config`, `project_name`, `run!`, `options`, etc.)
|
|
27
|
+
|
|
28
|
+
## Extending Target and Config
|
|
29
|
+
|
|
30
|
+
To add methods to `Bard::Target` or `Bard::Config`, reopen the class directly:
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
# lib/bard/plugins/my_plugin.rb
|
|
34
|
+
require "bard/target"
|
|
35
|
+
|
|
36
|
+
class Bard::Target
|
|
37
|
+
def my_feature(url = nil)
|
|
38
|
+
if url.nil?
|
|
39
|
+
@my_feature_url
|
|
40
|
+
else
|
|
41
|
+
@my_feature_url = url
|
|
42
|
+
enable_capability(:my_feature)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
require "bard/config"
|
|
48
|
+
|
|
49
|
+
class Bard::Config
|
|
50
|
+
def my_global_setting(value = nil)
|
|
51
|
+
if value.nil?
|
|
52
|
+
@my_global_setting
|
|
53
|
+
else
|
|
54
|
+
@my_global_setting = value
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Adding Strategies
|
|
61
|
+
|
|
62
|
+
Plugins can add deployment strategies or CI runners:
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
# Custom deploy strategy
|
|
66
|
+
module Bard
|
|
67
|
+
class DeployStrategy
|
|
68
|
+
class MyCloud < DeployStrategy
|
|
69
|
+
def deploy
|
|
70
|
+
# Deployment logic here
|
|
71
|
+
run! "my-cloud deploy #{target.key}"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Custom CI runner
|
|
78
|
+
module Bard
|
|
79
|
+
class CI
|
|
80
|
+
class Runner
|
|
81
|
+
class MyCI < Runner
|
|
82
|
+
def run
|
|
83
|
+
# Start CI run
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def status
|
|
87
|
+
# Return current status
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Strategies auto-register via Ruby's `inherited` hook. The class name determines the strategy key (e.g., `MyCloud` → `:my_cloud`).
|
|
96
|
+
|
|
97
|
+
## Plugin Loading
|
|
98
|
+
|
|
99
|
+
Plugins are loaded automatically from `lib/bard/plugins/`. The load order is alphabetical by filename. External plugins are loaded from the project's `lib/bard/plugins/` directory.
|
data/README.md
CHANGED
|
@@ -12,7 +12,7 @@ end
|
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
bard deploy
|
|
15
|
+
bard deploy
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
## Features
|
|
@@ -115,17 +115,21 @@ end
|
|
|
115
115
|
### Deployment
|
|
116
116
|
|
|
117
117
|
```bash
|
|
118
|
-
# Deploy to production
|
|
119
|
-
bard deploy
|
|
118
|
+
# Deploy current branch to production (default)
|
|
119
|
+
bard deploy
|
|
120
120
|
|
|
121
|
-
# Deploy to
|
|
122
|
-
bard deploy
|
|
121
|
+
# Deploy a specific branch to production
|
|
122
|
+
bard deploy feature-branch
|
|
123
|
+
|
|
124
|
+
# Deploy to a different target
|
|
125
|
+
bard deploy --target=staging
|
|
126
|
+
bard deploy feature-branch --target=staging
|
|
123
127
|
|
|
124
128
|
# Deploy feature branch to staging (no merge)
|
|
125
129
|
bard stage feature-branch
|
|
126
130
|
|
|
127
131
|
# Skip CI checks
|
|
128
|
-
bard deploy
|
|
132
|
+
bard deploy --skip-ci
|
|
129
133
|
```
|
|
130
134
|
|
|
131
135
|
### Data Management
|
|
@@ -459,6 +463,10 @@ See [ARCHITECTURE.md](ARCHITECTURE.md) for detailed architecture documentation.
|
|
|
459
463
|
|
|
460
464
|
See [CUSTOM_STRATEGIES.md](CUSTOM_STRATEGIES.md) for a step-by-step guide to creating custom deployment strategies.
|
|
461
465
|
|
|
466
|
+
## Plugin Development
|
|
467
|
+
|
|
468
|
+
See [PLUGINS.md](PLUGINS.md) for a guide to creating plugins.
|
|
469
|
+
|
|
462
470
|
## Development
|
|
463
471
|
|
|
464
472
|
```bash
|
data/Rakefile
CHANGED
data/bard.gemspec
CHANGED
|
@@ -15,11 +15,11 @@ Gem::Specification.new do |spec|
|
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0")
|
|
16
16
|
spec.executables = ["bard"]
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
18
|
+
spec.required_ruby_version = ">= 3.3"
|
|
18
19
|
spec.require_paths = ["lib"]
|
|
19
20
|
|
|
20
21
|
spec.add_dependency "thor", ">= 0.19.0"
|
|
21
22
|
spec.add_dependency "rvm"
|
|
22
|
-
spec.add_dependency "term-ansicolor", ">= 1.0.3"
|
|
23
23
|
spec.add_dependency "rbnacl"
|
|
24
24
|
spec.add_dependency "base64"
|
|
25
25
|
|
|
@@ -28,4 +28,5 @@ Gem::Specification.new do |spec|
|
|
|
28
28
|
spec.add_development_dependency "debug"
|
|
29
29
|
spec.add_development_dependency "cucumber"
|
|
30
30
|
spec.add_development_dependency "testcontainers"
|
|
31
|
+
spec.add_development_dependency "ostruct"
|
|
31
32
|
end
|
data/cucumber.yml
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
default: --publish-quiet
|
data/features/ci.feature
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
@server
|
|
2
|
+
Feature: bard ci
|
|
3
|
+
Run continuous integration tests.
|
|
4
|
+
|
|
5
|
+
Background:
|
|
6
|
+
Given a test server is running
|
|
7
|
+
|
|
8
|
+
Scenario: no CI configured error
|
|
9
|
+
When I run expecting failure: bard ci
|
|
10
|
+
Then the output should contain "No CI found"
|
|
11
|
+
And the output should contain "Re-run with --skip-ci to bypass CI"
|
|
12
|
+
|
|
13
|
+
Scenario: local CI runs successfully
|
|
14
|
+
Given a local CI script that passes
|
|
15
|
+
When I run: bard ci --local-ci
|
|
16
|
+
Then the output should contain "Continuous integration: starting build"
|
|
17
|
+
And the output should contain "Continuous integration: success!"
|
|
18
|
+
|
|
19
|
+
Scenario: local CI reports failure
|
|
20
|
+
Given a local CI script that fails with "Test failed: expected 1 but got 2"
|
|
21
|
+
When I run expecting failure: bard ci --local-ci
|
|
22
|
+
Then the output should contain "Test failed: expected 1 but got 2"
|
|
23
|
+
And the output should contain "Automated tests failed!"
|
|
24
|
+
|
|
25
|
+
Scenario: --ci option runs specified CI runner
|
|
26
|
+
Given a local CI script that passes
|
|
27
|
+
When I run: bard ci --ci=local
|
|
28
|
+
Then the output should contain "Continuous integration: starting build"
|
|
29
|
+
And the output should contain "Continuous integration: success!"
|
|
30
|
+
|
|
31
|
+
Scenario: --ci option reports failure from specified runner
|
|
32
|
+
Given a local CI script that fails with "Custom runner failed"
|
|
33
|
+
When I run expecting failure: bard ci --ci=local
|
|
34
|
+
Then the output should contain "Custom runner failed"
|
|
35
|
+
And the output should contain "Automated tests failed!"
|
|
36
|
+
|
|
37
|
+
Scenario: deploy passes --ci option to CI
|
|
38
|
+
Given a local CI script that passes
|
|
39
|
+
And I create a file "ci-option-test.txt" with content "ci option test"
|
|
40
|
+
And I commit the changes with message "Add CI option test file"
|
|
41
|
+
When I run: bard deploy --ci=local
|
|
42
|
+
Then the output should contain "Continuous integration: starting build"
|
|
43
|
+
And the output should contain "Continuous integration: success!"
|
|
44
|
+
And the output should contain "Deploy Succeeded"
|
|
45
|
+
|
|
46
|
+
Scenario: deploy runs CI before deploying
|
|
47
|
+
Given a local CI script that passes
|
|
48
|
+
And I create a file "ci-test.txt" with content "ci test"
|
|
49
|
+
And I commit the changes with message "Add CI test file"
|
|
50
|
+
When I run: bard deploy --local-ci
|
|
51
|
+
Then the output should contain "Continuous integration: starting build"
|
|
52
|
+
And the output should contain "Continuous integration: success!"
|
|
53
|
+
And the output should contain "Deploy Succeeded"
|
|
54
|
+
|
|
55
|
+
Scenario: deploy aborts if CI fails
|
|
56
|
+
Given a local CI script that fails with "Build failed"
|
|
57
|
+
And I create a file "ci-fail.txt" with content "ci fail test"
|
|
58
|
+
And I commit the changes with message "Add CI fail test file"
|
|
59
|
+
When I run expecting failure: bard deploy --local-ci
|
|
60
|
+
Then the output should contain "Continuous integration: starting build"
|
|
61
|
+
And the output should contain "Build failed"
|
|
62
|
+
And the output should contain "Automated tests failed!"
|
|
63
|
+
And the output should not contain "Deploy Succeeded"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@server
|
|
2
|
+
Feature: bard data
|
|
3
|
+
Copy database from a remote server to local.
|
|
4
|
+
|
|
5
|
+
Background:
|
|
6
|
+
Given a test server is running
|
|
7
|
+
|
|
8
|
+
Scenario: copies database from production to local
|
|
9
|
+
When I run: bard data
|
|
10
|
+
Then the output should contain "Dumping production database to file"
|
|
11
|
+
And the output should contain "Transfering file from production to local"
|
|
12
|
+
And the output should contain "Loading file into local database"
|
|
13
|
+
And a file "db/data.sql.gz" should exist locally
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
@server
|
|
2
|
+
Feature: bard deploy
|
|
3
|
+
Deploy code changes to a remote server.
|
|
4
|
+
|
|
5
|
+
Background:
|
|
6
|
+
Given a test server is running
|
|
7
|
+
|
|
8
|
+
Scenario: deploys code changes to the remote server
|
|
9
|
+
Given I create a file "DEPLOYED.txt" with content "deployed by bard"
|
|
10
|
+
And I commit the changes with message "Add deployed marker"
|
|
11
|
+
When I run: bard deploy --skip-ci
|
|
12
|
+
Then the output should contain "Deploy Succeeded"
|
|
13
|
+
When I run: bard run "cat DEPLOYED.txt"
|
|
14
|
+
Then the output should contain "deployed by bard"
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
@server
|
|
2
|
+
Feature: bard deploy git workflow
|
|
3
|
+
Git workflow behaviors during deploy.
|
|
4
|
+
|
|
5
|
+
Background:
|
|
6
|
+
Given a test server is running
|
|
7
|
+
|
|
8
|
+
Scenario: deploy on master pushes unpushed commits
|
|
9
|
+
Given I create a file "local-only.txt" with content "local commit"
|
|
10
|
+
And I commit the changes with message "Add local only file"
|
|
11
|
+
When I run: bard deploy --skip-ci
|
|
12
|
+
Then the output should contain "Deploy Succeeded"
|
|
13
|
+
When I run: bard run "cat local-only.txt"
|
|
14
|
+
Then the output should contain "local commit"
|
|
15
|
+
|
|
16
|
+
Scenario: feature branch fast-forward merge
|
|
17
|
+
Given I create and switch to branch "feature-branch"
|
|
18
|
+
And I create a file "feature.txt" with content "feature content"
|
|
19
|
+
And I commit the changes with message "Add feature"
|
|
20
|
+
When I run: bard deploy --skip-ci
|
|
21
|
+
Then the output should contain "Deploy Succeeded"
|
|
22
|
+
And I should be on branch "master"
|
|
23
|
+
And branch "feature-branch" should not exist locally
|
|
24
|
+
And branch "feature-branch" should not exist on origin
|
|
25
|
+
When I run: bard run "cat feature.txt"
|
|
26
|
+
Then the output should contain "feature content"
|
|
27
|
+
|
|
28
|
+
Scenario: feature branch requires rebase
|
|
29
|
+
Given I create and switch to branch "feature-branch"
|
|
30
|
+
And I create a file "feature.txt" with content "feature content"
|
|
31
|
+
And I commit the changes with message "Add feature"
|
|
32
|
+
And master has an additional commit from another source
|
|
33
|
+
When I run: bard deploy --skip-ci
|
|
34
|
+
Then the output should contain "The master branch has advanced"
|
|
35
|
+
And the output should contain "Attempting rebase"
|
|
36
|
+
And the output should contain "Deploy Succeeded"
|
|
37
|
+
And I should be on branch "master"
|
|
38
|
+
When I run: bard run "cat feature.txt"
|
|
39
|
+
Then the output should contain "feature content"
|
|
40
|
+
When I run: bard run "cat remote-change.txt"
|
|
41
|
+
Then the output should contain "remote change"
|
|
42
|
+
|
|
43
|
+
Scenario: feature branch rebase conflict
|
|
44
|
+
Given I create and switch to branch "feature-branch"
|
|
45
|
+
And I create a file "conflict.txt" with content "feature content"
|
|
46
|
+
And I commit the changes with message "Add conflicting file"
|
|
47
|
+
And master has a conflicting commit to "conflict.txt"
|
|
48
|
+
When I run expecting failure: bard deploy --skip-ci
|
|
49
|
+
Then the output should contain "The master branch has advanced"
|
|
50
|
+
And the output should contain "Attempting rebase"
|
|
51
|
+
And the output should contain "Running command failed"
|
|
52
|
+
|
|
53
|
+
Scenario: branch cleanup after deploy
|
|
54
|
+
Given I create and switch to branch "cleanup-test"
|
|
55
|
+
And I create a file "cleanup.txt" with content "cleanup test"
|
|
56
|
+
And I commit the changes with message "Add cleanup test file"
|
|
57
|
+
And I push branch "cleanup-test" to origin
|
|
58
|
+
When I run: bard deploy --skip-ci
|
|
59
|
+
Then the output should contain "Deleting branch: cleanup-test"
|
|
60
|
+
And the output should contain "Deploy Succeeded"
|
|
61
|
+
And I should be on branch "master"
|
|
62
|
+
And branch "cleanup-test" should not exist locally
|
|
63
|
+
And branch "cleanup-test" should not exist on origin
|
|
64
|
+
|
|
65
|
+
Scenario: deploy a branch without checking it out
|
|
66
|
+
Given I create and switch to branch "feature-branch"
|
|
67
|
+
And I create a file "feature.txt" with content "feature content"
|
|
68
|
+
And I commit the changes with message "Add feature"
|
|
69
|
+
And I switch to branch "master"
|
|
70
|
+
When I run: bard deploy feature-branch --skip-ci
|
|
71
|
+
Then the output should contain "Deploy Succeeded"
|
|
72
|
+
And I should be on branch "master"
|
|
73
|
+
And branch "feature-branch" should not exist locally
|
|
74
|
+
When I run: bard run "cat feature.txt"
|
|
75
|
+
Then the output should contain "feature content"
|
|
76
|
+
|
|
77
|
+
Scenario: deploy a branch that requires rebase without checking it out
|
|
78
|
+
Given I create and switch to branch "feature-branch"
|
|
79
|
+
And I create a file "feature.txt" with content "feature content"
|
|
80
|
+
And I commit the changes with message "Add feature"
|
|
81
|
+
And I switch to branch "master"
|
|
82
|
+
And master has an additional commit from another source
|
|
83
|
+
When I run: bard deploy feature-branch --skip-ci
|
|
84
|
+
Then the output should contain "The master branch has advanced"
|
|
85
|
+
And the output should contain "Attempting rebase"
|
|
86
|
+
And the output should contain "Deploy Succeeded"
|
|
87
|
+
And I should be on branch "master"
|
|
88
|
+
When I run: bard run "cat feature.txt"
|
|
89
|
+
Then the output should contain "feature content"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
@server
|
|
2
|
+
Feature: bard run
|
|
3
|
+
Execute commands on a remote server.
|
|
4
|
+
|
|
5
|
+
Background:
|
|
6
|
+
Given a test server is running
|
|
7
|
+
|
|
8
|
+
Scenario: executes a command on the remote server
|
|
9
|
+
When I run: bard run "echo hello"
|
|
10
|
+
Then the output should contain "hello"
|
|
11
|
+
|
|
12
|
+
Scenario: operates in the configured path
|
|
13
|
+
When I run: bard run "pwd"
|
|
14
|
+
Then the output should contain "testproject"
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Given /^a test server is running$/ do
|
|
2
|
+
raise "Test server failed to start" unless @container && @ssh_port
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
When /^I run: bard (.+)$/ do |command|
|
|
6
|
+
run_bard(command)
|
|
7
|
+
unless @status.success?
|
|
8
|
+
raise "Command failed with status: #{@status}\nOutput: #{@stdout}"
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
When /^I run expecting failure: bard (.+)$/ do |command|
|
|
13
|
+
run_bard(command)
|
|
14
|
+
unless !@status.success?
|
|
15
|
+
raise "Command succeeded but was expected to fail\nOutput: #{@stdout}"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Then /^the output should contain "([^\"]+)"$/ do |expected|
|
|
20
|
+
expect(@stdout).to include(expected)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Given /^I create a file "([^\"]+)" with content "([^\"]+)"$/ do |filename, content|
|
|
24
|
+
Dir.chdir(@test_dir) do
|
|
25
|
+
File.write(filename, content)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
Given /^I commit the changes with message "([^\"]+)"$/ do |message|
|
|
30
|
+
Dir.chdir(@test_dir) do
|
|
31
|
+
system("git add -A", out: File::NULL, err: File::NULL)
|
|
32
|
+
system("git commit -m '#{message}'", out: File::NULL, err: File::NULL)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
Then /^a file "([^\"]+)" should exist locally$/ do |filename|
|
|
37
|
+
path = File.join(@test_dir, filename)
|
|
38
|
+
expect(File.exist?(path)).to be(true), "Expected file #{filename} to exist at #{path}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Branch management
|
|
42
|
+
Given /^I create and switch to branch "([^"]+)"$/ do |branch_name|
|
|
43
|
+
Dir.chdir(@test_dir) do
|
|
44
|
+
system("git checkout -b #{branch_name}", out: File::NULL, err: File::NULL)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
Then /^I should be on branch "([^"]+)"$/ do |expected_branch|
|
|
49
|
+
Dir.chdir(@test_dir) do
|
|
50
|
+
current = `git rev-parse --abbrev-ref HEAD`.chomp
|
|
51
|
+
expect(current).to eq(expected_branch)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
Given /^I push branch "([^"]+)" to origin$/ do |branch_name|
|
|
56
|
+
Dir.chdir(@test_dir) do
|
|
57
|
+
system("git push -u origin #{branch_name}", out: File::NULL, err: File::NULL)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
Then /^branch "([^"]+)" should not exist locally$/ do |branch_name|
|
|
62
|
+
Dir.chdir(@test_dir) do
|
|
63
|
+
result = system("git rev-parse --verify #{branch_name}", out: File::NULL, err: File::NULL)
|
|
64
|
+
expect(result).to be(false), "Expected branch #{branch_name} to not exist locally"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
Then /^branch "([^"]+)" should not exist on origin$/ do |branch_name|
|
|
69
|
+
Dir.chdir(@test_dir) do
|
|
70
|
+
system("git fetch --prune origin", out: File::NULL, err: File::NULL)
|
|
71
|
+
result = system("git rev-parse --verify origin/#{branch_name}", out: File::NULL, err: File::NULL)
|
|
72
|
+
expect(result).to be(false), "Expected branch #{branch_name} to not exist on origin"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Simulating remote changes
|
|
77
|
+
Given /^master has an additional commit from another source$/ do
|
|
78
|
+
run_ssh "cd ~/testproject && git pull origin master"
|
|
79
|
+
run_ssh "cd ~/testproject && echo 'remote change' > remote-change.txt"
|
|
80
|
+
run_ssh "cd ~/testproject && git add remote-change.txt"
|
|
81
|
+
run_ssh "cd ~/testproject && git commit -m 'Remote commit on master'"
|
|
82
|
+
run_ssh "cd ~/testproject && git push origin master"
|
|
83
|
+
|
|
84
|
+
Dir.chdir(@test_dir) do
|
|
85
|
+
system("git fetch origin", out: File::NULL, err: File::NULL)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
Given /^master has a conflicting commit to "([^"]+)"$/ do |filename|
|
|
90
|
+
run_ssh "cd ~/testproject && git pull origin master"
|
|
91
|
+
run_ssh "cd ~/testproject && echo 'conflicting content from remote' > #{filename}"
|
|
92
|
+
run_ssh "cd ~/testproject && git add #{filename}"
|
|
93
|
+
run_ssh "cd ~/testproject && git commit -m 'Remote conflicting commit'"
|
|
94
|
+
run_ssh "cd ~/testproject && git push origin master"
|
|
95
|
+
|
|
96
|
+
Dir.chdir(@test_dir) do
|
|
97
|
+
system("git fetch origin", out: File::NULL, err: File::NULL)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# CI setup
|
|
102
|
+
Given /^a local CI script that passes$/ do
|
|
103
|
+
Dir.chdir(@test_dir) do
|
|
104
|
+
File.write("bin/rake", <<~'SCRIPT')
|
|
105
|
+
#!/bin/bash
|
|
106
|
+
case "$1" in
|
|
107
|
+
ci) echo "All tests passed!"; exit 0 ;;
|
|
108
|
+
esac
|
|
109
|
+
SCRIPT
|
|
110
|
+
FileUtils.chmod(0o755, "bin/rake")
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
Given /^a local CI script that fails with "([^"]+)"$/ do |error_message|
|
|
115
|
+
Dir.chdir(@test_dir) do
|
|
116
|
+
File.write("bin/rake", <<~SCRIPT)
|
|
117
|
+
#!/bin/bash
|
|
118
|
+
case "$1" in
|
|
119
|
+
ci) echo "#{error_message}"; exit 1 ;;
|
|
120
|
+
esac
|
|
121
|
+
SCRIPT
|
|
122
|
+
FileUtils.chmod(0o755, "bin/rake")
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
Given /^I switch to branch "([^"]+)"$/ do |branch_name|
|
|
127
|
+
Dir.chdir(@test_dir) do
|
|
128
|
+
system("git checkout #{branch_name}", out: File::NULL, err: File::NULL)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Output negation
|
|
133
|
+
Then /^the output should not contain "([^"]+)"$/ do |unexpected|
|
|
134
|
+
expect(@stdout).not_to include(unexpected)
|
|
135
|
+
end
|
|
136
|
+
|