The tool now requires at least one positional argument — the path(s) to
the Go main package(s) to build — and must be run from the module root
(the directory containing go.mod).
# single binary (module root is the main package)
monorel .
# multiple binaries under one module
monorel ./cmd/gsheet2csv ./cmd/gsheet2tsv ./cmd/gsheet2env
Changes:
- Add `binary` struct {name, mainPath} and `parseBinaries()`
- "." is special-cased: binary name is taken from the CWD, not "."
- filepath.Clean's "./"-stripping is undone so goreleaser sees an
explicit relative path (./cmd/foo not cmd/foo)
- `goreleaserYAML` now takes `projectName + []binary`
- Each binary gets its own `builds` entry (with `id:` and `main:`)
and its own `archives` entry (with `ids:` to link it to the build)
- `main:` is omitted when mainPath is "." (goreleaser default)
- Checksum is named <projectName>_VERSION_checksums.txt
- `printScript` takes `projectName + []binary`
- Summary line says "Binaries:" (plural) when more than one
- Upload step globs tar.gz + zip for every binary, then the checksum
- Require go.mod in CWD; error out with usage message when no args given
Also regenerates cmd/tcpfwd/.goreleaser.yaml via the new code path
(adds `id: tcpfwd` to builds/archives; no functional change otherwise).
Adds a standalone Go CLI tool (tools/monorel) that automates the
goreleaser + gh release workflow for modules living in a subdirectory
of a monorepo where goreleaser Pro is not available.
Run from any module subdirectory (e.g. cmd/tcpfwd):
monorel # writes .goreleaser.yaml + prints release script
monorel --help # (flag defaults)
What the tool does:
- Detects module path and binary name from git prefix
- Lists and semver-sorts tags matching <prefix>/v* (e.g. cmd/tcpfwd/v*)
- Computes version: exact tag → stable release; commits/dirty → pre-release
- Writes (or updates) .goreleaser.yaml with the binary name hard-coded,
{{.Env.VERSION}} used for filenames instead of the prefixed tag,
and release.disable: true (gh handles the GitHub Release)
- Prints a numbered bash script covering env vars, optional git tag,
goreleaser build, release notes, and gh release create/upload/publish
Also updates cmd/tcpfwd/.goreleaser.yaml (first output from monorel):
- Fixes stray trailing quote in ldflags
- Sets release.disable: true (was release.footer)
- Adds generated-by header comment
- connEntry.isIdle(now, threshold): caller supplies now instead of time.Since
- connRegistry.closeIdle(now, threshold): passes now through to isIdle
- trackingConn gains a clock func() time.Time field used in Read/Write
- handleConn takes clock func() time.Time; uses it to init lastRead/lastWrite
and passes it to trackingConn
- Call sites in main pass time.Now or time.Now() explicitly
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On SIGINT/SIGTERM:
- Stop accepting new connections
- Close connections idle longer than --idle-timeout (default 5s),
determined by LastRead/LastWrite timestamps tracked per connection pair
- Wait for active connections to drain up to --shutdown-timeout (default 30s)
- Force-close any remaining connections if the timeout is exceeded
Also switches isClosedConn to use errors.Is(err, net.ErrClosed) and
exits the accept loop cleanly when a listener is closed during shutdown.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Accept any number of local-port:remote-host:remote-port forwards as
positional arguments. Backward-compatible with existing --port/--target
flags. Adds --version/-V/version and --help/help handling matching the
auth-proxy pattern, including printVersion printed to stderr at startup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>