8 Commits

Author SHA1 Message Date
b1be4ce829
fix(monorel): rename bump flag -m → -r
-m was already used by git commit, making copy-pasting confusing.
-r (for "release component") avoids that conflict.
2026-03-01 19:13:49 -07:00
c55a869b82
feat(monorel): add subcommand dispatch (release, bump, init)
Restructure monorel to use flag.FlagSet-based subcommand dispatch so that
future subcommands can each carry their own flags cleanly.

  monorel release <binary-path>...
      Existing behaviour: write .goreleaser.yaml and print a bash release
      script.  Now a named subcommand; no behaviour change.

  monorel bump [-m major|minor|patch] <binary-path>...
      Create a new semver git tag at HEAD for each module.
      -m defaults to "patch".  Using a flag (-m) rather than a positional
      argument avoids ambiguity with binary paths that might literally be
      named "minor" or "patch".

  monorel init <binary-path>...
      For each module (in command-line order): write .goreleaser.yaml,
      commit it (skipped when file is unchanged), then run bump patch.
2026-03-01 19:13:49 -07:00
9812f52ee9
fix(monorel): explicit paths, POSIX vars, goreleaser.yaml warning
1. Script paths relative to invoking CWD (not module root):
   - git log pathspec: "-- relPath/" instead of "-- ./"
   - artifact globs:   relPath/dist/ instead of ./dist/
   - goreleaser only:  ( cd "relPath" && goreleaser ... ) inline subshell
   - when relPath==".": all paths use ./ and no cd is emitted
   The outer ( subshell ) wrapper is removed; each command is now
   copy-pasteable from the directory where monorel was invoked.

2. POSIX variable for release notes:
   RELEASE_NOTES= → <project>_release_notes= (no export; goreleaser
   does not need it; multiple modules no longer share the same name).

3. Warn before overwriting .goreleaser.yaml when:
   - the existing file contains {{ .ProjectName }} (stock config), AND
   - the module is a monorepo subdirectory (go.mod not adjacent to .git/)
   The file is still updated; the warning alerts the user that a
   non-monorel config was replaced.
2026-03-01 19:13:49 -07:00
76fbf74444
fix(monorel): error if binary path is not a main package
Add checkPackageMain(), which uses go/parser with PackageClauseOnly mode
(reads only the package-declaration token of each .go file — very fast)
to verify the resolved binary directory declares `package main`.

Called in groupByModule for every argument after resolving the absolute
path, before findModuleRoot.  Produces a helpful error, e.g.:

  monorel: error: .../io/transform/gsheet2csv is package "gsheet2csv",
                  not a main package
2026-03-01 19:13:49 -07:00
862eeebd6d
feat(monorel): auto-discover module root; submodule-aware .git detection
Major refactor: monorel no longer requires being run from the module root.
It now accepts paths to binary packages from any ancestor directory and
walks up from each path to find go.mod (groupByModule / findModuleRoot).

Binaries sharing a module root are grouped together. When the script must
cd into a module directory (multi-module run or different CWD) the per-module
output is wrapped in a bash subshell to prevent directory leakage.

The .git stop-marker now only triggers on a .git DIRECTORY, not a .git FILE.
A .git file means the path is inside a submodule whose real repository root
is further up the tree, so the search continues upward.
2026-03-01 19:13:49 -07:00
5716f0f757
fix(monorel): guard against nested go.mod in binary paths
Any directory on the path from the module root to a binary that
contains its own go.mod is a separate module; monorel should not try
to manage it.  Two cases are now caught with distinct errors:

  ../other              → "outside the module directory"
  ./cmd/go.mod          → "has its own go.mod" (intermediate dir)
  ./cmd/foo/go.mod      → "has its own go.mod" (binary dir itself)

Both suggest the correct fix: cd into that directory and run monorel
from there.
2026-03-01 19:13:49 -07:00
12c025e5e2
feat(monorel): require binary-path args; support multi-binary modules
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).
2026-03-01 19:13:45 -07:00
3676ef0f47
feat: add tools/monorel for monorepo submodule releases
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
2026-03-01 19:13:39 -07:00