Bard
A modular deployment tool for Ruby applications that makes deployment simple and extensible.
Quick Start
# bard.rb
target :production do
ssh "deploy@example.com:22"
endbard deploy productionFeatures
- Modular Capabilities: Enable only the features you need
- Pluggable Strategies: SSH, GitHub Pages, or create your own
- Default Targets: Pre-configured for common Bot and Rose workflows
- Git Integration: Built-in branch management and safety checks
- CI Integration: Auto-detects GitHub Actions or Jenkins
- Data Syncing: Copy databases and assets between targets
Installation
Add to your Gemfile:
gem 'bard'Or install globally:
gem install bardCore Concepts
Targets
A target is a deployment destination. Targets can be servers, serverless environments, static hosting, or anything else you can deploy to.
target :production do
ssh "deploy@example.com:22", path: "app"
endCapabilities
Capabilities are features enabled on targets. Common capabilities include:
- SSH: Remote command execution and file transfer
- Ping: Health check URLs
- Data: Database and file syncing
- Backup: Automatic backups during deployment
Deployment Strategies
Strategies determine how code gets deployed. Built-in strategies:
- SSH: Deploy via git pull on remote server
- GitHub Pages: Deploy static site to gh-pages branch
- Custom: Define your own (Jets, Docker, Kubernetes, etc.)
Configuration
Create a bard.rb file in your project root:
# Simple SSH deployment
target :production do
ssh "deploy@example.com:22",
path: "app",
gateway: "bastion@example.com:22"
end
# GitHub Pages static site
target :production do
github_pages "https://example.com"
end
# Custom strategy (Jets serverless)
require_relative 'lib/jets_deploy_strategy'
target :production do
jets "https://api.example.com", run_tests: true
endDefault Targets
Bard ships with default targets for Bot and Rose workflows. Override any in your bard.rb:
- :local - Local development (no SSH)
- :ci - Jenkins CI at staging.botandrose.com
- :staging - Staging server at staging.botandrose.com
- :gubs - Bot and Rose cloud server
# Override default staging to use Jets
target :staging do
jets "https://staging-api.example.com"
end
# Keep :ci, :gubs, :local as defaultsCommands
Deployment
# Deploy to production
bard deploy production
# Deploy to staging
bard deploy staging
# Deploy feature branch to staging (no merge)
bard stage feature-branch
# Skip CI checks
bard deploy production --skip-ciData Management
# Copy database and assets from production to local
bard data --from=production --to=local
# Copy staging data to local
bard data --from=staging --to=local
# Configure additional paths to sync
# bard.rb:
data "public/uploads", "public/system"SSH Commands
# SSH into a target
bard ssh production
# Run a command on a target
bard run production "bundle exec rails console"CI
# Run CI for current branch
bard ci
# Run tests locally
bard ci --local-ci
# Check CI status
bard ci --statusUtilities
# Open target URL in browser
bard open production
# Ping target to check health
bard ping production
# Show uncommitted changes
bard hurt
# Open changed files in vim
bard vimProvisioning
# Full server provisioning
bard provision deploy@new-server.com:22
# Configure nginx for current app
bard setupSSH Capability
Enable SSH to run commands and transfer files:
target :production do
ssh "user@host:port",
path: "deploy/path",
gateway: "bastion@host:port",
ssh_key: "/path/to/key",
env: "RAILS_ENV=production"
endThis provides:
-
target.run!(command)- Execute remote command (raises on error) -
target.run(command)- Execute remote command (silent on error) -
target.exec!(command)- Replace process with remote command -
target.copy_file(path, to: target)- Copy file to another target -
target.copy_dir(path, to: target)- Rsync directory to another target
Deployment Strategies
SSH Strategy
Deploy by running git pull on remote server:
target :production do
ssh "deploy@example.com:22"
endDeployment runs: git pull origin master && bin/setup
GitHub Pages Strategy
Deploy static site to GitHub Pages:
target :production do
github_pages "https://example.com"
endDeployment:
- Starts Rails server locally
- Mirrors site with wget
- Creates orphan commit with static assets
- Force-pushes to
gh-pagesbranch
Custom Strategies
Create your own deployment strategy:
# lib/jets_deploy_strategy.rb
module Bard
class DeployStrategy
class Jets < DeployStrategy
def deploy
target_name = target.key.to_s
options = target.strategy_options(:jets)
run! "rake vips:build:#{target_name}" unless options[:skip_build]
run! "bundle exec rspec" if should_run_tests?(target_name, options)
run! "jets deploy #{options[:env] || target_name}"
end
private
def should_run_tests?(target_name, options)
return options[:run_tests] if options.key?(:run_tests)
target_name == "production"
end
end
end
endUse it in your bard.rb:
require_relative 'lib/jets_deploy_strategy'
target :production do
jets "https://api.example.com", run_tests: true
end
target :staging do
jets "https://staging-api.example.com", skip_build: true
endStrategies auto-register via Ruby's inherited hook - no manual registration needed!
CI Configuration
Bard auto-detects your CI system:
- Finds
.github/workflows/ci.yml→ GitHub Actions - Otherwise → Jenkins (legacy)
Override via DSL:
# Force specific CI system
ci :github_actions
ci :jenkins
ci :local
# Disable CI
ci falsePing Configuration
Configure health check URLs:
target :production do
ssh "deploy@example.com:22"
ping "https://example.com", "/health", "/status"
endAuto-configured by deployment strategies:
# Ping URL automatically set from Jets URL
target :production do
jets "https://api.example.com"
endData Syncing
Database syncing is enabled by default when SSH is configured. Add file paths to sync:
# Global configuration
data "public/uploads", "public/system"
target :production do
ssh "deploy@example.com:22"
endThen sync:
bard data --from=production --to=localThis:
- Runs
bin/rake db:dumpon source - Copies
db/data.sql.gzvia SCP - Runs
bin/rake db:loadon destination - Rsyncs configured data paths
Backup Configuration
Control whether backups are created during deployment:
# Enable backups (default for SSH deployments)
backup true
# Disable backups (typical for serverless/static)
backup falseExample Configurations
Traditional Rails App
target :staging do
ssh "deploy@staging.example.com:22"
end
target :production do
ssh "deploy@production.example.com:22"
end
data "public/uploads"
backup trueServerless API (Jets)
require_relative 'lib/jets_deploy_strategy'
target :staging do
jets "https://staging-api.example.com"
end
target :production do
jets "https://api.example.com", run_tests: true
end
backup falseHybrid (Jets + SSH for debugging)
require_relative 'lib/jets_deploy_strategy'
target :staging do
jets "https://staging-api.example.com"
ssh "deploy@bastion.example.com:22" # Enables SSH commands
end
target :production do
jets "https://api.example.com"
# No SSH in production
end
backup falseStatic Site
target :production do
github_pages "https://example.com"
end
backup falseOverride Default Targets
# Override default staging to use Jets
target :staging do
jets "https://staging-api.example.com"
end
# Keep :ci, :gubs, :local targets as defaultsMigration from v1.x
See MIGRATION_GUIDE.md for detailed migration instructions.
Key changes in v2.0:
-
serverrenamed totarget - SSH configuration uses hash options
- Strategy-first configuration
- Capability-based commands
Architecture
Bard follows a modular, capability-based architecture:
- Core: Minimal git workflow and configuration
- Capabilities: Features enabled via DSL methods
- Strategies: Pluggable deployment strategies with auto-registration
- Subsystems: Independent and composable
See ARCHITECTURE.md for detailed architecture documentation.
Custom Strategy Guide
See CUSTOM_STRATEGIES.md for a step-by-step guide to creating custom deployment strategies.
Development
# Clone repository
git clone https://github.com/botandrose/bard.git
cd bard
# Install dependencies
bundle install
# Run tests
bundle exec rspec
# Run bard from source
bundle exec bin/bardLicense
MIT License. Copyright (c) 2018 Micah Geisel. See LICENSE for details.
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create new Pull Request