Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# CLAUDE.md

## Layering

`cmd/` is Cobra wiring only — command definitions, flag reading, client init. **There are no test files in `cmd/`; don't add any.** Logic worth testing goes in `internal/commands/<domain>` as a `RunX(...)` function, with dependencies injected so tests can fake them: a narrow `API` interface plus `NewAPI(client)`, `io.Reader` for confirmation prompts, `io.Writer` for output. Wanting to unit-test a `cmd/` helper means the logic is in the wrong package.

## The SDK owns auth and config

`massdriver/config` in the SDK is the sole authority on the config file — its schema, location, version, and which profile is active. Never resolve credentials or profiles in the CLI, and never add config keys the SDK doesn't read. If the CLI needs behavior the SDK lacks, change the SDK. The CLI only writes the file (`internal/configfile`) and passes `--profile` through as `massdriver.WithProfile`.

## Before finishing

- `make check` — tests and lint.
- `make docs` whenever a command, flag, or helpdoc changes. CI regenerates and fails on any diff.

## Comments

Default to none. Write one only when a reader who already understands the code still can't see *why*. Never narrate what the code says, and never narrate what changed or used to be there — git holds the history. No doc comments on unexported helpers.

## Tests

Table-driven, stdlib `testing`, hand-rolled fakes. One `_test.go` per source file — append cases rather than adding a file per scenario. For unexported access, switch the file to `package foo //nolint:testpackage // reason` instead of splitting the tests in two.
24 changes: 12 additions & 12 deletions cmd/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func NewCmdBundle() *cobra.Command { //nolint:funlen // cobra command builders a
Long: helpdocs.MustRender("bundle/list"),
RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
return runBundleList(&bundleListInput)
return runBundleList(cmd, &bundleListInput)
},
}
bundleListCmd.Flags().StringVarP(&bundleListInput.search, "search", "s", "", "Search bundles by name, readme, and changelog")
Expand Down Expand Up @@ -111,7 +111,7 @@ func NewCmdBundle() *cobra.Command { //nolint:funlen // cobra command builders a
Long: helpdocs.MustRender("bundle/new"),
RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
return runBundleNew(&bundleNewInput)
return runBundleNew(cmd, &bundleNewInput)
},
}
bundleNewCmd.Flags().StringVarP(&bundleNewInput.name, "name", "n", "", "Name of the new bundle. Setting this along with --template-name will disable the interactive prompt.")
Expand Down Expand Up @@ -200,7 +200,7 @@ func runBundleCreate(cmd *cobra.Command, args []string) error {

cmd.SilenceUsage = true

mdClient, err := massdriver.NewClient()
mdClient, err := newMassdriverClient(cmd)
if err != nil {
return fmt.Errorf("error initializing massdriver client: %w", err)
}
Expand Down Expand Up @@ -280,14 +280,14 @@ func runBundleNewFlags(input *bundleNew) (*templates.TemplateData, error) {
return templateData, nil
}

func runBundleNew(input *bundleNew) error {
func runBundleNew(cmd *cobra.Command, input *bundleNew) error {
ctx := context.Background()

var templateData *templates.TemplateData
var runErr error
if input.name == "" || input.templateName == "" {
// run the interactive prompt
mdClient, err := massdriver.NewClient()
mdClient, err := newMassdriverClient(cmd)
if err != nil {
return fmt.Errorf("error initializing massdriver client: %w", err)
}
Expand Down Expand Up @@ -357,7 +357,7 @@ func runBundleBuild(cmd *cobra.Command, args []string) error {
return err
}

mdClient, err := massdriver.NewClient()
mdClient, err := newMassdriverClient(cmd)
if err != nil {
return fmt.Errorf("error initializing massdriver client: %w", err)
}
Expand Down Expand Up @@ -391,7 +391,7 @@ func runBundleLint(cmd *cobra.Command, args []string) error {
return err
}

mdClient, err := massdriver.NewClient()
mdClient, err := newMassdriverClient(cmd)
if err != nil {
return fmt.Errorf("error initializing massdriver client: %w", err)
}
Expand Down Expand Up @@ -451,7 +451,7 @@ func runBundlePublish(cmd *cobra.Command, args []string) error {
return err
}

mdClient, err := massdriver.NewClient()
mdClient, err := newMassdriverClient(cmd)
if err != nil {
return fmt.Errorf("error initializing massdriver client: %w", err)
}
Expand Down Expand Up @@ -517,7 +517,7 @@ func runBundlePull(cmd *cobra.Command, args []string) error {
}
}

mdClient, err := massdriver.NewClient()
mdClient, err := newMassdriverClient(cmd)
if err != nil {
return fmt.Errorf("error initializing massdriver client: %w", err)
}
Expand All @@ -530,10 +530,10 @@ func runBundlePull(cmd *cobra.Command, args []string) error {
return nil
}

func runBundleList(input *bundleList) error {
func runBundleList(cmd *cobra.Command, input *bundleList) error {
ctx := context.Background()

mdClient, err := massdriver.NewClient()
mdClient, err := newMassdriverClient(cmd)
if err != nil {
return fmt.Errorf("error initializing massdriver client: %w", err)
}
Expand Down Expand Up @@ -595,7 +595,7 @@ func runBundleGet(cmd *cobra.Command, args []string) error {
}
cmd.SilenceUsage = true

mdClient, err := massdriver.NewClient()
mdClient, err := newMassdriverClient(cmd)
if err != nil {
return fmt.Errorf("error initializing massdriver client: %w", err)
}
Expand Down
16 changes: 16 additions & 0 deletions cmd/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cmd

import (
"github.com/massdriver-cloud/massdriver-sdk-go/massdriver"
"github.com/spf13/cobra"
)

// newMassdriverClient builds a client for the profile --profile names. An empty
// flag is not an override, leaving the SDK's own precedence untouched.
func newMassdriverClient(cmd *cobra.Command) (*massdriver.Client, error) {
profile, err := cmd.Flags().GetString("profile")
if err != nil {
return nil, err
}
return massdriver.NewClient(massdriver.WithProfile(profile))
}
11 changes: 5 additions & 6 deletions cmd/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/massdriver-cloud/mass/docs/helpdocs"
"github.com/massdriver-cloud/mass/internal/cli"
"github.com/massdriver-cloud/mass/internal/commands/component"
"github.com/massdriver-cloud/massdriver-sdk-go/massdriver"
"github.com/massdriver-cloud/massdriver-sdk-go/massdriver/platform/components"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -115,7 +114,7 @@ func runComponentAdd(cmd *cobra.Command, args []string) error {

cmd.SilenceUsage = true

mdClient, err := massdriver.NewClient()
mdClient, err := newMassdriverClient(cmd)
if err != nil {
return fmt.Errorf("error initializing massdriver client: %w", err)
}
Expand Down Expand Up @@ -155,7 +154,7 @@ func runComponentUpdate(cmd *cobra.Command, args []string) error {

cmd.SilenceUsage = true

mdClient, err := massdriver.NewClient()
mdClient, err := newMassdriverClient(cmd)
if err != nil {
return fmt.Errorf("error initializing massdriver client: %w", err)
}
Expand Down Expand Up @@ -192,7 +191,7 @@ func runComponentRemove(cmd *cobra.Command, args []string) error {
componentID := args[0]
cmd.SilenceUsage = true

mdClient, err := massdriver.NewClient()
mdClient, err := newMassdriverClient(cmd)
if err != nil {
return fmt.Errorf("error initializing massdriver client: %w", err)
}
Expand Down Expand Up @@ -229,7 +228,7 @@ func runComponentLink(cmd *cobra.Command, args []string) error {

cmd.SilenceUsage = true

mdClient, err := massdriver.NewClient()
mdClient, err := newMassdriverClient(cmd)
if err != nil {
return fmt.Errorf("error initializing massdriver client: %w", err)
}
Expand Down Expand Up @@ -270,7 +269,7 @@ func runComponentUnlink(cmd *cobra.Command, args []string) error {

cmd.SilenceUsage = true

mdClient, err := massdriver.NewClient()
mdClient, err := newMassdriverClient(cmd)
if err != nil {
return fmt.Errorf("error initializing massdriver client: %w", err)
}
Expand Down
Loading
Loading