dnsmadeeasy 0.4.0 → 1.0.3
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/ruby.yml +5 -10
- data/.gitignore +2 -0
- data/.rubocop.yml +5 -4
- data/.rubocop_todo.yml +251 -143
- data/CLAUDE.md +67 -0
- data/Gemfile +9 -1
- data/README.md +854 -0
- data/Rakefile +4 -4
- data/dnsmadeeasy.gemspec +56 -32
- data/docs/badges/coverage_badge.svg +21 -0
- data/docs/dry-cli-based-tools.webloc +8 -0
- data/docs/plan-zone-management.md +756 -0
- data/docs/plans/01-plan-ruby4-baseline.md +38 -0
- data/docs/plans/02-plan-dry-cli-launcher.md +44 -0
- data/docs/plans/03-plan-account-command.md +43 -0
- data/docs/plans/04-plan-zone-record-model.md +48 -0
- data/docs/plans/05-plan-zone-parser.md +41 -0
- data/docs/plans/06-plan-zone-formatter.md +43 -0
- data/docs/plans/07-plan-zone-export.md +58 -0
- data/docs/plans/08-plan-zone-diff.md +42 -0
- data/docs/plans/09-plan-zone-apply.md +69 -0
- data/docs/plans/10-plan-docs-cleanup.md +55 -0
- data/docs/plans/11-plan-zone-cli-arguments.md +114 -0
- data/docs/spec-zone-management.md +242 -0
- data/exe/dme +13 -2
- data/exe/dmez +6 -0
- data/lib/dme.rb +7 -2
- data/lib/dnsmadeeasy/api/client.rb +32 -26
- data/lib/dnsmadeeasy/cli/box_output.rb +9 -0
- data/lib/dnsmadeeasy/cli/commands/account.rb +222 -0
- data/lib/dnsmadeeasy/cli/commands/base.rb +119 -0
- data/lib/dnsmadeeasy/cli/commands/legacy_operation.rb +30 -0
- data/lib/dnsmadeeasy/cli/commands/version.rb +22 -0
- data/lib/dnsmadeeasy/cli/commands/zone.rb +392 -0
- data/lib/dnsmadeeasy/cli/commands.rb +19 -0
- data/lib/dnsmadeeasy/cli/input.rb +14 -0
- data/lib/dnsmadeeasy/cli/launcher.rb +53 -0
- data/lib/dnsmadeeasy/cli/message_helpers.rb +93 -0
- data/lib/dnsmadeeasy/cli/reported_error.rb +10 -0
- data/lib/dnsmadeeasy/credentials/api_keys.rb +11 -9
- data/lib/dnsmadeeasy/credentials.rb +0 -1
- data/lib/dnsmadeeasy/runner.rb +24 -24
- data/lib/dnsmadeeasy/types.rb +19 -0
- data/lib/dnsmadeeasy/version.rb +2 -1
- data/lib/dnsmadeeasy/zone/aname_flattener.rb +63 -0
- data/lib/dnsmadeeasy/zone/apply_executor.rb +189 -0
- data/lib/dnsmadeeasy/zone/apply_result.rb +22 -0
- data/lib/dnsmadeeasy/zone/diff.rb +152 -0
- data/lib/dnsmadeeasy/zone/file.rb +26 -0
- data/lib/dnsmadeeasy/zone/parser.rb +172 -0
- data/lib/dnsmadeeasy/zone/plan.rb +28 -0
- data/lib/dnsmadeeasy/zone/plan_action.rb +29 -0
- data/lib/dnsmadeeasy/zone/plan_renderer.rb +91 -0
- data/lib/dnsmadeeasy/zone/provider_record.rb +18 -0
- data/lib/dnsmadeeasy/zone/record.rb +44 -0
- data/lib/dnsmadeeasy/zone/record_set.rb +23 -0
- data/lib/dnsmadeeasy/zone/remote_adapter.rb +94 -0
- data/lib/dnsmadeeasy/zone/remote_records.rb +26 -0
- data/lib/dnsmadeeasy/zone/serializer.rb +119 -0
- data/lib/dnsmadeeasy.rb +61 -27
- metadata +212 -39
- data/.dme-help.png +0 -0
- data/README.adoc +0 -690
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# 01 Plan: Ruby 4 Baseline
|
|
2
|
+
|
|
3
|
+
## Stacked PR Metadata
|
|
4
|
+
|
|
5
|
+
- Plan identifier: `01`
|
|
6
|
+
- Branch: `stack-01-ruby4-baseline`
|
|
7
|
+
- Base branch: `master`
|
|
8
|
+
- PR title: `01: Establish Ruby 4 baseline for dnsmadeeasy 1.0`
|
|
9
|
+
- PR description must reference: `Plan 01 - Ruby 4 Baseline`
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
|
|
13
|
+
- Drop Ruby 2 support.
|
|
14
|
+
- Add Ruby 4 support.
|
|
15
|
+
- Bump `DnsMadeEasy::VERSION` to `1.0.0`.
|
|
16
|
+
- Update gem metadata and CI Ruby version.
|
|
17
|
+
- Add the first dependency baseline needed by later PRs only when it is directly required here.
|
|
18
|
+
- Preserve current library behavior.
|
|
19
|
+
|
|
20
|
+
## Implementation Notes
|
|
21
|
+
|
|
22
|
+
- Prefer Ruby 4 only with `spec.required_ruby_version = '~> 4.0'` unless we decide public compatibility requires Ruby 3.2+.
|
|
23
|
+
- Add `tsort` explicitly to quiet the Ruby 4.1 default-gem warning from `sym`.
|
|
24
|
+
- Update GitHub Actions from Ruby 2.7 and old `actions/setup-ruby` usage to current `ruby/setup-ruby`.
|
|
25
|
+
|
|
26
|
+
## RSpec Requirements
|
|
27
|
+
|
|
28
|
+
- Update or add specs proving `DnsMadeEasy::VERSION == '1.0.0'`.
|
|
29
|
+
- Keep the Ruby 4 keyword-argument compatibility specs passing.
|
|
30
|
+
- Use modern nested `describe`/`context` blocks with block-local `subject`.
|
|
31
|
+
- Use concise one-liner expectations, including `it { ... }` and `its(:property) { ... }` where readable.
|
|
32
|
+
|
|
33
|
+
## Acceptance Criteria
|
|
34
|
+
|
|
35
|
+
- `bundle exec rspec` passes on Ruby 4.
|
|
36
|
+
- CI config targets Ruby 4.
|
|
37
|
+
- The gem metadata no longer claims Ruby 2 support.
|
|
38
|
+
- No live DNS Made Easy calls are made.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# 02 Plan: dry-cli Launcher and Aruba Test Harness
|
|
2
|
+
|
|
3
|
+
## Stacked PR Metadata
|
|
4
|
+
|
|
5
|
+
- Plan identifier: `02`
|
|
6
|
+
- Branch: `stack-02-dry-cli-launcher`
|
|
7
|
+
- Base branch: `stack-01-ruby4-baseline`
|
|
8
|
+
- PR title: `02: Introduce dry-cli launcher and Aruba harness`
|
|
9
|
+
- PR description must reference: `Plan 02 - dry-cli Launcher and Aruba Test Harness`
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
|
|
13
|
+
- Add `dry-cli`.
|
|
14
|
+
- Include `tty-spinner` as a runtime dependency for later threaded zone export/apply progress reporting.
|
|
15
|
+
- Add a `DnsMadeEasy::CLI::Commands` registry.
|
|
16
|
+
- Add `DnsMadeEasy::CLI::Launcher`.
|
|
17
|
+
- Add `DnsMadeEasy::CLI::Commands::Base`.
|
|
18
|
+
- Add a `version` command.
|
|
19
|
+
- Configure Aruba for in-process CLI tests.
|
|
20
|
+
- Update `exe/dme` to call the launcher.
|
|
21
|
+
- Keep `DnsMadeEasy::Runner` temporarily for migration reference.
|
|
22
|
+
|
|
23
|
+
## Implementation Notes
|
|
24
|
+
|
|
25
|
+
- Follow the `../githuh` launcher shape, but keep the implementation smaller.
|
|
26
|
+
- All command output must use injected `stdout` and `stderr`.
|
|
27
|
+
- Do not put business logic in the launcher.
|
|
28
|
+
- Do not make zone commands in this PR.
|
|
29
|
+
|
|
30
|
+
## RSpec Requirements
|
|
31
|
+
|
|
32
|
+
- Add launcher specs using direct `StringIO` streams.
|
|
33
|
+
- Add Aruba specs for:
|
|
34
|
+
- `dme --help`
|
|
35
|
+
- `dme version`
|
|
36
|
+
- Use `subject(:launcher)` or block-local `subject { output }` per describe block.
|
|
37
|
+
- Use `its(:stdout)` style only where the object exposes a clear property; otherwise use `it { is_expected.to ... }`.
|
|
38
|
+
|
|
39
|
+
## Acceptance Criteria
|
|
40
|
+
|
|
41
|
+
- `dme --help` is handled through dry-cli.
|
|
42
|
+
- `dme version` prints `1.0.0`.
|
|
43
|
+
- Aruba runs the CLI in-process.
|
|
44
|
+
- Existing library specs still pass.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# 03 Plan: Account Command for Existing API Operations
|
|
2
|
+
|
|
3
|
+
## Stacked PR Metadata
|
|
4
|
+
|
|
5
|
+
- Plan identifier: `03`
|
|
6
|
+
- Branch: `stack-03-account-command`
|
|
7
|
+
- Base branch: `stack-02-dry-cli-launcher`
|
|
8
|
+
- PR title: `03: Move existing API operations under account command`
|
|
9
|
+
- PR description must reference: `Plan 03 - Account Command for Existing API Operations`
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
|
|
13
|
+
- Add `dme account <operation> [args...]`.
|
|
14
|
+
- Move existing CLI behavior from `DnsMadeEasy::Runner` into a dry-cli command.
|
|
15
|
+
- Preserve output formats where practical.
|
|
16
|
+
- Validate operation names using `DnsMadeEasy::Api::Client.public_operations`.
|
|
17
|
+
- Replace runner specs with Aruba command specs.
|
|
18
|
+
|
|
19
|
+
## Implementation Notes
|
|
20
|
+
|
|
21
|
+
- Treat `<operation>` as an argument to one `Account` command.
|
|
22
|
+
- Do not generate one dry-cli class per API method unless the single-command design becomes unworkable.
|
|
23
|
+
- For version 1.0, prefer a clear migration hint for old root operations like `dme domains`.
|
|
24
|
+
- Preserve method arity diagnostics where reasonable.
|
|
25
|
+
|
|
26
|
+
## RSpec Requirements
|
|
27
|
+
|
|
28
|
+
- Add Aruba specs for:
|
|
29
|
+
- `dme account operations`
|
|
30
|
+
- `dme account domains`
|
|
31
|
+
- `dme account records_for example.com`
|
|
32
|
+
- invalid account operation
|
|
33
|
+
- invalid arity where current behavior provides a useful message
|
|
34
|
+
- Mock `DnsMadeEasy.client`; do not hit the network.
|
|
35
|
+
- Use nested `describe '#call'`, `context 'with valid operation'`, and `context 'with invalid operation'`.
|
|
36
|
+
- Use `subject { output }` for CLI output examples and `its(:exit_status)` if command objects expose it.
|
|
37
|
+
|
|
38
|
+
## Acceptance Criteria
|
|
39
|
+
|
|
40
|
+
- Existing API operations are reachable through `dme account`.
|
|
41
|
+
- Old `Runner` can be deleted or made a thin deprecated wrapper.
|
|
42
|
+
- `bundle exec rspec` passes.
|
|
43
|
+
- No live DNS Made Easy calls are made.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# 04 Plan: Typed Zone Record Model
|
|
2
|
+
|
|
3
|
+
## Stacked PR Metadata
|
|
4
|
+
|
|
5
|
+
- Plan identifier: `04`
|
|
6
|
+
- Branch: `stack-04-zone-record-model`
|
|
7
|
+
- Base branch: `stack-03-account-command`
|
|
8
|
+
- PR title: `04: Add typed zone record domain model`
|
|
9
|
+
- PR description must reference: `Plan 04 - Typed Zone Record Model`
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
|
|
13
|
+
- Add `dry-types`.
|
|
14
|
+
- Add `dry-struct`.
|
|
15
|
+
- Define internal provider-neutral zone record objects.
|
|
16
|
+
- Define record-set and sorting behavior.
|
|
17
|
+
- Keep provider IDs out of serializable zone records.
|
|
18
|
+
|
|
19
|
+
## Implementation Notes
|
|
20
|
+
|
|
21
|
+
- Create `DnsMadeEasy::Types`.
|
|
22
|
+
- Support initial record types:
|
|
23
|
+
- `A`
|
|
24
|
+
- `AAAA`
|
|
25
|
+
- `CNAME`
|
|
26
|
+
- `MX`
|
|
27
|
+
- `NS`
|
|
28
|
+
- `PTR`
|
|
29
|
+
- `SPF`
|
|
30
|
+
- `SRV`
|
|
31
|
+
- `TXT`
|
|
32
|
+
- Represent DNS Made Easy metadata separately from record equality.
|
|
33
|
+
- Build deterministic sort keys now because serializer and diff will depend on them.
|
|
34
|
+
|
|
35
|
+
## RSpec Requirements
|
|
36
|
+
|
|
37
|
+
- Add specs for valid construction.
|
|
38
|
+
- Add specs for invalid record type, TTL, and required attributes.
|
|
39
|
+
- Add specs for deterministic sorting.
|
|
40
|
+
- Add specs proving provider metadata is separate from record equality.
|
|
41
|
+
- Use `subject(:record) { described_class.new(...) }`.
|
|
42
|
+
- Use `its(:owner) { ... }`, `its(:type) { ... }`, and `it { is_expected.to ... }` one-liners where useful.
|
|
43
|
+
|
|
44
|
+
## Acceptance Criteria
|
|
45
|
+
|
|
46
|
+
- Zone records are immutable typed value objects.
|
|
47
|
+
- Invalid input fails before parser/diff/apply logic can use it.
|
|
48
|
+
- `bundle exec rspec` passes.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# 05 Plan: Zone File Parser and Validation Command
|
|
2
|
+
|
|
3
|
+
## Stacked PR Metadata
|
|
4
|
+
|
|
5
|
+
- Plan identifier: `05`
|
|
6
|
+
- Branch: `stack-05-zone-parser`
|
|
7
|
+
- Base branch: `stack-04-zone-record-model`
|
|
8
|
+
- PR title: `05: Parse and validate standard zone files`
|
|
9
|
+
- PR description must reference: `Plan 05 - Zone File Parser and Validation Command`
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
|
|
13
|
+
- Add `dns-zonefile`.
|
|
14
|
+
- Add `dry-monads` and use `Dry::Monads::Result` for parser and validation service results.
|
|
15
|
+
- Add parser adapter at the boundary.
|
|
16
|
+
- Add `dme zone validate FILE`.
|
|
17
|
+
- Convert parser output immediately into internal zone records.
|
|
18
|
+
|
|
19
|
+
## Implementation Notes
|
|
20
|
+
|
|
21
|
+
- `aeden/dns-zonefile` is sufficient for v1 parsing of downloaded or standard RFC-style zone files.
|
|
22
|
+
- Parser and validation workflows should return `Success(value)` / `Failure(errors)` rather than raising for expected user-input errors.
|
|
23
|
+
- Do not leak `DNS::Zonefile::*` classes beyond the adapter.
|
|
24
|
+
- Unsupported syntax should produce actionable validation errors.
|
|
25
|
+
- `HTTPRED` is not represented in standard zone files and does not need parser support in v1.
|
|
26
|
+
|
|
27
|
+
## RSpec Requirements
|
|
28
|
+
|
|
29
|
+
- Add parser unit specs with fixture zone files.
|
|
30
|
+
- Add Aruba specs for:
|
|
31
|
+
- valid zone file
|
|
32
|
+
- invalid zone file
|
|
33
|
+
- unsupported record type
|
|
34
|
+
- Use `subject(:result) { described_class.new(...).call }` for service specs.
|
|
35
|
+
- Use `its(:records) { ... }`, `its(:errors) { ... }`, and one-liner `it { is_expected.to be_success }` style where available.
|
|
36
|
+
|
|
37
|
+
## Acceptance Criteria
|
|
38
|
+
|
|
39
|
+
- `dme zone validate FILE` succeeds for standard fixture zone files.
|
|
40
|
+
- Parser adapter returns internal records only.
|
|
41
|
+
- `bundle exec rspec` passes.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# 06 Plan: Canonical Zone Serializer and Formatter
|
|
2
|
+
|
|
3
|
+
## Stacked PR Metadata
|
|
4
|
+
|
|
5
|
+
- Plan identifier: `06`
|
|
6
|
+
- Branch: `stack-06-zone-formatter`
|
|
7
|
+
- Base branch: `stack-05-zone-parser`
|
|
8
|
+
- PR title: `06: Add canonical zone serializer and formatter`
|
|
9
|
+
- PR description must reference: `Plan 06 - Canonical Zone Serializer and Formatter`
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
|
|
13
|
+
- Add canonical serializer.
|
|
14
|
+
- Add `dme zone fmt FILE`.
|
|
15
|
+
- Optionally add `dme zone format FILE` as an alias.
|
|
16
|
+
- Normalize whitespace and ordering.
|
|
17
|
+
|
|
18
|
+
## Normalized Output Rules
|
|
19
|
+
|
|
20
|
+
- one zone per file
|
|
21
|
+
- explicit owner on every record
|
|
22
|
+
- `$ORIGIN`
|
|
23
|
+
- `$TTL`
|
|
24
|
+
- `@` for zone apex
|
|
25
|
+
- deterministic ordering
|
|
26
|
+
- normalized, aligned whitespace
|
|
27
|
+
- provider-managed SOA omitted
|
|
28
|
+
- apex NS records omitted by default
|
|
29
|
+
- delegated NS records preserved
|
|
30
|
+
|
|
31
|
+
## RSpec Requirements
|
|
32
|
+
|
|
33
|
+
- Add golden-file specs for formatter output.
|
|
34
|
+
- Add idempotency spec: parse, serialize, parse, serialize produces byte-identical output.
|
|
35
|
+
- Add specs for apex NS omission and delegated NS preservation.
|
|
36
|
+
- Use `subject(:serialized_zone) { described_class.new(...).to_s }`.
|
|
37
|
+
- Use one-liners for exact matches and property checks where readable.
|
|
38
|
+
|
|
39
|
+
## Acceptance Criteria
|
|
40
|
+
|
|
41
|
+
- `dme zone fmt FILE` emits canonical zone text.
|
|
42
|
+
- Already formatted files remain byte-identical.
|
|
43
|
+
- `bundle exec rspec` passes.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# 07 Plan: Remote Adapter and Zone Export
|
|
2
|
+
|
|
3
|
+
## Stacked PR Metadata
|
|
4
|
+
|
|
5
|
+
- Plan identifier: `07`
|
|
6
|
+
- Branch: `stack-07-zone-export`
|
|
7
|
+
- Base branch: `stack-06-zone-formatter`
|
|
8
|
+
- PR title: `07: Export DNS Made Easy records as canonical zone files`
|
|
9
|
+
- PR description must reference: `Plan 07 - Remote Adapter and Zone Export`
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
|
|
13
|
+
- Add remote record adapter.
|
|
14
|
+
- Add `dme zone export DOMAIN`.
|
|
15
|
+
- Convert DNS Made Easy API responses to internal zone records.
|
|
16
|
+
- Serialize remote records through the canonical serializer.
|
|
17
|
+
|
|
18
|
+
## Implementation Notes
|
|
19
|
+
|
|
20
|
+
- Use the existing API client as the provider boundary.
|
|
21
|
+
- Keep provider IDs separate from exported records.
|
|
22
|
+
- Omit `HTTPRED` from exports.
|
|
23
|
+
- Emit warnings listing omitted `HTTPRED` records.
|
|
24
|
+
- Write zone text to stdout by default.
|
|
25
|
+
- Write warnings to stderr so stdout remains pipe-safe.
|
|
26
|
+
- When export requires multiple independent provider calls, split work into bounded worker-thread chunks.
|
|
27
|
+
- Use one `TTY::Spinner` per active worker/chunk for interactive progress.
|
|
28
|
+
- Use `TTY::Spinner::Multi` for concurrent thread progress:
|
|
29
|
+
https://github.com/piotrmurach/tty-spinner#5-ttyspinnermulti-api
|
|
30
|
+
- Collect worker results and render final zone output deterministically after all workers finish.
|
|
31
|
+
- Inject a fake/no-op spinner in specs so output remains stable.
|
|
32
|
+
|
|
33
|
+
## Live Integration Note
|
|
34
|
+
|
|
35
|
+
Opt-in live specs may use:
|
|
36
|
+
|
|
37
|
+
- Domain: `isdue.today`
|
|
38
|
+
- DNS Made Easy domain ID: `8218117`
|
|
39
|
+
|
|
40
|
+
Live specs must be gated by `DNSMADEEASY_LIVE_TESTS=1` or equivalent and must only touch test-owned records.
|
|
41
|
+
|
|
42
|
+
## RSpec Requirements
|
|
43
|
+
|
|
44
|
+
- Add unit specs for remote adapter conversion.
|
|
45
|
+
- Add Aruba specs for export using a mocked client.
|
|
46
|
+
- Add specs proving `HTTPRED` is omitted and warning text is emitted.
|
|
47
|
+
- Add specs for chunked parallel execution with deterministic result ordering.
|
|
48
|
+
- Add specs for failed worker chunks and aggregated error reporting.
|
|
49
|
+
- Add optional live integration specs marked/skipped unless explicitly enabled.
|
|
50
|
+
- Use `subject(:records)`, `subject(:output)`, and `its(:warnings)` where the object model supports it.
|
|
51
|
+
|
|
52
|
+
## Acceptance Criteria
|
|
53
|
+
|
|
54
|
+
- `dme zone export example.com` produces deterministic zone output with mocked data.
|
|
55
|
+
- Provider metadata is not serialized.
|
|
56
|
+
- Independent provider reads can run concurrently with bounded worker threads.
|
|
57
|
+
- Progress is displayed with `TTY::Spinner` during interactive export work.
|
|
58
|
+
- `bundle exec rspec` passes without live credentials.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# 08 Plan: Zone Diff Engine and Plan Command
|
|
2
|
+
|
|
3
|
+
## Stacked PR Metadata
|
|
4
|
+
|
|
5
|
+
- Plan identifier: `08`
|
|
6
|
+
- Branch: `stack-08-zone-diff-plan`
|
|
7
|
+
- Base branch: `stack-07-zone-export`
|
|
8
|
+
- PR title: `08: Add zone diff engine and plan command`
|
|
9
|
+
- PR description must reference: `Plan 08 - Zone Diff Engine and Plan Command`
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
|
|
13
|
+
- Add diff engine.
|
|
14
|
+
- Add execution plan objects.
|
|
15
|
+
- Add text and JSON plan renderers.
|
|
16
|
+
- Add `dme zone plan FILE`.
|
|
17
|
+
|
|
18
|
+
## Implementation Notes
|
|
19
|
+
|
|
20
|
+
- Default behavior:
|
|
21
|
+
- create missing records
|
|
22
|
+
- update modified records only when unambiguous
|
|
23
|
+
- never delete records
|
|
24
|
+
- Multiple records with the same owner/type must be modeled as record sets.
|
|
25
|
+
- Prefer conservative create/delete reporting over unsafe update matching.
|
|
26
|
+
- Ambiguous changes should be reported as requiring manual intervention.
|
|
27
|
+
|
|
28
|
+
## RSpec Requirements
|
|
29
|
+
|
|
30
|
+
- Add unit specs for create, update, no-op, skipped delete, and ambiguous cases.
|
|
31
|
+
- Add golden-file specs for text plan output.
|
|
32
|
+
- Add JSON output specs.
|
|
33
|
+
- Add Aruba specs for `dme zone plan FILE` with mocked remote state.
|
|
34
|
+
- Use `subject(:plan) { described_class.new(...).call }`.
|
|
35
|
+
- Use `its(:creates)`, `its(:updates)`, `its(:skipped_deletes)`, and one-liner expectations.
|
|
36
|
+
|
|
37
|
+
## Acceptance Criteria
|
|
38
|
+
|
|
39
|
+
- Plan output is deterministic.
|
|
40
|
+
- Deletes are skipped by default.
|
|
41
|
+
- Ambiguous changes are not applied silently.
|
|
42
|
+
- `bundle exec rspec` passes.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# 09 Plan: Safe Zone Apply Command
|
|
2
|
+
|
|
3
|
+
## Stacked PR Metadata
|
|
4
|
+
|
|
5
|
+
- Plan identifier: `09`
|
|
6
|
+
- Branch: `stack-09-zone-apply`
|
|
7
|
+
- Base branch: `stack-08-zone-diff-plan`
|
|
8
|
+
- PR title: `09: Apply zone plans safely`
|
|
9
|
+
- PR description must reference: `Plan 09 - Safe Zone Apply Command`
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
|
|
13
|
+
- Add `dme zone apply FILE`.
|
|
14
|
+
- Reuse the same planner used by `zone plan`.
|
|
15
|
+
- Execute creates and updates through the existing API client.
|
|
16
|
+
- Keep deletes opt-in.
|
|
17
|
+
- Split independent API operations into bounded worker-thread chunks.
|
|
18
|
+
- Use one `TTY::Spinner` per active worker/chunk for interactive progress.
|
|
19
|
+
- Use `TTY::Spinner::Multi` for concurrent thread progress:
|
|
20
|
+
https://github.com/piotrmurach/tty-spinner#5-ttyspinnermulti-api
|
|
21
|
+
- Keep final execution summaries deterministic even when worker completion order varies.
|
|
22
|
+
|
|
23
|
+
## Safety Rules
|
|
24
|
+
|
|
25
|
+
- Never delete by default.
|
|
26
|
+
- Never delete SOA records.
|
|
27
|
+
- Never delete apex NS records in v1.
|
|
28
|
+
- Require confirmation unless `--yes` is provided.
|
|
29
|
+
- Fail before applying if parsing or validation fails.
|
|
30
|
+
- Report partial failures clearly.
|
|
31
|
+
- Parallelize only actions proven independent by the plan.
|
|
32
|
+
- Aggregate worker errors by action/chunk.
|
|
33
|
+
|
|
34
|
+
## Options (flags)
|
|
35
|
+
|
|
36
|
+
-a | --add-only Ensures that only new records are being added, especially if the zone file does not contain all existing records
|
|
37
|
+
-d | --delete-only Applies only the deletion part of the plan
|
|
38
|
+
-m | --merge Default mode - compare existing DNS Zone with the provided, and merge the differences, turning them into add/update or delete actions.
|
|
39
|
+
|
|
40
|
+
## Live Integration Note
|
|
41
|
+
|
|
42
|
+
Opt-in live specs may use:
|
|
43
|
+
|
|
44
|
+
- Domain: `isdue.today`
|
|
45
|
+
- DNS Made Easy domain ID: `8218117`
|
|
46
|
+
|
|
47
|
+
Live specs must only mutate predictable test records such as `_dnsmadeeasy-test.isdue.today` and must clean them up.
|
|
48
|
+
|
|
49
|
+
## RSpec Requirements
|
|
50
|
+
|
|
51
|
+
- Add unit specs for executor behavior.
|
|
52
|
+
- Add Aruba specs for confirmation flow.
|
|
53
|
+
- Add specs for `--yes`.
|
|
54
|
+
- Add specs for delete refusal without `--delete`.
|
|
55
|
+
- Add specs for threaded chunk execution.
|
|
56
|
+
- Add specs using fake/no-op spinner objects.
|
|
57
|
+
- Add specs proving final summaries are deterministic.
|
|
58
|
+
- Add optional gated live integration specs for create/update/delete of test-owned records.
|
|
59
|
+
- Use `subject(:result) { described_class.new(...).call }`.
|
|
60
|
+
- Use `its(:applied_actions)`, `its(:failed_actions)`, and concise one-liners where useful.
|
|
61
|
+
|
|
62
|
+
## Acceptance Criteria
|
|
63
|
+
|
|
64
|
+
- Apply executes the current plan.
|
|
65
|
+
- Apply refuses destructive operations unless explicitly allowed.
|
|
66
|
+
- Independent actions can run concurrently with bounded worker threads.
|
|
67
|
+
- Progress is displayed with `TTY::Spinner` during interactive apply work.
|
|
68
|
+
- Default test suite never touches live DNS.
|
|
69
|
+
- `bundle exec rspec` passes.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# 10 Plan: Documentation, Migration Notes, and Cleanup
|
|
2
|
+
|
|
3
|
+
## Stacked PR Metadata
|
|
4
|
+
|
|
5
|
+
- Plan identifier: `10`
|
|
6
|
+
- Branch: `stack-10-docs-cleanup`
|
|
7
|
+
- Base branch: `stack-09-zone-apply`
|
|
8
|
+
- PR title: `10: Document dnsmadeeasy 1.0 CLI and zone workflow`
|
|
9
|
+
- PR description must reference: `Plan 10 - Documentation, Migration Notes, and Cleanup`
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
|
|
13
|
+
- Update README examples for the new command tree.
|
|
14
|
+
- Document Ruby 4 and version 1.0 breaking changes.
|
|
15
|
+
- Document the zone-file workflow.
|
|
16
|
+
- Remove deprecated runner leftovers if still present.
|
|
17
|
+
- Ensure command examples are represented by smoke specs where practical.
|
|
18
|
+
|
|
19
|
+
## Documentation Requirements
|
|
20
|
+
|
|
21
|
+
Include examples for:
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
dme account domains
|
|
25
|
+
dme account records_for example.com
|
|
26
|
+
dme zone export example.com > example.com.zone
|
|
27
|
+
dme zone validate example.com.zone
|
|
28
|
+
dme zone fmt example.com.zone
|
|
29
|
+
dme zone plan example.com.zone
|
|
30
|
+
dme zone apply example.com.zone --yes
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Document that `HTTPRED` is omitted from standard zone exports in v1, with warnings.
|
|
34
|
+
|
|
35
|
+
Document the live integration test domain:
|
|
36
|
+
|
|
37
|
+
- Domain: `isdue.today`
|
|
38
|
+
- DNS Made Easy domain ID: `8218117`
|
|
39
|
+
|
|
40
|
+
## RSpec Requirements
|
|
41
|
+
|
|
42
|
+
- Add or update CLI smoke specs for README command examples where practical.
|
|
43
|
+
- Add specs for migration messages if old commands are intentionally unsupported.
|
|
44
|
+
- Keep specs in the modern style:
|
|
45
|
+
- nested `describe`/`context`
|
|
46
|
+
- block-local `subject`
|
|
47
|
+
- concise `it { ... }`
|
|
48
|
+
- `its(:property) { ... }` where it improves readability
|
|
49
|
+
|
|
50
|
+
## Acceptance Criteria
|
|
51
|
+
|
|
52
|
+
- README accurately reflects the 1.0 CLI.
|
|
53
|
+
- Old docs for root-level operations are removed or marked as legacy.
|
|
54
|
+
- All specs pass.
|
|
55
|
+
- The stacked PR series is ready to merge from `01` through `10`.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# 11 Plan: Consistent Zone CLI Arguments (and the Trailing-Dot 404)
|
|
2
|
+
|
|
3
|
+
## Stacked PR Metadata
|
|
4
|
+
|
|
5
|
+
- Plan identifier: `11`
|
|
6
|
+
- Branch: `11-zone-cli-arguments`
|
|
7
|
+
- Base branch: `master`
|
|
8
|
+
- PR title: `11: Make domain a positional argument across zone commands`
|
|
9
|
+
- PR description must reference: `Plan 11 - Consistent Zone CLI Arguments`
|
|
10
|
+
|
|
11
|
+
## The Bug That Started This
|
|
12
|
+
|
|
13
|
+
Found live, while writing the kig.re blog post announcing 1.0.1:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
$ dmez zone export kig.re --output=kig.re.zone # works
|
|
17
|
+
$ dmez zone plan kig.re.zone # 404 "Not Found"
|
|
18
|
+
$ dmez zone plan kig.re.zone --domain=kig.re # works
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`Plan#call` and `Apply#build_plan_context` fall back to the parsed zone's
|
|
22
|
+
origin when `--domain` is absent:
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
plan_domain = domain || desired_result.value!.origin
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The parser returns the origin exactly as written in the file: `kig.re.`,
|
|
29
|
+
with the RFC-mandated trailing dot. That FQDN goes straight into
|
|
30
|
+
`records_for("kig.re.")`, the API has no such domain, 404.
|
|
31
|
+
|
|
32
|
+
## The Design Decision
|
|
33
|
+
|
|
34
|
+
The deeper problem is inconsistency, not the dot. Today:
|
|
35
|
+
|
|
36
|
+
- `dmez zone export DOMAIN` — domain is a positional argument
|
|
37
|
+
- `dmez zone plan FILE --domain=NAME` — domain is an option
|
|
38
|
+
- `dmez zone apply FILE --domain=NAME` — domain is an option
|
|
39
|
+
|
|
40
|
+
Decision (Konstantin): **domain is consistently an argument, never an
|
|
41
|
+
option.** Zone files are provided by flags unless one is required for the
|
|
42
|
+
command; a required file becomes a required argument following the domain.
|
|
43
|
+
|
|
44
|
+
Applied to the command tree:
|
|
45
|
+
|
|
46
|
+
| Command | New shape | Change |
|
|
47
|
+
| ------- | --------- | ------ |
|
|
48
|
+
| `zone export` | `dmez zone export DOMAIN [--output=FILE]` | none (already correct; output is optional, stays a flag, defaults to stdout) |
|
|
49
|
+
| `zone plan` | `dmez zone plan DOMAIN FILE` | file was the only argument; domain was a flag |
|
|
50
|
+
| `zone apply` | `dmez zone apply DOMAIN FILE [modes]` | same |
|
|
51
|
+
| `zone validate` | `dmez zone validate FILE` | none (no provider involved, no domain to speak of) |
|
|
52
|
+
| `zone fmt` | `dmez zone fmt FILE` | none |
|
|
53
|
+
|
|
54
|
+
With `domain` required, origin inference is deleted rather than fixed. The
|
|
55
|
+
bug becomes structurally impossible: there is nothing left to infer.
|
|
56
|
+
|
|
57
|
+
## $ORIGIN Becomes a Cross-Check
|
|
58
|
+
|
|
59
|
+
Deleting the inference does not mean ignoring `$ORIGIN`. Plan and apply now
|
|
60
|
+
verify that the zone file agrees with the domain argument, before any API
|
|
61
|
+
call is made:
|
|
62
|
+
|
|
63
|
+
- Normalize both sides: strip one trailing dot, compare case-insensitively.
|
|
64
|
+
(`kig.re` == `kig.re.` == `KIG.RE.`)
|
|
65
|
+
- If the file has an `$ORIGIN` and it disagrees with the domain argument,
|
|
66
|
+
fail fast with both values shown. Diffing `foo.com` against
|
|
67
|
+
`bar.com.zone` should be an error, not a surprise apply.
|
|
68
|
+
- A zone file without `$ORIGIN` skips the check.
|
|
69
|
+
|
|
70
|
+
This converts yesterday's bug into a safety feature.
|
|
71
|
+
|
|
72
|
+
## Swapped-Argument Detection
|
|
73
|
+
|
|
74
|
+
`dmez zone plan valid.zone example.com` is the muscle-memory mistake the
|
|
75
|
+
new argument order invites. Two cheap guards:
|
|
76
|
+
|
|
77
|
+
- When the zone file path does not exist, say so plainly
|
|
78
|
+
(`Zone file not found: example.com`) instead of an unhandled `Errno::ENOENT`.
|
|
79
|
+
- When, additionally, the *domain* argument names an existing file, append:
|
|
80
|
+
`It looks like the arguments are swapped. Usage: dmez zone plan DOMAIN FILE`.
|
|
81
|
+
|
|
82
|
+
## Out of Scope
|
|
83
|
+
|
|
84
|
+
- `dme account` argument shapes.
|
|
85
|
+
- `validate`/`fmt` error-handling polish beyond what exists.
|
|
86
|
+
- Version bump: this is a breaking CLI change one day after 1.0.1 shipped
|
|
87
|
+
(16 downloads). Recommend releasing as **1.1.0** with the README calling
|
|
88
|
+
out the new shapes; the maintainer bumps the version at release time.
|
|
89
|
+
|
|
90
|
+
## RSpec Requirements
|
|
91
|
+
|
|
92
|
+
Update `spec/lib/dns_made_easy/cli/zone_aruba_spec.rb`:
|
|
93
|
+
|
|
94
|
+
- Rewrite every `zone plan` / `zone apply` invocation to
|
|
95
|
+
`dme zone plan example.com valid.zone ...` (domain first, file second).
|
|
96
|
+
- Add: plan with origin `example.com.` (trailing dot in file) and domain
|
|
97
|
+
argument `example.com` succeeds — the normalization test.
|
|
98
|
+
- Add: plan with a mismatched origin fails, names both values, makes no
|
|
99
|
+
API call.
|
|
100
|
+
- Add: plan with swapped arguments fails with the swap hint.
|
|
101
|
+
- Add: plan with a missing zone file fails with `Zone file not found`.
|
|
102
|
+
- Keep specs in the modern style: nested `describe`/`context`, block-local
|
|
103
|
+
`subject`, concise `it { ... }`, `its(:property) { ... }` where it reads
|
|
104
|
+
better.
|
|
105
|
+
|
|
106
|
+
## Acceptance Criteria
|
|
107
|
+
|
|
108
|
+
- `dmez zone plan kig.re kig.re.zone` round-trips against production with
|
|
109
|
+
`No changes.` (verified live, read-only).
|
|
110
|
+
- The 1.0.1 failure mode (`zone plan FILE` → 404) can no longer be
|
|
111
|
+
expressed: the CLI rejects the invocation with a usage error.
|
|
112
|
+
- Mismatched `$ORIGIN` vs domain argument fails before any API request.
|
|
113
|
+
- README zone examples reflect the new shapes.
|
|
114
|
+
- Full spec suite passes; rubocop clean.
|