Skip to content

Commit fd72b69

Browse files
Replace root help text with styled custom help function
- Swap heredoc-based Long/Example for a custom rootHelpFunc with colored section headers and grouped commands - Add buildExampleText helper with gray comments - Add Bold, BoldCyan, Gray style functions - Customize help/version flag usage strings
1 parent 1c48e9c commit fd72b69

2 files changed

Lines changed: 108 additions & 57 deletions

File tree

command/root.go

Lines changed: 96 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ package command
22

33
import (
44
"context"
5+
"fmt"
6+
"strings"
57

6-
"github.com/MakeNowJust/heredoc"
78
"github.com/deepsourcelabs/cli/buildinfo"
89
"github.com/deepsourcelabs/cli/command/auth"
910
completionCmd "github.com/deepsourcelabs/cli/command/completion"
@@ -14,71 +15,22 @@ import (
1415
"github.com/deepsourcelabs/cli/command/repository"
1516
"github.com/deepsourcelabs/cli/command/runs"
1617
"github.com/deepsourcelabs/cli/command/vulnerabilities"
18+
"github.com/deepsourcelabs/cli/internal/cli/style"
19+
"github.com/pterm/pterm"
1720
"github.com/spf13/cobra"
1821
)
1922

2023
func NewCmdRoot() *cobra.Command {
2124
cmd := &cobra.Command{
22-
Use: buildinfo.AppName + " <command> [flags]",
23-
Short: "DeepSource CLI",
24-
Long: heredoc.Docf(`
25-
DeepSource CLI — query code-quality data from the command line.
26-
27-
Authentication (required before all other commands):
28-
%[1]s auth login
29-
30-
Repository targeting:
31-
--repo <provider/owner/name> provider: gh, gl, bb, or ads
32-
If omitted, auto-detected from the current git remote.
33-
34-
Output format:
35-
--output json machine-readable JSON (supported by issues, metrics, runs,
36-
report-card, vulnerabilities)
37-
38-
Scope (where applicable):
39-
--commit <sha> specific commit
40-
--pr <number> pull request
41-
--default-branch repository default branch
42-
43-
Commands:
44-
issues List code-quality issues (--category, --analyzer, --limit, --pr)
45-
metrics Show code metrics (--metric)
46-
runs List analysis runs (--limit)
47-
report-card View report card (--commit)
48-
vulnerabilities List dependency vulnerabilities (--severity)
49-
report Upload analysis artifacts from CI (--analyzer, --key, --value-file)
50-
auth Login, logout, check status
51-
repo Repository info (status, dashboard)
52-
53-
Setup:
54-
completion Install shell completions for bash, zsh, or fish
55-
`, buildinfo.AppName),
56-
Example: heredoc.Docf(`
57-
# Check for security issues on the current branch
58-
%[1]s issues --output json --category security
59-
60-
# Get all issues for pull request #42
61-
%[1]s issues --repo gh/owner/name --pr 42 --output json
62-
63-
# View code metrics on the current branch
64-
%[1]s metrics --output json
65-
66-
# Check critical and high dependency vulnerabilities on the current branch
67-
%[1]s vulnerabilities --severity critical,high --output json
68-
69-
# View report card for a specific commit
70-
%[1]s report-card --commit abc123f --output json
71-
72-
# Report test coverage from CI
73-
%[1]s report --analyzer test-coverage --key go --value-file coverage.out
74-
75-
# List the 5 most recent analysis runs
76-
%[1]s runs --output json --limit 5
77-
`, buildinfo.AppName),
25+
Use: buildinfo.AppName + " <command> [flags]",
26+
Short: "DeepSource CLI",
27+
Long: style.BoldCyan("DeepSource CLI — Ship good code from the command line.") + "\n\nTo get started, run → " + buildinfo.AppName + " auth login",
7828
SilenceErrors: true,
7929
SilenceUsage: true,
8030
}
8131

32+
cmd.SetHelpFunc(rootHelpFunc)
33+
8234
// Set version using --version flag
8335
info := buildinfo.GetBuildInfo()
8436
if info != nil {
@@ -137,9 +89,96 @@ func NewCmdRoot() *cobra.Command {
13789
completionC.GroupID = "setup"
13890
cmd.AddCommand(completionC)
13991

92+
cmd.InitDefaultHelpFlag()
93+
cmd.Flags().Lookup("help").Usage = "Show usage and available commands"
94+
cmd.Flags().Lookup("version").Usage = "Print version and build info"
95+
14096
return cmd
14197
}
14298

99+
func buildExampleText() string {
100+
app := buildinfo.AppName
101+
examples := []struct {
102+
comment string
103+
cmd string
104+
}{
105+
{"Check for security issues on the current branch", app + " issues --output json --category security"},
106+
{"Get all issues for pull request #42", app + " issues --repo gh/owner/name --pr 42 --output json"},
107+
{"View code metrics on the current branch", app + " metrics --output json"},
108+
{"Check critical and high dependency vulnerabilities on the current branch", app + " vulnerabilities --severity critical,high --output json"},
109+
{"View report card for a specific commit", app + " report-card --commit abc123f --output json"},
110+
{"Report test coverage from CI", app + " report --analyzer test-coverage --key go --value-file coverage.out"},
111+
{"List the 5 most recent analysis runs", app + " runs --output json --limit 5"},
112+
}
113+
var lines []string
114+
for _, ex := range examples {
115+
lines = append(lines, style.Gray("# %s", ex.comment))
116+
lines = append(lines, ex.cmd)
117+
lines = append(lines, "")
118+
}
119+
// Remove trailing blank line
120+
if len(lines) > 0 {
121+
lines = lines[:len(lines)-1]
122+
}
123+
return strings.Join(lines, "\n")
124+
}
125+
126+
func rootHelpFunc(cmd *cobra.Command, _ []string) {
127+
out := cmd.OutOrStdout()
128+
129+
// Long description (already colored)
130+
fmt.Fprintln(out, cmd.Long)
131+
fmt.Fprintln(out)
132+
133+
// Usage
134+
fmt.Fprintf(out, "%s\n", style.BoldCyan("Usage:"))
135+
fmt.Fprintf(out, " %s\n\n", cmd.UseLine())
136+
137+
// Command groups
138+
groups := cmd.Groups()
139+
if len(groups) > 0 {
140+
for _, group := range groups {
141+
if group.ID == "auth" {
142+
continue
143+
}
144+
fmt.Fprintf(out, "%s\n", style.BoldCyan("%s", group.Title))
145+
for _, sub := range cmd.Commands() {
146+
if sub.GroupID == group.ID && sub.IsAvailableCommand() {
147+
name := sub.Name()
148+
padding := 17 - len(sub.Name())
149+
if padding < 2 {
150+
padding = 2
151+
}
152+
fmt.Fprintf(out, " %s%s%s\n", name, strings.Repeat(" ", padding), sub.Short)
153+
}
154+
}
155+
fmt.Fprintln(out)
156+
}
157+
}
158+
159+
// Examples
160+
examples := buildExampleText()
161+
if examples != "" {
162+
fmt.Fprintf(out, "%s\n", style.BoldCyan("Examples:"))
163+
for _, line := range strings.Split(examples, "\n") {
164+
fmt.Fprintf(out, " %s\n", line)
165+
}
166+
fmt.Fprintln(out)
167+
}
168+
169+
// Flags
170+
flagUsages := cmd.LocalFlags().FlagUsages()
171+
if flagUsages != "" {
172+
fmt.Fprintf(out, "%s\n", style.BoldCyan("Flags:"))
173+
fmt.Fprint(out, flagUsages)
174+
fmt.Fprintln(out)
175+
}
176+
177+
// Footer
178+
fmt.Fprintln(out, pterm.Gray("Run "+cmd.CommandPath()+" <command> --help to learn more about a command."))
179+
fmt.Fprintln(out, pterm.Gray("Full docs at docs.deepsource.com/docs/developers/cli/usage"))
180+
}
181+
143182
func Execute() error {
144183
return ExecuteContext(context.Background())
145184
}

internal/cli/style/style.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,18 @@ func Cyan(format string, a ...interface{}) string {
117117
return pterm.Cyan(fmt.Sprintf(format, a...))
118118
}
119119

120+
func Bold(format string, a ...interface{}) string {
121+
return pterm.Bold.Sprintf(format, a...)
122+
}
123+
124+
func BoldCyan(format string, a ...interface{}) string {
125+
return pterm.NewStyle(pterm.Bold, pterm.FgCyan).Sprintf(format, a...)
126+
}
127+
128+
func Gray(format string, a ...interface{}) string {
129+
return pterm.Gray(fmt.Sprintf(format, a...))
130+
}
131+
120132
// Pluralize returns singular when count is 1, plural otherwise.
121133
func Pluralize(count int, singular, plural string) string {
122134
if count == 1 {

0 commit comments

Comments
 (0)