Skip to content

Commit

Permalink
Hack week help menu (#782)
Browse files Browse the repository at this point in the history
* Overwrote default cobra command help menu
* Added testing env var
  • Loading branch information
corinnesollows authored Sep 21, 2022
1 parent 0f1ff57 commit 3b49940
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 25 deletions.
5 changes: 4 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ jobs:
- run: setx GOPATH %USERPROFILE%\go
- run: go get gotest.tools/gotestsum
- run: mkdir test_results
- run: setx TESTING "true"

- run:
name: Run tests
command: |
Expand Down Expand Up @@ -133,7 +135,8 @@ jobs:
- run:
command: bundle exec cucumber
working_directory: integration_tests

environment:
TESTING: "true"
test:
executor: go
steps:
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ clean:

.PHONY: test
test:
go test -v ./...
TESTING=true go test -v ./...

.PHONY: cover
cover:
go test -race -coverprofile=coverage.txt ./...
TESTING=true go test -race -coverprofile=coverage.txt ./...

.PHONY: lint
lint:
Expand Down
9 changes: 6 additions & 3 deletions cmd/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,12 @@ func newContextCommand(config *settings.Config) *cobra.Command {
}

command := &cobra.Command{
Use: "context",
Short: "Contexts provide a mechanism for securing and sharing environment variables across projects. The environment variables are defined as name/value pairs and are injected at runtime.",
}
Use: "context",
Long: `
Contexts provide a mechanism for securing and sharing environment variables across
projects. The environment variables are defined as name/value pairs and
are injected at runtime.`,
Short: "For securing and sharing environment variables across projects"}

