From c5038a1f53d4f551012664d22d9251a9103bd36f Mon Sep 17 00:00:00 2001 From: Jasoet Martohartono Date: Sat, 28 Mar 2026 13:40:03 +0700 Subject: [PATCH 1/7] chore(nix): add flake.nix with dev tool declarations --- flake.nix | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 flake.nix diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..7196b43 --- /dev/null +++ b/flake.nix @@ -0,0 +1,37 @@ +{ + description = "Go pkg/v2 development environment"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in { + devShells.default = pkgs.mkShell { + packages = [ + # Go toolchain + pkgs.go + pkgs.golangci-lint + pkgs.gofumpt + pkgs.gosec + + # Container CLIs (daemon is system-level) + pkgs.podman + pkgs.docker-client + pkgs.podman-compose + + # Other tools + pkgs.bun + pkgs.jq + ]; + + shellHook = '' + echo "pkg/v2 dev environment ready โ€” Go $(go version | awk '{print $3}')" + ''; + }; + }); +} From 47c4fa9332dad69cede4320baf2b7c45b8ff45b2 Mon Sep 17 00:00:00 2001 From: Jasoet Martohartono Date: Sat, 28 Mar 2026 13:40:35 +0700 Subject: [PATCH 2/7] chore(nix): add .envrc and gitignore .direnv/ --- .envrc | 1 + .gitignore | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 .envrc diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore index f44b3b0..57951b7 100644 --- a/.gitignore +++ b/.gitignore @@ -220,4 +220,7 @@ temporal.db .claude/* !.claude/settings.json !.claude/hooks/ -.claude/settings.local.json \ No newline at end of file +.claude/settings.local.json + +# Nix / direnv +.direnv/ \ No newline at end of file From 74c22fe6f179e718a19289c8ab7d36ef72145531 Mon Sep 17 00:00:00 2001 From: Jasoet Martohartono Date: Sat, 28 Mar 2026 13:48:28 +0700 Subject: [PATCH 3/7] feat(nix): wrap all task commands with nix develop -c CI workflows now run commands directly instead of through task, since CI provides its own tools via GitHub Actions setup steps. --- .github/workflows/ci.yml | 10 +---- .github/workflows/release.yml | 16 ++++---- Taskfile.yml | 69 +++++++++++++++++++++++------------ 3 files changed, 54 insertions(+), 41 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e6164d..d42f6a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,11 +19,8 @@ jobs: go-version: '1.26' check-latest: true - - name: Install Task - run: sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin - - name: Run tests - run: task ci:test + run: go test -race -count=1 ./... -tags=!examples lint: name: Lint @@ -38,11 +35,8 @@ jobs: go-version: '1.26' check-latest: true - - name: Install Task - run: sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin - - name: Install golangci-lint run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest - name: Run lint - run: task ci:lint + run: golangci-lint run ./... diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2d1f68a..fdf1fc0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,11 +22,8 @@ jobs: go-version: '1.26' check-latest: true - - name: Install Task - run: sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin - - name: Run tests - run: task ci:test + run: go test -race -count=1 ./... -tags=!examples release: name: Release @@ -48,9 +45,6 @@ jobs: go-version: '1.26' check-latest: true - - name: Install Task - run: sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin - - name: Setup Node.js uses: actions/setup-node@v6 with: @@ -65,10 +59,14 @@ jobs: - name: Release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: task release + run: bunx semantic-release - name: Warm Go module proxy if: success() run: | sleep 5 - task release:proxy-warmup + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") + if [ -n "$LATEST_TAG" ]; then + echo "Warming Go proxy for github.com/jasoet/pkg/v2@${LATEST_TAG}" + GOPROXY=https://proxy.golang.org GO111MODULE=on go list -m "github.com/jasoet/pkg/v2@${LATEST_TAG}" || true + fi diff --git a/Taskfile.yml b/Taskfile.yml index bba531d..0090c7a 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -1,6 +1,7 @@ version: '3' vars: + N: "nix develop -c" PODMAN_SOCKET: sh: | if command -v podman &> /dev/null; then @@ -39,16 +40,16 @@ tasks: desc: Run go mod vendor silent: true cmds: - - go mod tidy - - go mod vendor + - '{{.N}} go mod tidy' + - '{{.N}} go mod vendor' test: desc: Run unit tests with coverage silent: true cmds: - mkdir -p output - - go test -race -count=1 -coverprofile=output/coverage.out -covermode=atomic ./... -tags=!examples - - go tool cover -html=output/coverage.out -o output/coverage.html + - '{{.N}} go test -race -count=1 -coverprofile=output/coverage.out -covermode=atomic ./... -tags=!examples' + - '{{.N}} go tool cover -html=output/coverage.out -o output/coverage.html' - 'echo "โœ“ Coverage: output/coverage.html"' test:integration: @@ -60,8 +61,8 @@ tasks: TESTCONTAINERS_RYUK_DISABLED: '{{if .CONTAINER_HOST}}true{{end}}' cmds: - mkdir -p output - - go list ./... | grep -v examples | xargs go test -race -count=1 -coverprofile=output/coverage-integration.out -covermode=atomic -tags=integration -timeout=15m - - go tool cover -html=output/coverage-integration.out -o output/coverage-integration.html + - '{{.N}} bash -c "go list ./... | grep -v examples | xargs go test -race -count=1 -coverprofile=output/coverage-integration.out -covermode=atomic -tags=integration -timeout=15m"' + - '{{.N}} go tool cover -html=output/coverage-integration.out -o output/coverage-integration.html' - 'echo "โœ“ Integration coverage: output/coverage-integration.html"' test:argo: @@ -70,10 +71,10 @@ tasks: cmds: - task: argo:check - mkdir -p output - - go test -race -count=1 -coverprofile=output/coverage-argo.out -covermode=atomic -tags=argo -timeout=15m ./argo/... - - go tool cover -html=output/coverage-argo.out -o output/coverage-argo.html + - '{{.N}} go test -race -count=1 -coverprofile=output/coverage-argo.out -covermode=atomic -tags=argo -timeout=15m ./argo/...' + - '{{.N}} go tool cover -html=output/coverage-argo.out -o output/coverage-argo.html' - 'echo "โœ“ Argo coverage: output/coverage-argo.html"' - - go tool cover -func=output/coverage-argo.out | grep total + - '{{.N}} bash -c "go tool cover -func=output/coverage-argo.out | grep total"' test:complete: desc: Run ALL tests (unit + integration + argo) with single comprehensive coverage report @@ -86,11 +87,11 @@ tasks: - task: argo:check - mkdir -p output - echo "๐Ÿงช Running all tests (unit + integration + argo)..." - - go list ./... | grep -v examples | xargs go test -race -count=1 -coverprofile=output/coverage-complete.out -covermode=atomic -tags=integration,argo -timeout=20m -v - - go tool cover -html=output/coverage-complete.out -o output/coverage-complete.html + - '{{.N}} bash -c "go list ./... | grep -v examples | xargs go test -race -count=1 -coverprofile=output/coverage-complete.out -covermode=atomic -tags=integration,argo -timeout=20m -v"' + - '{{.N}} go tool cover -html=output/coverage-complete.out -o output/coverage-complete.html' - 'echo ""' - 'echo "โœ… Complete test coverage report:"' - - go tool cover -func=output/coverage-complete.out | grep total + - '{{.N}} bash -c "go tool cover -func=output/coverage-complete.out | grep total"' - 'echo "๐Ÿ“„ HTML Report: output/coverage-complete.html"' - 'echo "๐Ÿ“„ Coverage Data: output/coverage-complete.out"' @@ -136,7 +137,7 @@ tasks: desc: Run golangci-lint silent: true cmds: - - golangci-lint run ./... + - '{{.N}} golangci-lint run ./...' check: desc: Run all checks (test + lint) @@ -194,31 +195,51 @@ tasks: fi # Utilities - tools: - desc: Install development tools + nix:check: + desc: Verify Nix environment and tool availability silent: true cmds: - - go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest - - go install github.com/securego/gosec/v2/cmd/gosec@latest - - go install mvdan.cc/gofumpt@latest - - echo "โœ“ Tools installed" + - | + if ! command -v nix &> /dev/null; then + echo "โŒ Nix not installed" + echo " Install: curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install" + exit 1 + fi + echo "โœ… Nix $(nix --version)" + echo "Checking devShell tools..." + {{.N}} go version + {{.N}} golangci-lint --version + {{.N}} gofumpt --version + {{.N}} gosec --version + {{.N}} podman --version + {{.N}} docker --version + {{.N}} bun --version + {{.N}} jq --version + echo "โœ… All tools available" + + nix:update: + desc: Update flake inputs (bump tool versions) + silent: true + cmds: + - nix flake update + - echo "โœ… Flake inputs updated. Run 'task nix:check' to verify." fmt: desc: Format all Go files with gofumpt cmds: - - gofumpt -l -w . + - '{{.N}} gofumpt -l -w .' ci:test: desc: Run unit tests for CI (no coverage HTML) silent: true cmds: - - go test -race -count=1 ./... -tags=!examples + - '{{.N}} go test -race -count=1 ./... -tags=!examples' ci:lint: desc: Run golangci-lint for CI silent: true cmds: - - golangci-lint run ./... + - '{{.N}} golangci-lint run ./...' ci:check: desc: Run all CI checks (test + lint) @@ -231,7 +252,7 @@ tasks: desc: Run semantic-release (CI only) silent: true cmds: - - bunx semantic-release + - '{{.N}} bunx semantic-release' release:proxy-warmup: desc: Warm Go module proxy with latest tag @@ -241,7 +262,7 @@ tasks: LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") if [ -n "$LATEST_TAG" ]; then echo "Warming Go proxy for github.com/jasoet/pkg/v2@${LATEST_TAG}" - GOPROXY=https://proxy.golang.org GO111MODULE=on go list -m "github.com/jasoet/pkg/v2@${LATEST_TAG}" || true + {{.N}} bash -c "GOPROXY=https://proxy.golang.org GO111MODULE=on go list -m \"github.com/jasoet/pkg/v2@${LATEST_TAG}\"" || true fi clean: From af2db1bc5498662eb3c289055f7a8e91725565bd Mon Sep 17 00:00:00 2001 From: Jasoet Martohartono Date: Sat, 28 Mar 2026 13:49:33 +0700 Subject: [PATCH 4/7] docs: add nix development environment setup instructions --- INSTRUCTION.md | 6 +++++- README.md | 21 ++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/INSTRUCTION.md b/INSTRUCTION.md index 081b41b..d642459 100644 --- a/INSTRUCTION.md +++ b/INSTRUCTION.md @@ -27,6 +27,7 @@ attribute commits to AI. This applies to ALL commits, including those made by to - **Superpowers**: Ensure superpowers skills are installed. Use TDD for implementation, systematic-debugging for bugs. - **Commits**: Use Conventional Commits. Format: `(): `. Types: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `perf`, `ci`. - **Branching**: New branch for each feature/fix (`feat/...`, `fix/...`). PR with squash merge. Use `gh` for PR status and CI checks. +- **Nix**: All dev tools provided via `flake.nix`. Use `task ` which wraps commands with `nix develop -c`. Prerequisites: Nix (with flakes), go-task (global). - **Containers**: Dual Docker/Podman support. This is a shared library โ€” consumers use either runtime. - **Patterns**: Functional options for configuration. OTelConfig always injected via `With*()` options, never serialized (`yaml:"-" mapstructure:"-"`). Use `otel.Layers.Start*()` for instrumentation. - **Self-maintaining docs**: Update `INSTRUCTION.md`, `README.md`, and `AI_PATTERN.md` when making significant changes. @@ -44,6 +45,8 @@ attribute commits to AI. This applies to ALL commits, including those made by to | `/*_integration_test.go` | Integration tests (`//go:build integration`) | | `docs/plans/` | Design docs and implementation plans | | `.claude/` | Claude Code hooks and settings | +| `flake.nix` | Nix flake โ€” dev tool declarations | +| `.envrc` | direnv auto-activation (optional) | | `Taskfile.yml` | All project commands | | `INSTRUCTION.md` | AI dev context (this file) | | `AI_PATTERN.md` | AI library consumer patterns index | @@ -63,7 +66,8 @@ attribute commits to AI. This applies to ALL commits, including those made by to | `task vendor` | go mod tidy + vendor | | `task check` | test + lint | | `task clean` | Remove build artifacts | -| `task tools` | Install dev tools | +| `task nix:check` | Verify Nix environment and tool availability | +| `task nix:update` | Update flake inputs (bump tool versions) | | `task docker:check` | Verify Docker/Podman availability | | `task k8s:check` | Verify kubectl and cluster | | `task argo:check` | Verify Argo Workflows | diff --git a/README.md b/README.md index 4d75039..9c32039 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,24 @@ open output/coverage-all.html ## Development +### Development Setup + +**Prerequisites:** + +- **Nix** (with flakes enabled): install via [Determinate Nix Installer](https://install.determinate.systems/nix) +- **go-task** (global): `nix profile install nixpkgs#go-task` +- **gh** (optional): for PR management + +**Quick start:** + +```bash +task nix:check # verify environment +task test # run tests +task lint # run linter +``` + +All `task` commands execute through `nix develop -c` automatically, so you do not need to manually enter a Nix shell. + ### Development Commands ```bash @@ -537,7 +555,8 @@ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) 2. **Setup Development Environment** ```bash - task docker:check + task nix:check # verify Nix tools + task docker:check # verify Docker/Podman task test ``` From e53cda11e424656ead9d8daa59febf532fab7f6a Mon Sep 17 00:00:00 2001 From: Jasoet Martohartono Date: Sat, 28 Mar 2026 14:11:06 +0700 Subject: [PATCH 5/7] chore(nix): add flake.lock for reproducible version pinning --- flake.lock | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 flake.lock diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..f194334 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1774386573, + "narHash": "sha256-4hAV26quOxdC6iyG7kYaZcM3VOskcPUrdCQd/nx8obc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "46db2e09e1d3f113a13c0d7b81e2f221c63b8ce9", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} From f51525e5f06eb6e0495523e3b7f2f5feead9ddb6 Mon Sep 17 00:00:00 2001 From: Jasoet Martohartono Date: Sat, 28 Mar 2026 14:49:55 +0700 Subject: [PATCH 6/7] fix(ci): pin golangci-lint to v2.11.3 matching flake.nix --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d42f6a1..166ba01 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: check-latest: true - name: Install golangci-lint - run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@v2.11.3 - name: Run lint run: golangci-lint run ./... From 6ced8d7987819686e865ec600d96da6fc0be6c79 Mon Sep 17 00:00:00 2001 From: Jasoet Martohartono Date: Sat, 28 Mar 2026 14:53:18 +0700 Subject: [PATCH 7/7] fix(ci): use official golangci-lint install script for v2 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 166ba01..0061abb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: check-latest: true - name: Install golangci-lint - run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@v2.11.3 + run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.11.3 - name: Run lint run: golangci-lint run ./...