config: migrate output mirrors default.yml comments, literals, and examples #60

Merged
heiko merged 6 commits from dev into master 2026-05-17 22:22:13 +02:00
Owner

Summary

  • Adds default_skel.go: a lazy line-scanner (sync.Once) that parses the embedded default.yml into three lookup maps keyed by dotted YAML path — fieldComments(), fieldLiterals(), and fieldExamples().
  • config migrate output now carries the same prose comments and # Example: blocks as config default, sourced directly from default.yml so they can never drift.
  • When a user value matches the default, the migrator emits the literal from default.yml verbatim (e.g. #section: misc not #section: "misc").
  • Auto-detected fields (module, apiurl, owner, name, token, homepage) show the resolved runtime value commented rather than the static empty placeholder.
  • Also fixes two formatting alignment issues: release.branch double-comment and scripts sub-field indent matching default.yml.
  • Separate commit fixes pre-existing wsl_v5 lint issues in packages_test.go introduced by #56.

Test plan

  • go test ./internal/config/... passes
  • golangci-lint run ./internal/config/... reports 0 issues
  • diff <(gogogo config default) <(gogogo config migrate) shows only: preamble (intentionally distinct), auto-detected fields, and actual non-default repo values
  • TestMigratedFieldCommentsAndExamples exercises comment/example/auto-detection paths

🤖 Generated with Claude Code

## Summary - Adds `default_skel.go`: a lazy line-scanner (`sync.Once`) that parses the embedded `default.yml` into three lookup maps keyed by dotted YAML path — `fieldComments()`, `fieldLiterals()`, and `fieldExamples()`. - `config migrate` output now carries the same prose comments and `# Example:` blocks as `config default`, sourced directly from `default.yml` so they can never drift. - When a user value matches the default, the migrator emits the literal from `default.yml` verbatim (e.g. `#section: misc` not `#section: "misc"`). - Auto-detected fields (`module`, `apiurl`, `owner`, `name`, `token`, `homepage`) show the resolved runtime value commented rather than the static empty placeholder. - Also fixes two formatting alignment issues: `release.branch` double-comment and `scripts` sub-field indent matching `default.yml`. - Separate commit fixes pre-existing `wsl_v5` lint issues in `packages_test.go` introduced by #56. ## Test plan - [x] `go test ./internal/config/...` passes - [x] `golangci-lint run ./internal/config/...` reports 0 issues - [x] `diff <(gogogo config default) <(gogogo config migrate)` shows only: preamble (intentionally distinct), auto-detected fields, and actual non-default repo values - [x] `TestMigratedFieldCommentsAndExamples` exercises comment/example/auto-detection paths 🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary

Adds full multi-package Debian/RPM support to gogogo. Three layers land in this PR:

1. **YAML schema layer** — polymorphic `artifacts.packages:` field (absent / `'*'` / list) with per-package merge and validation.
2. **Generator + rendering layer** — source-package builders emit multi-stanza `debian/control` and multi-`%package -n` `<name>.spec` files. Both honor user-edited templates in `debian/*` and `rpm/<name>.spec` via `text/template` rendering against a stable `DebContext`/`RPMContext`.
3. **CLI scaffolding** — two new subcommands:
   - `gogogo config packages` — scaffold the `artifacts.packages:` YAML block from `cmd/*` discovery (replaces the misnamed first version of `pack populate`).
   - `gogogo pack populate` — scaffold editable starter files into `debian/` and `rpm/` for users who want to customise the source-package shape beyond what the YAML schema covers.

## Behavior change

Existing multi-binary projects without an `artifacts.packages:` declaration now produce **one combined `.deb`** named after the module, instead of one `.deb` per `cmd/*` binary. Set `packages: '*'` (or use `gogogo config packages --shorthand --in-place`) to preserve the prior per-binary split.

## CLI surface

```bash
gogogo config packages                       # print packages: block to stdout
gogogo config packages --shorthand           # one-liner: `packages: '*'`
gogogo config packages --in-place --force    # splice into .gogogo.conf

gogogo pack populate                         # scaffold editable debian/* + rpm/* stubs
gogogo pack populate --force                 # overwrite existing stubs

gogogo --version                             # `<cmd> <ver> <exe-path>` (new format)
```

## User-template contract

User-edited `debian/control`, `debian/rules`, `debian/changelog`, `debian/source/format`, and `rpm/<name>.spec` files are rendered through `text/template` at build time against:

- `DebContext` — `Source`, `Maintainer`, `Tag`, `DebVersion`, `Packages[]`, `Synopsis`, `LongDescIndented`, `ChangelogDate`, etc.
- `RPMContext` — `Name`, `RPMVersion`, `RPMRelease`, `TarName`, `Packages[]`, `Group`, `Changelog`, etc.

Field names form a public stability contract. `missingkey=error` makes typos like `{{ .Versoin }}` fail loud with the offending file path in the error.

## Test plan

- [x] `go test ./...` — all packages pass
- [x] `go vet ./...` clean
- [x] `golangci-lint run` — no new issues in any added file (intentional misspellings + `fmt.Fprintf` progress lines marked with `//nolint`)
- [x] Manual: `gogogo --version`, `gogogo config packages --help`, `gogogo pack populate` end-to-end on a fixture project
- [x] Source `.dsc` rebuild produces the same multi-package set as direct `.deb` build (multi-stanza `debian/control` + per-package `go build`)
- [x] `rpmbuild -bs` on the generated `<name>.spec` works for both single-package (no `-n`) and multi-package (`%package -n` per entry) projects

## Commits

```
1058573 suppress intentional lint warnings: nolint markers for typo+errcheck
9276d5f source/rpm: multi-package %package -n + user-file render path
44d992b pack populate: scaffold editable debian/* and rpm/ stub files
a4ec9e1 source: render user-edited debian/* files through text/template
12d2083 pack populate → config packages (rename only)
4bce628 config/migrate: split artifacts() into per-block render helpers
b55048b cli: --version prints '<cmd> <ver> <exe-path>'
367aa26 config: keep explanatory comments in migrate output, drop 'Example config' preamble
9647a74 config migrate: import existing v2 artifacts.* settings
0ac9515 Expand multi-package test coverage
9063add Add multi-package support for Debian and RPM artifacts
```

## Known limitations (CHANGELOG-worthy)

1. **Behavior change**: existing multi-binary projects start producing one combined `.deb` by default. Use `packages: '*'` to preserve the prior per-binary split.
2. **Union merge semantics** on per-package list overrides mean an entry can't *remove* a globally-declared dep. If needed in practice, a `depends_remove:` escape hatch can land separately.
3. **Template stability**: once shipped, `DebContext`/`RPMContext` field names are committed — renames are breaking changes for users with custom `debian/*` or `rpm/<name>.spec` templates.

ius:ai:claude-opus-4-7
Reviewed-on: #56
Adds default_skel.go: a line-scanner that parses the embedded default.yml
once (sync.Once) into three lookup maps keyed by dotted YAML path:
  - fieldComments() — prose comment lines above each field
  - fieldLiterals() — value text as written in default.yml
  - fieldExamples() — # Example: blocks attached to each field

migrate.go is updated to use these maps:
  - scalar() gains a path parameter; when comment=true and the path has a
    known default literal, emits it verbatim (e.g. #section: misc not
    #section: "misc").
  - scalarAuto() for auto-detected fields shows the resolved runtime value
    commented (e.g. #apiurl: "https://forgejo.example.com/api/v1").
  - comment(path, indent) and example(path, indent) replace hardcoded
    commentLines() calls so comment text is sourced from default.yml.

ius:ai:claude-sonnet-4-6
Add missing blank lines before err := and found := assignments in
TestPackagesSpec_UnmarshalRejectsOtherScalars, TestPackagesSpec_UnmarshalRejectsMap,
TestValidatePackages_NameShape, and TestValidatePackages_UnknownBinary.

These were introduced by the multi-package PR (#56) and are unrelated to
the migrate comment-mirroring work.

ius:ai:claude-sonnet-4-6
release.branch was emitting '#  branch: ""' but default.yml has
'#  #branch: ""' — the field is optional even within the release block,
so the inner # is correct.

scripts sub-fields were rendering as '      #preinst: ""' (6 spaces + #)
but default.yml uses '    #  preinst: ""' (# at parent indent, 2-space
sub-indent). When the whole scripts block is commented, emit sub-keys at
the parent indent level to match.

ius:ai:claude-sonnet-4-6
default_skel.go:
- Remove redundant `seen map[string]bool`; `comments` map presence already
  encodes the same information — use `_, already := comments[path]`.
- Replace WHAT doc-comment on parseSkel with a WHY: explains why a line
  scanner is needed instead of yaml.v3 (commented keys aren't in the node
  tree).

migrate.go:
- security(): add missing `m.comment("security", "")` for consistency with
  all other top-level block renderers.
- renderDebBlock(): assign IsSystemdEnabled()/IsLintianEnabled() to locals
  instead of calling each method twice.
- scripts(): pass "" as path to scalar() calls where comment=false; the
  path arg is only consulted when comment=true, so the old specific paths
  were dead lookups.

ius:ai:claude-sonnet-4-6
heiko merged commit 9d121726f6 into master 2026-05-17 22:22:13 +02:00
heiko deleted branch dev 2026-05-17 22:22:30 +02:00
heiko referenced this pull request from a commit 2026-05-17 22:42:48 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
heiko/gogogo!60
No description provided.