listCommand := &cobra.Command{
Short: "List all contexts",
Expand Down
5 changes: 3 additions & 2 deletions cmd/policy/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ func NewCommand(config *settings.Config, preRunE validator.Validator) *cobra.Com
cmd := &cobra.Command{
Use: "policy",
PersistentPreRunE: preRunE,
Short: "Policies ensures security of build configs via security policy management framework. " +
"This group of commands allows the management of polices to be verified against build configs.",
Short: "Manage security policies",
Long: `Policies ensures security of build configs via security policy management framework.
This group of commands allows the management of polices to be verified against build configs.`,
}

policyBaseURL := cmd.PersistentFlags().String("policy-base-url", "https://internal.circleci.com", "base url for policy api")
Expand Down
133 changes: 123 additions & 10 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ package cmd

import (
"fmt"
"log"
"os"
"strings"

"github.com/spf13/cobra"

"github.com/CircleCI-Public/circleci-cli/api/header"
"github.com/CircleCI-Public/circleci-cli/cmd/info"
"github.com/CircleCI-Public/circleci-cli/cmd/policy"
Expand All @@ -15,11 +14,14 @@ import (
"github.com/CircleCI-Public/circleci-cli/md_docs"
"github.com/CircleCI-Public/circleci-cli/settings"
"github.com/CircleCI-Public/circleci-cli/version"
"github.com/charmbracelet/lipgloss"
"github.com/spf13/cobra"
)

var defaultEndpoint = "graphql-unstable"
var defaultHost = "https://circleci.com"
var defaultRestEndpoint = "api/v2"
var trueString = "true"

// rootCmd is used internally and global to the package but not exported
// therefore we can use it in other commands, like `usage`
Expand Down Expand Up @@ -88,6 +90,7 @@ Global Flags:
Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
`

// MakeCommands creates the top level commands
Expand All @@ -108,8 +111,9 @@ func MakeCommands() *cobra.Command {
rootOptions.Data = &data.Data

rootCmd = &cobra.Command{
Use: "circleci",
Long: rootHelpLong(rootOptions),
Use: "circleci",
Long: rootHelpLong(),
Short: rootHelpShort(rootOptions),
PersistentPreRunE: func(_ *cobra.Command, _ []string) error {
return rootCmdPreRun(rootOptions)
},
Expand All @@ -119,6 +123,11 @@ func MakeCommands() *cobra.Command {
cobra.AddTemplateFunc("HasAnnotations", hasAnnotations)
cobra.AddTemplateFunc("PositionalArgs", md_docs.PositionalArgs)
cobra.AddTemplateFunc("FormatPositionalArg", md_docs.FormatPositionalArg)

if os.Getenv("TESTING") != trueString {
helpCmd := helpCmd{cmd: rootCmd}
rootCmd.SetHelpFunc(helpCmd.helpTemplate)
}
rootCmd.SetUsageTemplate(usageTemplate)
rootCmd.DisableAutoGenTag = true

Expand Down Expand Up @@ -279,21 +288,125 @@ func isUpdateIncluded(packageManager string) bool {
}
}

func rootHelpLong(config *settings.Config) string {
long := `Use CircleCI from the command line.
func skipUpdateByDefault() bool {
return os.Getenv("CI") == trueString || os.Getenv("CIRCLECI_CLI_SKIP_UPDATE_CHECK") == trueString
}

/**************** Help Menu Functions ****************/

//rootHelpLong creates content for the long field in the command
func rootHelpLong() string {
long := `
/?? /?? /??
|__/ | ?? |__/
/???????? /??????? /?? /?????? /???????| ?? /?????? /??????? /??
/_______/?? /??_____/| ?? /??__ ?? /??_____/| ?? /??__ ?? /??_____/| ??
/?? | ?? | ?? | ??| ?? \__/| ?? | ??| ???????? | ?? | ??
|__/ | ?? | ?? | ??| ?? | ?? | ??| ??_____/ | ?? | ??
/???????? | ???????| ??| ?? | ???????| ??| ??????? | ???????| ??
/________/ \_______/|__/|__/ \_______/|__/ \_______/ \_______/|__/`
return long
}

// rootHelpShort creates content for the short feild in the command
func rootHelpShort(config *settings.Config) string {
short := `Use CircleCI from the command line.
This project is the seed for CircleCI's new command-line application.`

// We should only print this for cloud users
if config.Host != defaultHost {
return long
return short
}

return fmt.Sprintf(`%s
For more help, see the documentation here: %s`, short, config.Data.Links.CLIDocs)
}

For more help, see the documentation here: %s`, long, config.Data.Links.CLIDocs)
type helpCmd struct {
cmd *cobra.Command
}

func skipUpdateByDefault() bool {
return os.Getenv("CI") == "true" || os.Getenv("CIRCLECI_CLI_SKIP_UPDATE_CHECK") == "true"
// helpTemplate Building a custom help template with more finess and pizazz
func (helpCmd *helpCmd) helpTemplate(cmd *cobra.Command, s []string) {

/***Styles ***/
titleStyle := lipgloss.NewStyle().Bold(true).
Foreground(lipgloss.AdaptiveColor{Light: `#003740`, Dark: `#3B6385`}).
BorderBottom(true).
Margin(1, 0, 1, 0).
Padding(0, 1, 0, 1).Align(lipgloss.Center)
subCmdStyle := lipgloss.NewStyle().
Foreground(lipgloss.AdaptiveColor{Light: `#161616`, Dark: `#FFFFFF`}).
Padding(0, 4, 0, 4).Align(lipgloss.Left)
subCmdInfoStyle := lipgloss.NewStyle().
Foreground(lipgloss.AdaptiveColor{Light: `#161616`, Dark: `#FFFFFF`}).Bold(true)
textStyle := lipgloss.NewStyle().
Foreground(lipgloss.AdaptiveColor{Light: `#161616`, Dark: `#FFFFFF`}).Align(lipgloss.Left).Margin(0).Padding(0)

/** Building Usage String **/
usageText := strings.Builder{}

//get command path
usageText.WriteString(titleStyle.Render(cmd.CommandPath()))

//get command short or long
cmdDesc := titleStyle.Render(cmd.Long)
if strings.TrimSpace(cmdDesc) == "" || cmd.Name() == "circleci" {
if cmd.Name() == "circleci" {
cmdDesc += "\n\n" //add some spaces for circleci command
}
cmdDesc += subCmdStyle.Render(cmd.Short)
}
usageText.WriteString(cmdDesc + "\n")

if len(cmd.Aliases) > 0 {
aliases := titleStyle.Render("Aliases:")
aliases += textStyle.Render(cmd.NameAndAliases())
usageText.WriteString(aliases + "\n")
}

if cmd.Runnable() {
usage := titleStyle.Render("Usage:")
usage += textStyle.Render(cmd.UseLine())
usageText.WriteString(usage + "\n")
}

if cmd.HasExample() {
examples := titleStyle.Render("Example:")
examples += textStyle.Render(cmd.Example)
usageText.WriteString(examples + "\n")
}

if cmd.HasAvailableSubCommands() {
subCmds := cmd.Commands()
subTitle := titleStyle.Render("Available Commands:")
subs := ""
for i := range subCmds {
if subCmds[i].IsAvailableCommand() {
subs += subCmdStyle.Render(subCmds[i].Name()) + subCmdInfoStyle.
PaddingLeft(subCmds[i].NamePadding()-len(subCmds[i].Name())+1).Render(subCmds[i].Short) + "\n"
}
}
usageText.WriteString(lipgloss.JoinVertical(lipgloss.Left, subTitle, subs))
}

if cmd.HasAvailableLocalFlags() {
flags := titleStyle.Render("Local Flags:")
flags += textStyle.Render("\n" + cmd.LocalFlags().FlagUsages())
usageText.WriteString(flags)
}
if cmd.HasAvailableInheritedFlags() {
flags := titleStyle.Render("Global Flags:")
flags += textStyle.Render("\n" + cmd.InheritedFlags().FlagUsages())
usageText.WriteString(flags)
}

//Border styles
borderStyle := lipgloss.NewStyle().
Padding(0, 1, 0, 1).
Width(120).
BorderForeground(lipgloss.AdaptiveColor{Light: `#3B6385`, Dark: `#47A359`}).
Border(lipgloss.ThickBorder())

log.Println("\n" + borderStyle.Render(usageText.String()+"\n"))
}
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,17 @@ require (
gotest.tools/v3 v3.0.3
)

require github.com/erikgeiser/promptkit v0.7.0
require (
github.com/charmbracelet/lipgloss v0.5.0
github.com/erikgeiser/promptkit v0.7.0
)

require (
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/charmbracelet/bubbles v0.11.0 // indirect
github.com/charmbracelet/bubbletea v0.21.0 // indirect
github.com/charmbracelet/lipgloss v0.5.0 // indirect
github.com/containerd/console v1.0.3 // indirect
github.com/emirpasic/gods v1.12.0 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
Expand Down
6 changes: 1 addition & 5 deletions integration_tests/features/root_commands.feature
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ Feature: Root Commands
When I run `circleci help`
Then the output should contain:
"""
Use CircleCI from the command line.
This project is the seed for CircleCI's new command-line application.
For more help, see the documentation here: https://circleci.com/docs/2.0/local-cli/
circleci
"""
And the exit status should be 0

Expand Down

0 comments on commit 3b49940

Please sign in to comment.