bard 1.7.4 → 2.0.0.beta
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/ARCHITECTURE.md +957 -0
- data/CUSTOM_STRATEGIES.md +701 -0
- data/MIGRATION_GUIDE.md +498 -0
- data/README.md +489 -0
- data/lib/bard/cli/deploy.rb +12 -3
- data/lib/bard/command.rb +25 -9
- data/lib/bard/config.rb +118 -43
- data/lib/bard/copy.rb +57 -13
- data/lib/bard/default_config.rb +35 -0
- data/lib/bard/deploy_strategy/github_pages.rb +135 -0
- data/lib/bard/deploy_strategy/ssh.rb +19 -0
- data/lib/bard/deploy_strategy.rb +60 -0
- data/lib/bard/ssh_server.rb +100 -0
- data/lib/bard/target.rb +239 -0
- data/lib/bard/version.rb +1 -1
- data/spec/bard/capability_spec.rb +97 -0
- data/spec/bard/config_spec.rb +1 -1
- data/spec/bard/deploy_strategy/ssh_spec.rb +67 -0
- data/spec/bard/deploy_strategy_spec.rb +107 -0
- data/spec/bard/dynamic_dsl_spec.rb +126 -0
- data/spec/bard/ssh_server_spec.rb +169 -0
- data/spec/bard/target_spec.rb +239 -0
- metadata +24 -2
data/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,957 @@
|
|
|
1
|
+
# Bard 2.0.0 Architecture
|
|
2
|
+
|
|
3
|
+
## Vision
|
|
4
|
+
|
|
5
|
+
A modular deployment tool where:
|
|
6
|
+
- **Core** provides minimal git workflow and configuration
|
|
7
|
+
- **Capabilities** are enabled via DSL methods
|
|
8
|
+
- **Deployment strategies** are pluggable and auto-registered
|
|
9
|
+
- **Subsystems** are independent and composable
|
|
10
|
+
|
|
11
|
+
## Core Concepts
|
|
12
|
+
|
|
13
|
+
### Target
|
|
14
|
+
A deployment destination. Targets are strategy-agnostic and capability-based.
|
|
15
|
+
|
|
16
|
+
### Capability
|
|
17
|
+
A feature enabled on a target (e.g., SSH, database, file copying, CI).
|
|
18
|
+
|
|
19
|
+
### Deployment Strategy
|
|
20
|
+
How code gets deployed to a target. Strategies are pluggable and auto-register via `inherited` hook.
|
|
21
|
+
|
|
22
|
+
## Subsystems
|
|
23
|
+
|
|
24
|
+
### 1. Core (always enabled)
|
|
25
|
+
**Files:**
|
|
26
|
+
- `lib/bard/config.rb` - Configuration DSL
|
|
27
|
+
- `lib/bard/target.rb` - Target (formerly Server) definition
|
|
28
|
+
- `lib/bard/git.rb` - Git utilities
|
|
29
|
+
- `lib/bard/cli.rb` - CLI framework
|
|
30
|
+
- `lib/bard/deploy_strategy.rb` - Base strategy class with auto-registration
|
|
31
|
+
- `lib/bard/default_config.rb` - Default target configurations
|
|
32
|
+
|
|
33
|
+
**Responsibilities:**
|
|
34
|
+
- Load default configuration
|
|
35
|
+
- Load and evaluate `bard.rb` (overrides defaults)
|
|
36
|
+
- Provide target registry
|
|
37
|
+
- Git workflow (branching, merging, fast-forward checks)
|
|
38
|
+
- Deployment strategy auto-registration
|
|
39
|
+
|
|
40
|
+
**DSL:**
|
|
41
|
+
```ruby
|
|
42
|
+
target :production do
|
|
43
|
+
# DSL methods enable capabilities
|
|
44
|
+
end
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Commands:**
|
|
48
|
+
- `bard deploy` - Core git workflow + delegates to strategy
|
|
49
|
+
- `bard hurt` - Show uncommitted changes (git-based, no target needed)
|
|
50
|
+
- `bard vim` - Open changed files in vim (git-based, no target needed)
|
|
51
|
+
|
|
52
|
+
**Default Targets:**
|
|
53
|
+
Defined in `lib/bard/default_config.rb` (can be overridden in `bard.rb`):
|
|
54
|
+
- `:local` - No SSH, path `./`, ping `#{project_name}.local`
|
|
55
|
+
- `:ci` - Jenkins at `staging.botandrose.com`
|
|
56
|
+
- `:staging` - SSH to `staging.botandrose.com`
|
|
57
|
+
- `:gubs` - SSH to Bot and Rose cloud server
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
### 2. SSH Capability
|
|
62
|
+
**Files:**
|
|
63
|
+
- `lib/bard/ssh_server.rb` - SSH connection abstraction
|
|
64
|
+
- `lib/bard/command.rb` - Remote command execution
|
|
65
|
+
- `lib/bard/copy.rb` - SCP/rsync file transfer
|
|
66
|
+
|
|
67
|
+
**Enabled by:**
|
|
68
|
+
```ruby
|
|
69
|
+
target :production do
|
|
70
|
+
ssh "user@host:port",
|
|
71
|
+
path: "deploy/path",
|
|
72
|
+
gateway: "bastion@host:port",
|
|
73
|
+
ssh_key: "/path/to/key",
|
|
74
|
+
env: "RAILS_ENV=production"
|
|
75
|
+
end
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Provides:**
|
|
79
|
+
- `target.server` - Access to SSHServer object
|
|
80
|
+
- `target.run!(cmd)` - Execute remote command
|
|
81
|
+
- `target.run(cmd)` - Execute remote command (no exception on failure)
|
|
82
|
+
- `target.exec!(cmd)` - Replace current process with remote command
|
|
83
|
+
- `target.copy_file(path, to:)` - Copy file to another target
|
|
84
|
+
- `target.copy_dir(path, to:)` - Rsync directory to another target
|
|
85
|
+
|
|
86
|
+
**Commands enabled:**
|
|
87
|
+
- `bard ssh [target]` - SSH into target
|
|
88
|
+
- `bard run [target] "command"` - Run command on target
|
|
89
|
+
|
|
90
|
+
**Auto-configuration:**
|
|
91
|
+
- Sets ping URL from hostname
|
|
92
|
+
|
|
93
|
+
**Error handling:**
|
|
94
|
+
- Commands that require SSH fail with clear message if capability not enabled
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### 3. Deployment Strategies
|
|
99
|
+
|
|
100
|
+
#### SSH Strategy (built-in)
|
|
101
|
+
**File:** `lib/bard/deploy_strategy/ssh.rb`
|
|
102
|
+
|
|
103
|
+
**Enabled by:**
|
|
104
|
+
```ruby
|
|
105
|
+
target :production do
|
|
106
|
+
ssh "user@host:port"
|
|
107
|
+
end
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Deployment behavior:**
|
|
111
|
+
1. Runs `git pull origin master && bin/setup` on remote server
|
|
112
|
+
|
|
113
|
+
**Requires:** SSH capability
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
#### GitHub Pages Strategy (built-in)
|
|
118
|
+
**File:** `lib/bard/deploy_strategy/github_pages.rb`
|
|
119
|
+
|
|
120
|
+
**Enabled by:**
|
|
121
|
+
```ruby
|
|
122
|
+
target :production do
|
|
123
|
+
github_pages "https://example.com"
|
|
124
|
+
end
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Deployment behavior:**
|
|
128
|
+
1. Starts Rails server locally
|
|
129
|
+
2. Mirrors site with wget
|
|
130
|
+
3. Creates orphan commit with static assets
|
|
131
|
+
4. Force-pushes to `gh-pages` branch
|
|
132
|
+
|
|
133
|
+
**Requires:** None (runs locally)
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
#### Custom Strategies (user-defined)
|
|
138
|
+
**Example:** Jets deployment (lives in crucible project)
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
# In crucible project: lib/jets_deploy_strategy.rb
|
|
142
|
+
module Bard
|
|
143
|
+
class DeployStrategy
|
|
144
|
+
class Jets < DeployStrategy
|
|
145
|
+
def deploy
|
|
146
|
+
target_name = target.key.to_s
|
|
147
|
+
options = target.strategy_options(:jets)
|
|
148
|
+
|
|
149
|
+
run! "rake vips:build:#{target_name}" unless options[:skip_build]
|
|
150
|
+
run! "bundle exec rspec" if should_run_tests?(target_name, options)
|
|
151
|
+
run! "jets deploy #{options[:env] || target_name}"
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
private
|
|
155
|
+
|
|
156
|
+
def should_run_tests?(target_name, options)
|
|
157
|
+
return options[:run_tests] if options.key?(:run_tests)
|
|
158
|
+
target_name == "production"
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Usage:**
|
|
166
|
+
```ruby
|
|
167
|
+
# In crucible/bard.rb
|
|
168
|
+
require_relative 'lib/jets_deploy_strategy'
|
|
169
|
+
|
|
170
|
+
target :production do
|
|
171
|
+
jets "https://api.example.com", run_tests: true
|
|
172
|
+
end
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Auto-registered:** ✅ Via `DeployStrategy.inherited` hook
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
### 4. CI Capability
|
|
180
|
+
**Files:**
|
|
181
|
+
- `lib/bard/ci.rb` - CI abstraction
|
|
182
|
+
- `lib/bard/ci/local.rb` - Local test runner
|
|
183
|
+
- `lib/bard/ci/jenkins.rb` - Jenkins integration
|
|
184
|
+
- `lib/bard/ci/github_actions.rb` - GitHub Actions integration
|
|
185
|
+
|
|
186
|
+
**Auto-enabled:** Based on detection:
|
|
187
|
+
- `.github/workflows/ci.yml` exists → GitHub Actions
|
|
188
|
+
- Otherwise → Jenkins (legacy)
|
|
189
|
+
|
|
190
|
+
**Override via DSL:**
|
|
191
|
+
```ruby
|
|
192
|
+
# Force specific CI system
|
|
193
|
+
ci :github_actions
|
|
194
|
+
ci :jenkins
|
|
195
|
+
ci :local
|
|
196
|
+
|
|
197
|
+
# Disable CI
|
|
198
|
+
ci false
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Commands:**
|
|
202
|
+
- `bard ci [branch]` - Run CI checks
|
|
203
|
+
- `--local-ci` - Run tests locally
|
|
204
|
+
- `--status` - Check CI status
|
|
205
|
+
- `--resume` - Resume existing CI build
|
|
206
|
+
|
|
207
|
+
**Used by:** `bard deploy` (unless `--skip-ci`)
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
### 5. Data Capability
|
|
212
|
+
**Files:**
|
|
213
|
+
- `lib/bard/cli/data.rb` - Data sync command
|
|
214
|
+
|
|
215
|
+
**Enabled by:**
|
|
216
|
+
Database syncing is enabled by default, provided that SSH capability exists on both source and destination targets. The `data` DSL configures additional file paths to sync with rsync.
|
|
217
|
+
```ruby
|
|
218
|
+
# Global configuration (applies to all targets)
|
|
219
|
+
data "public/uploads", "public/system"
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Commands enabled:**
|
|
223
|
+
- `bard data --from=production --to=local` - Copy database and assets
|
|
224
|
+
|
|
225
|
+
**Behavior:**
|
|
226
|
+
1. Runs `bin/rake db:dump` on source target
|
|
227
|
+
2. Copies `db/data.sql.gz` via SCP
|
|
228
|
+
3. Runs `bin/rake db:load` on destination target
|
|
229
|
+
4. Rsyncs each configured data path if configured
|
|
230
|
+
|
|
231
|
+
**Requires:**
|
|
232
|
+
- SSH capability on both source and destination targets
|
|
233
|
+
|
|
234
|
+
**Opitional:**
|
|
235
|
+
- Additional data paths to rsync configured via `data` DSL
|
|
236
|
+
|
|
237
|
+
**Safety:**
|
|
238
|
+
- Warns when pushing to production
|
|
239
|
+
- Requires confirmation with full production URL
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
### 6. Backup Capability
|
|
244
|
+
**Enabled by:**
|
|
245
|
+
```ruby
|
|
246
|
+
# Global configuration
|
|
247
|
+
backup true # Enable backups (default for SSH deployments)
|
|
248
|
+
backup false # Disable backups (typical for serverless/static)
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Purpose:**
|
|
252
|
+
Controls whether database backups are created during deployment/provisioning.
|
|
253
|
+
|
|
254
|
+
**Used by:**
|
|
255
|
+
- Deployment process
|
|
256
|
+
- Provisioning scripts
|
|
257
|
+
|
|
258
|
+
**Separate from:** Data capability (backup is about creating backups, data is about syncing)
|
|
259
|
+
|
|
260
|
+
**Requires:** SSH capability (backups are stored on remote servers)
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
### 7. Master Key Capability
|
|
265
|
+
**Files:**
|
|
266
|
+
- `lib/bard/cli/master_key.rb` - Master key sync
|
|
267
|
+
|
|
268
|
+
**Commands:**
|
|
269
|
+
- `bard master_key --from=production --to=local` - Copy Rails master key
|
|
270
|
+
|
|
271
|
+
**Behavior:**
|
|
272
|
+
- Copies `config/master.key` via SCP between targets
|
|
273
|
+
|
|
274
|
+
**Requires:** SSH capability on both source and destination targets
|
|
275
|
+
|
|
276
|
+
**Used by:**
|
|
277
|
+
- `bard provision` (initial setup)
|
|
278
|
+
- Manual key distribution
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
### 8. Staging Capability
|
|
283
|
+
**Commands:**
|
|
284
|
+
- `bard stage [branch]` - Deploy feature branch to staging without merge
|
|
285
|
+
|
|
286
|
+
**Behavior:**
|
|
287
|
+
1. Pushes branch to origin
|
|
288
|
+
2. Checks out branch on staging server via SSH
|
|
289
|
+
3. Runs `bin/setup`
|
|
290
|
+
4. Pings staging
|
|
291
|
+
|
|
292
|
+
**Requires:**
|
|
293
|
+
- SSH capability on `:staging` target
|
|
294
|
+
- `:production` target must be defined (otherwise use `bard deploy staging`)
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
### 9. Ping Capability
|
|
299
|
+
**Enabled by:**
|
|
300
|
+
```ruby
|
|
301
|
+
target :production do
|
|
302
|
+
ping "https://example.com"
|
|
303
|
+
ping "/health", "/status" # Multiple paths
|
|
304
|
+
end
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**Auto-enabled by:** Deployment strategies that provide URLs
|
|
308
|
+
|
|
309
|
+
**Commands:**
|
|
310
|
+
- `bard ping [target]` - Check if URLs respond
|
|
311
|
+
|
|
312
|
+
**Behavior:**
|
|
313
|
+
- Makes HTTP requests to ping URLs
|
|
314
|
+
- Follows redirects
|
|
315
|
+
- Exits with error if any URL is down
|
|
316
|
+
|
|
317
|
+
**Used by:** `bard deploy` (after successful deployment)
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
### 10. Provisioning (Separate Command)
|
|
322
|
+
**Files:**
|
|
323
|
+
- `lib/bard/provision.rb` - Provision orchestration
|
|
324
|
+
- `lib/bard/provision/*.rb` - Individual provisioning steps
|
|
325
|
+
|
|
326
|
+
**Commands:**
|
|
327
|
+
- `bard setup` - Configure nginx for current app
|
|
328
|
+
- `bard provision [ssh_url]` - Full server provisioning
|
|
329
|
+
|
|
330
|
+
**Provisioning steps:**
|
|
331
|
+
1. SSH - Configure SSH access
|
|
332
|
+
2. User - Create deployment user
|
|
333
|
+
3. AuthorizedKeys - Install SSH keys
|
|
334
|
+
4. Swapfile - Create swap
|
|
335
|
+
5. Apt - Install system packages
|
|
336
|
+
6. MySQL - Install and configure MySQL
|
|
337
|
+
7. Repo - Clone git repository
|
|
338
|
+
8. MasterKey - Install Rails master key
|
|
339
|
+
9. RVM - Install Ruby
|
|
340
|
+
10. App - Bundle and setup app
|
|
341
|
+
11. Passenger - Install Passenger
|
|
342
|
+
12. HTTP - Configure nginx
|
|
343
|
+
13. LogRotation - Configure log rotation
|
|
344
|
+
14. Data - Import initial data (if backup enabled)
|
|
345
|
+
15. Deploy - Initial deployment
|
|
346
|
+
|
|
347
|
+
**Requires:** SSH capability on target
|
|
348
|
+
|
|
349
|
+
**Note:** Provisioning is a one-time server setup command, not a deployment capability
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
### 11. Open Capability
|
|
354
|
+
**Commands:**
|
|
355
|
+
- `bard open [target]` - Open target URL in browser
|
|
356
|
+
|
|
357
|
+
**Behavior:**
|
|
358
|
+
- Uses `ping` URL from target configuration
|
|
359
|
+
- Opens in system default browser
|
|
360
|
+
|
|
361
|
+
**Requires:** Ping URL configured on target
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Capability Dependency Tree
|
|
366
|
+
|
|
367
|
+
```
|
|
368
|
+
Core (always enabled)
|
|
369
|
+
├── Git workflow
|
|
370
|
+
├── Target registry
|
|
371
|
+
└── Strategy auto-registration
|
|
372
|
+
|
|
373
|
+
SSH Capability
|
|
374
|
+
├── Enables: run!, run, exec!, copy_file, copy_dir
|
|
375
|
+
├── Required by: SSH strategy, backup, data, master_key, provisioning
|
|
376
|
+
└── Commands: bard ssh, bard run
|
|
377
|
+
|
|
378
|
+
CI Capability
|
|
379
|
+
├── Auto-detected (github actions / jenkins)
|
|
380
|
+
├── Overridable via DSL
|
|
381
|
+
└── Used by: bard deploy (unless --skip-ci)
|
|
382
|
+
|
|
383
|
+
Data Capability
|
|
384
|
+
├── Requires: SSH on both targets
|
|
385
|
+
└── Commands: bard data
|
|
386
|
+
|
|
387
|
+
Backup Capability
|
|
388
|
+
├── Requires: SSH
|
|
389
|
+
└── Used by: deployment, provisioning
|
|
390
|
+
|
|
391
|
+
Master Key Capability
|
|
392
|
+
├── Requires: SSH on both targets
|
|
393
|
+
└── Commands: bard master_key
|
|
394
|
+
|
|
395
|
+
Ping Capability
|
|
396
|
+
├── Auto-configured by deployment strategies
|
|
397
|
+
└── Commands: bard ping, bard open
|
|
398
|
+
|
|
399
|
+
Deployment Strategies
|
|
400
|
+
├── SSH: requires SSH capability
|
|
401
|
+
├── GitHub Pages: no requirements
|
|
402
|
+
└── Custom (Jets, Docker, etc.): defined by user
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## Modular Architecture
|
|
408
|
+
|
|
409
|
+
### Capability Registration
|
|
410
|
+
|
|
411
|
+
Capabilities are enabled implicitly via DSL methods:
|
|
412
|
+
|
|
413
|
+
```ruby
|
|
414
|
+
# Enable SSH capability
|
|
415
|
+
ssh "user@host"
|
|
416
|
+
|
|
417
|
+
# Enable GitHub Pages deployment
|
|
418
|
+
github_pages "https://example.com"
|
|
419
|
+
|
|
420
|
+
# Enable data sync
|
|
421
|
+
data "public/uploads"
|
|
422
|
+
|
|
423
|
+
# Enable/disable backups
|
|
424
|
+
backup true
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Capability Detection
|
|
428
|
+
|
|
429
|
+
Commands check for capabilities before executing:
|
|
430
|
+
|
|
431
|
+
```ruby
|
|
432
|
+
# In bard/cli/data.rb
|
|
433
|
+
def data
|
|
434
|
+
from = config[options[:from]]
|
|
435
|
+
to = config[options[:to]]
|
|
436
|
+
|
|
437
|
+
# Will raise "SSH not configured for this target" if capability missing
|
|
438
|
+
from.run! "bin/rake db:dump"
|
|
439
|
+
from.copy_file "db/data.sql.gz", to: to
|
|
440
|
+
to.run! "bin/rake db:load"
|
|
441
|
+
|
|
442
|
+
# Only sync if data paths configured
|
|
443
|
+
config.data.each do |path|
|
|
444
|
+
from.copy_dir path, to: to
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Strategy Auto-Registration
|
|
450
|
+
|
|
451
|
+
```ruby
|
|
452
|
+
# In lib/bard/deploy_strategy.rb
|
|
453
|
+
class DeployStrategy
|
|
454
|
+
@strategies = {}
|
|
455
|
+
|
|
456
|
+
def self.inherited(subclass)
|
|
457
|
+
name = extract_strategy_name(subclass)
|
|
458
|
+
strategies[name] = subclass
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
# User defines custom strategy
|
|
463
|
+
class DeployStrategy::Docker < DeployStrategy
|
|
464
|
+
def deploy
|
|
465
|
+
# ...
|
|
466
|
+
end
|
|
467
|
+
end
|
|
468
|
+
# Automatically registers as :docker strategy
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Dynamic DSL Methods
|
|
472
|
+
|
|
473
|
+
```ruby
|
|
474
|
+
# In lib/bard/target.rb
|
|
475
|
+
def method_missing(method, *args, **kwargs)
|
|
476
|
+
if Bard::DeployStrategy[method]
|
|
477
|
+
enable_strategy(method, *args, **kwargs)
|
|
478
|
+
else
|
|
479
|
+
super
|
|
480
|
+
end
|
|
481
|
+
end
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
This allows any registered strategy to be used as a DSL method without modifying Target class.
|
|
485
|
+
|
|
486
|
+
### Default Configuration
|
|
487
|
+
|
|
488
|
+
```ruby
|
|
489
|
+
# lib/bard/default_config.rb
|
|
490
|
+
module Bard
|
|
491
|
+
DEFAULT_CONFIG = proc do |project_name|
|
|
492
|
+
target :local do
|
|
493
|
+
ssh false
|
|
494
|
+
path "./"
|
|
495
|
+
ping "#{project_name}.local"
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
target :ci do
|
|
499
|
+
ssh "jenkins@staging.botandrose.com:22022"
|
|
500
|
+
path "jobs/#{project_name}/workspace"
|
|
501
|
+
ping false
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
target :staging do
|
|
505
|
+
ssh "www@staging.botandrose.com:22022"
|
|
506
|
+
path project_name
|
|
507
|
+
ping "#{project_name}.botandrose.com"
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
target :gubs do
|
|
511
|
+
ssh "botandrose@cloud.hackett.world:22022"
|
|
512
|
+
path "Sites/#{project_name}"
|
|
513
|
+
ping false
|
|
514
|
+
end
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Loaded before user's `bard.rb`, so user can override any default target.
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
## Migration Path (1.x → 2.0.0)
|
|
524
|
+
|
|
525
|
+
### Breaking Changes
|
|
526
|
+
|
|
527
|
+
1. **`server` renamed to `target`**
|
|
528
|
+
- Rationale: More accurate for serverless deployments
|
|
529
|
+
- Migration: `server` is aliased to `target` for compatibility (deprecated)
|
|
530
|
+
|
|
531
|
+
2. **SSH configuration changes**
|
|
532
|
+
```ruby
|
|
533
|
+
# Old (1.x)
|
|
534
|
+
server :production do
|
|
535
|
+
ssh "user@host:port"
|
|
536
|
+
path "deploy/path"
|
|
537
|
+
gateway "bastion@host:port"
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
# New (2.0)
|
|
541
|
+
target :production do
|
|
542
|
+
ssh "user@host:port",
|
|
543
|
+
path: "deploy/path",
|
|
544
|
+
gateway: "bastion@host:port"
|
|
545
|
+
end
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
3. **Strategy-first configuration**
|
|
549
|
+
```ruby
|
|
550
|
+
# Old (1.x)
|
|
551
|
+
server :production do
|
|
552
|
+
github_pages true
|
|
553
|
+
ping "https://example.com"
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
# New (2.0)
|
|
557
|
+
target :production do
|
|
558
|
+
github_pages "https://example.com" # Sets both strategy and ping
|
|
559
|
+
end
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
### Deprecation Warnings
|
|
563
|
+
|
|
564
|
+
Version 1.9.x can include deprecation warnings for:
|
|
565
|
+
- Using `server` instead of `target`
|
|
566
|
+
- Old-style SSH configuration
|
|
567
|
+
- Old-style strategy configuration
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
## Benefits of New Architecture
|
|
572
|
+
|
|
573
|
+
1. **Modularity**: Capabilities are independent and composable
|
|
574
|
+
2. **Extensibility**: Custom deployment strategies without gem modification
|
|
575
|
+
3. **Clarity**:
|
|
576
|
+
- `target` vs `server` distinction
|
|
577
|
+
- Clear capability dependencies (e.g., "data requires SSH")
|
|
578
|
+
4. **Auto-registration**: Strategies register themselves via Ruby's `inherited` hook
|
|
579
|
+
5. **Type safety**: Commands fail fast with clear messages if capability not enabled
|
|
580
|
+
6. **Flexibility**: Mix capabilities (e.g., Jets + SSH for debugging)
|
|
581
|
+
7. **Simplicity**: Default case is concise and clear
|
|
582
|
+
8. **Organization-specific**: Ships with Bot and Rose defaults, easily overridden
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## Example Configurations
|
|
587
|
+
|
|
588
|
+
### Traditional Rails App
|
|
589
|
+
```ruby
|
|
590
|
+
target :staging do
|
|
591
|
+
ssh "deploy@staging.example.com:22"
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
target :production do
|
|
595
|
+
ssh "deploy@production.example.com:22"
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
data "public/uploads"
|
|
599
|
+
backup true
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
### Serverless API (Jets)
|
|
603
|
+
```ruby
|
|
604
|
+
require_relative 'lib/jets_deploy_strategy'
|
|
605
|
+
|
|
606
|
+
target :staging do
|
|
607
|
+
jets "https://staging-api.example.com"
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
target :production do
|
|
611
|
+
jets "https://api.example.com", run_tests: true
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
backup false
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### Hybrid (Jets + SSH for debugging)
|
|
618
|
+
```ruby
|
|
619
|
+
require_relative 'lib/jets_deploy_strategy'
|
|
620
|
+
|
|
621
|
+
target :staging do
|
|
622
|
+
jets "https://staging-api.example.com"
|
|
623
|
+
ssh "deploy@bastion.example.com:22" # Enables SSH commands for debugging
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
target :production do
|
|
627
|
+
jets "https://api.example.com"
|
|
628
|
+
# No SSH in production
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
backup false
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### Static Site
|
|
635
|
+
```ruby
|
|
636
|
+
target :production do
|
|
637
|
+
github_pages "https://example.com"
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
backup false
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
### Override Default Targets
|
|
644
|
+
```ruby
|
|
645
|
+
# Override default staging configuration
|
|
646
|
+
target :staging do
|
|
647
|
+
jets "https://staging-api.example.com"
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
# Keep default :ci, :gubs, :local targets as-is
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
### Custom CI Configuration
|
|
654
|
+
```ruby
|
|
655
|
+
# Force local CI (ignore GitHub Actions)
|
|
656
|
+
ci :local
|
|
657
|
+
|
|
658
|
+
# Or disable CI entirely
|
|
659
|
+
ci false
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
---
|
|
663
|
+
|
|
664
|
+
## Implementation Checklist
|
|
665
|
+
|
|
666
|
+
### Phase 1: Documentation (Write the Spec)
|
|
667
|
+
**Goal:** Document the v2.0.0 API completely before implementation
|
|
668
|
+
|
|
669
|
+
- [ ] Update README.md with v2 API (already done)
|
|
670
|
+
- [ ] Finalize ARCHITECTURE.md (this file)
|
|
671
|
+
- [ ] Create MIGRATION_GUIDE.md (v1 → v2)
|
|
672
|
+
- [ ] Document all breaking changes
|
|
673
|
+
- [ ] Provide migration examples for each change
|
|
674
|
+
- [ ] Include automated migration scripts if possible
|
|
675
|
+
- [ ] Document custom strategy creation
|
|
676
|
+
- [ ] Step-by-step guide
|
|
677
|
+
- [ ] Example implementations (Docker, Kubernetes, etc.)
|
|
678
|
+
- [ ] Auto-registration explanation
|
|
679
|
+
- [ ] Document capability dependencies
|
|
680
|
+
- [ ] Capability dependency tree diagram
|
|
681
|
+
- [ ] Error messages for missing capabilities
|
|
682
|
+
- [ ] Add examples for all common use cases
|
|
683
|
+
- [ ] Traditional Rails app
|
|
684
|
+
- [ ] Serverless (Jets, Lambda)
|
|
685
|
+
- [ ] Static sites (GitHub Pages)
|
|
686
|
+
- [ ] Hybrid deployments
|
|
687
|
+
- [ ] Document default targets and how to override
|
|
688
|
+
|
|
689
|
+
**Success criteria:**
|
|
690
|
+
- Documentation is comprehensive and clear
|
|
691
|
+
- All v2 features are documented
|
|
692
|
+
- Migration path is well-explained
|
|
693
|
+
- Examples cover common use cases
|
|
694
|
+
|
|
695
|
+
---
|
|
696
|
+
|
|
697
|
+
### Phase 2: Testing (TDD - Write Failing Tests)
|
|
698
|
+
**Goal:** Write comprehensive tests that define v2.0.0 behavior
|
|
699
|
+
|
|
700
|
+
- [ ] Test capability system
|
|
701
|
+
- [ ] Capabilities are enabled by DSL methods
|
|
702
|
+
- [ ] Capabilities are checked before command execution
|
|
703
|
+
- [ ] Clear error messages when capability missing
|
|
704
|
+
- [ ] Test strategy auto-registration
|
|
705
|
+
- [ ] Strategies auto-register via `inherited` hook
|
|
706
|
+
- [ ] Strategy name extraction from class name
|
|
707
|
+
- [ ] Strategy retrieval from registry
|
|
708
|
+
- [ ] Test dynamic DSL methods
|
|
709
|
+
- [ ] `method_missing` enables strategies
|
|
710
|
+
- [ ] Auto-configuration of ping URLs
|
|
711
|
+
- [ ] Strategy options storage
|
|
712
|
+
- [ ] Test default configuration
|
|
713
|
+
- [ ] Defaults load before user config
|
|
714
|
+
- [ ] User can override defaults
|
|
715
|
+
- [ ] Default targets work as expected
|
|
716
|
+
- [ ] Test Target (formerly Server)
|
|
717
|
+
- [ ] `target` DSL method creates targets
|
|
718
|
+
- [ ] `server` DSL method works with deprecation (v1.9.x)
|
|
719
|
+
- [ ] SSH configuration with hash options
|
|
720
|
+
- [ ] Capability tracking
|
|
721
|
+
- [ ] Test SSH capability
|
|
722
|
+
- [ ] SSHServer creation
|
|
723
|
+
- [ ] run!, run, exec! methods
|
|
724
|
+
- [ ] copy_file, copy_dir methods
|
|
725
|
+
- [ ] Error when SSH not configured
|
|
726
|
+
- [ ] Test deployment strategies
|
|
727
|
+
- [ ] SSH strategy requires SSH capability
|
|
728
|
+
- [ ] GitHub Pages strategy runs locally
|
|
729
|
+
- [ ] Custom strategy auto-registers
|
|
730
|
+
- [ ] Test data capability
|
|
731
|
+
- [ ] Database sync works with SSH
|
|
732
|
+
- [ ] Additional paths sync if configured
|
|
733
|
+
- [ ] Error when SSH missing on source/destination
|
|
734
|
+
- [ ] Test CI capability
|
|
735
|
+
- [ ] Auto-detection (GitHub Actions vs Jenkins)
|
|
736
|
+
- [ ] Manual override via DSL
|
|
737
|
+
- [ ] Disable via `ci false`
|
|
738
|
+
- [ ] Integration tests
|
|
739
|
+
- [ ] Full deployment workflows
|
|
740
|
+
- [ ] Multi-target data copying
|
|
741
|
+
- [ ] Strategy-specific deployments
|
|
742
|
+
|
|
743
|
+
**Success criteria:**
|
|
744
|
+
- All tests fail (features not implemented yet)
|
|
745
|
+
- Tests clearly define expected behavior
|
|
746
|
+
- Edge cases are covered
|
|
747
|
+
- Error scenarios are tested
|
|
748
|
+
|
|
749
|
+
---
|
|
750
|
+
|
|
751
|
+
### Phase 3: Core Refactoring
|
|
752
|
+
**Goal:** Implement core v2.0.0 architecture
|
|
753
|
+
|
|
754
|
+
- [ ] Rename `Server` to `Target`
|
|
755
|
+
- [ ] Create `lib/bard/target.rb`
|
|
756
|
+
- [ ] Migrate code from `lib/bard/server.rb`
|
|
757
|
+
- [ ] Keep `server.rb` as alias for compatibility
|
|
758
|
+
- [ ] Implement capability tracking system
|
|
759
|
+
- [ ] `enable_capability(name)` method
|
|
760
|
+
- [ ] `has_capability?(name)` method
|
|
761
|
+
- [ ] `require_capability!(name)` with clear errors
|
|
762
|
+
- [ ] Add `DeployStrategy` base class with auto-registration
|
|
763
|
+
- [ ] Create `lib/bard/deploy_strategy.rb`
|
|
764
|
+
- [ ] Implement `inherited` hook for auto-registration
|
|
765
|
+
- [ ] Strategy name extraction from class name
|
|
766
|
+
- [ ] Strategy registry (`DeployStrategy.strategies`)
|
|
767
|
+
- [ ] Extract default configuration
|
|
768
|
+
- [ ] Create `lib/bard/default_config.rb`
|
|
769
|
+
- [ ] Move default targets from Config initialization
|
|
770
|
+
- [ ] Load defaults before user config
|
|
771
|
+
- [ ] Update `Config` class
|
|
772
|
+
- [ ] Load default config first
|
|
773
|
+
- [ ] Then load user `bard.rb`
|
|
774
|
+
- [ ] Support `target` DSL method
|
|
775
|
+
- [ ] Keep `server` alias with deprecation
|
|
776
|
+
|
|
777
|
+
**Success criteria:**
|
|
778
|
+
- Tests for core features pass
|
|
779
|
+
- Capability tracking works
|
|
780
|
+
- Strategies auto-register
|
|
781
|
+
- Default config can be overridden
|
|
782
|
+
|
|
783
|
+
---
|
|
784
|
+
|
|
785
|
+
### Phase 4: SSH Capability
|
|
786
|
+
**Goal:** Refactor SSH into a capability
|
|
787
|
+
|
|
788
|
+
- [ ] Extract SSH connection to `SSHServer` class
|
|
789
|
+
- [ ] Create `lib/bard/ssh_server.rb`
|
|
790
|
+
- [ ] Move SSH-specific methods from Target
|
|
791
|
+
- [ ] URI parsing and connection strings
|
|
792
|
+
- [ ] Update `ssh` DSL method
|
|
793
|
+
- [ ] Accept hash options (path, gateway, ssh_key, env)
|
|
794
|
+
- [ ] Create SSHServer instance
|
|
795
|
+
- [ ] Enable SSH capability
|
|
796
|
+
- [ ] Auto-configure ping from hostname
|
|
797
|
+
- [ ] Add capability checks
|
|
798
|
+
- [ ] `run!` requires SSH capability
|
|
799
|
+
- [ ] `copy_file` requires SSH capability
|
|
800
|
+
- [ ] `copy_dir` requires SSH capability
|
|
801
|
+
- [ ] Clear error messages when SSH missing
|
|
802
|
+
- [ ] Update commands to check SSH capability
|
|
803
|
+
- [ ] `bard ssh` requires SSH
|
|
804
|
+
- [ ] `bard run` requires SSH
|
|
805
|
+
- [ ] Error message: "SSH not configured for this target"
|
|
806
|
+
|
|
807
|
+
**Success criteria:**
|
|
808
|
+
- SSH tests pass
|
|
809
|
+
- SSH is properly isolated as a capability
|
|
810
|
+
- Error messages are clear
|
|
811
|
+
- Commands fail gracefully without SSH
|
|
812
|
+
|
|
813
|
+
---
|
|
814
|
+
|
|
815
|
+
### Phase 5: Strategy Extraction
|
|
816
|
+
**Goal:** Extract deployment strategies into separate classes
|
|
817
|
+
|
|
818
|
+
- [ ] Create `DeployStrategy::SSH`
|
|
819
|
+
- [ ] Move SSH deployment logic
|
|
820
|
+
- [ ] `git pull origin master && bin/setup`
|
|
821
|
+
- [ ] Require SSH capability
|
|
822
|
+
- [ ] Create `DeployStrategy::GithubPages`
|
|
823
|
+
- [ ] Move GitHub Pages deployment logic
|
|
824
|
+
- [ ] Static site building
|
|
825
|
+
- [ ] Git commit and push to gh-pages
|
|
826
|
+
- [ ] Update `deploy.rb` to use strategy registry
|
|
827
|
+
- [ ] Look up strategy from registry
|
|
828
|
+
- [ ] Instantiate and call `deploy`
|
|
829
|
+
- [ ] Error if strategy not found
|
|
830
|
+
- [ ] Add `method_missing` to Target
|
|
831
|
+
- [ ] Check if method is registered strategy
|
|
832
|
+
- [ ] Enable capability and set deploy_strategy
|
|
833
|
+
- [ ] Store options for strategy
|
|
834
|
+
- [ ] Auto-configure ping URL
|
|
835
|
+
|
|
836
|
+
**Success criteria:**
|
|
837
|
+
- Strategy tests pass
|
|
838
|
+
- Deployment strategies are isolated
|
|
839
|
+
- Dynamic DSL methods work
|
|
840
|
+
- Custom strategies can be registered
|
|
841
|
+
|
|
842
|
+
---
|
|
843
|
+
|
|
844
|
+
### Phase 6: Capability Commands
|
|
845
|
+
**Goal:** Update all commands to be capability-aware
|
|
846
|
+
|
|
847
|
+
- [ ] Update `data` command
|
|
848
|
+
- [ ] Database sync always available with SSH
|
|
849
|
+
- [ ] `data` DSL only adds optional file paths
|
|
850
|
+
- [ ] Check SSH capability on source and destination
|
|
851
|
+
- [ ] Clear error when SSH missing
|
|
852
|
+
- [ ] Update `master_key` command
|
|
853
|
+
- [ ] Require SSH on source and destination
|
|
854
|
+
- [ ] Clear error when SSH missing
|
|
855
|
+
- [ ] Update `backup` capability
|
|
856
|
+
- [ ] Separate from `data`
|
|
857
|
+
- [ ] Controls whether backups are created
|
|
858
|
+
- [ ] Requires SSH (backups stored on servers)
|
|
859
|
+
- [ ] Add CI configuration DSL
|
|
860
|
+
- [ ] `ci :github_actions` - force GitHub Actions
|
|
861
|
+
- [ ] `ci :jenkins` - force Jenkins
|
|
862
|
+
- [ ] `ci :local` - run locally
|
|
863
|
+
- [ ] `ci false` - disable CI
|
|
864
|
+
- [ ] Auto-detect by default
|
|
865
|
+
- [ ] Update all remaining commands
|
|
866
|
+
- [ ] `bard stage` requires SSH on staging
|
|
867
|
+
- [ ] `bard ping` requires ping URLs
|
|
868
|
+
- [ ] `bard open` requires ping URLs
|
|
869
|
+
- [ ] `bard provision` requires SSH
|
|
870
|
+
- [ ] Add clear error messages
|
|
871
|
+
- [ ] "SSH not configured for this target"
|
|
872
|
+
- [ ] "Ping URL not configured for this target"
|
|
873
|
+
- [ ] "CI is disabled for this project"
|
|
874
|
+
|
|
875
|
+
**Success criteria:**
|
|
876
|
+
- All capability tests pass
|
|
877
|
+
- Commands check capabilities properly
|
|
878
|
+
- Error messages are helpful
|
|
879
|
+
- No regressions in functionality
|
|
880
|
+
|
|
881
|
+
---
|
|
882
|
+
|
|
883
|
+
### Phase 7: v1.9.x Transitional Release (Dual API Support)
|
|
884
|
+
**Goal:** Support both v1 and v2 APIs simultaneously with deprecation warnings
|
|
885
|
+
|
|
886
|
+
- [ ] Add deprecation warning infrastructure
|
|
887
|
+
- [ ] Support both `server` and `target` DSL methods
|
|
888
|
+
- [ ] `target` is the new primary method
|
|
889
|
+
- [ ] `server` calls `target` with deprecation warning
|
|
890
|
+
- [ ] Support both old and new SSH configuration styles
|
|
891
|
+
```ruby
|
|
892
|
+
# v1 style (deprecated, still works)
|
|
893
|
+
target :production do
|
|
894
|
+
ssh "user@host:port"
|
|
895
|
+
path "deploy/path"
|
|
896
|
+
gateway "bastion@host"
|
|
897
|
+
end
|
|
898
|
+
|
|
899
|
+
# v2 style (preferred)
|
|
900
|
+
target :production do
|
|
901
|
+
ssh "user@host:port", path: "deploy/path", gateway: "bastion@host"
|
|
902
|
+
end
|
|
903
|
+
```
|
|
904
|
+
- [ ] Support both old and new github_pages configuration
|
|
905
|
+
```ruby
|
|
906
|
+
# v1 style (deprecated, still works)
|
|
907
|
+
target :production do
|
|
908
|
+
github_pages true
|
|
909
|
+
ping "https://example.com"
|
|
910
|
+
end
|
|
911
|
+
|
|
912
|
+
# v2 style (preferred)
|
|
913
|
+
target :production do
|
|
914
|
+
github_pages "https://example.com"
|
|
915
|
+
end
|
|
916
|
+
```
|
|
917
|
+
- [ ] Add deprecation warnings that guide users to v2 API
|
|
918
|
+
- [ ] Update CHANGELOG with deprecation notices
|
|
919
|
+
- [ ] Release v1.9.0 with dual API support
|
|
920
|
+
|
|
921
|
+
**Success criteria:**
|
|
922
|
+
- All existing projects work without changes
|
|
923
|
+
- Deprecation warnings guide users to new API
|
|
924
|
+
- v2 API is fully functional alongside v1 API
|
|
925
|
+
|
|
926
|
+
---
|
|
927
|
+
|
|
928
|
+
### Phase 8: v2.0.0 Release
|
|
929
|
+
**Goal:** Release v2.0.0 with v1 API removed
|
|
930
|
+
|
|
931
|
+
- [ ] Remove v1 API compatibility code
|
|
932
|
+
- [ ] Remove `server` alias (breaking change)
|
|
933
|
+
- [ ] Remove old-style SSH configuration support
|
|
934
|
+
- [ ] Remove old-style strategy configuration
|
|
935
|
+
- [ ] Turn deprecation warnings into errors (if v1 API used)
|
|
936
|
+
- [ ] Update CHANGELOG with all breaking changes
|
|
937
|
+
- [ ] Ensure all tests pass
|
|
938
|
+
- [ ] Release v2.0.0
|
|
939
|
+
|
|
940
|
+
**Success criteria:**
|
|
941
|
+
- Only v2 API supported
|
|
942
|
+
- All tests pass
|
|
943
|
+
- Documentation is up to date
|
|
944
|
+
- CHANGELOG documents all changes
|
|
945
|
+
|
|
946
|
+
---
|
|
947
|
+
|
|
948
|
+
## Success Metrics
|
|
949
|
+
|
|
950
|
+
- [ ] Crucible successfully uses Jets deployment strategy
|
|
951
|
+
- [ ] Existing projects work with minimal bard.rb changes
|
|
952
|
+
- [ ] Documentation is clear and comprehensive
|
|
953
|
+
- [ ] Custom strategies can be created without modifying gem
|
|
954
|
+
- [ ] All tests pass
|
|
955
|
+
- [ ] No regressions in existing functionality
|
|
956
|
+
- [ ] Clear error messages when capabilities missing
|
|
957
|
+
- [ ] Default targets work as expected and can be overridden
|