template / commit
adding plan of near-future improvements
IMPROVEMENTS.md | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/IMPROVEMENTS.md b/IMPROVEMENTS.md new file mode 100644 index 0000000..0a6d1d0 --- /dev/null +++ b/IMPROVEMENTS.md @@ -0,0 +1,153 @@ +# Improvement Plan + +Ordered roughly by effort, lowest first. Each section lists the concrete changes needed. + +--- + +## 1. Drop `golang.org/x/exp` dependency + +`golang.org/x/exp/slices` was a backport of the stdlib `slices` package (available since +Go 1.21). Replace every import with the stdlib package. + +Files to update: + +- [config.go](config.go) — `import "golang.org/x/exp/slices"` → `import "slices"` +- [profile.go](profile.go) — same +- [name_pattern_test.go](name_pattern_test.go) — same + +After swapping imports, run `go mod tidy` to remove the `golang.org/x/exp` entries from +`go.mod` and `go.sum`. + +--- + +## 2. Upgrade Go version + +`go.mod` declares `go 1.24.0` / `toolchain go1.24.4`, but the GitLab CI image is already +`golang:1.25`. Align `go.mod` with the CI image so the declared minimum matches what is +actually tested against. + +Steps: + +1. Run `go mod tidy` after updating the `go` directive in [go.mod](go.mod). +2. Update `toolchain` line to match the current patch release. +3. Verify all tests still pass. + +--- + +## 3. Reorganize source files into a nested directory + +All `.go` files currently live at the repo root alongside config files, making the layout +cluttered. The standard Go layout for a CLI tool is: + +```text +cmd/ + template/ + main.go ← entry point only; wire dependencies here +internal/ + core/ ← or any name: "engine", "template", etc. + config.go + config_test.go + default_config.go + ...all other .go files... +``` + +Concrete steps: + +1. Create `cmd/template/` and `internal/core/` directories. +2. Move `main.go` to `cmd/template/main.go`. Keep it thin — just flag parsing and calls + into `internal/core`. +3. Move every other `.go` file (including test files) to `internal/core/`. +4. Change the package declaration in all moved files from `package main` to `package core` + (or chosen name). +5. Re-export only what `cmd/template/main.go` needs. +6. Update the `Makefile` build target: `go build ./cmd/template/`. +7. Update `.goreleaser.yaml` main path if it references a specific file. +8. Run `go test ./...` to confirm nothing broke. + +**Note:** `monkey-patch.go` and `test-common.go` contain test-support code. They can live +alongside the production code in `internal/core/` (Go only compiles `_test.go` files during +tests) or move into a `internal/core/testutil/` sub-package. + +--- + +## 4. Improve test coverage + +Current tests focus on the happy path. Priority areas for new tests: + +### 4a. Error paths in config handling ([config.go](config.go)) + +- `loadConfig` — file not found, malformed YAML, invalid permissions +- `saveConfig` — write failure (read-only directory) +- `validateConfig` — all validation branches (duplicate names, multiple defaults) + +### 4b. Error paths in file creation ([file.go](file.go)) + +- `createFile` — template parse error, template execution error, `os.Create` failure, + `os.WriteFile` failure +- `readFile` — file not found + +### 4c. Profile processing edge cases ([profile.go](profile.go)) + +- `processProfile` with `ScriptType` (currently untested or minimally tested) +- `createEntity` failure cases: mkdir failure, nested file creation failure +- `validateProfile` — all invalid combinations (missing target, unsupported OS, etc.) + +### 4d. Extras loading ([extras.go](extras.go)) + +- Missing extras file (should not error) +- Malformed extras YAML + +### 4e. `mainLogic` integration ([main.go](main.go)) + +- Profile not found +- Config load failure +- Piped stdin with a folder-type profile (should be an error or no-op) + +### 4f. Coverage tooling + +Add a coverage threshold gate to the Makefile so CI fails if coverage drops below a chosen +minimum (e.g., 70%): + +```makefile +test: + go test ./... -coverprofile=test-coverage.out + go tool cover -func=test-coverage.out | grep total | awk '{if ($$3+0 < 70) exit 1}' +``` + +--- + +## 5. Reduce `main.go` size + +At 584 lines, [main.go](main.go) mixes CLI wiring, settings construction, and business +logic. After the reorganization in item 3, consider splitting it further: + +- Keep `main.go` (in `cmd/template/`) to flag definitions and `main()` only (~100 lines). +- Move `createSettings()`, `mainLogic()`, and `findProfile()` into `internal/core/` where + they are easier to unit-test without going through the CLI layer. + +--- + +## 6. Clean up `default_config.go` + +At 397 lines, [default_config.go](default_config.go) is unwieldy. Options: + +- Split into per-profile files: `profiles_daily.go`, `profiles_git.go`, etc. +- Or load default profiles from an embedded YAML file (`//go:embed defaults.yaml`) so + non-Go contributors can read and edit profiles without touching Go code. + +The embedded YAML approach also makes it easy to write a single test that validates every +default profile passes `validateProfile()`. + +--- + +## 7. Minor housekeeping + +- **Empty `src/` directory** — remove it (or document its purpose). +- **`test-common.go`** — this file contains only a package declaration. Either add shared + test helpers to it or delete it. +- **`dev-setup` script** — is gitignored but checked-in? Verify its contents don't contain + credentials and decide if it should be tracked. +- **`.DS_Store`** — add `**/.DS_Store` to [.gitignore](.gitignore) to prevent future + commits of macOS metadata files. +- **CI image pinning** — `.gitlab-ci.yml` uses `golang:1.25` (unpinned minor). Pin to a + digest or a patch tag (`golang:1.25.0`) for reproducible builds.