New upstream release.
Kali Janitor
2 years ago
0 | name: CI | |
1 | ||
2 | on: push | |
3 | ||
4 | jobs: | |
5 | test: | |
6 | strategy: | |
7 | matrix: | |
8 | go: ["1.12", "1.13", "1.14"] | |
9 | runs-on: ubuntu-latest | |
10 | steps: | |
11 | - name: Set up Go ${{ matrix.go }} | |
12 | uses: actions/setup-go@v1 | |
13 | with: | |
14 | go-version: ${{ matrix.go }} | |
15 | id: go | |
16 | - name: Checkout the code | |
17 | uses: actions/checkout@v2 | |
18 | ||
19 | - name: Test with Go ${{ matrix.go }} | |
20 | run: go test -v -coverprofile=profile.cov ./... | |
21 | ||
22 | - name: Send coverage with Go ${{ matrix.go }} | |
23 | uses: shogo82148/actions-goveralls@v1 | |
24 | with: | |
25 | path-to-profile: profile.cov | |
26 | flag-name: Go-${{ matrix.go }} | |
27 | parallel: true | |
28 | ||
29 | lint: | |
30 | runs-on: ubuntu-latest | |
31 | steps: | |
32 | - name: Checkout the code | |
33 | uses: actions/checkout@v2 | |
34 | ||
35 | - name: Set up Go | |
36 | uses: actions/setup-go@v1 | |
37 | with: | |
38 | go-version: 1.14 | |
39 | id: go | |
40 | ||
41 | - name: lint | |
42 | uses: golangci/golangci-lint-action@v1 | |
43 | with: | |
44 | version: v1.28 | |
45 | ||
46 | readme: | |
47 | runs-on: ubuntu-latest | |
48 | steps: | |
49 | - name: Set up Go | |
50 | uses: actions/setup-go@v1 | |
51 | with: | |
52 | go-version: 1.14 | |
53 | id: go | |
54 | ||
55 | ||
56 | - name: Checkout the code | |
57 | uses: actions/checkout@v2 | |
58 | ||
59 | - name: Set GOPATH | |
60 | run: echo ::set-env name=GOPATH::$GITHUB_WORKSPACE/go | |
61 | ||
62 | - name: Readme Check | |
63 | run: export PATH="$GOPATH/bin:$PATH"; make readmecheck.setup readmecheck | |
64 | ||
65 | finish: | |
66 | needs: test | |
67 | runs-on: ubuntu-latest | |
68 | steps: | |
69 | - uses: shogo82148/actions-goveralls@v1 | |
70 | with: | |
71 | parallel-finished: true |
0 | name: Release | |
1 | ||
2 | # Triggered only when a tag is pushed | |
3 | on: | |
4 | push: | |
5 | branches: | |
6 | - "!*" | |
7 | tags: | |
8 | - "v*" | |
9 | jobs: | |
10 | release: | |
11 | runs-on: ubuntu-latest | |
12 | name: Release | |
13 | steps: | |
14 | - name: Check out code | |
15 | uses: actions/checkout@v2 | |
16 | with: | |
17 | fetch-depth: 0 | |
18 | ||
19 | - name: Release the application | |
20 | uses: goreleaser/goreleaser-action@v2 | |
21 | with: | |
22 | args: release --rm-dist | |
23 | env: | |
24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
0 | project_name: mow.cli | |
1 | build: | |
2 | skip: true | |
3 | release: | |
4 | github: | |
5 | prerelease: auto | |
6 | changelog: | |
7 | sort: asc | |
8 | filters: | |
9 | exclude: | |
10 | - '^docs:' | |
11 | - '^test:' |
0 | language: go | |
1 | go: | |
2 | - "1.12" | |
3 | - "1.11" | |
4 | ||
5 | sudo: false | |
6 | ||
7 | env: | |
8 | - GO111MODULE=on | |
9 | ||
10 | install: make setup | |
11 | ||
12 | script: make check test-cover | |
13 | ||
14 | deploy: | |
15 | provider: releases | |
16 | api_key: | |
17 | secure: D2fwuS7n54ZkjfRmLMEAnwR2lQLa5xd+4s0l65pI6UN4ljVfQwQiFdZXaZWFr8PYSTKTm0UPj6Iqqw7VOl8I6iDzcaOqN3hoh5mDaJ7kyo7GZRPodwK9MKdOp5dPw459L2Atll8kxb4iYmfnjmcl0lDCUuWvMxXx+zgiFTB7BO0= | |
18 | skip_cleanup: true | |
19 | on: | |
20 | tags: true | |
21 | go: "1.12" |
0 | 0 | test: |
1 | 1 | go test ./... |
2 | ||
3 | test-cover: | |
4 | go list -f '{{if len .TestGoFiles}}"go test -coverprofile={{.Dir}}/.coverprofile {{.ImportPath}}"{{end}}' ./... | xargs -L 1 sh -c | |
5 | gover | |
6 | goveralls -coverprofile=gover.coverprofile -service=travis-ci | |
7 | 2 | |
8 | 3 | check: readmecheck |
9 | 4 | bin/golangci-lint run |
12 | 7 | autoreadme -f |
13 | 8 | |
14 | 9 | readmecheck: |
15 | sed '$ d' README.md > README.original.md | |
10 | head -n -1 README.md > README.original.md | |
16 | 11 | autoreadme -f |
17 | sed '$ d' README.md > README.generated.md | |
12 | head -n -1 README.md > README.generated.md | |
18 | 13 | diff README.generated.md README.original.md |
19 | 14 | |
20 | setup: | |
21 | go get golang.org/x/tools/cmd/cover | |
22 | go get github.com/mattn/goveralls | |
23 | go get github.com/modocache/gover | |
24 | go get github.com/divan/autoreadme | |
25 | curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.16.0 | |
15 | lint.setup: | |
16 | curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.28.0 | |
26 | 17 | |
27 | .PHONY: test check lint vet fmtcheck ineffassign readmecheck | |
18 | ||
19 | readmecheck.setup: | |
20 | go get github.com/jawher/autoreadme | |
21 | ||
22 | .PHONY: test check doc readmecheck lint.setup readmecheck.setup |
0 | 0 | # mow.cli |
1 | [![Build Status](https://travis-ci.org/jawher/mow.cli.svg?branch=master)](https://travis-ci.org/jawher/mow.cli) | |
2 | [![GoDoc](https://godoc.org/github.com/github.com/jawher/mow.cli?status.svg)](https://godoc.org/github.com/jawher/mow.cli) | |
1 | ![CI](https://github.com/jawher/mow.cli/workflows/CI/badge.svg) | |
2 | [![GoDoc](https://pkg.go.dev/badge/github.com/jawher/mow.cli)](https://pkg.go.dev/github.com/jawher/mow.cli) | |
3 | 3 | [![Coverage Status](https://coveralls.io/repos/github/jawher/mow.cli/badge.svg?branch=master)](https://coveralls.io/github/jawher/mow.cli?branch=master) |
4 | 4 | |
5 | 5 | Package cli provides a framework to build command line applications in Go with most of the burden of arguments parsing and validation placed on the framework instead of the user. |
106 | 106 | familiar commands such as git and docker. We build a fictional utility called |
107 | 107 | uman to manage users in a system. It provides two commands that can be invoked: |
108 | 108 | list and get. The list command takes an optional flag to specify all users |
109 | including disabled ones. The get command requries one argument, the user ID, | |
109 | including disabled ones. The get command requires one argument, the user ID, | |
110 | 110 | and takes an optional flag to specify a detailed listing. |
111 | 111 | |
112 | 112 | ```go |
154 | 154 | // Declare our second command, which is invocable with "uman get" |
155 | 155 | app.Command("get", "get a user details", func(cmd *cli.Cmd) { |
156 | 156 | var ( |
157 | detailed = cmd.BoolOpt("detailed", false, "Disaply detailed info") | |
157 | detailed = cmd.BoolOpt("detailed", false, "Display detailed info") | |
158 | 158 | id = cmd.StringArg("ID", "", "The user id to display") |
159 | 159 | ) |
160 | 160 | |
615 | 615 | $ docker job log clear |
616 | 616 | ``` |
617 | 617 | |
618 | Commands can be hidden in the help messages. | |
619 | This can prove useful to deprecate a command so that it does not appear to new users in the help, but still exists to not break existing scripts. | |
620 | To hide a command, set the Hidden field to true: | |
621 | ||
622 | ``` | |
623 | app.Command("login", "login to the backend (DEPRECATED: please use auth instead)", func(cmd *cli.Cmd)) { | |
624 | cmd.Hidden = true | |
625 | } | |
626 | ``` | |
627 | ||
618 | 628 | As a convenience, to assign an Action to a func with no arguments, use |
619 | 629 | ActionCommand when defining the Command. For example, the following two |
620 | 630 | statements are equivalent: |
1061 | 1071 | Please see the `LICENSE` file for details. |
1062 | 1072 | |
1063 | 1073 | * * * |
1064 | Automatically generated by [autoreadme](https://github.com/jimmyfrasche/autoreadme) on 2019.02.24 | |
1074 | Automatically generated by [autoreadme](https://github.com/jawher/autoreadme) on 2020.08.08 |
0 | 0 | # mow.cli |
1 | [![Build Status](https://travis-ci.org/{{.RepoPath}}.svg?branch=master)](https://travis-ci.org/{{.RepoPath}}) | |
2 | [![GoDoc](https://godoc.org/github.com/{{.Import}}?status.svg)](https://godoc.org/{{.Import}}) | |
3 | [![Coverage Status](https://coveralls.io/repos/github/{{.RepoPath}}/badge.svg?branch=master)](https://coveralls.io/github/{{.RepoPath}}?branch=master) | |
1 | ![CI](https://github.com/jawher/mow.cli/workflows/CI/badge.svg) | |
2 | [![GoDoc](https://pkg.go.dev/badge/github.com/jawher/mow.cli)](https://pkg.go.dev/github.com/jawher/mow.cli) | |
3 | [![Coverage Status](https://coveralls.io/repos/github/jawher/mow.cli/badge.svg?branch=master)](https://coveralls.io/github/jawher/mow.cli?branch=master) | |
4 | 4 | |
5 | 5 | {{.Synopsis}} |
6 | 6 | |
106 | 106 | familiar commands such as git and docker. We build a fictional utility called |
107 | 107 | uman to manage users in a system. It provides two commands that can be invoked: |
108 | 108 | list and get. The list command takes an optional flag to specify all users |
109 | including disabled ones. The get command requries one argument, the user ID, | |
109 | including disabled ones. The get command requires one argument, the user ID, | |
110 | 110 | and takes an optional flag to specify a detailed listing. |
111 | 111 | |
112 | 112 | ```go |
154 | 154 | // Declare our second command, which is invocable with "uman get" |
155 | 155 | app.Command("get", "get a user details", func(cmd *cli.Cmd) { |
156 | 156 | var ( |
157 | detailed = cmd.BoolOpt("detailed", false, "Disaply detailed info") | |
157 | detailed = cmd.BoolOpt("detailed", false, "Display detailed info") | |
158 | 158 | id = cmd.StringArg("ID", "", "The user id to display") |
159 | 159 | ) |
160 | 160 | |
304 | 304 | Please see the `LICENSE` file for details. |
305 | 305 | |
306 | 306 | * * * |
307 | Automatically generated by [autoreadme](https://github.com/jimmyfrasche/autoreadme) on {{.Today}} | |
307 | Automatically generated by [autoreadme](https://github.com/jawher/autoreadme) on {{.Today}} |
393 | 393 | panic(fmt.Sprintf("duplicate argument name %q", arg.Name)) |
394 | 394 | } |
395 | 395 | |
396 | arg.DefaultValue = values.DefaultValue(arg.Value) | |
397 | ||
396 | 398 | arg.ValueSetFromEnv = values.SetFromEnv(arg.Value, arg.EnvVar) |
397 | 399 | |
398 | 400 | c.args = append(c.args, &arg) |
779 | 779 | |
780 | 780 | func TestHelpAndVersionWithOptionsEnd(t *testing.T) { |
781 | 781 | for _, flag := range []string{"-h", "--help", "-v", "--version"} { |
782 | testHelpAndVersionWithOptionsEnd(flag, t) | |
782 | t.Run(flag, func(t *testing.T) { | |
783 | testHelpAndVersionWithOptionsEnd(flag, t) | |
784 | }) | |
783 | 785 | } |
784 | 786 | } |
785 | 787 | |
786 | 788 | var genGolden = flag.Bool("g", false, "Generate golden file(s)") |
787 | 789 | |
788 | 790 | func TestHelpMessage(t *testing.T) { |
789 | var out, err string | |
790 | defer captureAndRestoreOutput(&out, &err)() | |
791 | ||
792 | exitCalled := false | |
793 | defer exitShouldBeCalledWith(t, 0, &exitCalled)() | |
794 | ||
795 | app := App("app", "App Desc") | |
796 | app.Spec = "[-bdsuikqs] BOOL1 [STR1] INT3..." | |
797 | ||
798 | // Options | |
799 | app.Bool(BoolOpt{Name: "b bool1 u uuu", Value: false, EnvVar: "BOOL1", Desc: "Bool Option 1"}) | |
800 | app.Bool(BoolOpt{Name: "bool2", Value: true, EnvVar: " ", Desc: "Bool Option 2"}) | |
801 | app.Bool(BoolOpt{Name: "d", Value: true, EnvVar: "BOOL3", Desc: "Bool Option 3", HideValue: true}) | |
802 | ||
803 | app.String(StringOpt{Name: "s str1", Value: "", EnvVar: "STR1", Desc: "String Option 1"}) | |
804 | app.String(StringOpt{Name: "str2", Value: "a value", Desc: "String Option 2"}) | |
805 | app.String(StringOpt{Name: "v", Value: "another value", EnvVar: "STR3", Desc: "String Option 3", HideValue: true}) | |
806 | ||
807 | app.Int(IntOpt{Name: "i int1", Value: 0, EnvVar: "INT1 ALIAS_INT1"}) | |
808 | app.Int(IntOpt{Name: "int2", Value: 1, EnvVar: "INT2", Desc: "Int Option 2"}) | |
809 | app.Int(IntOpt{Name: "k", Value: 1, EnvVar: "INT3", Desc: "Int Option 3", HideValue: true}) | |
810 | ||
811 | app.Strings(StringsOpt{Name: "x strs1", Value: nil, EnvVar: "STRS1", Desc: "Strings Option 1"}) | |
812 | app.Strings(StringsOpt{Name: "strs2", Value: []string{"value1", "value2"}, EnvVar: "STRS2", Desc: "Strings Option 2"}) | |
813 | app.Strings(StringsOpt{Name: "z", Value: []string{"another value"}, EnvVar: "STRS3", Desc: "Strings Option 3", HideValue: true}) | |
814 | ||
815 | app.Ints(IntsOpt{Name: "q ints1", Value: nil, EnvVar: "INTS1", Desc: "Ints Option 1"}) | |
816 | app.Ints(IntsOpt{Name: "ints2", Value: []int{1, 2, 3}, EnvVar: "INTS2", Desc: "Ints Option 2"}) | |
817 | app.Ints(IntsOpt{Name: "j", Value: []int{1}, EnvVar: "INTS3", Desc: "Ints Option 3", HideValue: true}) | |
818 | ||
819 | // Args | |
820 | app.Bool(BoolArg{Name: "BOOL1", Value: false, EnvVar: "BOOL1", Desc: "Bool Argument 1"}) | |
821 | app.Bool(BoolArg{Name: "BOOL2", Value: true, Desc: "Bool Argument 2"}) | |
822 | app.Bool(BoolArg{Name: "BOOL3", Value: true, EnvVar: "BOOL3", Desc: "Bool Argument 3", HideValue: true}) | |
823 | ||
824 | app.String(StringArg{Name: "STR1", Value: "", EnvVar: "STR1", Desc: "String Argument 1"}) | |
825 | app.String(StringArg{Name: "STR2", Value: "a value", EnvVar: "STR2", Desc: "String Argument 2"}) | |
826 | app.String(StringArg{Name: "STR3", Value: "another value", EnvVar: "STR3", Desc: "String Argument 3", HideValue: true}) | |
827 | ||
828 | app.Int(IntArg{Name: "INT1", Value: 0, EnvVar: "INT1", Desc: "Int Argument 1"}) | |
829 | app.Int(IntArg{Name: "INT2", Value: 1, EnvVar: "INT2", Desc: "Int Argument 2"}) | |
830 | app.Int(IntArg{Name: "INT3", Value: 1, EnvVar: "INT3", Desc: "Int Argument 3", HideValue: true}) | |
831 | ||
832 | app.Strings(StringsArg{Name: "STRS1", Value: nil, EnvVar: "STRS1", Desc: "Strings Argument 1"}) | |
833 | app.Strings(StringsArg{Name: "STRS2", Value: []string{"value1", "value2"}, EnvVar: "STRS2"}) | |
834 | app.Strings(StringsArg{Name: "STRS3", Value: []string{"another value"}, EnvVar: "STRS3", Desc: "Strings Argument 3", HideValue: true}) | |
835 | ||
836 | app.Ints(IntsArg{Name: "INTS1", Value: nil, EnvVar: "INTS1", Desc: "Ints Argument 1"}) | |
837 | app.Ints(IntsArg{Name: "INTS2", Value: []int{1, 2, 3}, EnvVar: "INTS2", Desc: "Ints Argument 2"}) | |
838 | app.Ints(IntsArg{Name: "INTS3", Value: []int{1}, EnvVar: "INTS3", Desc: "Ints Argument 3", HideValue: true}) | |
839 | ||
840 | app.Action = func() {} | |
841 | ||
842 | app.Command("command1", "command1 description", func(cmd *Cmd) {}) | |
843 | app.Command("command2", "command2 description", func(cmd *Cmd) {}) | |
844 | app.Command("command3", "command3 description", func(cmd *Cmd) {}) | |
845 | ||
846 | require.NoError(t, | |
847 | app.Run([]string{"app", "-h"})) | |
848 | ||
849 | if *genGolden { | |
850 | require.NoError(t, | |
851 | ioutil.WriteFile("testdata/help-output.txt.golden", []byte(err), 0644)) | |
852 | } | |
853 | ||
854 | expected, e := ioutil.ReadFile("testdata/help-output.txt") | |
855 | require.NoError(t, e, "Failed to read the expected help output from testdata/help-output.txt") | |
856 | ||
857 | require.Equal(t, expected, []byte(err)) | |
791 | cases := []struct { | |
792 | name string | |
793 | params []string | |
794 | env map[string]string | |
795 | exitCode int | |
796 | }{ | |
797 | {name: "top-help", params: []string{"app", "-h"}}, | |
798 | {name: "top-help-i-user", params: []string{"app", "-i=5"}, exitCode: 2}, | |
799 | {name: "top-help-i-env", params: []string{"app"}, env: map[string]string{"INT1": "25"}, exitCode: 2}, | |
800 | {name: "command1", params: []string{"app", "command1", "-h"}}, | |
801 | {name: "command2", params: []string{"app", "command2", "-h"}}, | |
802 | {name: "command3", params: []string{"app", "command3", "-h"}}, | |
803 | {name: "command3-child1", params: []string{"app", "command3", "child1", "-h"}}, | |
804 | {name: "command3-child2", params: []string{"app", "command3", "child2", "-h"}}, | |
805 | {name: "command4", params: []string{"app", "command4", "-h"}}, | |
806 | } | |
807 | for _, cas := range cases { | |
808 | cas := cas | |
809 | t.Run(cas.name, func(t *testing.T) { | |
810 | t.Logf("case: %+v", cas) | |
811 | var out, stdErr string | |
812 | defer captureAndRestoreOutput(&out, &stdErr)() | |
813 | defer setAndRestoreEnv(cas.env)() | |
814 | ||
815 | exitCalled := false | |
816 | defer exitShouldBeCalledWith(t, cas.exitCode, &exitCalled)() | |
817 | ||
818 | app := App("app", "App Desc") | |
819 | app.Spec = "[-bdsuikqs] [BOOL1 STR1 INT3...]" | |
820 | ||
821 | // Options | |
822 | app.Bool(BoolOpt{Name: "b bool1 u uuu", Value: false, EnvVar: "BOOL1", Desc: "Bool Option 1"}) | |
823 | app.Bool(BoolOpt{Name: "bool2", Value: true, EnvVar: " ", Desc: "Bool Option 2"}) | |
824 | app.Bool(BoolOpt{Name: "d", Value: true, EnvVar: "BOOL3", Desc: "Bool Option 3", HideValue: true}) | |
825 | ||
826 | app.String(StringOpt{Name: "s str1", Value: "", EnvVar: "STR1", Desc: "String Option 1"}) | |
827 | app.String(StringOpt{Name: "str2", Value: "a value", Desc: "String Option 2"}) | |
828 | app.String(StringOpt{Name: "v", Value: "another value", EnvVar: "STR3", Desc: "String Option 3", HideValue: true}) | |
829 | ||
830 | app.Int(IntOpt{Name: "i int1", Value: 0, EnvVar: "INT1 ALIAS_INT1"}) | |
831 | app.Int(IntOpt{Name: "int2", Value: 1, EnvVar: "INT2", Desc: "Int Option 2"}) | |
832 | app.Int(IntOpt{Name: "k", Value: 1, EnvVar: "INT3", Desc: "Int Option 3", HideValue: true}) | |
833 | ||
834 | app.Strings(StringsOpt{Name: "x strs1", Value: nil, EnvVar: "STRS1", Desc: "Strings Option 1"}) | |
835 | app.Strings(StringsOpt{Name: "strs2", Value: []string{"value1", "value2"}, EnvVar: "STRS2", Desc: "Strings Option 2"}) | |
836 | app.Strings(StringsOpt{Name: "z", Value: []string{"another value"}, EnvVar: "STRS3", Desc: "Strings Option 3", HideValue: true}) | |
837 | ||
838 | app.Ints(IntsOpt{Name: "q ints1", Value: nil, EnvVar: "INTS1", Desc: "Ints Option 1"}) | |
839 | app.Ints(IntsOpt{Name: "ints2", Value: []int{1, 2, 3}, EnvVar: "INTS2", Desc: "Ints Option 2"}) | |
840 | app.Ints(IntsOpt{Name: "j", Value: []int{1}, EnvVar: "INTS3", Desc: "Ints Option 3", HideValue: true}) | |
841 | ||
842 | // Args | |
843 | app.Bool(BoolArg{Name: "BOOL1", Value: false, EnvVar: "BOOL1", Desc: "Bool Argument 1"}) | |
844 | app.Bool(BoolArg{Name: "BOOL2", Value: true, Desc: "Bool Argument 2"}) | |
845 | app.Bool(BoolArg{Name: "BOOL3", Value: true, EnvVar: "BOOL3", Desc: "Bool Argument 3", HideValue: true}) | |
846 | ||
847 | app.String(StringArg{Name: "STR1", Value: "", EnvVar: "STR1", Desc: "String Argument 1"}) | |
848 | app.String(StringArg{Name: "STR2", Value: "a value", EnvVar: "STR2", Desc: "String Argument 2"}) | |
849 | app.String(StringArg{Name: "STR3", Value: "another value", EnvVar: "STR3", Desc: "String Argument 3", HideValue: true}) | |
850 | ||
851 | app.Int(IntArg{Name: "INT1", Value: 0, EnvVar: "INT1", Desc: "Int Argument 1"}) | |
852 | app.Int(IntArg{Name: "INT2", Value: 1, EnvVar: "INT2", Desc: "Int Argument 2"}) | |
853 | app.Int(IntArg{Name: "INT3", Value: 1, EnvVar: "INT3", Desc: "Int Argument 3", HideValue: true}) | |
854 | ||
855 | app.Strings(StringsArg{Name: "STRS1", Value: nil, EnvVar: "STRS1", Desc: "Strings Argument 1"}) | |
856 | app.Strings(StringsArg{Name: "STRS2", Value: []string{"value1", "value2"}, EnvVar: "STRS2"}) | |
857 | app.Strings(StringsArg{Name: "STRS3", Value: []string{"another value"}, EnvVar: "STRS3", Desc: "Strings Argument 3", HideValue: true}) | |
858 | ||
859 | app.Ints(IntsArg{Name: "INTS1", Value: nil, EnvVar: "INTS1", Desc: "Ints Argument 1"}) | |
860 | app.Ints(IntsArg{Name: "INTS2", Value: []int{1, 2, 3}, EnvVar: "INTS2", Desc: "Ints Argument 2"}) | |
861 | app.Ints(IntsArg{Name: "INTS3", Value: []int{1}, EnvVar: "INTS3", Desc: "Ints Argument 3", HideValue: true}) | |
862 | ||
863 | app.Command("command1", "command1 description", func(cmd *Cmd) {}) | |
864 | app.Command("command2", "command2 description", func(cmd *Cmd) {}) | |
865 | app.Command("command3", "command3 description", func(cmd *Cmd) { | |
866 | cmd.Command("child1", "child1 description", func(cmd *Cmd) { | |
867 | cmd.StringArg("ARG1", "", "arg1 desc") | |
868 | }) | |
869 | cmd.Command("child2", "child2 description", func(cmd *Cmd) { | |
870 | cmd.Hidden = true | |
871 | cmd.StringOpt("o opt", "", "opt desc") | |
872 | }) | |
873 | }) | |
874 | app.Command("command4", "command4 description", func(cmd *Cmd) { | |
875 | cmd.Hidden = true | |
876 | }) | |
877 | ||
878 | fmt.Printf("calling app with %+v\n", cas.params) | |
879 | require.NoError(t, | |
880 | app.Run(cas.params)) | |
881 | ||
882 | filename := fmt.Sprintf("testdata/help-output-%s.txt", cas.name) | |
883 | ||
884 | if *genGolden { | |
885 | require.NoError(t, | |
886 | ioutil.WriteFile(filename, []byte(stdErr), 0644)) | |
887 | } | |
888 | ||
889 | expected, e := ioutil.ReadFile(filename) | |
890 | require.NoError(t, e, "Failed to read the expected help output from %s", filename) | |
891 | ||
892 | require.Equal(t, string(expected), stdErr) | |
893 | }) | |
894 | } | |
858 | 895 | } |
859 | 896 | |
860 | 897 | func TestLongHelpMessage(t *testing.T) { |
2200 | 2237 | return captureAndRestoreOutput(nil, nil) |
2201 | 2238 | } |
2202 | 2239 | |
2240 | func setAndRestoreEnv(env map[string]string) func() { | |
2241 | backup := map[string]string{} | |
2242 | for k, v := range env { | |
2243 | backup[k] = os.Getenv(k) | |
2244 | os.Setenv(k, v) | |
2245 | } | |
2246 | ||
2247 | return func() { | |
2248 | for k, v := range backup { | |
2249 | os.Setenv(k, v) | |
2250 | } | |
2251 | } | |
2252 | } | |
2253 | ||
2203 | 2254 | func captureAndRestoreOutput(out, err *string) func() { |
2204 | 2255 | oldStdOut := stdOut |
2205 | 2256 | oldStdErr := stdErr |
11 | 11 | "github.com/jawher/mow.cli/internal/fsm" |
12 | 12 | "github.com/jawher/mow.cli/internal/lexer" |
13 | 13 | "github.com/jawher/mow.cli/internal/parser" |
14 | "github.com/jawher/mow.cli/internal/values" | |
15 | 14 | ) |
16 | 15 | |
17 | 16 | /* |
30 | 29 | Spec string |
31 | 30 | // The command long description to be shown when help is requested |
32 | 31 | LongDesc string |
32 | // Hide this command in the help messages | |
33 | Hidden bool | |
33 | 34 | // The command error handling strategy |
34 | 35 | ErrorHandling flag.ErrorHandling |
35 | 36 | |
543 | 544 | for _, arg := range c.args { |
544 | 545 | var ( |
545 | 546 | env = formatEnvVarsForHelp(arg.EnvVar) |
546 | value = formatValueForHelp(arg.HideValue, arg.Value) | |
547 | value = formatValueForHelp(arg.HideValue, arg.DefaultValue) | |
547 | 548 | ) |
548 | 549 | printTabbedRow(w, arg.Name, joinStrings(arg.Desc, env, value)) |
549 | 550 | } |
556 | 557 | var ( |
557 | 558 | optNames = formatOptNamesForHelp(opt) |
558 | 559 | env = formatEnvVarsForHelp(opt.EnvVar) |
559 | value = formatValueForHelp(opt.HideValue, opt.Value) | |
560 | value = formatValueForHelp(opt.HideValue, opt.DefaultValue) | |
560 | 561 | ) |
561 | 562 | printTabbedRow(w, optNames, joinStrings(opt.Desc, env, value)) |
562 | 563 | } |
563 | 564 | } |
564 | 565 | |
565 | if len(c.commands) > 0 { | |
566 | commands := make([]*Cmd, 0, len(c.commands)) | |
567 | for _, c := range c.commands { | |
568 | if err := c.doInit(); err != nil { | |
569 | panic(err) | |
570 | } | |
571 | ||
572 | if c.Hidden { | |
573 | continue | |
574 | } | |
575 | ||
576 | commands = append(commands, c) | |
577 | } | |
578 | ||
579 | if len(commands) > 0 { | |
566 | 580 | fmt.Fprint(w, "\t\nCommands:\t\n") |
567 | 581 | |
568 | for _, c := range c.commands { | |
582 | for _, c := range commands { | |
569 | 583 | fmt.Fprintf(w, " %s\t%s\n", strings.Join(c.aliases, ", "), c.desc) |
570 | 584 | } |
571 | 585 | } |
572 | 586 | |
573 | if len(c.commands) > 0 { | |
587 | if len(commands) > 0 { | |
574 | 588 | fmt.Fprintf(w, "\t\nRun '%s COMMAND --help' for more information on a command.\n", path) |
575 | 589 | } |
576 | 590 | |
603 | 617 | } |
604 | 618 | } |
605 | 619 | |
606 | func formatValueForHelp(hide bool, v flag.Value) string { | |
620 | func formatValueForHelp(hide bool, v string) string { | |
607 | 621 | if hide { |
608 | 622 | return "" |
609 | 623 | } |
610 | 624 | |
611 | if dv, ok := v.(values.DefaultValued); ok { | |
612 | if dv.IsDefault() { | |
613 | return "" | |
614 | } | |
615 | } | |
616 | ||
617 | return fmt.Sprintf("(default %s)", v.String()) | |
625 | if v == "" { | |
626 | return "" | |
627 | } | |
628 | ||
629 | return fmt.Sprintf("(default %s)", v) | |
618 | 630 | } |
619 | 631 | |
620 | 632 | func formatEnvVarsForHelp(envVars string) string { |
0 | golang-github-jawher-mow.cli (1.2.0-0kali1) UNRELEASED; urgency=low | |
1 | ||
2 | * New upstream release. | |
3 | ||
4 | -- Kali Janitor <[email protected]> Sun, 23 Jan 2022 04:00:34 -0000 | |
5 | ||
0 | 6 | golang-github-jawher-mow.cli (1.1.0-0kali1) kali-dev; urgency=medium |
1 | 7 | |
2 | 8 | * Initial release |
286 | 286 | $ docker job r # using the alias we defined |
287 | 287 | $ docker job log show |
288 | 288 | $ docker job log clear |
289 | ||
290 | Commands can be hidden in the help messages. | |
291 | This can prove useful to deprecate a command so that it does not appear to new users in the help, but still exists to not break existing scripts. | |
292 | To hide a command, set the Hidden field to true: | |
293 | ||
294 | app.Command("login", "login to the backend (DEPRECATED: please use auth instead)", func(cmd *cli.Cmd)) { | |
295 | cmd.Hidden = true | |
296 | } | |
289 | 297 | |
290 | 298 | As a convenience, to assign an Action to a func with no arguments, use |
291 | 299 | ActionCommand when defining the Command. For example, the following two |
1 | 1 | |
2 | 2 | require ( |
3 | 3 | github.com/stretchr/objx v0.2.0 // indirect |
4 | github.com/stretchr/testify v1.3.0 | |
4 | github.com/stretchr/testify v1.4.0 | |
5 | gopkg.in/yaml.v2 v2.2.5 // indirect | |
5 | 6 | ) |
7 | ||
8 | go 1.13 |
2 | 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
3 | 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
4 | 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
5 | github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= | |
5 | 6 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
7 | github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= | |
6 | 8 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= |
7 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= | |
8 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | |
9 | 9 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= |
10 | 10 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= |
11 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= | |
12 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | |
13 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |
14 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= | |
15 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |
16 | gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= | |
17 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
13 | 13 | ValueSetFromEnv bool |
14 | 14 | ValueSetByUser *bool |
15 | 15 | Value flag.Value |
16 | DefaultValue string | |
16 | 17 | } |
53 | 53 | |
54 | 54 | return nil |
55 | 55 | } |
56 | ||
57 | func DefaultValue(v flag.Value) string { | |
58 | if dv, ok := v.(DefaultValued); ok { | |
59 | if dv.IsDefault() { | |
60 | return "" | |
61 | } | |
62 | } | |
63 | return v.String() | |
64 | } |
466 | 466 | } |
467 | 467 | |
468 | 468 | func (c *Cmd) mkOpt(opt container.Container) { |
469 | opt.DefaultValue = values.DefaultValue(opt.Value) | |
469 | 470 | opt.ValueSetFromEnv = values.SetFromEnv(opt.Value, opt.EnvVar) |
470 | 471 | |
471 | 472 | opt.Names = mkOptStrs(opt.Name) |
0 | ||
1 | Usage: app command3 COMMAND [arg...] | |
2 | ||
3 | command3 description | |
4 | ||
5 | Commands: | |
6 | child1 child1 description | |
7 | ||
8 | Run 'app command3 COMMAND --help' for more information on a command. |
0 | ||
1 | Usage: app [-bdsuikqs] [BOOL1 STR1 INT3...] COMMAND [arg...] | |
2 | ||
3 | App Desc | |
4 | ||
5 | Arguments: | |
6 | BOOL1 Bool Argument 1 (env $BOOL1) | |
7 | BOOL2 Bool Argument 2 (default true) | |
8 | BOOL3 Bool Argument 3 (env $BOOL3) | |
9 | STR1 String Argument 1 (env $STR1) | |
10 | STR2 String Argument 2 (env $STR2) (default "a value") | |
11 | STR3 String Argument 3 (env $STR3) | |
12 | INT1 Int Argument 1 (env $INT1) (default 0) | |
13 | INT2 Int Argument 2 (env $INT2) (default 1) | |
14 | INT3 Int Argument 3 (env $INT3) | |
15 | STRS1 Strings Argument 1 (env $STRS1) | |
16 | STRS2 (env $STRS2) (default ["value1", "value2"]) | |
17 | STRS3 Strings Argument 3 (env $STRS3) | |
18 | INTS1 Ints Argument 1 (env $INTS1) | |
19 | INTS2 Ints Argument 2 (env $INTS2) (default [1, 2, 3]) | |
20 | INTS3 Ints Argument 3 (env $INTS3) | |
21 | ||
22 | Options: | |
23 | -b, --bool1 Bool Option 1 (env $BOOL1) | |
24 | --bool2 Bool Option 2 (default true) | |
25 | -d Bool Option 3 (env $BOOL3) | |
26 | -s, --str1 String Option 1 (env $STR1) | |
27 | --str2 String Option 2 (default "a value") | |
28 | -v String Option 3 (env $STR3) | |
29 | -i, --int1 (env $INT1, $ALIAS_INT1) (default 0) | |
30 | --int2 Int Option 2 (env $INT2) (default 1) | |
31 | -k Int Option 3 (env $INT3) | |
32 | -x, --strs1 Strings Option 1 (env $STRS1) | |
33 | --strs2 Strings Option 2 (env $STRS2) (default ["value1", "value2"]) | |
34 | -z Strings Option 3 (env $STRS3) | |
35 | -q, --ints1 Ints Option 1 (env $INTS1) | |
36 | --ints2 Ints Option 2 (env $INTS2) (default [1, 2, 3]) | |
37 | -j Ints Option 3 (env $INTS3) | |
38 | ||
39 | Commands: | |
40 | command1 command1 description | |
41 | command2 command2 description | |
42 | command3 command3 description | |
43 | ||
44 | Run 'app COMMAND --help' for more information on a command. |
0 | ||
1 | Usage: app [-bdsuikqs] [BOOL1 STR1 INT3...] COMMAND [arg...] | |
2 | ||
3 | App Desc | |
4 | ||
5 | Arguments: | |
6 | BOOL1 Bool Argument 1 (env $BOOL1) | |
7 | BOOL2 Bool Argument 2 (default true) | |
8 | BOOL3 Bool Argument 3 (env $BOOL3) | |
9 | STR1 String Argument 1 (env $STR1) | |
10 | STR2 String Argument 2 (env $STR2) (default "a value") | |
11 | STR3 String Argument 3 (env $STR3) | |
12 | INT1 Int Argument 1 (env $INT1) (default 0) | |
13 | INT2 Int Argument 2 (env $INT2) (default 1) | |
14 | INT3 Int Argument 3 (env $INT3) | |
15 | STRS1 Strings Argument 1 (env $STRS1) | |
16 | STRS2 (env $STRS2) (default ["value1", "value2"]) | |
17 | STRS3 Strings Argument 3 (env $STRS3) | |
18 | INTS1 Ints Argument 1 (env $INTS1) | |
19 | INTS2 Ints Argument 2 (env $INTS2) (default [1, 2, 3]) | |
20 | INTS3 Ints Argument 3 (env $INTS3) | |
21 | ||
22 | Options: | |
23 | -b, --bool1 Bool Option 1 (env $BOOL1) | |
24 | --bool2 Bool Option 2 (default true) | |
25 | -d Bool Option 3 (env $BOOL3) | |
26 | -s, --str1 String Option 1 (env $STR1) | |
27 | --str2 String Option 2 (default "a value") | |
28 | -v String Option 3 (env $STR3) | |
29 | -i, --int1 (env $INT1, $ALIAS_INT1) (default 0) | |
30 | --int2 Int Option 2 (env $INT2) (default 1) | |
31 | -k Int Option 3 (env $INT3) | |
32 | -x, --strs1 Strings Option 1 (env $STRS1) | |
33 | --strs2 Strings Option 2 (env $STRS2) (default ["value1", "value2"]) | |
34 | -z Strings Option 3 (env $STRS3) | |
35 | -q, --ints1 Ints Option 1 (env $INTS1) | |
36 | --ints2 Ints Option 2 (env $INTS2) (default [1, 2, 3]) | |
37 | -j Ints Option 3 (env $INTS3) | |
38 | ||
39 | Commands: | |
40 | command1 command1 description | |
41 | command2 command2 description | |
42 | command3 command3 description | |
43 | ||
44 | Run 'app COMMAND --help' for more information on a command. |
0 | ||
1 | Usage: app [-bdsuikqs] [BOOL1 STR1 INT3...] COMMAND [arg...] | |
2 | ||
3 | App Desc | |
4 | ||
5 | Arguments: | |
6 | BOOL1 Bool Argument 1 (env $BOOL1) | |
7 | BOOL2 Bool Argument 2 (default true) | |
8 | BOOL3 Bool Argument 3 (env $BOOL3) | |
9 | STR1 String Argument 1 (env $STR1) | |
10 | STR2 String Argument 2 (env $STR2) (default "a value") | |
11 | STR3 String Argument 3 (env $STR3) | |
12 | INT1 Int Argument 1 (env $INT1) (default 0) | |
13 | INT2 Int Argument 2 (env $INT2) (default 1) | |
14 | INT3 Int Argument 3 (env $INT3) | |
15 | STRS1 Strings Argument 1 (env $STRS1) | |
16 | STRS2 (env $STRS2) (default ["value1", "value2"]) | |
17 | STRS3 Strings Argument 3 (env $STRS3) | |
18 | INTS1 Ints Argument 1 (env $INTS1) | |
19 | INTS2 Ints Argument 2 (env $INTS2) (default [1, 2, 3]) | |
20 | INTS3 Ints Argument 3 (env $INTS3) | |
21 | ||
22 | Options: | |
23 | -b, --bool1 Bool Option 1 (env $BOOL1) | |
24 | --bool2 Bool Option 2 (default true) | |
25 | -d Bool Option 3 (env $BOOL3) | |
26 | -s, --str1 String Option 1 (env $STR1) | |
27 | --str2 String Option 2 (default "a value") | |
28 | -v String Option 3 (env $STR3) | |
29 | -i, --int1 (env $INT1, $ALIAS_INT1) (default 0) | |
30 | --int2 Int Option 2 (env $INT2) (default 1) | |
31 | -k Int Option 3 (env $INT3) | |
32 | -x, --strs1 Strings Option 1 (env $STRS1) | |
33 | --strs2 Strings Option 2 (env $STRS2) (default ["value1", "value2"]) | |
34 | -z Strings Option 3 (env $STRS3) | |
35 | -q, --ints1 Ints Option 1 (env $INTS1) | |
36 | --ints2 Ints Option 2 (env $INTS2) (default [1, 2, 3]) | |
37 | -j Ints Option 3 (env $INTS3) | |
38 | ||
39 | Commands: | |
40 | command1 command1 description | |
41 | command2 command2 description | |
42 | command3 command3 description | |
43 | ||
44 | Run 'app COMMAND --help' for more information on a command. |
0 | ||
1 | Usage: app [-bdsuikqs] BOOL1 [STR1] INT3... COMMAND [arg...] | |
2 | ||
3 | App Desc | |
4 | ||
5 | Arguments: | |
6 | BOOL1 Bool Argument 1 (env $BOOL1) | |
7 | BOOL2 Bool Argument 2 (default true) | |
8 | BOOL3 Bool Argument 3 (env $BOOL3) | |
9 | STR1 String Argument 1 (env $STR1) | |
10 | STR2 String Argument 2 (env $STR2) (default "a value") | |
11 | STR3 String Argument 3 (env $STR3) | |
12 | INT1 Int Argument 1 (env $INT1) (default 0) | |
13 | INT2 Int Argument 2 (env $INT2) (default 1) | |
14 | INT3 Int Argument 3 (env $INT3) | |
15 | STRS1 Strings Argument 1 (env $STRS1) | |
16 | STRS2 (env $STRS2) (default ["value1", "value2"]) | |
17 | STRS3 Strings Argument 3 (env $STRS3) | |
18 | INTS1 Ints Argument 1 (env $INTS1) | |
19 | INTS2 Ints Argument 2 (env $INTS2) (default [1, 2, 3]) | |
20 | INTS3 Ints Argument 3 (env $INTS3) | |
21 | ||
22 | Options: | |
23 | -b, --bool1 Bool Option 1 (env $BOOL1) | |
24 | --bool2 Bool Option 2 (default true) | |
25 | -d Bool Option 3 (env $BOOL3) | |
26 | -s, --str1 String Option 1 (env $STR1) | |
27 | --str2 String Option 2 (default "a value") | |
28 | -v String Option 3 (env $STR3) | |
29 | -i, --int1 (env $INT1, $ALIAS_INT1) (default 0) | |
30 | --int2 Int Option 2 (env $INT2) (default 1) | |
31 | -k Int Option 3 (env $INT3) | |
32 | -x, --strs1 Strings Option 1 (env $STRS1) | |
33 | --strs2 Strings Option 2 (env $STRS2) (default ["value1", "value2"]) | |
34 | -z Strings Option 3 (env $STRS3) | |
35 | -q, --ints1 Ints Option 1 (env $INTS1) | |
36 | --ints2 Ints Option 2 (env $INTS2) (default [1, 2, 3]) | |
37 | -j Ints Option 3 (env $INTS3) | |
38 | ||
39 | Commands: | |
40 | command1 command1 description | |
41 | command2 command2 description | |
42 | command3 command3 description | |
43 | ||
44 | Run 'app COMMAND --help' for more information on a command. |