From 36f0ed9b5250910884f22edadb3081b03217356d Mon Sep 17 00:00:00 2001 From: Andriy Oblivantsev Date: Sun, 3 May 2026 10:29:27 +0100 Subject: [PATCH] docs: add CONTRIBUTING guide and expand README Add CONTRIBUTING.md for testing, PR checks, and release-please flow; link from README and AGENTS. Document envc bash sourcing (set -a, source <(...)) for YAML/INI. Co-authored-by: Cursor --- AGENTS.md | 31 ++----------- CONTRIBUTING.md | 64 +++++++++++++++++++++++++++ README.md | 113 +++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 161 insertions(+), 47 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/AGENTS.md b/AGENTS.md index 11af450..423bb06 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,39 +14,16 @@ Convert **env**, **YAML**, **JSON**, and **INI** into nested `map[string]any` an Breaking changes require a new major SemVer tag (or `/v2` module path if the policy changes). -## Testing policy +## Testing policy, PR checklist, and releases -Follows the eSlider "no synthetic mocks" policy (see [.cursor/rules/no-synthetic-mocks.mdc](.cursor/rules/no-synthetic-mocks.mdc)): - -- **Unit tests** — pure inputs for merge, keymap, structconv, env flat-map helpers. -- **`httptest`** — allowed only to test **our** HTTP client behaviour in `internal/source` (not third-party API emulation). -- **Fixtures** — real files under `fixtures/`; `testfixtures` resolves paths from module root. +Human-oriented detail lives in **[CONTRIBUTING.md](CONTRIBUTING.md)** (testing rules, +`go test` / lint commands, Conventional Commits, and the release-please / GoReleaser flow). +Follow that document for any change that will ship in a versioned release. ## Decisions Architecture Significant Requirements: [docs/asr/README.md](docs/asr/README.md). -## Checklist before release - -Local sanity check (CI runs the same on every PR): - -```sh -go mod tidy -go vet ./... -go test -race -shuffle=on -count=1 ./... -golangci-lint run --timeout 5m -``` - -Versioning is **automated via [release-please](https://github.com/googleapis/release-please-action)** -and [GoReleaser](https://goreleaser.com) — do **not** hand-edit version strings or tag manually: - -1. Commit using [Conventional Commits](https://www.conventionalcommits.org/) - (`feat:`, `fix:`, `feat!:` for breaking, etc.). -2. `.github/workflows/release-please.yml` opens a release PR on each push to `main` - with the computed next SemVer and an updated `CHANGELOG.md`. -3. Merging that PR creates the `vX.Y.Z` tag. `.github/workflows/release.yml` then runs - GoReleaser to publish cross-platform `envc` binaries and a GitHub Release. - ## Related - `inventar/docs/asr/ASR-0008.md` — Go library module conventions diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..77430b9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,64 @@ +# Contributing to go-config + +Thank you for helping improve this module. This document covers **testing expectations**, +**local checks**, and **how releases are cut** (so nobody tags or edits versions by hand). + +For repository purpose, public API notes, and agent-oriented context, see [AGENTS.md](AGENTS.md). + +## Testing policy + +This project follows the eSlider **no synthetic mocks** policy (see [.cursor/rules/no-synthetic-mocks.mdc](.cursor/rules/no-synthetic-mocks.mdc)): + +- **Unit tests** — pure inputs for merge, keymap, structconv, env flat-map helpers. +- **`httptest`** — allowed only to test **our** HTTP client behaviour in `internal/source` (not third-party API emulation). +- **Fixtures** — real files under `fixtures/`; `testfixtures` resolves paths from module root. + +## Before you open a pull request + +Run the same checks CI will run (adjust paths if your checkout layout differs): + +```sh +go mod tidy +go vet ./... +go test -race -shuffle=on -count=1 ./... +golangci-lint run --timeout 5m +``` + +## Commit messages + +Use [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `perf:`, +`feat!:` or `BREAKING CHANGE:` for breaking changes, etc.). Release automation reads these +messages to choose the next SemVer. + +## Release and versioning + +Versions are **computed from git history**, not edited in Go source. Do **not** create +release tags manually or bump version constants in code. + +### CI on every change + +1. Every push and pull request runs [`test.yml`](.github/workflows/test.yml) (matrix: Go + 1.22, 1.23, stable × linux / macOS / windows, with `-race -shuffle=on`) and + [`lint.yml`](.github/workflows/lint.yml) (`go vet` + `golangci-lint`). + +### Release Please and GoReleaser + +2. On pushes to `main`, [`release-please.yml`](.github/workflows/release-please.yml) parses + commits since the last tag and opens (or updates) a **release pull request** that bumps + [`CHANGELOG.md`](CHANGELOG.md) and [`.release-please-manifest.json`](.release-please-manifest.json) + to the next SemVer. + +3. **Merging that release PR** creates the git tag `vX.Y.Z` and a GitHub Release. + +4. The tag triggers [`release.yml`](.github/workflows/release.yml), which runs + [GoReleaser](https://goreleaser.com) to cross-compile the `envc` binary (linux / darwin / + windows × amd64 / arm64), injects `-X main.version={{.Version}}` (and related ldflags) at + link time, and attaches archives plus `checksums.txt` to the release. + +Local `go install` builds of `envc` report `dev` for `envc version` unless you pass your own +`-ldflags`; release binaries show the released version. + +## Architecture decisions + +Repo-local ASRs: [docs/asr/README.md](docs/asr/README.md). Broader eSlider Go module +conventions: `inventar/docs/asr/ASR-0008.md` (see [AGENTS.md](AGENTS.md) — Related). diff --git a/README.md b/README.md index e5c726c..7b6db29 100644 --- a/README.md +++ b/README.md @@ -87,12 +87,100 @@ os.WriteFile("out.json", b, 0o644) ## CLI: `envc` +Formats for `--from` / `--to`: `yaml`, `json`, `ini`, `env`. Run `envc help` or +`envc -h` for flags. + | Command | Purpose | | ------------------------------------------------------------------ | --------------------------------------------------------------- | | `envc convert --from yaml --to env --input - --output -` | Convert stdin YAML to dotenv on stdout | -| `envc get --from yaml --path service.name config.yaml` | Print one path (dot-separated; segments normalized like codecs) | +| `envc get --from yaml --path service.name config.yaml` | Print one path (dot segments map to lower+alnum keys) | | `envc merge --from yaml --to json --output out.json a.yaml b.yaml` | Deep-merge multiple YAML files, emit JSON | +### Help and version + +```sh +envc help +envc version +``` + +### `convert` examples + +```sh +# Pipe YAML in, JSON on stdout (default --input - and --output -) +printf 'app:\n port: 8080\n' | envc convert --from yaml --to json + +# File → file +envc convert --from json --to yaml --input settings.json --output settings.yaml + +# Remote YAML → local dotenv +envc convert --from yaml --to env \ + --input https://example.com/config.yaml \ + --output .env.generated +``` + +### Apply YAML or INI to the **current** bash session + +`envc convert … --to env` prints **dotenv-style** lines (`KEY=value`). They are normal +shell assignments, not `export` lines, so use **`set -a`** (allexport) if child processes +must see the variables. **Process substitution** `<(…)` needs **bash** (not plain `sh`). + +```bash +# YAML → current shell (and export to children while sourcing) +set -a +source <(envc convert --from yaml --to env --input config.yaml) +set +a + +# INI → current shell +set -a +source <(envc convert --from ini --to env --input app.ini) +set +a +``` + +Same idea from stdin: + +```bash +set -a +source <(cat deploy.yaml | envc convert --from yaml --to env) +set +a +``` + +Only do this with **trusted** config files (same caution as `source` on any generated +script): values are expanded by the shell when you `source` them. + +### `get` examples + +Path segments use the same **lower+alnum** rules as the library (e.g. `sub-service` +and `SubService` both address `subservice`). + +```sh +# Value from a file +envc get --from yaml --path app.port config.yaml + +# Nested key; stdin when the last argument is `-` or omitted with a pipe +cat config.yaml | envc get --from yaml --path service.subservice.name - +``` + +### `merge` examples + +Sources are merged **in order** (later files override scalar leaves; maps recurse). +Use `-` once to read **one** merged stdin blob as a source (same format as the others). + +```sh +envc merge --from yaml --to json defaults.yaml overrides.yaml + +# Write merged JSON to stdout, then save +envc merge --from yaml --to json base.yaml local.yaml | tee merged.json + +# Stdin plus files: first load stdin as YAML, then merge each file +cat patch.yaml | envc merge --from yaml --to yaml - base.yaml +``` + +### Stdin and `-` + +With `--input -` (convert) or `-` as the get/merge input, `envc` reads **until EOF**. +From an interactive terminal with no pipe, that waits until you press **Ctrl-D** +(end of input). Prefer `--input path` or a URL when scripting. + ## API (all codecs) | Method | Description | @@ -122,26 +210,11 @@ INI uses dotted sections, e.g. `[service.subservice]` with `name=...`. | [go-onlyoffice](https://github.com/eSlider/go-onlyoffice) | OnlyOffice API | | [go-ollama](https://github.com/eSlider/go-ollama) | Ollama client | -## Release flow +## Contributing -Versions are **computed from git history**, never hardcoded in source. Commit with -[Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `feat!:` …) -and the pipeline takes care of the rest: - -1. Every push / PR runs [`test.yml`](.github/workflows/test.yml) (matrix: Go 1.22, 1.23, - stable × linux/macOS/windows, `-race -shuffle=on`) and - [`lint.yml`](.github/workflows/lint.yml) (`go vet` + `golangci-lint`). -2. On merges to `main`, [`release-please.yml`](.github/workflows/release-please.yml) - parses commits since the last tag and opens a "release PR" that bumps `CHANGELOG.md` - and `.release-please-manifest.json` to the next SemVer. -3. Merging that PR creates the git tag `vX.Y.Z` and a GitHub Release. -4. The tag triggers [`release.yml`](.github/workflows/release.yml), which runs - [GoReleaser](https://goreleaser.com) to cross-compile `envc` (linux/darwin/windows × - amd64/arm64) with `-X main.version={{.Version}}` injected at link time and attach - archives + `checksums.txt` to the release. - -No version string lives in Go source — `envc version` prints the value baked in by the -release build, or `dev` for local `go install` builds. +Testing expectations, local commands, commit message conventions, and how **release-please** +and **GoReleaser** publish tags and `envc` binaries are documented in +**[CONTRIBUTING.md](CONTRIBUTING.md)**. ## Decisions