Skip to content

Cleanup and error flow refactor (PR 1 of 2)#26

Merged
AbsolutOD merged 7 commits into
mainfrom
feature/cleanup-error-flow
May 6, 2026
Merged

Cleanup and error flow refactor (PR 1 of 2)#26
AbsolutOD merged 7 commits into
mainfrom
feature/cleanup-error-flow

Conversation

@AbsolutOD

Copy link
Copy Markdown
Owner

Summary

Implements PR 1 of the cleanup-and-tests design (docs/superpowers/specs/2026-05-05-cleanup-and-tests-design.md). Removes dead code and migrates the codebase from ad-hoc os.Exit / panic error handling to idiomatic cobra error flow. PR 2 (pure-logic tests) follows after this merges.

Commits (in order)

  1. chore: remove dead code (AwsParam, setPrefixes) — drops unreferenced struct, method, and supporting ParamType constants.
  2. refactor: client.New returns error instead of panic — unsupported backend now returns fmt.Errorf("unsupported backend %q", c.Backend).
  3. refactor: ssm methods return errors; remove handleAwsErrInit / Save / GetOne / GetMany / Copy / Delete all return (value, error). Adds mapErr helper that falls back to the raw error when the AWS-error mapper returns nil (was previously a silent-swallow bug). client.Client interface updated to match.
  4. refactor: cmd subcommands use RunE with SilenceUsage — every subcommand flips RunRunE, sets cmd.SilenceUsage = true as the first line, and propagates errors via return err. The args-empty checks in cmd/copy.go become errors.New(...) per the bug-audit note.
  5. refactor: env-var validation moves to PersistentPreRunEAWS_DEFAULT_REGION / AWS_PROFILE checks, client.New construction, viper.ReadInConfig, and MarkFlagRequired("env") move into rootCmd.PersistentPreRunE. slog config stays in cobra.OnInitialize. Execute() exits 1 on any error.
  6. refactor: use ssm paginator for GetParametersByPath — replaces the recursive getNextParams with awsssm.NewGetParametersByPathPaginator and the standard for paginator.HasMorePages() loop.
  7. chore: update CLAUDE.md error-flow notes — reflects the PersistentPreRunE flow, the (value, error) interface, and the exit-code collapse.

External behavior changes (per spec)

  • Exit code on missing AWS_DEFAULT_REGION / AWS_PROFILE collapses from 1 / 2 to a uniform 1. MarkFlagRequired failure also collapses from 3 to 1. (These codes were undocumented and look incidental.)
  • Cobra now prefixes errors with Error: on stderr, replacing the bare fmt.Println style. Usage is suppressed for runtime errors via SilenceUsage.
  • esp --help continues to work without AWS env vars (cobra short-circuits before PersistentPreRunE, same as it did before OnInitialize).

Test Plan

  • go build ./... clean
  • go vet ./... clean
  • go test ./... — all packages report ok or [no test files]
  • esp --help prints usage with no AWS env vars set, exit 0
  • esp version with no AWS_DEFAULT_REGIONError: AWS_DEFAULT_REGION environment variable is not set, exit 1
  • esp version with AWS_DEFAULT_REGION set but no AWS_PROFILEError: AWS_PROFILE environment variable is not set, exit 1
  • Smoke test against a real AWS account (reviewer)

AbsolutOD added 7 commits May 5, 2026 22:34
- Drop the unused AwsParam struct, its isValid() method, and the
  ParamType/String/SecureString/StringList constants that only
  existed to support isValid(). Nothing else referenced them.
- Drop the empty setPrefixes() method on app.Config.

No behavior change.
client.New(*app.Config) now returns (*EspClient, error). An
unsupported backend produces fmt.Errorf("unsupported backend %q",
c.Backend) instead of panicking. The lone caller in cmd/root.go
prints the error and exits 1.

The os.Exit at the call site is interim — commit 5 moves env-var
validation and client construction into PersistentPreRunE so the
error flows back through cobra.
Stop the side-effecting "fmt.Printf + os.Exit" pattern inside the
SSM client and surface failures as returned errors:

- Service.Init returns error from config.LoadDefaultConfig instead
  of os.Exit(1).
- Service.Save / GetOne / GetMany / Copy / Delete return
  (..., error). New mapErr helper applies the per-action mapper
  and falls back to the raw error when the mapper returns nil
  (which previously caused unrecognized errors to be silently
  swallowed).
- getNextParams propagates errors through recursion. (Replaced
  by the v2 paginator in a follow-up commit.)
- handleAwsErr is deleted; internal/ssm/utils.go drops its
  fmt and os imports.

The Client interface in internal/client/client.go is updated to
match the new signatures; EspClient wrapper methods (GetParam,
ListParams, Save, Delete, Copy, Move) propagate errors. New now
also returns the Init error.

cmd subcommands still use Run: in this commit and handle the new
errors with fmt.Fprintln(os.Stderr, err) + os.Exit(1) — this
scaffolding is replaced by RunE / return err in the next commit.
Flip every subcommand (copy, delete, get, list, move, put, init,
version) from Run to RunE returning error. First line of every
RunE body is cmd.SilenceUsage = true so cobra prints usage on
flag/arg misuse (which fires before RunE) but not on runtime
errors from the body.

Sweeps away the temporary fmt.Fprintln(stderr, err) + os.Exit(1)
scaffolding from the previous commit — those become return err.
The args-empty checks in cmd/copy.go that previously printed and
called os.Exit become return errors.New(...) per the spec's bug
audit.

External behavior on the happy path is unchanged. On errors,
cobra now prefixes the message with "Error:" before printing —
small UX shift accepted in the design.
The legacy initConfig hook ran via cobra.OnInitialize and called
os.Exit on env-var failures (exit 1 for missing AWS_DEFAULT_REGION,
2 for missing AWS_PROFILE, 3 for MarkFlagRequired failure).

Split that into:

- configureLogging (cobra.OnInitialize): just slog setup. No I/O,
  no failure path.
- persistentPreRun (rootCmd.PersistentPreRunE): env-var checks,
  client.New, viper config read, MarkFlagRequired("env"). All
  failures return error so cobra surfaces them as
  "Error: <message>" on stderr; Execute() exits 1.

PersistentPreRunE is wired in init() rather than the rootCmd
literal to avoid an initialization cycle (rootCmd ↔ persistentPreRun).

Cobra short-circuits before PersistentPreRunE for --help, so help
output still renders without AWS credentials. Exit code on env-var
failure collapses from {1,2,3} to a uniform 1, matching the spec.
Replace the manual NextToken recursion in GetMany / getNextParams
with awsssm.NewGetParametersByPathPaginator and a standard
for paginator.HasMorePages() { paginator.NextPage(...) } loop.
Cuts the iteration logic in half and uses the v2-idiomatic shape.

External behavior unchanged on the happy path; error handling
still flows through mapErr(GetMany, err).
Reflect the PR 1 refactor in the architecture overview:

- AWS_DEFAULT_REGION / AWS_PROFILE checks now live in
  PersistentPreRunE; failures return error → cobra prints
  "Error: <msg>" → Execute() exits 1. Note the exit-code
  collapse from {1,2} to a uniform 1.
- client.New now returns (*EspClient, error) on unsupported
  backend instead of panicking; Client interface methods
  return (value, error).
@AbsolutOD AbsolutOD merged commit e2a35dc into main May 6, 2026
@AbsolutOD AbsolutOD mentioned this pull request May 6, 2026
4 tasks
@AbsolutOD AbsolutOD deleted the feature/cleanup-error-flow branch May 7, 2026 01:53
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.

1 participant