Skip to content

Releases: mpyw/goroutinectx

v0.12.0

Choose a tag to compare

@github-actions github-actions released this 05 Oct 00:45
Immutable release. Only release title and notes can be modified.
df4572b

goroutinectx can now run inside golangci-lint, as a module plugin. Nothing changes for the command or go vet.

golangci-lint

goroutinectx is not bundled with golangci-lint, so build a binary that holds it. (#77)

.custom-gcl.yml:

version: v2.13.1  # the golangci-lint release to build
plugins:
  - module: github.com/mpyw/goroutinectx
    import: github.com/mpyw/goroutinectx/plugin
    version: v0.12.0

.golangci.yml:

version: "2"
linters:
  enable:
    - goroutinectx
  settings:
    custom:
      goroutinectx:
        type: module
        description: Checks goroutine context propagation.
        settings:
          goroutine-deriver: github.com/my-example-app/telemetry/apm.NewGoroutineContext
          context-carriers:
            - github.com/labstack/echo/v4.Context
          external-spawner:
            - github.com/example/workerpool.Pool.Submit
          spawnerlabel: true
golangci-lint custom  # writes ./custom-gcl
./custom-gcl run ./...

The keys under settings are the flag names. A key left out keeps its default, and an unknown key stops the run.

Key Flag Setting
goroutine-deriver A string The same string. , means OR and + means AND, so it stays one string
external-spawner, context-carriers A comma-separated string A list, one name per item
Each checker, such as goroutine or spawnerlabel A bool A bool

Other changes

  • The run logic moves from analyzer.go to internal/run, so the flags and the plugin build the same configuration. The flags, their defaults, and ErrNoInspector are unchanged. (#77)
  • The agent skills vendored from declscope are updated to 0.18.0.

Install

mise use "github:mpyw/goroutinectx@0.12.0"

Full changelog: v0.11.0...v0.12.0

Changelog

  • df4572b feat: add a golangci-lint module plugin, and bump to 0.12.0 (#77)

v0.11.0

Choose a tag to compare

@github-actions github-actions released this 29 Sep 00:55
Immutable release. Only release title and notes can be modified.
e618ba7

//goroutinectx:ignore is now read strictly: a reason goes after //, and a name goroutinectx does not know is reported. An ignore that silences nothing is now reported as unused, as it was meant to be.

Important

goroutinectx now requires Go 1.27. It required 1.26 before.

Some reports can appear in code that has not changed. Each points at an ignore or directive that did nothing:

  • an ignore on a line with no violation, now reported as unused;
  • an unknown checker or directive name, such as //goroutinectx:ignore gorutine;
  • //goroutinectx:ignore errgroup on a conc call. Use conc there.

//goroutinectx:ignore

(#66)

Comment 0.10.0 0.11.0
//goroutinectx:ignore // why Silenced nothing: // why was read as a checker Ignores every checker
//goroutinectx:ignore goroutine - why Ignores goroutine The same. - why is kept for compatibility
//goroutinectx:ignore intentionally detached Silenced nothing, reported as unused unknown checker "intentionally detached", with the valid names
//goroutinectx:ignore goroutine,typo Ignored goroutine Reported, and ignores nothing
//goroutinectx:ignore conc Silenced nothing Ignores the conc checker
//goroutinectx:ignore errgroup on a conc call Silenced it Reported as unused. Use conc
//goroutinectx:ignre Did nothing, silently unknown directive goroutinectx:ignre

An ignore counts as used only when it silences a report. The check used to consult the ignore before it ran. So an ignore on a clean line was never reported as unused.

//line directives

Ignores, spawner directives and the generated-file skip were keyed by names and lines that a //line directive changes. (#63)

Case 0.10.0 0.11.0
An ignore below //line Did not silence, and was reported unused Silences
A generated file with //line Analyzed and reported Skipped
Two //line regions whose lines touch A spawner directive could attach to the wrong function Lines are those in the file

Performance

Looking up what was assigned to a variable walked the whole file, and rebuilt an inspector, on every lookup. It now uses the pass inspector. On a file with many closure reassignments, a run fell from 18.5 s to 1.2 s of CPU. On typical code the difference is within noise. (#64)

Other changes

  • Code reads more directly. Duplicated closure checks and a duplicated package match are shared, and needless nil checks are gone. Output is unchanged. (#68, #69, #70, #71)
  • The agent skills vendored from declscope are updated to 0.15.0, which adds declscope-authoring. (#72)

Install

mise use "github:mpyw/goroutinectx@0.11.0"

Full changelog: v0.10.0...v0.11.0

Changelog

  • 27a900d Bump declscope version
  • 340d3e3 chore(deps): bump declscope to 0.12.0, and turn on rules.unused: strict (#56)
  • a94d68a fix: read //goroutinectx:ignore as declscope reads its ignore (#66)
  • a6f23f2 fix: use unadjusted positions so //line directives do not move directives (#63)
  • 29dee91 perf: look up assignments with the pass inspector (#64)
  • 5a3fb0b refactor: adopt Go 1.27 syntax and require Go 1.27
  • 21c7716 refactor: drop nil checks that a comma-ok assertion already makes (#71)
  • ab051c1 refactor: reuse the closure checks and the package path match (#70)
  • c89cfa0 refactor: say searches and splits with slices and strings (#68)
  • bcf3f7b refactor: walk assignments through two iterators in probe (#69)

v0.10.0

Choose a tag to compare

@github-actions github-actions released this 24 Sep 00:32
Immutable release. Only release title and notes can be modified.
e491941

Directives are now read exactly as Go reads them, through go/ast.ParseDirective. Only the canonical form is a directive, names match exactly, and a comment that is meant as a directive but spelled differently is reported. The minimum Go version is now 1.26.

Important

This release has three breaking changes.

  • // goroutinectx:ignore and // goroutinectx:spawner, with a space after //, used to work. They now have no effect and are reported.
  • Lookalikes such as //goroutinectx:ignored and //goroutinectx:spawnerX used to match. They now have no effect.
  • Go 1.25 is no longer supported.

See Migrating.

Only //goroutinectx:name is a directive

A directive is a line comment with no space after //, no space after the colon, and a lowercase name. The arguments of ignore read as before: a checker list, a reason after - or //, and empty arguments to ignore every checker.

//goroutinectx:ignore goroutine - the caller cancels this one
go worker()

Malformed directives are reported

Any other comment whose text, after // or /*, starts with goroutinectx: once any space is skipped has no effect. It is reported with one message:

worker.go:12:1: malformed goroutinectx directive: write it as //goroutinectx:name
Comment 0.9.3 0.10.0
//goroutinectx:ignore Directive Directive
// goroutinectx:ignore (space or tab after //) Directive Malformed
//goroutinectx: ignore Ordinary comment Malformed
/* goroutinectx:ignore */ Ordinary comment Malformed
//goroutinectx:Ignore Ordinary comment Malformed
//goroutinectx: Ordinary comment Malformed

The same applies to spawner. The report matters most there. A spawner that has no effect means the functions passed to it are no longer checked, and nothing else would show it. Prose that mentions a directive partway through a comment is not reported.

Names match exactly

A directive used to match on its prefix, so a longer name counted:

Comment 0.9.3 0.10.0
//goroutinectx:ignored Ignore every checker Ordinary comment
//goroutinectx:spawnerX Spawner Ordinary comment

These are valid directive syntax with an unknown name, so they are not reported as malformed.

Go 1.26 or later

ast.ParseDirective was added in Go 1.26. The go directive in go.mod is now 1.26.0, and CI tests Go 1.26 and 1.27, the two releases Go supports. The prebuilt binaries do not need Go at all.

Migrating

Run goroutinectx 0.10.0 over the repository.

You see Do this
malformed goroutinectx directive Rewrite the comment as //goroutinectx:ignore or //goroutinectx:spawner: no space after // or after the colon, a line comment, a lowercase name
A report under //goroutinectx:ignored or another lookalike Use the exact name, //goroutinectx:ignore
A new report in a function passed to a helper marked //goroutinectx:spawnerX or similar Use the exact name, //goroutinectx:spawner
The build asks for a newer Go Build with Go 1.26 or later, or install a prebuilt binary

Full changelog: v0.9.3...v0.10.0

v0.9.3

Choose a tag to compare

@github-actions github-actions released this 15 Sep 16:37
Immutable release. Only release title and notes can be modified.
7df5197

Changelog

v0.9.2

Choose a tag to compare

@github-actions github-actions released this 15 Sep 12:54
Immutable release. Only release title and notes can be modified.
cd0f5d7

Changelog

  • cd0f5d7 Adopt declscope, and align the file names with what they hold (#40)

v0.9.1

Choose a tag to compare

@github-actions github-actions released this 01 Sep 03:54
Immutable release. Only release title and notes can be modified.
55c3ca9

Changelog

Enabled Immutable Releases

v0.9.0

Choose a tag to compare

@github-actions github-actions released this 01 Sep 03:47
4252019

Changelog

  • 4252019 feat: publish prebuilt binaries and document mise install (#38)

v0.8.0

Choose a tag to compare

@mpyw mpyw released this 22 Aug 01:47
e75b6b5

What's Changed

  • refactor: use external tests and add t.Parallel() by @mpyw in #25
  • fix: revert internal tests to internal package by @mpyw in #26
  • [Claude] Remove MCP configuration from the repository by @mpyw in #27
  • [Claude] Add Dependabot configuration by @mpyw in #28
  • chore(deps): bump codecov/codecov-action from 5 to 7 by @dependabot[bot] in #30
  • chore(deps): bump actions/checkout from 4 to 7 by @dependabot[bot] in #29
  • chore(deps): bump golangci/golangci-lint-action from 7 to 9 by @dependabot[bot] in #31
  • chore(deps): bump actions/setup-go from 5 to 6 by @dependabot[bot] in #32
  • chore(deps): bump actions/setup-go from 6 to 7 by @dependabot[bot] in #35
  • chore: Go 1.27 modernization (go fix) + generic method coverage by @mpyw in #36
  • chore(deps)!: bump x/tools to v0.49.0, drop Go 1.24 support by @mpyw in #37

New Contributors

Full Changelog: v0.7.5...v0.8.0

v0.7.5

Choose a tag to compare

@mpyw mpyw released this 26 Dec 03:41
7fface6

Bug Fixes

  • Conditional reassignment detection: Fixed false negatives when variables holding closures are conditionally reassigned

    • Previously, only the last assignment was checked
    • Now checks ALL assignments from the last unconditional assignment onwards
    • Affects: goroutine, errgroup, spawner checkers
  • Factory pattern conditional reassignment: Fixed detection in factory functions that return conditionally reassigned variables

    • Previously short-circuited when finding any nested func literal using context
    • Now correctly checks only what's actually returned
    • Added recursive context-checking for nested factories (triple higher-order patterns)

Example

func example(ctx context.Context) {
    fn := func() { _ = ctx }  // uses ctx
    if condition {
        fn = func() { /* no ctx */ }  // doesn't use ctx
    }
    go fn()  // Now correctly warns: not all paths use ctx
}

Full Changelog: v0.7.4...v0.7.5

v0.7.4

Choose a tag to compare

@mpyw mpyw released this 26 Dec 00:31
4fb020b

What's Changed

Bug Fixes

  • Fix regression where -goroutine-deriver flag didn't work with errgroup/waitgroup/conc/spawner checkers

Improvements

  • Rename CallArgChecker to SpawnCallbackChecker for clarity
  • Fix export consistency (unexported types with unexported fields)
  • Add comprehensive tests for deriver checking with errgroup, waitgroup, and spawner
  • Add probe unit tests for funcLitOfLiteralKey
  • Add IIFE and nested factory test cases for improved coverage

Coverage

  • FactoryCallReturnsContextUsingFunc: 66.7% → 88.9%
  • funcLitOfLiteralKey: 75.0% → 100.0%
  • Total probe/checkers: 85.7% → 86.6%

Note: v0.7.2 and v0.7.3 have been retracted due to the deriver regression. Please use v0.7.4 instead.