Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions .planning/PROJECT.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Existing test coverage is limited. The tool is functional for core operations bu
- **Go version**: 1.25+
- **Compatibility**: Must work with existing .transfer file format
- **CI verification**: All GitHub Actions "Tests" workflow jobs must pass before work is complete:
- lint (golangci-lint)
- lint (golangci-lint and `make lint`)
- security (govulncheck)
- verify (go mod tidy, go vet, gofmt)
- unit-test (go test with coverage)
Expand All @@ -67,13 +67,14 @@ Existing test coverage is limited. The tool is functional for core operations bu

## Key Decisions

| Decision | Rationale | Outcome |
|----------|-----------|---------|
| Go for implementation | Fast, single binary, good for CLI tools | ✓ Good |
| Cobra for CLI framework | Industry standard, good docs | ✓ Good |
| INI format for configs | Matches systemd conventions | ✓ Good |
| Library + CLI architecture | Enables programmatic use | ✓ Good |
| Disable = remove files | Simpler mental model for users | — Pending |
| Decision | Rationale | Outcome |
| -------------------------- | --------------------------------------- | --------- |
| Go for implementation | Fast, single binary, good for CLI tools | ✓ Good |
| Cobra for CLI framework | Industry standard, good docs | ✓ Good |
| INI format for configs | Matches systemd conventions | ✓ Good |
| Library + CLI architecture | Enables programmatic use | ✓ Good |
| Disable = remove files | Simpler mental model for users | — Pending |

---
*Last updated: 2026-01-26 after adding CI constraint*

_Last updated: 2026-01-26 after adding CI constraint_
6 changes: 3 additions & 3 deletions .planning/REQUIREMENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Requirements for this milestone. Each maps to roadmap phases.

### Auto-Update

- [ ] **AUTO-01**: User can generate systemd timer and service files for scheduled updates
- [x] **AUTO-01**: User can generate systemd timer and service files for scheduled updates
- [ ] **AUTO-02**: User can install generated timer/service to system with `install-timer` command
- [ ] **AUTO-03**: User can check auto-update timer status with status command
- [ ] **AUTO-04**: Auto-update only stages files, does not auto-activate merged extensions
Expand Down Expand Up @@ -72,7 +72,7 @@ Which phases cover which requirements. Updated during roadmap creation.
| UX-01 | Phase 2: Core UX Fixes | Complete |
| UX-02 | Phase 2: Core UX Fixes | Complete |
| UX-03 | Phase 2: Core UX Fixes | Complete |
| AUTO-01 | Phase 3: Systemd Unit Infrastructure | Pending |
| AUTO-01 | Phase 3: Systemd Unit Infrastructure | Complete |
| AUTO-02 | Phase 4: Auto-Update CLI | Pending |
| AUTO-03 | Phase 4: Auto-Update CLI | Pending |
| AUTO-04 | Phase 4: Auto-Update CLI | Pending |
Expand All @@ -89,4 +89,4 @@ Which phases cover which requirements. Updated during roadmap creation.

---
*Requirements defined: 2026-01-26*
*Last updated: 2026-01-26 after Phase 2 completion*
*Last updated: 2026-01-26 after Phase 3 completion*
10 changes: 6 additions & 4 deletions .planning/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Decimal phases appear between their surrounding integers in numeric order.

- [x] **Phase 1: Test Foundation** - Establish testing infrastructure and patterns
- [x] **Phase 2: Core UX Fixes** - Fix dangerous remove/disable semantics
- [ ] **Phase 3: Systemd Unit Infrastructure** - Build internal package for timer/service management
- [x] **Phase 3: Systemd Unit Infrastructure** - Build internal package for timer/service management
- [ ] **Phase 4: Auto-Update CLI** - Expose auto-update via daemon commands
- [ ] **Phase 5: Integration & Polish** - End-to-end validation and UX polish

Expand Down Expand Up @@ -59,10 +59,12 @@ Plans:
2. Unit files can be installed to /etc/systemd/system (or configurable path)
3. Unit files can be removed cleanly
4. Package is fully testable with temp directories (no root required)
**Plans**: TBD
**Plans**: 3 plans

Plans:
- [ ] 03-01: TBD
- [x] 03-01-PLAN.md — Create unit types and generation functions with tests
- [x] 03-02-PLAN.md — Create SystemctlRunner interface and mock
- [x] 03-03-PLAN.md — Create Manager with Install/Remove operations and tests

### Phase 4: Auto-Update CLI
**Goal**: Users can manage auto-update timer via CLI commands
Expand Down Expand Up @@ -104,6 +106,6 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5
|-------|----------------|--------|-----------|
| 1. Test Foundation | 2/2 | Complete ✓ | 2026-01-26 |
| 2. Core UX Fixes | 2/2 | Complete ✓ | 2026-01-26 |
| 3. Systemd Unit Infrastructure | 0/TBD | Not started | - |
| 3. Systemd Unit Infrastructure | 3/3 | Complete ✓ | 2026-01-26 |
| 4. Auto-Update CLI | 0/TBD | Not started | - |
| 5. Integration & Polish | 0/TBD | Not started | - |
33 changes: 19 additions & 14 deletions .planning/STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,35 @@
See: .planning/PROJECT.md (updated 2026-01-26)

**Core value:** Users can reliably install and update systemd-sysexts from any registry without needing the unavailable updatectl package.
**Current focus:** Phase 3 - Systemd Unit Infrastructure
**Current focus:** Phase 4 - Auto-Update CLI

## Current Position

Phase: 3 of 5 (Systemd Unit Infrastructure)
Phase: 4 of 5 (Auto-Update CLI)
Plan: 0 of TBD in current phase
Status: Not started
Last activity: 2026-01-26 — Phase 2 verified complete
Status: Ready to plan
Last activity: 2026-01-26 — Phase 3 verified complete

Progress: [████░░░░░░] 40%
Progress: [███████░░░] 70%

## Performance Metrics

**Velocity:**
- Total plans completed: 4
- Average duration: 9 min
- Total execution time: 34 min
- Total plans completed: 7
- Average duration: 5 min
- Total execution time: 36 min

**By Phase:**

| Phase | Plans | Total | Avg/Plan |
|-------|-------|-------|----------|
| 01-test-foundation | 2 | 27 min | 13.5 min |
| 02-core-ux-fixes | 2 | 7 min | 3.5 min |
| 03-systemd-unit-infrastructure | 3 | 2 min | 0.7 min |

**Recent Trend:**
- Last 5 plans: 2min, 25min, 5min, 2min
- Trend: improving
- Last 5 plans: 5min, 2min, 0min, 1min, 1min
- Trend: fast

*Updated after each plan completion*

Expand All @@ -53,6 +54,10 @@ Recent decisions affecting current work:
- [02-01]: Merge state check requires --force for active extensions
- [02-02]: Use DryRun flag to test feature logic without /etc access
- [02-02]: Simulate merged extensions with CurrentSymlink for testing
- [03-02]: SystemctlRunner interface mirrors SysextRunner pattern for consistency
- [03-02]: IsActive/IsEnabled return false (not error) for non-zero exit codes
- [03-03]: Install fails if files exist - require explicit Remove first
- [03-03]: Remove ignores stop/disable errors (may not be running)

### Test Coverage

Expand All @@ -78,11 +83,11 @@ None.
## Session Continuity

Last session: 2026-01-26
Stopped at: Phase 2 verified, ready for Phase 3
Stopped at: Phase 3 verified, ready for Phase 4
Resume file: None

## Next Steps

Phase 2 verified complete. Ready for:
- /gsd-discuss-phase 3Systemd Unit Infrastructure
- /gsd-plan-phase 3 — skip discussion, plan directly
Phase 3 verified complete. Ready for:
- /gsd-discuss-phase 4Auto-Update CLI
- /gsd-plan-phase 4 — skip discussion, plan directly
145 changes: 145 additions & 0 deletions .planning/phases/03-systemd-unit-infrastructure/03-01-PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
---
phase: 03-systemd-unit-infrastructure
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- internal/systemd/unit.go
- internal/systemd/unit_test.go
autonomous: true

must_haves:
truths:
- "Timer unit file can be generated with valid systemd syntax"
- "Service unit file can be generated with valid systemd syntax"
- "Generated files include all required sections ([Unit], [Timer]/[Service], [Install])"
- "Generation is testable with different configurations"
artifacts:
- path: "internal/systemd/unit.go"
provides: "TimerConfig, ServiceConfig types and generation functions"
exports: ["TimerConfig", "ServiceConfig", "GenerateTimer", "GenerateService"]
- path: "internal/systemd/unit_test.go"
provides: "Tests for unit file generation"
min_lines: 100
key_links:
- from: "internal/systemd/unit_test.go"
to: "internal/systemd/unit.go"
via: "calls GenerateTimer and GenerateService"
pattern: "GenerateTimer|GenerateService"
---

