Skip to content

refactor: Restructure repository to follow cli-guide.md patterns #1

@rianjs

Description

@rianjs

Description

Restructure the repository from flat cmd/ layout to the recommended internal/cmd/<resource>/ pattern, create supporting packages, and establish the foundation for testable, maintainable code.

Current State

cmd/
├── root.go, apps.go, alerts.go, config.go, dashboards.go,
├── deployments.go, entities.go, logs.go, nerdgraph.go,
├── nrql.go, synthetics.go, users.go
internal/
├── client/client.go (1005 lines)
└── keychain/keychain.go
main.go

Target State

cmd/newrelic-cli/
└── main.go                         # Minimal entry point
api/                                 # Public, importable API client
├── client.go, types.go, errors.go
├── applications.go, alerts.go, dashboards.go, ...
└── testdata/*.json                 # Test fixtures
internal/
├── cmd/                            # Cobra commands
│   ├── root/root.go
│   ├── apps/{apps,list,get,metrics}.go
│   ├── alerts/policies/{policies,list,get}.go
│   ├── config/{config,set_api_key,set_account_id,...}.go
│   ├── dashboards/{dashboards,list,get}.go
│   ├── deployments/{deployments,list,create}.go
│   ├── entities/{entities,search}.go
│   ├── logs/rules/{rules,list,create,delete}.go
│   ├── nerdgraph/{nerdgraph,query}.go
│   ├── nrql/{nrql,query}.go
│   ├── synthetics/{synthetics,list,get}.go
│   └── users/{users,list,get}.go
├── config/                         # Renamed from keychain
│   └── config.go
├── version/
│   └── version.go                  # Build-time version injection
└── view/
    └── view.go                     # Output formatting (table/json/plain)

Tasks

1.1 Create entry point structure

  • Create cmd/newrelic-cli/main.go with minimal entry point
  • Move to importing root command from internal/cmd/root
  • Delete old main.go

1.2 Create version package

  • Create internal/version/version.go with Version, Commit, Date variables
  • Update root command to use version.Version
  • Update Makefile ldflags to inject all three values
  • Add version template: newrelic-cli version {{.Version}} (commit: {{.Commit}}, built: {{.Date}})

1.3 Create view package for output formatting

  • Create internal/view/view.go with Renderer struct
  • Implement FormatTable, FormatJSON, FormatPlain constants
  • Implement NewRenderer(format, noColor), RenderTable(), RenderJSON(), RenderPlain()
  • Add ValidateFormat() function
  • Add color support via github.com/fatih/color
  • Replace global --json flag with --output / -o (table|json|plain)
  • Add --no-color global flag

1.4 Refactor API client to api/ package

  • Create api/ directory at project root
  • Extract Client struct and core methods to api/client.go
  • Extract all types to api/types.go
  • Create api/errors.go for ErrorResponse
  • Split methods by resource: applications.go, alerts.go, dashboards.go, etc.
  • Create api/testdata/ with JSON fixtures
  • Add NewClientWithURL() constructor for testing

1.5 Restructure commands to internal/cmd/

  • Create internal/cmd/root/root.go with global flags
  • Create package per resource under internal/cmd/
  • Split each command file into separate files per subcommand
  • Implement Options struct pattern for all commands
  • Extract RunE logic into separate run* functions with injectable client
  • Make stdin injectable via Options for confirmation testing

1.6 Rename keychain to config

  • Rename internal/keychain/ to internal/config/
  • Update package name and all imports

Unit Tests Required

  • internal/view/view_test.go:
    • TestRenderer_RenderTable
    • TestRenderer_RenderJSON
    • TestRenderer_RenderPlain
    • TestValidateFormat

Integration Tests

Command Expected
newrelic-cli --version Shows version, commit, date
newrelic-cli --help Shows all commands
newrelic-cli apps list Table output (default)
newrelic-cli apps list -o json Valid JSON array
newrelic-cli apps list -o plain Tab-separated, no headers

Acceptance Criteria

  • All tasks complete
  • make build succeeds
  • make test passes
  • All existing commands work identically
  • New output formats work correctly

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions