# Add branchless trail creation

`5921e40`→[main](/content/gh/entireio/cli/commits/main/index.html)·

dipree·3w ago·3 files·+231 added/-113 removed

## Sessions

6604ab821878View transcript

## Changes

3

- cmd/entire/cli

- api

- Mtrail_types.go+3/-2

- Mtrail_cmd.go+203/-111

- Mtrail_cmd_test.go+25

```
77 unmodified lines

78
79
80
81
81
82
83
83
84
85
86
87

77 unmodified lines

```

```go
type TrailCreateRequest struct {
	Title      string `json:"title"`
	Body       string `json:"body,omitempty"`
	BranchName string `json:"branch_name"`
	BranchAction string   `json:"branch_action,omitempty"`
	Base         string   `json:"base,omitempty"`
	Status       string   `json:"status,omitempty"`
}
```

```go
func newTrailCreateCmd() *cobra.Command {
	var title, body, base, branch, status string
	var checkout bool
	var checkout, noBranch bool

cmd := &cobra.Command{
		Use:   "create",
		Short: "Create a trail for the current or a new branch",
		Args:  cobra.NoArgs,
		RunE: func(cmd *cobra.Command, _ []string) error {
			return runTrailCreate(cmd, title, body, base, branch, status, checkout)
		},
	}
	
	cmd.Flags().StringVar(&branch, "branch", "", "Branch for the trail (defaults to current branch)")
	cmd.Flags().StringVar(&status, "status", "", "Initial status (defaults to open)")
	cmd.Flags().BoolVar(&checkout, "checkout", false, "Check out the branch after creating it")
	cmd.Flags().BoolVar(&noBranch, "no-branch", false, "Create a branchless trail")

return cmd
}
```

```go
func runTrailCreate(cmd *cobra.Command, title, body, base, branch, statusStr string, checkout bool) error {
	ctx := cmd.Context()
	w := cmd.OutOrStdout()
	errW := cmd.ErrOrStderr()

if err := validateTrailCreateFlagCombos(cmd, checkout, noBranch); err != nil {
		return err
	}

repo, err := strategy.OpenRepository(ctx)
	if err != nil {
		return fmt.Errorf("failed to open repository: %w", err)
	}
	defer repo.Close()

// Determine base branch.
	if base == "" {
		base = strategy.GetDefaultBranchName(repo)
		if base == "" {
			base = defaultBaseBranch
		}
	}

base = resolveTrailCreateBase(repo, base)
	_, currentBranch, _ := isOnDefaultBranchRepo(repo)
	title, body, base, branch, statusStr, err = resolveTrailCreateFields(cmd, w, title, body, base, branch, statusStr, currentBranch, noBranch)
	if err != nil {
		return err
	}
	if err := validateTrailCreateFields(ctx, title, branch, statusStr, noBranch); err != nil {
		return err
	}

client, err := NewAuthenticatedAPIClient(ctx, trailInsecureHTTP(cmd))
	if err != nil {
		return renderDataAPIAuthError(cmd.ErrOrStderr(), err)
	}
	forge, owner, repoName, err := resolveTrailRemote(ctx)
	if err != nil {
		return err
	}

branchState, err := prepareTrailCreateBranch(w, errW, repo, branch, currentBranch, noBranch)
	if err != nil {
		return err
	}

createResp, err := postTrailCreate(ctx, client, forge, owner, repoName, title, body, branch, base, statusStr)
	if err != nil {
		cleanupCreatedTrailBranch(repo, branch, branchState.LocalCreated, branchState.RemotePushed, errW)
		return err
	}
	printTrailCreateResult(w, createResp.Trail)

return maybeCheckoutTrailCreateBranch(ctx, cmd, w, branch, currentBranch, checkout, branchState.NeedsCreation)
}
```

### Tests

```go
func TestNewTrailCreateRequestCanBeBranchless(t *testing.T) {
	req := newTrailCreateRequest("title", "body", "", "main", "open")

require.Equal(t, api.TrailCreateRequest{
		Title:  "title",
		Body:   "body",
		Base:   "main",
		Status: "open",
	}, req)

encoded, err := json.Marshal(req)
	require.NoError(t, err)
	require.NotContains(t, string(encoded), "branch_name")
	require.NotContains(t, string(encoded), "branch_action")
}

func TestPrepareTrailCreateBranchSkipsBranchlessTrail(t *testing.T) {
	state, err := prepareTrailCreateBranch(io.Discard, io.Discard, nil, "", "main", true)

require.NoError(t, err)
	require.False(t, state.NeedsCreation)
	require.False(t, state.LocalCreated)
	require.False(t, state.RemotePushed)
}

func TestCleanupCreatedTrailBranch(t *testing.T) {
	// Example test function here, implementation can be added later.
}
```
