Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
18b3d12
ci(release): add next prerelease and release/v2 maintenance branch roles
jasoet Jul 22, 2026
81186f9
ci(release): gate releases on integration tests
jasoet Jul 22, 2026
647db56
ci: add gorelease API-compatibility gate (blocking on main/release-v2…
jasoet Jul 22, 2026
b3ac799
ci: run workflow on next and release/v2; fix gorelease conditions for…
jasoet Jul 22, 2026
d010abe
test(archtest): add convention-enforcement test package (OTelConfig t…
jasoet Jul 22, 2026
1048dff
docs(instruction): document v3 branch model, archtest, and v3 backlog
jasoet Jul 22, 2026
ead6e0e
chore: gitignore .superpowers workflow scratch
jasoet Jul 22, 2026
08f97cd
test(archtest,ci): strengthen WithOTelConfig signature assertions; re…
jasoet Jul 22, 2026
ce00ab2
feat!: change module path to github.com/jasoet/pkg/v3
jasoet Jul 22, 2026
08b56f2
ci(release): point release notes and docs at /v3 module path
jasoet Jul 22, 2026
f3cdbd3
docs(plans): add v3 phase 3 plan (otel core + logging merge)
jasoet Jul 22, 2026
1d7e508
feat(otel)!: absorb logging package into otel
jasoet Jul 22, 2026
5370379
fix: swap remaining logging imports to otel in tagged tests and examples
jasoet Jul 22, 2026
5f37850
feat(otel)!: replace mutating Config builders with functional options
jasoet Jul 22, 2026
50c1e41
test(otel): add SpanHelper/LayerContext behavioral tests with in-memo…
jasoet Jul 22, 2026
8f9a6b4
docs(otel): align README with v3 API; add Output-verified examples
jasoet Jul 22, 2026
10f3627
docs: remove stale logging references after package merge
jasoet Jul 22, 2026
b93538e
docs(plans): add v3 phase 4 plan (config + retry)
jasoet Jul 22, 2026
7673567
feat(config)!: replace viper-leaking APIs with functional options
jasoet Jul 22, 2026
c1774de
docs(config): align README with v3 options API; add compile-checked e…
jasoet Jul 22, 2026
26ee01c
feat(retry)!: functional options, OTelConfig tags, Do-time validation
jasoet Jul 22, 2026
8294252
docs(retry): align README with v3 options API; add compile-checked ex…
jasoet Jul 22, 2026
87eaa38
docs(config): fix stale examples README and NestedEnvVars references;…
jasoet Jul 22, 2026
9ecfe87
docs(plans): add v3 phase 5 plan (rest de-leak)
jasoet Jul 22, 2026
6cc5af1
feat(rest)!: library-owned Response replaces resty.Response in public…
jasoet Jul 22, 2026
b78ad52
feat(rest)!: unexport error constructors; wire retry counter into res…
jasoet Jul 22, 2026
b4985d5
docs(rest): rewrite README against real API and telemetry; add compil…
jasoet Jul 22, 2026
c3ca8c3
fix(rest): count only actual retries in retry counter; guard nil resp…
jasoet Jul 22, 2026
3f3dd80
docs(plans): add v3 phase 6 plan (db unification)
jasoet Jul 22, 2026
c786eb4
feat(db)!: NewPool functional options; pool metrics no longer gated o…
jasoet Jul 22, 2026
767cd71
feat(db)!: dedupe migration API to sql.DB variants; instrument with o…
jasoet Jul 22, 2026
688ff58
docs(db): rewrite README against v3 API; add compile-checked examples
jasoet Jul 22, 2026
f7ede11
docs(db): correct otelgorm span names; fix stale Pool() refs and doc …
jasoet Jul 22, 2026
9c6f98a
docs(plans): add v3 phase 7 plan (docker de-leak)
jasoet Jul 22, 2026
41d8450
feat(docker)!: ContainerTarget replaces docker client in WaitStrategy
jasoet Jul 22, 2026
77f4344
feat(docker)!: surface cleanup — OTelConfig tags, WaitHealthy rename,…
jasoet Jul 22, 2026
842a0de
docs(docker): fix endpoint wait-pattern drift; rewrite README for Con…
jasoet Jul 22, 2026
866ca5f
docs(docker): fix ContainerTarget godoc; record remaining de-leak dec…
jasoet Jul 22, 2026
58eb851
docs(plans): add v3 phase 8 plan (grpc cleanup)
jasoet Jul 22, 2026
bce8648
feat(grpc)!: remove dead and misleading exported symbols
jasoet Jul 22, 2026
afe10e5
fix(grpc): support Start/Stop/Start cycles, reset running on failed s…
jasoet Jul 22, 2026
3e2ccb3
fix(grpc): synchronize grpcServer access; restore double-Start atomicity
jasoet Jul 22, 2026
ceca712
fix(grpc): lock grpcServer read in Stop
jasoet Jul 22, 2026
c6ae270
feat(grpc): add WithGatewayRegistrar; rewrite README against options API
jasoet Jul 22, 2026
62ace20
fix(grpc): strip gateway base path at mount; mount gateway when regis…
jasoet Jul 22, 2026
bbea79b
fix(grpc): guard Stop during in-flight Start; add H2C restart coverag…
jasoet Jul 22, 2026
6aeba4a
docs(plans): record grpc behavior changes for migration guide
jasoet Jul 22, 2026
aee46ec
docs(plans): add v3 phase 9 plan (server lifecycle + OTel)
jasoet Jul 22, 2026
bb76332
feat(server)!: Server type with programmatic Start/Shutdown lifecycle
jasoet Jul 22, 2026
f0aabfc
fix(server): error on restart-after-shutdown, idempotent Shutdown, cl…
jasoet Jul 22, 2026
2252c7e
feat(server): auto-install OTel tracing and metrics middleware when O…
jasoet Jul 22, 2026
7c627f2
docs(server): rewrite README for Server API; correct health-endpoint …
jasoet Jul 22, 2026
4923a1c
docs(server): correct template note, otel options snippet, and orderi…
jasoet Jul 22, 2026
4db6552
docs(plans): add v3 phase 10 plan (ssh unification)
jasoet Jul 22, 2026
72fe6a7
feat(ssh): add OTelConfig plumbing and otel.Layers instrumentation
jasoet Jul 22, 2026
a64ba8f
test(ssh): add LocalAddr coverage and real HTTP forwarding assertion
jasoet Jul 22, 2026
868974d
docs(plans): record ssh fix-wave items (half-close, forward logger)
jasoet Jul 22, 2026
dc93388
docs(ssh): rewrite README against real API (no auto-reconnection, sec…
jasoet Jul 22, 2026
4b08c31
fix(ssh): propagate half-close in forward, config-aware forward logge…
jasoet Jul 22, 2026
af9fc7c
docs(ssh): correct half-close limitation; record v3.x and migration n…
jasoet Jul 22, 2026
692714d
docs(plans): add v3 phase 11 plan (temporal unification)
jasoet Jul 22, 2026
cadc208
feat(temporal)!: typed constructors and functional options
jasoet Jul 22, 2026
e6fa18d
test(temporal): backfill unit tests for logger adapter, query validat…
jasoet Jul 22, 2026
ef7d02a
docs(temporal): rewrite README for typed constructors and SDK-integra…
jasoet Jul 22, 2026
f4c7e32
docs(examples): replace foreign import paths in temporal example comm…
jasoet Jul 22, 2026
0064100
docs(temporal): fix dashboard README and template table for typed con…
jasoet Jul 22, 2026
0a8b205
docs(plans): add v3 phase 12 plan (argo unification)
jasoet Jul 22, 2026
14f3450
feat(argo)!: simplify Option to func(*Config); fix in-cluster Namespa…
jasoet Jul 22, 2026
87cfa0d
feat(argo)!: operations read OTel config from context; client injects it
jasoet Jul 22, 2026
2874664
docs(argo): rewrite README against real API and context-based OTel flow
jasoet Jul 23, 2026
54e724f
docs(argo): remove stale client.Close and chained-builder doc snippets
jasoet Jul 23, 2026
e29f995
docs(argo): fix builder doc snippet, migration framing, Go badge; rec…
jasoet Jul 23, 2026
10bb072
docs(plans): add v3 phase 13 plan (utilities)
jasoet Jul 23, 2026
5e5cc3c
feat(compress)!: complete sentinel error contract; honor WithMaxArchi…
jasoet Jul 23, 2026
f4ee1ad
feat(concurrent)!: fix ExecuteConcurrentlyTyped type-parameter order
jasoet Jul 23, 2026
5af7fce
fix(base32): normalize input in AppendChecksum/ValidateChecksum; gold…
jasoet Jul 23, 2026
4f85ddf
docs: correct v2->v3 references, drop removed logging package and db …
jasoet Aug 12, 2026
22bc886
ci: fix proxy-warmup module path to v3 and tagged-code coverage
jasoet Aug 12, 2026
5163c9c
fix(otel)!: correct OTLP endpoint handling and dedupe span exception …
jasoet Aug 12, 2026
87c6089
fix(rest)!: copy caller headers, idempotent-only retries, honor Retry…
jasoet Aug 12, 2026
f8550e2
fix(server): record true HTTP status for error and 404 responses
jasoet Aug 12, 2026
b9591d0
fix(config): correct struct-tag docs and nested-env matching
jasoet Aug 12, 2026
8ee33ce
fix(concurrent): validate nil resultBuilder and capture panic stack
jasoet Aug 12, 2026
6526463
fix(retry): guard nil operation and preserve error context on cancel
jasoet Aug 12, 2026
d7de3df
fix(ssh): stop accept-loop busy-spin and make dial context-aware
jasoet Aug 12, 2026
3227d88
fix(compress): refuse symlink writes, truncate overwrites, hard size cap
jasoet Aug 12, 2026
e982df6
fix(base32): normalize input across all entry points, add sentinel er…
jasoet Aug 12, 2026
f725d83
fix(grpc): keep H2C timeouts off gRPC streams and fix trace propagation
jasoet Aug 12, 2026
743677b
fix(docker): eliminate use-after-Close race and container/leak footguns
jasoet Aug 12, 2026
78f2b48
fix(db): make MSSQL work by default, escape DSNs, stop pinning pool c…
jasoet Aug 12, 2026
71ba6e1
fix(argo): generate runnable commands and harden the builder
jasoet Aug 12, 2026
a538f35
fix(temporal): agree on namespace, fix history attribution, add TLS/auth
jasoet Aug 12, 2026
ad07e54
test(archtest): register db WithOTelConfig and guard against vacuous …
jasoet Aug 12, 2026
0e88f25
style: resolve lint and vet findings surfaced by the tagged-code gate
jasoet Aug 12, 2026
2cb3954
test: fix two flaky/broken tests surfaced by the runner
jasoet Aug 16, 2026
573f74f
test(grpc): make blocking health handler honor context cancellation
jasoet Aug 16, 2026
a029e5e
ci: pin gorelease and keep the v3 release PR off the blocking API gat…
jasoet Aug 17, 2026
92d9045
fix(server,grpc): continue inbound W3C traces in HTTP middleware (#60)
jasoet Aug 17, 2026
941c7ba
fix(docker): guard nil NetworkSettings in Executor network methods (#61)
jasoet Aug 17, 2026
8d4a6ec
docs: add v2 to v3 migration guide, ADRs, and domain glossary (#62)
jasoet Aug 17, 2026
143822b
docs: correct coverage figures, stale examples, and broken links (#63)
jasoet Aug 17, 2026
b9b19e4
test(db): wait for real Postgres readiness, not just the mapped port …
jasoet Aug 17, 2026
d802f3a
docs: rewrite maintaining guide for the v3 branch and release model (…
jasoet Aug 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/RELEASE_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,5 @@ Only `feat`, `fix`, `perf`, and `refactor` commits trigger releases. Use `chore`

The release workflow warms the proxy automatically. If it still shows stale data:
```bash
GOPROXY=https://proxy.golang.org go list -m github.com/jasoet/pkg/v2@v2.x.x
GOPROXY=https://proxy.golang.org go list -m github.com/jasoet/pkg/v3@v3.x.x
```
37 changes: 34 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ name: CI

on:
push:
branches: [main]
branches: [main, next, 'release/v2']
tags: ['*']
pull_request:
branches: [main]
branches: [main, next, 'release/v2']

env:
# Pinned so a blocking API gate is reproducible. Matches the golang.org/x/exp
# pseudo-version already in go.mod; bump both together.
GORELEASE_VERSION: v0.0.0-20251113190631-e25ba8c21ef6

jobs:
ci:
Expand All @@ -17,9 +22,35 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Lint
run: nix develop --command golangci-lint run ./...

- name: Test
run: nix develop --command go test -race -count=1 ./... -tags=!examples
run: nix develop --command go test -race -count=1 ./...

- name: Vet (including build-tagged code)
# Compiles and vets example/integration/argo-tagged files that the untagged
# build never sees, closing the gap where tagged code regressions slip past CI.
run: nix develop --command go vet -tags='example integration argo' ./...

- name: API compatibility check
# Breaking API changes are intended on the v3 line, so this gate is
# informational wherever `next` is involved and blocking everywhere else:
# - ref_name == 'next' : pushes to next
# - base_ref == 'next' : PRs targeting next
# - head_ref == 'next' : the next -> main v3 release PR. Without this
# clause base_ref is 'main' and the blocking gate fires on the whole
# intended v3 break set, making the release PR unmergeable.
if: github.ref_name != 'next' && github.base_ref != 'next' && github.head_ref != 'next'
run: nix develop --command go run golang.org/x/exp/cmd/gorelease@${{ env.GORELEASE_VERSION }}

- name: API compatibility report (informational on next)
if: github.ref_name == 'next' || github.base_ref == 'next' || github.head_ref == 'next'
# gorelease reports "no baseline version" until the first non-prerelease
# /v3 tag exists on main; that is expected for the v3 release PR and is
# why this run must not gate the merge.
continue-on-error: true
run: nix develop --command go run golang.org/x/exp/cmd/gorelease@${{ env.GORELEASE_VERSION }}
12 changes: 8 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,25 @@ name: Release

on:
push:
branches: [main]
branches: [main, next, 'release/v2']
workflow_dispatch:

jobs:
test:
name: Test
runs-on: [self-hosted, local, macOS, ARM64]
timeout-minutes: 45
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Test
run: nix develop --command go test -race -count=1 ./... -tags=!examples
run: nix develop --command go test -race -count=1 ./...

- name: Integration tests
run: nix develop --command bash -c "go list ./... | grep -v examples | xargs go test -count=1 -tags=integration -timeout=20m"

release:
name: Release
Expand Down Expand Up @@ -55,6 +59,6 @@ jobs:
sleep 5
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 nix develop --command go list -m "github.com/jasoet/pkg/v2@${LATEST_TAG}" || true
echo "Warming Go proxy for github.com/jasoet/pkg/v3@${LATEST_TAG}"
GOPROXY=https://proxy.golang.org GO111MODULE=on nix develop --command go list -m "github.com/jasoet/pkg/v3@${LATEST_TAG}" || true
fi
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,6 @@ temporal.db
.worktrees/

# Node.js (semantic-release)
node_modules/
node_modules/
# Superpowers workflow scratch (task briefs, reports, review diffs)
.superpowers/
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# golangci-lint configuration for github.com/jasoet/pkg/v2
# golangci-lint configuration for github.com/jasoet/pkg/v3
# Go utility library with focus on reliability, security, and performance

version: "2"
Expand Down
12 changes: 10 additions & 2 deletions .releaserc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
{
"branches": [
"main"
"main",
{
"name": "next",
"prerelease": true
},
{
"name": "release/v2",
"range": "2.13.x"
}
],
"plugins": [
[
Expand Down Expand Up @@ -78,7 +86,7 @@
]
},
"writerOpts": {
"headerPartial": "## [{{version}}]({{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}) ({{date}})\n\n**Full Changelog**: {{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}\n\n```\ngo get github.com/jasoet/pkg/v2@{{currentTag}}\n```"
"headerPartial": "## [{{version}}]({{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}) ({{date}})\n\n**Full Changelog**: {{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}\n\n```\ngo get github.com/jasoet/pkg/v3@{{currentTag}}\n```"
}
}
],
Expand Down
30 changes: 18 additions & 12 deletions AI_PATTERN.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# AI Pattern Guide

Guide for AI assistants working on projects that **use** `github.com/jasoet/pkg/v2`. This file is an index — read the linked READMEs and examples for full details.
Guide for AI assistants working on projects that **use** `github.com/jasoet/pkg/v3`. This file is an index — read the linked READMEs and examples for full details.

## Quick Start

```go
import "github.com/jasoet/pkg/v2/<package>"
import "github.com/jasoet/pkg/v3/<package>"
```

**Go Version:** 1.26+ (generics required)
**Install:** `go get github.com/jasoet/pkg/v2@latest`
**Install:** `go get github.com/jasoet/pkg/v3@latest`
**v1 (no OTel):** `go get github.com/jasoet/pkg@v1.6.0` — preserved on [`release/v1`](https://github.com/jasoet/pkg/tree/release/v1) branch, unmaintained.
**Project Template:** See [PROJECT_TEMPLATE.md](PROJECT_TEMPLATE.md) for recommended project structure, wiring patterns, test tiers (E2E), Swagger/OpenAPI setup, and Taskfile targets.

Expand Down Expand Up @@ -80,7 +80,6 @@ cfg, err := config.LoadString[AppConfig](yamlContent, "APP")
|---------|-------------|--------|----------|
| [otel](./otel/) | OpenTelemetry unified config (tracing, metrics, logging) | [README](otel/README.md) | [examples_test.go](otel/examples_test.go), [instrumentation_example_test.go](otel/instrumentation_example_test.go) |
| [config](./config/) | Type-safe YAML config with env overrides and validation | [README](config/README.md) | [examples/](examples/config/) |
| [logging](./logging/) | Structured logging with zerolog + OTel LoggerProvider | [README](logging/README.md) | [examples/](examples/logging/) |
| [db](./db/) | Multi-database (PostgreSQL, MySQL, MSSQL) with GORM + migrations | [README](db/README.md) | [examples/](examples/db/) |
| [docker](./docker/) | Container executor with dual API (functional + struct) | [README](docker/README.md) | [examples/](examples/docker/) |
| [server](./server/) | HTTP server with Echo, health checks, graceful shutdown | [README](server/README.md) | [examples/](examples/server/) |
Expand All @@ -99,28 +98,35 @@ cfg, err := config.LoadString[AppConfig](yamlContent, "APP")
### Connect to a Database

```go
pool, _ := db.ConnectionConfig{
DBType: db.Postgresql, Host: "localhost", Port: 5432,
Username: "user", Password: "pass", DBName: "mydb",
OTelConfig: otelConfig,
}.Pool()
pool, _ := db.NewPool(
db.WithConnectionConfig(db.ConnectionConfig{
DBType: db.Postgresql, Host: "localhost", Port: 5432,
Username: "user", Password: "pass", DBName: "mydb",
}),
db.WithOTelConfig(otelConfig),
)
```

> [db/README.md](db/README.md) for migrations, multi-DB, connection pooling.

### Start an HTTP Server

```go
cfg := server.DefaultConfig(8080, operation, shutdown)
server.StartWithConfig(cfg)
srv, _ := server.New(
server.WithPort(8080),
server.WithOperation(operation),
server.WithShutdown(shutdown),
)
go func() { <-shutdownSignal; _ = srv.Shutdown(context.Background()) }()
err := srv.Start() // blocks until Shutdown
```

> [server/README.md](server/README.md) for health checks, middleware, EchoConfigurer.

### Add Retry Logic

```go
cfg := retry.DefaultConfig().WithName("db.connect").WithOTel(otelConfig)
cfg := retry.New(retry.WithName("db.connect"), retry.WithOTelConfig(otelConfig))
err := retry.Do(ctx, cfg, func(ctx context.Context) error { return db.Ping(ctx) })
```

Expand Down
69 changes: 69 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# pkg

A Go utility library of independent packages, each wrapping one concern (HTTP, gRPC,
database, containers, workflows) with OpenTelemetry instrumentation built in. Consumers
import only the packages they need.

## Language

### Package kinds

**Utility package**:
A package whose wrapped dependency is incidental to why a consumer imports it — `rest`,
`config`, `db`, `docker`, `server`, `grpc`, `compress`, `concurrent`, `retry`, `ssh`,
`base32`. Third-party types are hidden from public signatures.
_Avoid_: wrapper package, helper package

**SDK-integration package**:
A package whose whole purpose is to make a specific vendor SDK easier to use — `temporal`
and `argo`. Vendor types appear in public signatures deliberately, because the consumer is
writing against that SDK anyway.
_Avoid_: leaky package, thin wrapper

**Selective de-leak**:
The decision to hide a third-party type behind a library-owned one in a utility package
while deliberately keeping it visible in an SDK-integration package. See
[ADR 0004](docs/adr/0004-selective-de-leak-of-third-party-types.md).
_Avoid_: abstraction, encapsulation

**Escape hatch**:
A public method that deliberately returns a third-party type inside an otherwise de-leaked
package, because no library-owned shape would carry the same information. Documented as
such, never an oversight.
_Avoid_: leak, loophole, backdoor

### Conventions

**Convention contract**:
The set of rules every configurable package must satisfy — functional options constructor,
`OTelConfig` field with the non-serialized tags, `WithOTelConfig` option, instrumentation
through `otel.Layers`, and `Example*` tests behind README snippets.
_Avoid_: standard, style guide

**Convention test**:
A test in `internal/archtest` that enforces the convention contract mechanically, by
reflection over registered config structs and by compile-time assignment of each package's
`WithOTelConfig`. Adding a package means extending the registry.
_Avoid_: architecture test, lint rule

**OTel injection point**:
`WithOTelConfig(*otel.Config)` — the single supported way to give a package its telemetry
providers. See [ADR 0002](docs/adr/0002-otel-config-is-injected-never-serialized.md).
_Avoid_: otel setup, telemetry config

**Docs-of-record**:
An `Example*` test that a README snippet is copied from, so documentation cannot drift from
a compiling API. A README code block without one is not trusted.
_Avoid_: sample, snippet test

### Release lines

**v3 line**:
Work on the `next` branch, published as `v3.0.0-next.N` prereleases, merged to `main` as
`v3.0.0`. The only line receiving features. See
[ADR 0001](docs/adr/0001-freeze-v2-and-ship-v3-as-one-big-bang.md).

**Frozen line**:
`release/v2`, pinned at v2.13.1, open to emergency patches only. `release/v1` is closed
entirely at v1.6.0.
_Avoid_: legacy, deprecated, maintenance branch
Loading
Loading