nvoi 0.1.6 → 0.1.8
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/.claude/todo/refactor/12-cli-db-command.md +128 -0
- data/.claude/todo/refactor-execution/00-entrypoint.md +49 -0
- data/.claude/todo/refactor-execution/01-objects.md +42 -0
- data/.claude/todo/refactor-execution/02-utils.md +41 -0
- data/.claude/todo/refactor-execution/03-external-cloud.md +38 -0
- data/.claude/todo/refactor-execution/04-external-dns.md +35 -0
- data/.claude/todo/refactor-execution/05-external-other.md +46 -0
- data/.claude/todo/refactor-execution/06-cli-deploy.md +45 -0
- data/.claude/todo/refactor-execution/07-cli-delete.md +43 -0
- data/.claude/todo/refactor-execution/08-cli-exec.md +30 -0
- data/.claude/todo/refactor-execution/09-cli-credentials.md +34 -0
- data/.claude/todo/refactor-execution/10-cli-db.md +31 -0
- data/.claude/todo/refactor-execution/11-cli-router.md +44 -0
- data/.claude/todo/refactor-execution/12-cleanup.md +120 -0
- data/.claude/todo/refactor-execution/_monitoring-strategy.md +126 -0
- data/.claude/todos/buckets.md +41 -0
- data/.claude/todos.md +550 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +35 -4
- data/Rakefile +1 -1
- data/ingest +0 -0
- data/lib/nvoi/cli/config/command.rb +219 -0
- data/lib/nvoi/cli/delete/steps/teardown_dns.rb +12 -11
- data/lib/nvoi/cli/deploy/command.rb +27 -11
- data/lib/nvoi/cli/deploy/steps/build_image.rb +48 -6
- data/lib/nvoi/cli/deploy/steps/configure_tunnel.rb +15 -13
- data/lib/nvoi/cli/deploy/steps/deploy_service.rb +8 -15
- data/lib/nvoi/cli/deploy/steps/setup_k3s.rb +10 -1
- data/lib/nvoi/cli/logs/command.rb +66 -0
- data/lib/nvoi/cli/onboard/command.rb +761 -0
- data/lib/nvoi/cli/unlock/command.rb +72 -0
- data/lib/nvoi/cli.rb +257 -0
- data/lib/nvoi/config_api/actions/app.rb +30 -30
- data/lib/nvoi/config_api/actions/compute_provider.rb +31 -31
- data/lib/nvoi/config_api/actions/database.rb +42 -42
- data/lib/nvoi/config_api/actions/domain_provider.rb +40 -0
- data/lib/nvoi/config_api/actions/env.rb +12 -12
- data/lib/nvoi/config_api/actions/init.rb +67 -0
- data/lib/nvoi/config_api/actions/secret.rb +12 -12
- data/lib/nvoi/config_api/actions/server.rb +35 -35
- data/lib/nvoi/config_api/actions/service.rb +52 -0
- data/lib/nvoi/config_api/actions/volume.rb +18 -18
- data/lib/nvoi/config_api/base.rb +15 -21
- data/lib/nvoi/config_api/result.rb +5 -5
- data/lib/nvoi/config_api.rb +51 -28
- data/lib/nvoi/external/cloud/aws.rb +26 -1
- data/lib/nvoi/external/cloud/hetzner.rb +27 -1
- data/lib/nvoi/external/cloud/scaleway.rb +32 -6
- data/lib/nvoi/external/containerd.rb +1 -44
- data/lib/nvoi/external/dns/cloudflare.rb +34 -16
- data/lib/nvoi/external/ssh.rb +0 -12
- data/lib/nvoi/external/ssh_tunnel.rb +100 -0
- data/lib/nvoi/objects/configuration.rb +20 -0
- data/lib/nvoi/utils/namer.rb +9 -0
- data/lib/nvoi/utils/retry.rb +1 -1
- data/lib/nvoi/version.rb +1 -1
- data/lib/nvoi.rb +16 -0
- data/templates/app-ingress.yaml.erb +3 -1
- metadata +27 -1
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# 12 - Cleanup Execution
|
|
2
|
+
|
|
3
|
+
## Reference
|
|
4
|
+
Read from: `/Users/ben/Desktop/nvoi-rb/lib/nvoi/`
|
|
5
|
+
|
|
6
|
+
## Build
|
|
7
|
+
|
|
8
|
+
### Zeitwerk Pattern (dev-only dependency)
|
|
9
|
+
|
|
10
|
+
**Gemfile:**
|
|
11
|
+
```ruby
|
|
12
|
+
group :development do
|
|
13
|
+
gem "zeitwerk"
|
|
14
|
+
end
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**lib/nvoi.rb:**
|
|
18
|
+
```ruby
|
|
19
|
+
# frozen_string_literal: true
|
|
20
|
+
|
|
21
|
+
if defined?(Nvoi::AUTOLOADERS)
|
|
22
|
+
require "zeitwerk"
|
|
23
|
+
Nvoi::AUTOLOADERS << Zeitwerk::Loader.for_gem.tap do |loader|
|
|
24
|
+
loader.ignore("#{__dir__}/nvoi/loader.rb")
|
|
25
|
+
loader.setup
|
|
26
|
+
end
|
|
27
|
+
else
|
|
28
|
+
require_relative "nvoi/loader"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
module Nvoi
|
|
32
|
+
VERSION = "0.1.0"
|
|
33
|
+
end
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**bin/generate_loader** (script to regenerate loader.rb):
|
|
37
|
+
```ruby
|
|
38
|
+
#!/usr/bin/env ruby
|
|
39
|
+
require "zeitwerk"
|
|
40
|
+
|
|
41
|
+
loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
|
|
42
|
+
loader.ignore("#{__dir__}/../lib/nvoi/loader.rb")
|
|
43
|
+
|
|
44
|
+
requires = []
|
|
45
|
+
loader.on_load do |cpath, value, abspath|
|
|
46
|
+
requires << abspath.sub("#{__dir__}/../lib/", "").sub(".rb", "")
|
|
47
|
+
end
|
|
48
|
+
loader.setup
|
|
49
|
+
loader.eager_load
|
|
50
|
+
|
|
51
|
+
File.write("#{__dir__}/../lib/nvoi/loader.rb", <<~RUBY)
|
|
52
|
+
# frozen_string_literal: true
|
|
53
|
+
# AUTO-GENERATED by bin/generate_loader - do not edit manually
|
|
54
|
+
|
|
55
|
+
#{requires.map { |r| "require_relative \"#{r.sub('nvoi/', '')}\"" }.join("\n")}
|
|
56
|
+
RUBY
|
|
57
|
+
|
|
58
|
+
puts "Generated lib/nvoi/loader.rb with #{requires.size} requires"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**lib/nvoi/loader.rb** (auto-generated, committed):
|
|
62
|
+
```ruby
|
|
63
|
+
# frozen_string_literal: true
|
|
64
|
+
# AUTO-GENERATED by bin/generate_loader - do not edit manually
|
|
65
|
+
|
|
66
|
+
require_relative "version"
|
|
67
|
+
require_relative "objects/server"
|
|
68
|
+
# ... all files in dependency order
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Create config files
|
|
72
|
+
|
|
73
|
+
Create `lib/nvoi/version.rb`:
|
|
74
|
+
- From reference
|
|
75
|
+
|
|
76
|
+
Create `lib/nvoi/config/` (keep config types):
|
|
77
|
+
- `types.rb` - Config classes (Application, ServerConfig, etc.) - use `Objects::ServiceSpec`
|
|
78
|
+
- Other config files as needed
|
|
79
|
+
|
|
80
|
+
## Validate
|
|
81
|
+
|
|
82
|
+
- [ ] `tree lib/nvoi -L 2` matches target structure
|
|
83
|
+
- [ ] No old directories: `providers/`, `cloudflare/`, `remote/`, `service/`, `steps/`, `deployer/`, `k8s/`, `database/`, `credentials/`
|
|
84
|
+
- [ ] `ruby bin/generate_loader` runs without error
|
|
85
|
+
- [ ] `lib/nvoi.rb` loads without error (with and without Zeitwerk)
|
|
86
|
+
|
|
87
|
+
## Test
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
cd /Users/ben/Desktop/nvoi-rb-refactor
|
|
91
|
+
|
|
92
|
+
# Test with Zeitwerk (dev mode)
|
|
93
|
+
NVOI_AUTOLOADERS=1 ruby -e "module Nvoi; AUTOLOADERS = []; end; require './lib/nvoi'; p Nvoi::Objects::Server"
|
|
94
|
+
|
|
95
|
+
# Test without Zeitwerk (production mode - uses loader.rb)
|
|
96
|
+
ruby -e "require './lib/nvoi'; p Nvoi::Objects::Server"
|
|
97
|
+
|
|
98
|
+
# Full test suite
|
|
99
|
+
bundle exec rake test
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Full test suite must pass.**
|
|
103
|
+
|
|
104
|
+
## Commit
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
git add -A && git commit -m "Phase 12: Final wiring with Zeitwerk pattern"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Final Verification
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# CLI smoke test
|
|
114
|
+
./exe/nvoi --help
|
|
115
|
+
./exe/nvoi deploy --help
|
|
116
|
+
./exe/nvoi delete --help
|
|
117
|
+
./exe/nvoi exec --help
|
|
118
|
+
./exe/nvoi credentials --help
|
|
119
|
+
./exe/nvoi db --help
|
|
120
|
+
```
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Monitoring Strategy
|
|
2
|
+
|
|
3
|
+
## Per-Step Validation
|
|
4
|
+
|
|
5
|
+
### After Every Step
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bundle exec rake test # Must pass
|
|
9
|
+
ruby -c lib/nvoi.rb # Syntax check
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Step-Specific Assertions
|
|
15
|
+
|
|
16
|
+
### 01-objects
|
|
17
|
+
- [ ] `Objects::Server.new(id: "1", name: "x", status: "running", public_ipv4: "1.2.3.4")` works
|
|
18
|
+
- [ ] All Structs accessible under `Nvoi::Objects::`
|
|
19
|
+
- [ ] Old Struct definitions removed from source files
|
|
20
|
+
- [ ] All references updated to `Objects::`
|
|
21
|
+
- [ ] `grep -r "Providers::Server" lib/` returns nothing
|
|
22
|
+
|
|
23
|
+
### 02-utils
|
|
24
|
+
- [ ] `Utils::Logger.new` works
|
|
25
|
+
- [ ] `Utils::Namer.new(config).hostname("app", "example.com")` returns `"app.example.com"`
|
|
26
|
+
- [ ] `Utils::ConfigLoader.new.load(path)` returns config
|
|
27
|
+
- [ ] `Utils::Crypto` encrypts/decrypts
|
|
28
|
+
- [ ] Old files deleted: `logger.rb`, `constants.rb`, `errors.rb`, `config/naming.rb`, etc.
|
|
29
|
+
- [ ] `grep -r "Config::ResourceNamer" lib/` returns nothing
|
|
30
|
+
|
|
31
|
+
### 03-external-cloud
|
|
32
|
+
- [ ] `External::Cloud.for(config)` returns correct provider
|
|
33
|
+
- [ ] `External::Cloud::Hetzner.new(token)` instantiates
|
|
34
|
+
- [ ] Provider methods work: `find_server`, `create_server`, etc.
|
|
35
|
+
- [ ] `providers/` directory deleted
|
|
36
|
+
- [ ] `grep -r "Providers::Hetzner" lib/` returns nothing
|
|
37
|
+
|
|
38
|
+
### 04-external-dns
|
|
39
|
+
- [ ] `External::DNS::Cloudflare.new(token, account_id)` instantiates
|
|
40
|
+
- [ ] `setup_tunnel` method exists and callable
|
|
41
|
+
- [ ] `cloudflare/` directory deleted
|
|
42
|
+
- [ ] `grep -r "Cloudflare::Client" lib/` returns nothing
|
|
43
|
+
|
|
44
|
+
### 05-external-other
|
|
45
|
+
- [ ] `External::SSH.new(ip, key)` instantiates
|
|
46
|
+
- [ ] `External::Kubectl.new(ssh)` instantiates
|
|
47
|
+
- [ ] `External::Containerd.new(ssh)` instantiates
|
|
48
|
+
- [ ] `External::Database.provider_for("postgres")` returns provider
|
|
49
|
+
- [ ] `remote/` directory deleted
|
|
50
|
+
- [ ] `k8s/` directory deleted
|
|
51
|
+
- [ ] `database/` directory deleted
|
|
52
|
+
- [ ] `grep -r "Remote::SSHExecutor" lib/` returns nothing
|
|
53
|
+
|
|
54
|
+
### 06-cli-deploy
|
|
55
|
+
- [ ] `CLI::Deploy::Command.new(options).run` callable
|
|
56
|
+
- [ ] All steps in `cli/deploy/steps/` load without error
|
|
57
|
+
- [ ] Step order matches original flow
|
|
58
|
+
- [ ] `service/deploy.rb` deleted
|
|
59
|
+
- [ ] `steps/` directory deleted
|
|
60
|
+
- [ ] `deployer/` directory deleted
|
|
61
|
+
- [ ] `grep -r "Service::DeployService" lib/` returns nothing
|
|
62
|
+
|
|
63
|
+
### 07-cli-delete
|
|
64
|
+
- [ ] `CLI::Delete::Command.new(options).run` callable
|
|
65
|
+
- [ ] Teardown order preserved (detach → delete servers → delete volumes → etc.)
|
|
66
|
+
- [ ] `service/delete.rb` deleted
|
|
67
|
+
- [ ] `grep -r "Service::DeleteService" lib/` returns nothing
|
|
68
|
+
|
|
69
|
+
### 08-cli-exec
|
|
70
|
+
- [ ] `CLI::Exec::Command.new(options).run(["ls"])` callable
|
|
71
|
+
- [ ] `--all` flag works
|
|
72
|
+
- [ ] `-i` interactive works
|
|
73
|
+
- [ ] `service/exec.rb` deleted
|
|
74
|
+
|
|
75
|
+
### 09-cli-credentials
|
|
76
|
+
- [ ] `CLI::Credentials::Edit::Command.new(options).run` callable
|
|
77
|
+
- [ ] `CLI::Credentials::Show::Command.new(options).run` callable
|
|
78
|
+
- [ ] `credentials/` directory deleted
|
|
79
|
+
|
|
80
|
+
### 10-cli-db
|
|
81
|
+
- [ ] `CLI::Db::Command.new(options).branch_create` callable
|
|
82
|
+
- [ ] `branch_list`, `branch_restore`, `branch_download` callable
|
|
83
|
+
- [ ] `service/db.rb` deleted
|
|
84
|
+
|
|
85
|
+
### 11-cli-router
|
|
86
|
+
- [ ] `nvoi deploy --help` works
|
|
87
|
+
- [ ] `nvoi delete --help` works
|
|
88
|
+
- [ ] `nvoi exec --help` works
|
|
89
|
+
- [ ] `nvoi credentials --help` works
|
|
90
|
+
- [ ] `nvoi db --help` works
|
|
91
|
+
- [ ] `cli.rb` is < 100 lines
|
|
92
|
+
- [ ] `service/` directory deleted (should be empty by now)
|
|
93
|
+
|
|
94
|
+
### 12-cleanup
|
|
95
|
+
- [ ] No empty directories remain
|
|
96
|
+
- [ ] `tree lib/nvoi -L 2` matches expected structure
|
|
97
|
+
- [ ] Full test suite passes
|
|
98
|
+
- [ ] No orphan requires in `lib/nvoi.rb`
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Integration Smoke Test (End)
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Dry run (no actual cloud calls)
|
|
106
|
+
nvoi deploy --help
|
|
107
|
+
nvoi delete --help
|
|
108
|
+
nvoi exec --help
|
|
109
|
+
nvoi credentials show --help
|
|
110
|
+
nvoi db branch --help
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
If all help commands work → routing is correct.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Rollback
|
|
118
|
+
|
|
119
|
+
If any step fails:
|
|
120
|
+
```bash
|
|
121
|
+
git checkout HEAD~1 -- .
|
|
122
|
+
# or
|
|
123
|
+
git reset --hard HEAD~1
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Single commit = single rollback.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Scaleway Bucket Automation
|
|
2
|
+
|
|
3
|
+
Automate bucket provisioning for new tenants/environments.
|
|
4
|
+
|
|
5
|
+
## API
|
|
6
|
+
|
|
7
|
+
No separate management API - use S3-compatible REST API directly via `aws-sdk-s3` gem.
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
require "aws-sdk-s3"
|
|
11
|
+
|
|
12
|
+
client = Aws::S3::Client.new(
|
|
13
|
+
region: "fr-par",
|
|
14
|
+
endpoint: "https://s3.fr-par.scw.cloud",
|
|
15
|
+
access_key_id: Rails.application.credentials.dig(:scaleway, :access_key_id),
|
|
16
|
+
secret_access_key: Rails.application.credentials.dig(:scaleway, :secret_key)
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Create bucket
|
|
20
|
+
client.create_bucket(bucket: "tenant-#{tenant_slug}-#{Rails.env}")
|
|
21
|
+
|
|
22
|
+
# Set CORS
|
|
23
|
+
client.put_bucket_cors(
|
|
24
|
+
bucket: bucket_name,
|
|
25
|
+
cors_configuration: {
|
|
26
|
+
cors_rules: [{
|
|
27
|
+
allowed_origins: ["https://notiplus.com", "https://*.notiplus.com"],
|
|
28
|
+
allowed_methods: ["GET", "PUT"],
|
|
29
|
+
allowed_headers: ["*"],
|
|
30
|
+
max_age_seconds: 3000
|
|
31
|
+
}]
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Tasks
|
|
37
|
+
|
|
38
|
+
- [ ] Create `Scaleway::BucketService` to handle create/configure
|
|
39
|
+
- [ ] Add rake task for provisioning new environment buckets
|
|
40
|
+
- [ ] Hook into tenant creation flow (if multi-tenant)
|
|
41
|
+
- [ ] Add lifecycle rules for old/temp files cleanup
|