bard-new 0.1.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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +42 -0
  3. data/.gitignore +4 -0
  4. data/CLAUDE.md +55 -0
  5. data/Gemfile +10 -0
  6. data/Gemfile.lock +179 -0
  7. data/README.md +107 -0
  8. data/Rakefile +8 -0
  9. data/bard-new.gemspec +25 -0
  10. data/features/new.feature +12 -0
  11. data/features/provision.feature +10 -0
  12. data/features/step_definitions/bard_new_steps.rb +64 -0
  13. data/features/support/bard-coverage +16 -0
  14. data/features/support/env.rb +22 -0
  15. data/features/support/new_server.rb +136 -0
  16. data/features/support/provision_server.rb +282 -0
  17. data/lib/bard/new/cli/new.rb +102 -0
  18. data/lib/bard/new/cli/provision.rb +32 -0
  19. data/lib/bard/new/provision/app.rb +9 -0
  20. data/lib/bard/new/provision/apt.rb +15 -0
  21. data/lib/bard/new/provision/authorizedkeys.rb +23 -0
  22. data/lib/bard/new/provision/base.rb +17 -0
  23. data/lib/bard/new/provision/data.rb +23 -0
  24. data/lib/bard/new/provision/deploy.rb +9 -0
  25. data/lib/bard/new/provision/http.rb +15 -0
  26. data/lib/bard/new/provision/logrotation.rb +27 -0
  27. data/lib/bard/new/provision/masterkey.rb +17 -0
  28. data/lib/bard/new/provision/mysql.rb +21 -0
  29. data/lib/bard/new/provision/nginx.rb +31 -0
  30. data/lib/bard/new/provision/repo.rb +71 -0
  31. data/lib/bard/new/provision/rvm.rb +20 -0
  32. data/lib/bard/new/provision/ssh.rb +79 -0
  33. data/lib/bard/new/provision/swapfile.rb +21 -0
  34. data/lib/bard/new/provision/user.rb +43 -0
  35. data/lib/bard/new/rails_template.rb +213 -0
  36. data/lib/bard/new/version.rb +5 -0
  37. data/lib/bard/plugins/new.rb +2 -0
  38. data/spec/acceptance/docker/Dockerfile.new +68 -0
  39. data/spec/acceptance/docker/Dockerfile.provision +41 -0
  40. data/spec/acceptance/docker/entrypoint-new.sh +3 -0
  41. data/spec/acceptance/docker/test_key +27 -0
  42. data/spec/acceptance/docker/test_key.pub +1 -0
  43. data/spec/bard/new/cli/new_spec.rb +85 -0
  44. data/spec/bard/new/cli/provision_spec.rb +40 -0
  45. data/spec/bard/new/provision/app_spec.rb +33 -0
  46. data/spec/bard/new/provision/apt_spec.rb +39 -0
  47. data/spec/bard/new/provision/authorizedkeys_spec.rb +40 -0
  48. data/spec/bard/new/provision/base_spec.rb +34 -0
  49. data/spec/bard/new/provision/data_spec.rb +54 -0
  50. data/spec/bard/new/provision/deploy_spec.rb +33 -0
  51. data/spec/bard/new/provision/http_spec.rb +57 -0
  52. data/spec/bard/new/provision/logrotation_spec.rb +34 -0
  53. data/spec/bard/new/provision/masterkey_spec.rb +62 -0
  54. data/spec/bard/new/provision/mysql_spec.rb +55 -0
  55. data/spec/bard/new/provision/nginx_spec.rb +81 -0
  56. data/spec/bard/new/provision/repo_spec.rb +208 -0
  57. data/spec/bard/new/provision/rvm_spec.rb +49 -0
  58. data/spec/bard/new/provision/ssh_spec.rb +242 -0
  59. data/spec/bard/new/provision/swapfile_spec.rb +33 -0
  60. data/spec/bard/new/provision/user_spec.rb +103 -0
  61. data/spec/spec_helper.rb +19 -0
  62. metadata +214 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8201fa5a621130b02195491b4639865adcc88eb94ec86bceb3f3c2008cb7ece9
