Improvement Plan
Ordered roughly by effort, lowest first. Each section lists the concrete changes needed.
✅ 1. Drop golang.org/x/exp dependency
Replaced golang.org/x/exp/slices with the stdlib slices package in
config.go, profile.go, and
name_pattern_test.go. Removed the dependency
from go.mod via go mod tidy.
✅ 2. Upgrade Go version
go.mod now declares go 1.25.0, driven by the project's actual transitive
deps. The GitLab CI image (golang:1.25) is aligned.
✅ 3. Reorganize source files into a nested directory
All source files moved out of the repo root into:
cmd/
template/
main.go ← 14-line entry point; sets Version, calls core.Run()
internal/
core/
app.go ← CLI wiring + all orchestration logic
config.go
profile.go
... (all other files)
Makefile build and install targets updated to ./cmd/template/.
.goreleaser.yaml updated with main: ./cmd/template/.
✅ 4. Tool management via separate module
Dev tools (golangci-lint, gomarklint, goreleaser) are now version-pinned in
tools/go.mod, keeping their hundreds of transitive dependencies
out of the main go.mod. The Makefile installs them via
cd tools && go install ... and exposes make lint and make lint-docs targets.
✅ 5. Reduce main.go size
cmd/template/main.go is now 14 lines. All CLI wiring,
settings construction (createSettings), profile resolution (findProfile), and
orchestration (runMain) live in internal/core/app.go
where they are reachable by tests without going through the CLI layer.
✅ 6. Improve test coverage
Coverage raised from ~56% to 67.7%. Threshold gate in Makefile raised to 65%.
New tests added across:
- app_test.go —
readEnvVars(all env var branches),loadAndMergeUserConfig(file not found, valid merge, invalid YAML, merge error from invalid global config),findProfile(named profile, default profile, no-profile error) - file_test.go —
createFileerror paths (OSCreatefailure,OSWriteFilefailure in template and empty-template paths),readFile(happy path and missing file) - profile_test.go —
createEntityerror paths (mkdir failure, chdir failure, invalid file-name pattern inside folder, subdir mkdir failure,createFilefailure for bothFolderTypeandFileType),processProfileedge cases (target-dir mkdir/chdir failures,createEntityerror with and withoutRunPostscriptOnFailureswallow, invalid post-script template, post script with no output, post script that exits non-zero),ScriptTypeprofile - profile_test.go — new
TestCreateNewNameForPatternsGetVersionError:getVersionused in a non-last pattern returns an error
Remaining uncovered paths are inherently untestable in unit tests: CLI wiring
(Run, createSettings, runMain), the Windows branch of shellCommandAndArgs,
and error branches in yaml.Marshal / bufio.Writer that the library panics on
rather than returning errors.
✅ 7. Clean up default_config.go
default_config.go shrunk from 396 lines to 18
by switching to //go:embed defaults.yaml. All 14 profiles now live in
defaults.yaml as plain YAML, editable without
touching Go code.
Added omitempty to the IsDefault and IsDisabled bool fields in Profile
so marshaling produces clean output (zero values omitted).
✅ 8. Minor housekeeping
- Empty
src/directory — removed. .DS_Store—**/.DS_Storeadded to .gitignore.- CI image pinning — .fw-ci.yml pinned to
golang:1.25.4.