feat(go-config): multi-format codecs, envc CLI, fixtures, ASRs
- Module github.com/eslider/go-config with env/yaml/json/ini packages - internal: source, keymap, merge, structconv, bytesutil - cmd/envc: convert, get, merge - docs/asr ASR-0001..0008, README/CHANGELOG/AGENTS refresh - golangci-lint v2 config; tests + fixtures Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
# ASR-0001: Module rename and multi-package layout
|
||||
|
||||
## Context
|
||||
|
||||
The original `github.com/eslider/go-env` module only decoded process environment variables. The product scope expanded to YAML, JSON, INI, URLs, multi-source merging, and a CLI. The old name and single-package layout no longer matched the capability surface.
|
||||
|
||||
## Decision
|
||||
|
||||
1. The canonical module path is **`github.com/eslider/go-config`**.
|
||||
2. Format-specific code lives in first-class subpackages: **`env/`**, **`yaml/`**, **`json/`**, **`ini/`**.
|
||||
3. Shared building blocks live under **`internal/{source,keymap,merge,structconv,bytesutil}`**.
|
||||
4. The CLI lives at **`cmd/envc/`** (one binary per inventar **ASR-0008** §2 — CLI inside the same module).
|
||||
5. The GitHub repository is named **`eSlider/go-config`** (renamed from `go-env`).
|
||||
|
||||
## Consequences
|
||||
|
||||
- Consumers must change their `import` paths and `go get` target.
|
||||
- CI, badges, and documentation reference `go-config` and `eslider/go-config`.
|
||||
|
||||
## Status
|
||||
|
||||
Accepted — 2026-05-02.
|
||||
|
||||
## References
|
||||
|
||||
- inventar ASR-0008 — Go library module conventions
|
||||
- ASR-0002 — API clean break
|
||||
@@ -0,0 +1,24 @@
|
||||
# ASR-0002: Clean break from go-env v0.1.0
|
||||
|
||||
## Context
|
||||
|
||||
`go-env` v0.1.0 exposed package-level helpers (`Unmarshal`, `UnmarshalPrefix`, `AsMap`, …). The new design is `Codec`-centric with multiple sources per format.
|
||||
|
||||
## Decision
|
||||
|
||||
1. **No compatibility shims** in `go-config` re-exporting the old API.
|
||||
2. v0.1.0 remains tagged on git history as `github.com/eslider/go-env@v0.1.0` for archival consumers.
|
||||
3. Migration path is documented in `CHANGELOG.md` and the README.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Single-call-site migrations must switch to `env.New(env.WithCurrentEnvironment(), …).Unmarshal(&cfg)`.
|
||||
|
||||
## Status
|
||||
|
||||
Accepted — 2026-05-02.
|
||||
|
||||
## References
|
||||
|
||||
- CHANGELOG `[0.2.0]`
|
||||
- ASR-0001
|
||||
@@ -0,0 +1,25 @@
|
||||
# ASR-0003: Uniform codec API and Source abstraction
|
||||
|
||||
## Context
|
||||
|
||||
Users switch between YAML, JSON, INI, and env-file formats; a different function surface per format would increase cognitive load and test matrices.
|
||||
|
||||
## Decision
|
||||
|
||||
1. Every format package exports **`New(opts...) *Codec`** with **`Map`**, **`Unmarshal`**, **`UnmarshalContext`**, **`Marshal`**, **`WriteTo`**.
|
||||
2. Bytes, readers, files, and URLs are modeled by **`internal/source.Source`** with **`Open(ctx) (io.ReadCloser, error)`**.
|
||||
3. HTTP(S) sources support **`WithHTTPHeader`** and **`WithHTTPClient`**.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Cross-format examples in the README stay structurally identical.
|
||||
- URL behaviour is testable with `httptest` against our client only.
|
||||
|
||||
## Status
|
||||
|
||||
Accepted — 2026-05-02.
|
||||
|
||||
## References
|
||||
|
||||
- ASR-0005 — merge semantics across multiple sources
|
||||
- ASR-0008 — httptest policy alignment
|
||||
@@ -0,0 +1,23 @@
|
||||
# ASR-0004: Configurable key normalization
|
||||
|
||||
## Context
|
||||
|
||||
Real-world configuration mixes `kebab-case`, `snake_case`, `SCREAMING_SNAKE`, and struct field names. Requiring `mapstructure` tags on every field is noisy.
|
||||
|
||||
## Decision
|
||||
|
||||
1. After parsing and merging, codecs run **`internal/keymap.Walk`** with a **`Normalizer`** (default **`LowerAlnum`**: lowercase + strip non `[a-z0-9]`).
|
||||
2. Callers may set **`WithKeyNormalizer(nil)`** to disable walking, or supply a custom function.
|
||||
|
||||
## Consequences
|
||||
|
||||
- POSIX env keys without `-` still align with YAML keys that contain hyphens once normalized.
|
||||
- CLI `get` applies the same normalizer to each path segment for consistency.
|
||||
|
||||
## Status
|
||||
|
||||
Accepted — 2026-05-02.
|
||||
|
||||
## References
|
||||
|
||||
- ASR-0003
|
||||
@@ -0,0 +1,26 @@
|
||||
# ASR-0005: Multi-source deep-merge semantics
|
||||
|
||||
## Context
|
||||
|
||||
Layered configuration (defaults file < local overrides < process environment) requires predictable composition rules.
|
||||
|
||||
## Decision
|
||||
|
||||
1. Sources are applied in **option order** (left → right). Each source parses to a `map[string]any`, then **`merge.DeepMerge`** folds them.
|
||||
2. **Maps recurse** — nested keys are unioned; existing nested maps are not replaced wholesale by a sibling scalar.
|
||||
3. **Scalar leaves** use **last-write-wins** (later source wins).
|
||||
4. **Slices** default to **`merge.Replace`**; **`WithSliceMerge(merge.Concat)`** appends prior and new slice elements.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Env files and `WithCurrentEnvironment()` compose when ordered **lowest → highest** priority.
|
||||
- Tests lock behaviour via `fixtures/merge/*`.
|
||||
|
||||
## Status
|
||||
|
||||
Accepted — 2026-05-02.
|
||||
|
||||
## References
|
||||
|
||||
- ASR-0003
|
||||
- `internal/merge`
|
||||
@@ -0,0 +1,26 @@
|
||||
# ASR-0006: Third-party library choices
|
||||
|
||||
## Context
|
||||
|
||||
We need battle-tested parsers and struct bridging without maintaining our own grammars.
|
||||
|
||||
## Decision
|
||||
|
||||
1. **Struct / map bridging:** `github.com/go-viper/mapstructure/v2` (maintained fork of `mitchellh/mapstructure`).
|
||||
2. **YAML:** `gopkg.in/yaml.v3`.
|
||||
3. **JSON:** `encoding/json` (stdlib).
|
||||
4. **INI:** `gopkg.in/ini.v1` with `Loose` parsing for tolerant files.
|
||||
5. **`.env` files:** `github.com/joho/godotenv` (`UnmarshalBytes`).
|
||||
6. **CLI:** stdlib `flag` only (no Cobra).
|
||||
|
||||
## Consequences
|
||||
|
||||
- `go.mod` carries the above direct dependencies (plus transitive modules as resolved by MVS).
|
||||
|
||||
## Status
|
||||
|
||||
Accepted — 2026-05-02.
|
||||
|
||||
## References
|
||||
|
||||
- [go-viper/mapstructure](https://github.com/go-viper/mapstructure)
|
||||
@@ -0,0 +1,24 @@
|
||||
# ASR-0007: CLI `envc` — convert, get, merge
|
||||
|
||||
## Context
|
||||
|
||||
Operators need a small tool to translate configuration between formats and to inspect merged trees without writing Go.
|
||||
|
||||
## Decision
|
||||
|
||||
1. Binary name **`envc`**; module path **`github.com/eslider/go-config/cmd/envc`** (`go install …/cmd/envc@latest`).
|
||||
2. Subcommands: **`convert`**, **`get`**, **`merge`** — each implemented as a **`Run*(args, stdin, stdout, stderr) int`** function for in-process tests.
|
||||
3. **No** third-party CLI framework in v1 of the CLI.
|
||||
|
||||
## Consequences
|
||||
|
||||
- `cmd/envc` may grow flags; keep business logic in subpackages, not in `main` beyond wiring.
|
||||
|
||||
## Status
|
||||
|
||||
Accepted — 2026-05-02.
|
||||
|
||||
## References
|
||||
|
||||
- inventar ASR-0008 §2 — CLI placement
|
||||
- ASR-0003
|
||||
@@ -0,0 +1,25 @@
|
||||
# ASR-0008: GitHub presentation and release flow
|
||||
|
||||
## Context
|
||||
|
||||
The repository was renamed from `eSlider/go-env` to `eSlider/go-config`. The v0.1.0 tag existed locally before the rename. Presentation should match other eSlider `go-*` libraries (e.g. `go-matrix-bot`).
|
||||
|
||||
## Decision
|
||||
|
||||
1. **v0.1.0 preservation:** push tag `v0.1.0` and create a GitHub **Release** with notes extracted from `CHANGELOG.md` before landing breaking work.
|
||||
2. **Development branch:** `release/v2` carries the `go-config` implementation until merged to `main`.
|
||||
3. **Rename:** `gh repo rename go-config` from `go-env`; local `origin` URL updated to `https://github.com/eSlider/go-config.git`.
|
||||
4. **Metadata:** `gh repo edit` sets description, **`homepage`** `https://pkg.go.dev/github.com/eslider/go-config`, and **topics** (`go`, `golang`, `config`, `yaml`, `json`, `ini`, `env`, `dotenv`, `mapstructure`, `codec`, `encoder`, `decoder`, `cli`, `library`).
|
||||
5. **README:** badges row, mermaid architecture diagram, hero snippet, quick starts, CLI table, API tables, related libraries, link to `docs/asr/`.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Old `github.com/eslider/go-env` URLs redirect for a limited GitHub window; module path for v0.1.0 code remains the historical `go-env` import.
|
||||
|
||||
## Status
|
||||
|
||||
Accepted — 2026-05-02.
|
||||
|
||||
## References
|
||||
|
||||
- [go-matrix-bot](https://github.com/eSlider/go-matrix-bot) — README pattern reference
|
||||
@@ -0,0 +1,14 @@
|
||||
# Architecture Significant Requirements (ASRs)
|
||||
|
||||
Repo-local decisions for `go-config` (numbering starts at ASR-0001). Org-wide policies remain under `inventar/docs/asr/`.
|
||||
|
||||
| ID | Title |
|
||||
| --- | --- |
|
||||
| [ASR-0001](ASR-0001-module-rename-and-layout.md) | Module rename and multi-package layout |
|
||||
| [ASR-0002](ASR-0002-clean-break-from-v0.1.0.md) | Clean break from go-env v0.1.0 |
|
||||
| [ASR-0003](ASR-0003-uniform-codec-api-and-source-abstraction.md) | Uniform codec API and Source abstraction |
|
||||
| [ASR-0004](ASR-0004-configurable-key-normalization.md) | Configurable key normalization |
|
||||
| [ASR-0005](ASR-0005-multi-source-deep-merge-semantics.md) | Multi-source deep-merge semantics |
|
||||
| [ASR-0006](ASR-0006-third-party-library-choices.md) | Third-party library choices |
|
||||
| [ASR-0007](ASR-0007-cli-envc-convert-get-merge.md) | CLI `envc`: convert, get, merge |
|
||||
| [ASR-0008](ASR-0008-github-presentation-and-release-flow.md) | GitHub presentation and release flow |
|
||||
Reference in New Issue
Block a user