Skip to content

Refactor: align codebase with engineering standards#96

Merged
rianjs merged 13 commits intomainfrom
refactor/standards-alignment
Feb 16, 2026
Merged

Refactor: align codebase with engineering standards#96
rianjs merged 13 commits intomainfrom
refactor/standards-alignment

Conversation

@rianjs
Copy link
Contributor

@rianjs rianjs commented Feb 15, 2026

Summary

Closes #97

Comprehensive refactoring to align the gro codebase with engineering standards for consistency, mechanical enforcement, and maintainability.

Architecture & Enforcement

  • Add structural tests (internal/architecture/architecture_test.go) enforcing codebase patterns at CI time
  • Add coverage gate to CI (60% threshold)

Code Standards

  • Propagate context.Context through all API client methods and command handlers
  • Relocate interfaces to consumer packages (interface-at-consumer pattern)
  • Remove deprecated gmail wrapper functions
  • Add signal handling with context propagation

Test Infrastructure

  • Remove testify dependency, replace with stdlib assertion helpers
  • Centralize CaptureStdout and generic WithFactory[T] helpers
  • Add t.Parallel() to safe test files
  • Add function-field mock structs with compile-time interface checks

Documentation

  • Restructure CLAUDE.md as concise TOC (~90 lines, down from ~350)
  • Create docs/architecture.md, docs/golden-principles.md, docs/adding-a-domain.md
  • Add package doc comments to all packages

Bug Fixes

  • Fix --json flag ignored on empty results across all list/search commands

Build & Lint

  • Align Makefile targets and CI workflow
  • Clean up stale lint suppressions

Test plan

  • make check passes (tidy, lint, test, build)
  • make test-cover-check passes (63.6% > 60% threshold)
  • All 12 structural architecture tests pass
  • 12 new empty-results-with-JSON unit tests pass
  • Integration tests pass against live Google APIs (mail, calendar, contacts, drive)
  • golangci-lint reports 0 issues

- Add STANDARDS.md to repo
- Add revive, gosec, errorlint, exhaustive linters to .golangci.yml
- Add `tidy` and `check` targets to Makefile
- Fix errorlint: replace type assertions with errors.As in
  errors.IsRetryable() and initcmd.errorAs (bug fixes - wrapped errors
  were silently missed)
- Fix gosec: add nolint annotations for legitimate file operations
- Fix revive: rename unused parameters to _, fix labelIds -> labelIDs
- Add temporary lint exclusions for issues addressed by later commits
  (package comments, interface stuttering, mock comments)
Create internal/testutil/assert.go with generic test helpers that
replace testify assertions: Equal, NoError, Error, ErrorIs, Contains,
NotContains, Len, Nil, NotNil, True, False, Empty, NotEmpty, Greater,
GreaterOrEqual, Less.

All helpers use t.Helper() for accurate failure line reporting and
accept testing.TB for flexibility. Includes comprehensive tests.
Migrate all 44 test files from testify/assert and testify/require to
either the internal testutil package or raw stdlib assertions. Packages
that would create import cycles (auth, config, keychain, log, gmail,
calendar, contacts, drive) use stdlib directly.

Adds SliceContains and LenSlice helpers to testutil. Fixes Nil helper
to correctly handle nil slices/pointers boxed into interface values
using reflection.

Removes github.com/stretchr/testify and all transitive dependencies
(go-spew, go-difflib, yaml.v3) from go.mod.
Replace all "failed to X" error prefixes with present participle form
("Xing") across 40 source and test files (149 replacements). This
follows Go error string conventions where errors describe what was
happening when the failure occurred, not that it failed.
Move interface definitions to the packages that consume them per Go best
practices. Each cmd/ package now owns its interface (MailClient,
CalendarClient, ContactsClient, DriveClient) and its mock. This removes
the coupling between implementation and consumer packages and eliminates
the centralized testutil/mocks.go file.
All command handlers now extract context from the cobra command and pass
it through to client constructors. This enables proper cancellation via
signal handling. The ClientFactory signature now accepts context.Context.
Main now creates a signal-aware context (SIGINT, SIGTERM) and passes it
through ExecuteContext, enabling graceful cancellation of in-flight API
calls when the user presses Ctrl+C.
Callers now use auth.X() directly instead of gmail.X() wrappers.
Removes GetConfigDir, GetCredentialsPath, GetOAuthConfig,
ExchangeAuthCode, GetAuthURL, and ShortenPath from the gmail package.
Add package-level doc comments to all 15 packages that were missing them.
Fix lint issues: goimports ordering, unused parameters, exhaustive switch,
and unused struct field.
Add parallel markers to 18 test files that don't use shared mutable
state (ClientFactory, os.Stdout, os.Chdir). Subtests using t.Setenv
correctly omit t.Parallel() since the two are incompatible.
Thread context.Context through all API client methods (gmail, calendar,
contacts, drive) so cancellation and deadlines propagate to Google API
calls. Fix error wrapping in NewClient constructors to follow standards.
Update PersistentTokenSource to accept context instead of using
context.Background(). Align Makefile check target to use tidy instead
of fmt, and update CI Go version from 1.21 to 1.24 to match go.mod.
…docs

Add harness engineering infrastructure to mechanically enforce codebase
conventions and improve agent legibility:

- Structural tests (internal/architecture/) enforce client interfaces,
  ClientFactory, NewCommand(), --json flags, dependency direction, and
  read-only scopes across all domain packages
- Centralize captureOutput/withMockClient/withFailingClientFactory into
  testutil.CaptureStdout and testutil.WithFactory[T] generics
- Restructure AGENT.md (338->93 lines) into progressive-disclosure docs/
  with architecture.md, golden-principles.md, and adding-a-domain.md
- Clean up stale lint suppressions in .golangci.yml
- Add coverage gate (60% floor) to Makefile and CI
All list/search commands now output [] instead of plaintext "No X found"
messages when --json is active and there are no results. This fixes JSON
piping (e.g., `gro mail search "..." --json | jq ...`) which previously
failed with a parse error on empty result sets.

Affected commands: mail search, mail thread, mail labels, mail attachments
list, calendar events/today/week, calendar list, contacts list/search/groups,
drive list/search/drives.

Adds 12 unit tests covering the empty-results-with-JSON path for each
affected command.
@rianjs rianjs changed the title refactor: align codebase with STANDARDS.md Refactor: align codebase with engineering standards Feb 16, 2026
@rianjs rianjs merged commit 2c0db8d into main Feb 16, 2026
2 checks passed
@rianjs rianjs deleted the refactor/standards-alignment branch February 16, 2026 11:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor: align codebase with engineering standards

1 participant