4
+ data.tar.gz: f4d6efff097acd5ca4e20d54d07be348b4d8616928860a39d09cca688b4ba81a
5
+ SHA512:
6
+ metadata.gz: 0f1e688442793919d59477e855cf2db2b03ab09b7b8118a6a8a686acb8f412e13609fba9bf793729af83efd6424a2b66000422b9796fa543e56ac6a1ee3d72b9
7
+ data.tar.gz: 146fa6ba13c75198b1fabda558860a8faf1c3ee3d22732ecc51f43ea0eb2938573ddb1fdbd6f2608e090132b9d08da9c54c043923ecf5bb8b9a009757e862ba7
@@ -0,0 +1,42 @@
1
+ name: CI
2
+ on: [push, pull_request]
3
+ jobs:
4
+ test:
5
+ strategy:
6
+ fail-fast: false
7
+ matrix:
8
+ ruby: [ "3.3", "3.4", "4.0" ]
9
+
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - name: Checkout code
13
+ uses: actions/checkout@v4
14
+
15
+ - name: Set up Ruby
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ bundler-cache: true
20
+
21
+ - name: Install Podman
22
+ run: |
23
+ sudo apt-get update -y
24
+ sudo apt-get install -y podman
25
+ sudo nohup podman system service --time=0 tcp://127.0.0.1:8080 > /tmp/podman-service.log 2>&1 &
26
+ for i in {1..30}; do
27
+ if curl --silent --fail http://127.0.0.1:8080/v1.40/version >/dev/null 2>&1; then
28
+ echo "Podman REST API ready at tcp://127.0.0.1:8080"
29
+ break
30
+ fi
31
+ sleep 1
32
+ done
33
+ echo "DOCKER_HOST=tcp://127.0.0.1:8080" >> $GITHUB_ENV
34
+
35
+ - name: Build test container images
36
+ run: |
37
+ sudo podman pull ubuntu:24.04
38
+ sudo podman build -t bard-test-provision -f spec/acceptance/docker/Dockerfile.provision spec/acceptance/docker
39
+ sudo podman build -t bard-test-new -f spec/acceptance/docker/Dockerfile.new .
40
+
41
+ - name: Run tests
42
+ run: bundle exec rake
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ /coverage
2
+ /pkg
3
+ .ruby-version
4
+ .ruby-gemset
data/CLAUDE.md ADDED
@@ -0,0 +1,55 @@
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 this gem is
6
+
7
+ `bard-new` is a plugin for the `bard` CLI gem ([botandrose/bard](https://github.com/botandrose/bard)). It adds two subcommands:
8
+
9
+ - `bard new <project-name>` — scaffolds a new Rails app using `lib/bard/new/rails_template.rb`, optionally pushes to GitHub and stages a deploy.
10
+ - `bard provision [ssh_url]` — idempotently provisions a fresh Ubuntu 24.04 host into a production target, step by step.
11
+
12
+ The plugin entry point is `lib/bard/plugins/new.rb`. The parent `bard` gem's plugin loader auto-requires it (by convention); the gemspec depends on `bard`.
13
+
14
+ ## Architecture
15
+
16
+ ### CLI layer (`lib/bard/new/cli/`)
17
+ Reopens `Bard::CLI` (a Thor subclass from the `bard` gem) and adds `new` and `provision` commands. `new.rb` shells out to `env -i bash -lc` + RVM to run `rails new` with the template; `provision.rb` iterates over `PROVISION_STEPS` and dispatches each to a `Bard::Provision::<Step>` class.
18
+
19
+ ### Provision steps (`lib/bard/new/provision/`)
20
+ Each step is a `Struct.new(:config, :ssh_url)` subclass of `Bard::Provision` (see `base.rb`) implementing `#call`. Steps are **idempotent** — they check current state before acting (e.g. `Nginx#http_responding?`, `SSH#password_auth_enabled?`) and print ` ✓` at the end. `provision_server` returns a duped target whose `ssh` points at the raw `ssh_url` being provisioned; `target` is the final production target from `bard.rb`. The order in `PROVISION_STEPS` matters (SSH → User → AuthorizedKeys → ... → Data).
21
+
22
+ ### Rails template (`lib/bard/new/rails_template.rb`)
23
+ Drives `rails new -m` — generates Gemfile (bard-rails, solid_*, sprockets+dartsass, importmap/turbo/stimulus, exception_notification, puma), writes `Procfile`, adds a `bootstrap` rake task that does `db:prepare` + (in production) `assets:precompile` + `foreman export systemd-user` + `systemctl --user restart`, and runs `bard install && bin/setup && bard setup` after bundle. Reads `ruby_version` and `project_name` from the current `rvm current name`.
24
+
25
+ ### Test infrastructure
26
+ Both cucumber features spin up a real **Podman** container (via `docker-api` against the podman socket) using `spec/acceptance/docker/Dockerfile.{new,provision}`, then SSH in with `spec/acceptance/docker/test_key`. The `@new` tag gives a deploy-ready Ubuntu + RVM + pre-installed bard/bard-new gems for exercising `bard new` — `Dockerfile.new` clones `bard` from GitHub (branch `v2.0`) during the build and `COPY`s the bard-new working tree in (build context is the repo root). The `@provision` tag gives a raw-ish Ubuntu + systemd for exercising the provision steps end-to-end (build context is just `spec/acceptance/docker/`).
27
+
28
+ Coverage is written by both cucumber (`features/support/env.rb`) and rspec (`spec/spec_helper.rb`) via SimpleCov — the cucumber runs shell out through `features/support/bard-coverage`, a wrapper that starts SimpleCov before exec'ing the `bard` binary so the subprocess's line coverage is merged in.
29
+
30
+ ## Commands
31
+
32
+ ```bash
33
+ # Full suite (default rake task runs both)
34
+ bundle exec rake
35
+
36
+ # Unit specs only
37
+ bundle exec rspec
38
+ bundle exec rspec spec/bard/new/provision/nginx_spec.rb # single file
39
+
40
+ # Cucumber — tags select which container gets built/started
41
+ bundle exec cucumber features/new.feature # @new tag
42
+ bundle exec cucumber features/provision.feature # @provision tag
43
+ ```
44
+
45
+ Cucumber runs are slow (they build and boot containers). Per global rules: **always** pipe cucumber output to a uniquely-named file in `/tmp/` and grep it, and never run the full cucumber suite speculatively.
46
+
47
+ Podman must be installed and `systemctl --user start podman.socket` must succeed — the test harness auto-starts it and sets `DOCKER_HOST` to the user socket.
48
+
49
+ ## Conventions specific to this repo
50
+
51
+ - Provision step output format is `print "Name:"` → one `print " action,"` per side effect → `puts " ✓"`. Preserve this when adding/editing steps.
52
+ - Provision steps MUST be idempotent and check state before acting — they are re-run against already-provisioned servers.
53
+ - `provision_server` (raw `ssh_url`) vs `target` (configured production target) is a load-bearing distinction; the SSH step rewrites `ssh_url` to the target port mid-flight so later steps connect to the reconfigured port.
54
+ - New provision steps: add the class name to `PROVISION_STEPS` in `lib/bard/new/cli/provision.rb` in the correct order, create `lib/bard/new/provision/<name>.rb` with a `Bard::Provision::<Name>` class, and add `spec/bard/new/provision/<name>_spec.rb`.
55
+ - The rails template's Ruby version is hardcoded to `ruby-4.0.2` in `cli/new.rb#new_ruby_version`.
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "bard", github: "botandrose/bard", branch: "v2.0"
6
+
7
+ group :test do
8
+ gem "simplecov", require: false
9
+ gem "webmock", require: false
10
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,179 @@
1
+ GIT
2
+ remote: https://github.com/botandrose/bard.git
3
+ revision: eed2de978df9a6e26bd98c2ca1e02da5586e22a0
4
+ branch: v2.0
5
+ specs:
6
+ bard (2.0.0)
7
+ base64
8
+ rbnacl
9
+ rvm
10
+ term-ansicolor (>= 1.0.3)
11
+ thor (>= 0.19.0)
12
+
13
+ PATH
14
+ remote: .
15
+ specs:
16
+ bard-new (0.1.0)
17
+ bard
18
+
19
+ GEM
20
+ remote: http://rubygems.org/
21
+ specs:
22
+ addressable (2.8.9)
23
+ public_suffix (>= 2.0.2, < 8.0)
24
+ base64 (0.3.0)
25
+ bigdecimal (4.1.0)
26
+ builder (3.3.0)
27
+ crack (1.0.1)
28
+ bigdecimal
29
+ rexml
30
+ cucumber (10.2.0)
31
+ base64 (~> 0.2)
32
+ builder (~> 3.2)
33
+ cucumber-ci-environment (> 9, < 12)
34
+ cucumber-core (> 15, < 17)
35
+ cucumber-cucumber-expressions (> 17, < 20)
36
+ cucumber-html-formatter (> 21, < 23)
37
+ diff-lcs (~> 1.5)
38
+ logger (~> 1.6)
39
+ mini_mime (~> 1.1)
40
+ multi_test (~> 1.1)
41
+ sys-uname (~> 1.3)
42
+ cucumber-ci-environment (11.0.0)
43
+ cucumber-core (16.2.0)
44
+ cucumber-gherkin (> 36, < 40)
45
+ cucumber-messages (> 31, < 33)
46
+ cucumber-tag-expressions (> 6, < 9)
47
+ cucumber-cucumber-expressions (19.0.0)
48
+ bigdecimal
49
+ cucumber-gherkin (39.0.0)
50
+ cucumber-messages (>= 31, < 33)
51
+ cucumber-html-formatter (22.3.0)
52
+ cucumber-messages (> 23, < 33)
53
+ cucumber-messages (32.2.0)
54
+ cucumber-tag-expressions (8.1.0)
55
+ date (3.5.1)
56
+ debug (1.11.1)
57
+ irb (~> 1.10)
58
+ reline (>= 0.3.8)
59
+ diff-lcs (1.6.2)
60
+ docile (1.4.1)
61
+ docker-api (2.4.0)
62
+ excon (>= 0.64.0)
63
+ multi_json
64
+ erb (6.0.2)
65
+ excon (1.4.2)
66
+ logger
67
+ ffi (1.17.4)
68
+ ffi (1.17.4-aarch64-linux-gnu)
69
+ ffi (1.17.4-aarch64-linux-musl)
70
+ ffi (1.17.4-arm-linux-gnu)
71
+ ffi (1.17.4-arm-linux-musl)
72
+ ffi (1.17.4-arm64-darwin)
73
+ ffi (1.17.4-x86-linux-gnu)
74
+ ffi (1.17.4-x86-linux-musl)
75
+ ffi (1.17.4-x86_64-darwin)
76
+ ffi (1.17.4-x86_64-linux-gnu)
77
+ ffi (1.17.4-x86_64-linux-musl)
78
+ hashdiff (1.2.1)
79
+ io-console (0.8.2)
80
+ irb (1.17.0)
81
+ pp (>= 0.6.0)
82
+ prism (>= 1.3.0)
83
+ rdoc (>= 4.0.0)
84
+ reline (>= 0.4.2)
85
+ logger (1.7.0)
86
+ memoist3 (1.0.0)
87
+ mini_mime (1.1.5)
88
+ mize (0.6.1)
89
+ multi_json (1.19.1)
90
+ multi_test (1.1.0)
91
+ pp (0.6.3)
92
+ prettyprint
93
+ prettyprint (0.2.0)
94
+ prism (1.9.0)
95
+ psych (5.3.1)
96
+ date
97
+ stringio
98
+ public_suffix (7.0.5)
99
+ rake (13.3.1)
100
+ rbnacl (7.1.2)
101
+ ffi (~> 1)
102
+ rdoc (7.2.0)
103
+ erb
104
+ psych (>= 4.0.0)
105
+ tsort
106
+ readline (0.0.4)
107
+ reline
108
+ reline (0.6.3)
109
+ io-console (~> 0.5)
110
+ rexml (3.4.4)
111
+ rspec (3.13.2)
112
+ rspec-core (~> 3.13.0)
113
+ rspec-expectations (~> 3.13.0)
114
+ rspec-mocks (~> 3.13.0)
115
+ rspec-core (3.13.6)
116
+ rspec-support (~> 3.13.0)
117
+ rspec-expectations (3.13.5)
118
+ diff-lcs (>= 1.2.0, < 2.0)
119
+ rspec-support (~> 3.13.0)
120
+ rspec-mocks (3.13.8)
121
+ diff-lcs (>= 1.2.0, < 2.0)
122
+ rspec-support (~> 3.13.0)
123
+ rspec-support (3.13.7)
124
+ rvm (1.11.3.9)
125
+ simplecov (0.22.0)
126
+ docile (~> 1.1)
127
+ simplecov-html (~> 0.11)
128
+ simplecov_json_formatter (~> 0.1)
129
+ simplecov-html (0.13.2)
130
+ simplecov_json_formatter (0.1.4)
131
+ stringio (3.2.0)
132
+ sync (0.5.0)
133
+ sys-uname (1.5.1)
134
+ ffi (~> 1.1)
135
+ memoist3 (~> 1.0.0)
136
+ term-ansicolor (1.11.3)
137
+ tins (~> 1)
138
+ testcontainers (0.2.0)
139
+ testcontainers-core (= 0.2.0)
140
+ testcontainers-core (0.2.0)
141
+ docker-api (~> 2.2)
142
+ thor (1.5.0)
143
+ tins (1.52.0)
144
+ bigdecimal
145
+ mize (~> 0.6)
146
+ readline
147
+ sync
148
+ tsort (0.2.0)
149
+ webmock (3.26.2)
150
+ addressable (>= 2.8.0)
151
+ crack (>= 0.3.2)
152
+ hashdiff (>= 0.4.0, < 2.0.0)
153
+
154
+ PLATFORMS
155
+ aarch64-linux-gnu
156
+ aarch64-linux-musl
157
+ arm-linux-gnu
158
+ arm-linux-musl
159
+ arm64-darwin
160
+ ruby
161
+ x86-linux-gnu
162
+ x86-linux-musl
163
+ x86_64-darwin
164
+ x86_64-linux-gnu
165
+ x86_64-linux-musl
166
+
167
+ DEPENDENCIES
168
+ bard!
169
+ bard-new!
170
+ cucumber
171
+ debug
172
+ rake
173
+ rspec
174
+ simplecov
175
+ testcontainers
176
+ webmock
177
+
178
+ BUNDLED WITH
179
+ 2.7.2
data/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # bard-new
2
+
3
+ A plugin for the [bard](https://github.com/botandrose/bard) CLI that scaffolds new Rails projects and provisions Ubuntu servers into Bot & Rose production targets.
4
+
5
+ Adds two subcommands:
6
+
7
+ - `bard new <project-name>` — scaffold a new Rails app, push it to GitHub, and stage a deploy.
8
+ - `bard provision [ssh_url]` — idempotently provision a fresh Ubuntu 24.04 host into a production target.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ gem install bard-new
14
+ ```
15
+
16
+ The parent `bard` gem auto-requires installed plugins by convention, so the new commands appear under `bard --help` once the gem is installed.
17
+
18
+ ## `bard new`
19
+
20
+ ```bash
21
+ bard new my_project
22
+ ```
23
+
24
+ Steps:
25
+
26
+ 1. Validates the project name (lowercase letters and digits only, must start with a letter).
27
+ 2. Creates an RVM gemset (`ruby-4.0.2@<project-name>`) and installs Rails (`~> 8.1.0`).
28
+ 3. Runs `rails new` against [`lib/bard/new/rails_template.rb`](lib/bard/new/rails_template.rb), which:
29
+ - writes a Gemfile with `bard-rails`, `solid_*`, sprockets + dartsass, importmap/turbo/stimulus, `exception_notification`, and `puma`
30
+ - writes a `Procfile`
31
+ - adds a `bootstrap` rake task (runs `db:prepare`, and in production runs `assets:precompile`, exports systemd-user units via `foreman`, and restarts the service)
32
+ - runs `bard install && bin/setup && bard setup`
33
+ 4. Creates a private GitHub repo, pushes the initial commit, uploads `config/master.key` as an Actions secret, and enables branch protection on `master`.
34
+ 5. Stages the new project (`bard deploy --clone`).
35
+
36
+ Options:
37
+
38
+ - `--skip-github` — skip GitHub repo creation and push.
39
+ - `--skip-stage` — skip the staging deploy.
40
+
41
+ ## `bard provision`
42
+
43
+ ```bash
44
+ bard provision deploy@new-server.example.com:22
45
+ ```
46
+
47
+ If `ssh_url` is omitted, the `:production` target's SSH URL from `bard.rb` is used.
48
+
49
+ The command iterates through the provisioning steps in order and dispatches each to a class under `Bard::Provision`. Every step is **idempotent** — it inspects current state and skips work that's already done — so re-running against a partially or fully provisioned host is safe.
50
+
51
+ | Step | What it does |
52
+ |------------------|------------------------------------------------------------------------------|
53
+ | `SSH` | Hardens sshd, switches to the port configured on the production target. |
54
+ | `User` | Creates the deploy user. |
55
+ | `AuthorizedKeys` | Installs SSH keys. |
56
+ | `Swapfile` | Allocates a swapfile. |
57
+ | `Apt` | Installs base system packages. |
58
+ | `MySQL` | Installs and configures MySQL, creates the app database and user. |
59
+ | `Repo` | Clones the application repo into the deploy path. |
60
+ | `MasterKey` | Installs `config/master.key`. |
61
+ | `RVM` | Installs RVM and the project's Ruby version. |
62
+ | `App` | Runs `bin/setup` / app bootstrap. |
63
+ | `Nginx` | Installs and configures nginx + TLS. |
64
+ | `Deploy` | Performs the initial deploy. |
65
+ | `HTTP` | Verifies the site responds. |
66
+ | `LogRotation` | Configures logrotate. |
67
+ | `Data` | Syncs initial data. |
68
+
69
+ Options:
70
+
71
+ - `--steps step1 step2 …` — run only a subset of steps (names match the table above).
72
+
73
+ ## Development
74
+
75
+ The test suite uses real Podman containers to exercise both commands end-to-end. You need:
76
+
77
+ - Podman with the user socket enabled: `systemctl --user start podman.socket`
78
+
79
+ ```bash
80
+ bundle install
81
+
82
+ # Full suite (rspec + cucumber)
83
+ bundle exec rake
84
+
85
+ # Unit specs
86
+ bundle exec rspec
87
+ bundle exec rspec spec/bard/new/provision/nginx_spec.rb
88
+
89
+ # Cucumber — tags select which container image gets built
90
+ bundle exec cucumber features/new.feature # @new
91
+ bundle exec cucumber features/provision.feature # @provision
92
+ ```
93
+
94
+ Cucumber runs are slow because they build and boot containers; run individual features rather than the full suite.
95
+
96
+ ## Adding a provision step
97
+
98
+ 1. Add the class name to `PROVISION_STEPS` in [`lib/bard/new/cli/provision.rb`](lib/bard/new/cli/provision.rb) at the correct position — ordering matters (e.g. `SSH` must run before `User`, which must run before `AuthorizedKeys`).
99
+ 2. Create `lib/bard/new/provision/<name>.rb` defining `Bard::Provision::<Name>` as a subclass of `Bard::Provision` (a `Struct.new(:config, :ssh_url)`) with a `#call` method.
100
+ 3. Make `#call` idempotent — check current state before making changes.
101
+ 4. Follow the output convention: `print "Name:"`, then one `print " action,"` per side effect, then `puts " ✓"`.
102
+ 5. Use `provision_server` to SSH to the host being provisioned (raw `ssh_url`) and `target` for the final production target from `bard.rb`. The `SSH` step rewrites `ssh_url` to the configured port mid-flight, so later steps connect to the reconfigured host.
103
+ 6. Add `spec/bard/new/provision/<name>_spec.rb`.
104
+
105
+ ## License
106
+
107
+ MIT. Copyright (c) Micah Geisel.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "cucumber/rake/task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ Cucumber::Rake::Task.new(:cucumber)
7
+
8
+ task :default => [:spec, :cucumber]
data/bard-new.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "bard/new/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "bard-new"
7
+ spec.version = Bard::New::VERSION
8
+ spec.authors = ["Micah Geisel"]
9
+ spec.email = ["micah@botandrose.com"]
10
+ spec.summary = "Project creation and server provisioning for bard."
11
+ spec.homepage = "http://github.com/botandrose/bard-new"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
+ spec.require_paths = ["lib"]
17
+
18
+ spec.add_dependency "bard"
19
+
20
+ spec.add_development_dependency "rake"
21
+ spec.add_development_dependency "rspec"
22
+ spec.add_development_dependency "debug"
23
+ spec.add_development_dependency "cucumber"
24
+ spec.add_development_dependency "testcontainers"
25
+ end
@@ -0,0 +1,12 @@
1
+ @new
2
+ Feature: bard new
3
+ Create a new bard-managed Rails project.
4
+
5
+ Background:
6
+ Given a bard new server is running
7
+
8
+ Scenario: creates a new Rails project
9
+ When I run bard new "testproject"
10
+ Then the output should contain "Project testproject created!"
11
+ And the project "testproject" should run successfully
12
+ And the project "testproject" should respond to http://testproject.localhost
@@ -0,0 +1,10 @@
1
+ @provision
2
+ Feature: bard provision
3
+ Background:
4
+ Given a provision server is running
5
+
6
+ Scenario: provisions a server with nginx reverse proxy
7
+ When I provision the system
8
+ And I set up the test project
9
+ And I provision the app
10
+ Then the site should be running
@@ -0,0 +1,64 @@
1
+ Then /^the output should contain "([^\"]+)"$/ do |expected|
2
+ expect(@stdout).to include(expected)
3
+ end
4
+
5
+ # bard new steps
6
+ Given /^a bard new server is running$/ do
7
+ raise "New server failed to start" unless @new_container && @new_ssh_port
8
+ end
9
+
10
+ When /^I run bard new "([^"]+)"$/ do |project_name|
11
+ run_bard_remote("new #{project_name} --skip-github --skip-stage")
12
+ unless @status.success?
13
+ raise "bard new failed with status: #{@status}\nOutput: #{@stdout}"
14
+ end
15
+ end
16
+
17
+ Then /^the project "([^"]+)" should run successfully$/ do |project_name|
18
+ stdout, status = run_new_ssh("cd /tmp/bardwork/#{project_name} && bin/rails runner 'puts :bard_test_ok'")
19
+ expect(status).to be_success, "rails runner failed:\n#{stdout}"
20
+ expect(stdout).to include("bard_test_ok")
21
+ end
22
+
23
+ Then /^the project "([^"]+)" should respond to http:\/\/(.+)$/ do |project_name, hostname|
24
+ Open3.capture2e(
25
+ "timeout", "3",
26
+ "ssh", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null",
27
+ "-p", @new_ssh_port.to_s, "-i", new_ssh_key_path,
28
+ "deploy@localhost",
29
+ "bash -lc 'cd /tmp/bardwork/#{project_name} && setsid -f bundle exec puma -p 3000 </dev/null >/tmp/puma.log 2>&1'"
30
+ )
31
+ sleep 5
32
+ stdout, status = run_new_ssh("curl -sf -H 'Host: #{hostname}' http://localhost/")
33
+ expect(status).to be_success, "HTTP request to #{hostname} failed:\n#{stdout}"
34
+ expect(stdout).to include(project_name)
35
+ end
36
+
37
+ # bard provision steps
38
+ Given /^a provision server is running$/ do
39
+ raise "Provision server failed to start" unless @container && @ssh_port
40
+ end
41
+
42
+ When /^I provision the system$/ do
43
+ run_provision_phase1
44
+ unless @status.success?
45
+ raise "Provision phase 1 failed:\n#{@stdout}"
46
+ end
47
+ end
48
+
49
+ When /^I set up the test project$/ do
50
+ setup_test_project
51
+ end
52
+
53
+ When /^I provision the app$/ do
54
+ run_provision_phase2
55
+ unless @status.success?
56
+ raise "Provision phase 2 failed:\n#{@stdout}"
57
+ end
58
+ end
59
+
60
+ Then /^the site should be running$/ do
61
+ stdout, status = Open3.capture2e("curl -sf http://127.0.0.1:#{@http_port}/")
62
+ expect(status).to be_success, "Site not responding on port #{@http_port}"
63
+ expect(stdout).to include("hello from testproject")
64
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ root = File.expand_path("../../..", __FILE__)
3
+
4
+ require "simplecov"
5
+ SimpleCov.root(root)
6
+ SimpleCov.start do
7
+ command_name "Cucumber (subprocess #{$$})"
8
+ track_files "lib/**/*.rb"
9
+ add_filter "spec/"
10
+ add_filter "features/"
11
+ coverage_dir "#{root}/coverage"
12
+ end
13
+
14
+ $LOAD_PATH.unshift("#{root}/lib")
15
+ require "bard/cli"
16
+ Bard::CLI.start ARGV
@@ -0,0 +1,22 @@
1
+ require "simplecov"
2
+ SimpleCov.start do
3
+ command_name "Cucumber"
4
+ track_files "lib/**/*.rb"
5
+ add_filter "spec/"
6
+ add_filter "features/"
7
+ end
8
+
9
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
10
+ require "bard/cli"
11
+ require 'rspec/expectations'
12
+ require 'fileutils'
13
+
14
+ ENV["PATH"] = "#{File.dirname(File.expand_path(__FILE__))}:#{ENV['PATH']}"
15
+ ENV["GIT_DIR"] = nil
16
+ ENV["GIT_WORK_TREE"] = nil
17
+ ENV["GIT_INDEX_FILE"] = nil
18
+
19
+ ROOT = File.expand_path(File.dirname(__FILE__) + '/../..')
20
+
21
+ # Ensure tmp directory exists
22
+ FileUtils.mkdir_p(File.join(ROOT, "tmp"))