From 97a672f0f284f7415e4a2676dbe9d27c259785ce Mon Sep 17 00:00:00 2001 From: Spiegel Date: Sat, 9 May 2026 10:37:13 +0900 Subject: [PATCH] docs: refresh README and consolidate CI workflows --- .github/copilot-instructions.md | 39 ++++++++++++ .github/workflows/ci.yml | 64 +++++++++++++++++++ .github/workflows/codeql-analysis.yml | 58 ----------------- .github/workflows/codeql.yml | 35 +++++++++++ .github/workflows/lint.yml | 50 --------------- .github/workflows/vulns.yml | 19 ------ README.md | 89 ++++++++++++++++++++++++++- 7 files changed, 225 insertions(+), 129 deletions(-) create mode 100644 .github/copilot-instructions.md create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/codeql.yml delete mode 100644 .github/workflows/lint.yml delete mode 100644 .github/workflows/vulns.yml diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..6299192 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,39 @@ +# Copilot Instructions for github.com/goark/errs + +## Project Overview +- This repository provides `github.com/goark/errs`, a Go package for structured error wrapping and multi-error handling. +- Main module target is Go 1.20+. +- There is a nested module under `zapobject/` that should stay in sync with top-level changes when relevant. +- If dependency or Go-version related files are changed, keep `go.mod` (root), `zapobject/go.mod`, and `go.work` consistency in mind. + +## Coding Guidelines +- Keep public APIs backward compatible unless explicitly requested. +- Follow idiomatic Go naming and error handling patterns. +- Keep code comments in English. +- Avoid introducing new dependencies unless there is a clear benefit. + +## Testing and Validation +- Prefer `task` commands for local validation. +- Primary checks: + - `task test` + - `task govulncheck` +- For broad validation, run: + - `task` +- Before proposing a merge, run at least `task test` and `task govulncheck`. For wide-ranging changes, run `task`. + +## CI/Workflow Expectations +- Keep GitHub Actions workflows minimal and readable. +- CI should cover lint, tests, and reachable-vulnerability checks. +- Keep workflow action versions reasonably up to date. +- Keep `ci.yml` split into independent jobs for lint/test and govulncheck where possible for faster feedback. +- Use `golang/govulncheck-action` for govulncheck in CI unless there is a strong reason to change. + +## Documentation Expectations +- When behavior or developer flow changes, update `README.md` in the same change. +- Keep usage examples executable and aligned with current API. +- Keep README links to sample programs under `sample/` and `zapobject/` aligned with current behavior. + +## API and Compatibility Notes +- Do not introduce new usage of deprecated `Cause()`; prefer `errors.Is`/`errors.As` compatible flows and `Unwrap`/`Unwraps`. +- Treat changes to exported symbols, function signatures, and observable error formatting behavior as potentially breaking. +- Error string and JSON formatting are validated by tests; when output behavior changes, update README examples and test expectations in the same change. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..31d2952 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,64 @@ +name: ci + +on: + push: + branches: + - master + pull_request: + +permissions: + contents: read + +jobs: + test-and-lint: + name: lint and test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - uses: actions/setup-go@v6 + with: + go-version-file: go.mod + cache-dependency-path: | + go.sum + zapobject/go.sum + + - name: golangci-lint + uses: golangci/golangci-lint-action@v9 + with: + version: latest + args: --enable gosec + + - name: Test root module + run: go test -shuffle on ./... + + - name: Test zapobject module + working-directory: zapobject + run: go test -shuffle on ./... + + govulncheck-root: + name: govulncheck (root) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Run govulncheck for root module + uses: golang/govulncheck-action@v1 + with: + go-version-file: go.mod + go-package: ./... + repo-checkout: false + + govulncheck-zapobject: + name: govulncheck (zapobject) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Run govulncheck for zapobject module + uses: golang/govulncheck-action@v1 + with: + work-dir: zapobject + go-version-file: go.mod + go-package: ./... + repo-checkout: false diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index c189f79..0000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,58 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -name: "CodeQL" - -on: - push: - branches: [master] - pull_request: - # The branches below must be a subset of the branches above - branches: [master] - schedule: - - cron: '0 20 * * 0' - -jobs: - CodeQL-Build: - # CodeQL runs on ubuntu-latest, windows-latest, and macos-latest - runs-on: ubuntu-latest - - permissions: - # required for all workflows - security-events: write - - # only required for workflows in private repositories - actions: read - contents: read - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - # Override language selection by uncommenting this and choosing your languages - with: - languages: go - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below). - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # πŸ“š https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following - # three lines and modify them (or add more) to build your code if your - # project uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..28b32f6 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,35 @@ +name: CodeQL + +on: + push: + branches: + - master + pull_request: + branches: + - master + schedule: + - cron: "0 20 * * 0" + +permissions: + actions: read + contents: read + security-events: write + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: go + + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + - name: Perform CodeQL analysis + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 084bb8a..0000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: lint -on: - push: - branches: - - master - pull_request: - -permissions: - contents: read - # Optional: allow read access to pull request. Use with `only-new-issues` option. - # pull-requests: read -jobs: - golangci: - name: lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 - with: - go-version-file: 'go.mod' - - name: golangci-lint - uses: golangci/golangci-lint-action@v9 - with: - # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version - version: latest - - # Optional: working directory, useful for monorepos - # working-directory: somedir - - # Optional: golangci-lint command line arguments. - args: --enable gosec - - # Optional: show only new issues if it's a pull request. The default value is `false`. - # only-new-issues: true - - # Optional: if set to true then the all caching functionality will be complete disabled, - # takes precedence over all other caching options. - # skip-cache: true - - # Optional: if set to true then the action don't cache or restore ~/go/pkg. - # skip-pkg-cache: true - - # Optional: if set to true then the action don't cache or restore ~/.cache/go-build. - # skip-build-cache: true - - name: testing - run: go test -shuffle on ./... - - name: install govulncheck - run: go install golang.org/x/vuln/cmd/govulncheck@latest - - name: running govulncheck - run: govulncheck ./... diff --git a/.github/workflows/vulns.yml b/.github/workflows/vulns.yml deleted file mode 100644 index 20d0d97..0000000 --- a/.github/workflows/vulns.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: vulns -on: - push: - branches: - - master - pull_request: -jobs: - vulns: - name: Vulnerability scanner - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version-file: 'go.mod' - - name: WriteGoList - run: go list -json -m all > go.list - - name: Nancy - uses: sonatype-nexus-community/nancy-github-action@main diff --git a/README.md b/README.md index 16432e8..6478d75 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # [errs] -- Error handling for Golang -[![check vulns](https://github.com/goark/errs/workflows/vulns/badge.svg)](https://github.com/goark/errs/actions) -[![lint status](https://github.com/goark/errs/workflows/lint/badge.svg)](https://github.com/goark/errs/actions) +[![ci status](https://github.com/goark/errs/workflows/ci/badge.svg)](https://github.com/goark/errs/actions) +[![codeql status](https://github.com/goark/errs/workflows/CodeQL/badge.svg)](https://github.com/goark/errs/actions) [![GitHub license](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://raw.githubusercontent.com/goark/errs/master/LICENSE) [![GitHub release](http://img.shields.io/github/release/goark/errs.svg)](https://github.com/goark/errs/releases/latest) @@ -10,8 +10,79 @@ This package is required Go 1.20 or later. **Migrated repository to [github.com/goark/errs][errs]** +## Design goals + +- Wrap any `error` and collect context at the point of failure +- Add arbitrary key/value context with `WithContext` +- Include caller function name in context by default +- Print structured error data with `%+v` (JSON-like output) +- Handle multi-errors in a concurrency-safe way via `errs.Errors` + +## Development + +### Requirements + +- Go 1.20 or later +- [Task](https://taskfile.dev/) command + +### Local validation + +```text +task test +task govulncheck +``` + +Run all maintenance tasks: + +```text +task +``` + +## CI Workflows + +- `ci`: lint (`golangci-lint` with `gosec`), tests, and `govulncheck` +- `CodeQL`: scheduled and push/PR static analysis + ## Usage +### Sample programs + +All sample files under `sample/` use the `run` build tag. + +```text +go run -tags run ./sample/sample1.go +``` + +- New error with cause and context: [sample/sample1.go](sample/sample1.go) +- Wrap existing error with context: [sample/sample2.go](sample/sample2.go) +- Wrap sentinel error with cause: [sample/sample3.go](sample/sample3.go) +- Multiple causes with `errors.Join`: [sample/sample4.go](sample/sample4.go) +- Multi-error with `errs.Join`: [sample/sample5.go](sample/sample5.go) +- Concurrency-safe multi-error accumulation: [sample/sample6.go](sample/sample6.go) +- Zap structured logging object example: [zapobject/example_test.go](zapobject/example_test.go) + +### Print formats + +- `%v`: human readable error message +- `%#v`: Go-syntax-like internal structure +- `%+v`: structured JSON-like representation + +### Helper functions compatible with stdlib + +`errs.Is`, `errs.As`, and `errs.Unwrap` are thin wrappers around `errors.Is`, `errors.As`, and `errors.Unwrap`. + +`errs.Unwraps` returns `[]error` and works for both single-cause and multi-cause errors. +For a single cause, it returns a one-element slice. +For multiple causes, it returns all causes as a slice. + +`errs.EncodeJSON` serializes generic `error` values by traversing unwrap chains when possible. + +### Edge-case behavior + +- `errs.New("")` returns `nil` +- `errs.Wrap(nil)` returns `nil` +- If `WithCause` is given multiple times, the last cause is used + ### Create new error instance with cause ```go @@ -198,4 +269,18 @@ func main() { } ``` +### Structured logging with Zap + +Use the submodule `github.com/goark/errs/zapobject` to log errors as structured objects. + +```go +logger.Error("failed", zap.Object("error", zapobject.New(err))) +``` + +Without `zapobject`, `zap.Error(err)` writes string fields only. + +## Background article (Japanese) + +- [Go 言θͺžη”¨γ‚¨γƒ©γƒΌγƒγƒ³γƒ‰γƒͺング・パッケージ](https://text.baldanders.info/release/errs-package-for-golang/) + [errs]: https://github.com/goark/errs "goark/errs: Error handling for Golang"