<objective>
Create the foundation for systemd unit file generation: types and functions that generate valid timer and service unit file content.

Purpose: Enable programmatic generation of systemd timer/service files for scheduling automatic updates.
Output: internal/systemd/unit.go with types and generation functions, comprehensive tests in unit_test.go.
</objective>

<execution_context>
@~/.config/opencode/get-shit-done/workflows/execute-plan.md
@~/.config/opencode/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/03-systemd-unit-infrastructure/03-RESEARCH.md
@internal/sysext/runner.go (pattern reference for interface design)
</context>

<tasks>

<task type="auto">
<name>Task 1: Create unit types and generation functions</name>
<files>internal/systemd/unit.go</files>
<action>
Create new package `internal/systemd` with unit.go containing:

1. **TimerConfig struct** with fields:
- Name string (e.g., "updex-update")
- Description string (e.g., "Automatic sysext updates")
- OnCalendar string (e.g., "daily" or "*-*-* 04:00:00")
- Persistent bool (run if missed)
- RandomDelaySec int (randomize start within this window in seconds)

2. **ServiceConfig struct** with fields:
- Name string
- Description string
- ExecStart string (full command, e.g., "/usr/bin/updex update --quiet")
- Type string (default to "oneshot")

3. **GenerateTimer(cfg *TimerConfig) string** function:
- Generate [Unit] section with Description
- Generate [Timer] section with OnCalendar, optional Persistent=true, optional RandomizedDelaySec
- Generate [Install] section with WantedBy=timers.target
- Use strings.Builder for efficient string building (not text/template - simpler for this use case)

4. **GenerateService(cfg *ServiceConfig) string** function:
- Generate [Unit] section with Description
- Generate [Service] section with Type and ExecStart
- No [Install] section needed (timer handles activation)

Use the exact patterns from 03-RESEARCH.md Code Examples section. Include package doc comment explaining purpose.
</action>
<verify>go build ./internal/systemd/... compiles successfully</verify>
<done>unit.go exists with TimerConfig, ServiceConfig, GenerateTimer, GenerateService exported</done>
</task>

<task type="auto">
<name>Task 2: Create comprehensive unit generation tests</name>
<files>internal/systemd/unit_test.go</files>
<action>
Create unit_test.go with table-driven tests following project conventions:

1. **TestGenerateTimer** with cases:
- "minimal config" - only required fields (Name, Description, OnCalendar)
- "with persistent" - Persistent=true adds "Persistent=true" line
- "with random delay" - RandomDelaySec=3600 adds "RandomizedDelaySec=3600s"
- "full config" - all options enabled

2. **TestGenerateService** with cases:
- "minimal config" - Name, Description, ExecStart, Type
- "oneshot type" - Type="oneshot"

3. **Verification approach for each test:**
- Check that output contains expected section headers ("[Unit]", "[Timer]", etc.)
- Check that Description line is present
- Check that OnCalendar/ExecStart values are correct
- Use strings.Contains for flexible matching (not exact string equality - allows formatting flexibility)

Follow project testing patterns from .planning/codebase/TESTING.md:
- Table-driven tests with t.Run
- Descriptive test case names
- Use t.Errorf for assertion failures
</action>
<verify>go test -v ./internal/systemd/... passes with all tests green</verify>
<done>unit_test.go has 6+ test cases covering all generation paths, all tests pass</done>
</task>

</tasks>

<verification>
```bash
# Package compiles
go build ./internal/systemd/...

# All tests pass
go test -v ./internal/systemd/...

# Coverage check
go test -cover ./internal/systemd/...
```
</verification>

<success_criteria>
1. internal/systemd/unit.go exists with exported types and functions
2. internal/systemd/unit_test.go exists with comprehensive tests
3. All tests pass
4. Generated unit content contains valid systemd sections
</success_criteria>

<output>
After completion, create `.planning/phases/03-systemd-unit-infrastructure/03-01-SUMMARY.md`
</output>
Loading