Skip to content

Commit

Permalink
Merge pull request #145 from jmattheis/help
Browse files Browse the repository at this point in the history
Add `help` and `version` cli
  • Loading branch information
jmattheis authored Jun 10, 2024
2 parents 5cdb687 + 350875b commit ae1b2c8
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 43 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- uses: actions/checkout@v4
- uses: golangci/golangci-lint-action@v3
with:
version: v1.55.2
version: v1.57.2
test:
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.repository != github.event.pull_request.head.repo.full_name)
runs-on: ubuntu-latest
Expand Down
4 changes: 2 additions & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
run:
skip-dirs:
issues:
exclude-dirs:
- example

linters:
Expand Down
21 changes: 21 additions & 0 deletions cli/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cli

import "github.com/jmattheis/goverter"

type Command interface {
_c()
}

type Generate struct {
Config *goverter.GenerateConfig
}

type Help struct {
Usage string
}

type Version struct{}

func (*Help) _c() {}
func (*Generate) _c() {}
func (*Version) _c() {}
70 changes: 49 additions & 21 deletions cli/parse.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package cli

import (
"errors"
"flag"
"fmt"
"io"

"github.com/jmattheis/goverter"
"github.com/jmattheis/goverter/config"
Expand All @@ -20,19 +22,43 @@ func (s *Strings) Set(value string) error {
return nil
}

func Parse(args []string) (*goverter.GenerateConfig, error) {
switch len(args) {
case 0:
return nil, usage("unknown")
case 1:
return nil, usageErr("missing command: ", args[0])
default:
if args[1] != "gen" {
return nil, usageErr("unknown command: "+args[1], args[0])
func Parse(args []string) (Command, error) {
if len(args) == 0 {
return nil, usageErr("invalid args", "unknown")
}
cmd := args[0]

fs := flag.NewFlagSet(cmd, flag.ContinueOnError)
fs.Usage = func() {}
fs.SetOutput(io.Discard)

if err := fs.Parse(args[1:]); err != nil {
if errors.Is(err, flag.ErrHelp) {
return &Help{Usage: usage(cmd)}, nil
}
return nil, usageErr(err.Error(), cmd)
}

subArgs := fs.Args()
if len(subArgs) == 0 {
return nil, usageErr("missing command", cmd)
}

fs := flag.NewFlagSet(args[0], flag.ContinueOnError)
switch subArgs[0] {
case "gen":
return parseGen(cmd, subArgs[1:])
case "version":
return &Version{}, nil
case "help":
return &Help{Usage: usage(cmd)}, nil
default:
return nil, usageErr("unknown command "+subArgs[0], cmd)
}
}

func parseGen(cmd string, args []string) (Command, error) {
fs := flag.NewFlagSet(cmd, flag.ContinueOnError)
fs.SetOutput(io.Discard)
fs.Usage = func() {}

var global Strings
Expand All @@ -43,13 +69,17 @@ func Parse(args []string) (*goverter.GenerateConfig, error) {
outputConstraint := fs.String("output-constraint", "!goverter", "")
cwd := fs.String("cwd", "", "")

if err := fs.Parse(args[2:]); err != nil {
return nil, usageErr(err.Error(), args[0])
if err := fs.Parse(args); err != nil {
if errors.Is(err, flag.ErrHelp) {
return &Help{Usage: usage(cmd)}, nil
}
return nil, usageErr(err.Error(), cmd)
}

patterns := fs.Args()

if len(patterns) == 0 {
return nil, usageErr("missing PATTERN", args[0])
return nil, usageErr("missing PATTERN", cmd)
}

c := goverter.GenerateConfig{
Expand All @@ -63,17 +93,18 @@ func Parse(args []string) (*goverter.GenerateConfig, error) {
Location: "command line (-g, -global)",
},
}

return &c, nil
return &Generate{Config: &c}, nil
}

func usageErr(err, cmd string) error {
return fmt.Errorf("Error: %s\n%s", err, usage(cmd))
}

func usage(cmd string) error {
return fmt.Errorf(`Usage:
func usage(cmd string) string {
return fmt.Sprintf(`Usage:
%s gen [OPTIONS] PACKAGE...
%s help
%s version
PACKAGE(s):
Define the import paths goverter will use to search for converter interfaces.
Expand All @@ -93,9 +124,6 @@ OPTIONS:
apply settings to all defined converters. For a list of available
settings see: https://goverter.jmattheis.de/reference/settings
-h, --help:
display this help page
-output-constraint [constraint]: (default: !goverter)
A build constraint added to all files generated by goverter.
Can be disabled by supplying an empty string.
Expand All @@ -107,5 +135,5 @@ Examples:
%s gen -g 'ignoreMissing no' -g 'skipCopySameType' ./simple
Documentation:
Full documentation is available here: https://goverter.jmattheis.de`, cmd, cmd, cmd, cmd, cmd)
Full documentation is available here: https://goverter.jmattheis.de`, cmd, cmd, cmd, cmd, cmd, cmd, cmd)
}
38 changes: 32 additions & 6 deletions cli/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ func TestError(t *testing.T) {
args []string
contains string
}{
{[]string{}, "unknown gen [OPTIONS]"},
{[]string{}, "Error: invalid args"},
{[]string{"goverter"}, "goverter gen [OPTIONS]"},
{[]string{"goverter"}, "Error: missing command"},
{[]string{"goverter", "test"}, "Error: unknown command: test"},
{[]string{"goverter", "-u"}, "Error: flag provided but not defined: -u"},
{[]string{"goverter", "test"}, "Error: unknown command test"},
{[]string{"goverter", "gen"}, "Error: missing PATTERN"},
{[]string{"goverter", "gen", "-u"}, "Error: flag provided but not defined: -u"},
{[]string{"goverter", "gen", "-g"}, "Error: flag needs an argument: -g"},
Expand All @@ -34,6 +35,31 @@ func TestError(t *testing.T) {
}
}

func TestHelp(t *testing.T) {
tests := [][]string{
{"goverter", "help"},
{"goverter", "-h"},
{"goverter", "--help"},
{"goverter", "gen", "-h"},
{"goverter", "gen", "--help"},
}

for _, test := range tests {
test := test
t.Run(strings.Join(test, " "), func(t *testing.T) {
cmd, err := cli.Parse(test)
require.NoError(t, err)
require.IsType(t, &cli.Help{}, cmd)
})
}
}

func TestVersion(t *testing.T) {
cmd, err := cli.Parse([]string{"goverter", "version"})
require.NoError(t, err)
require.IsType(t, &cli.Version{}, cmd)
}

func TestSuccess(t *testing.T) {
actual, err := cli.Parse([]string{
"goverter",
Expand All @@ -48,7 +74,7 @@ func TestSuccess(t *testing.T) {
})
require.NoError(t, err)

expected := &goverter.GenerateConfig{
expected := &cli.Generate{&goverter.GenerateConfig{
PackagePatterns: []string{"pattern1", "pattern2"},
WorkingDir: "file/path",
OutputBuildConstraint: "",
Expand All @@ -58,15 +84,15 @@ func TestSuccess(t *testing.T) {
Location: "command line (-g, -global)",
Lines: []string{"g1", "g2", "g3 oops"},
},
}
}}
require.Equal(t, expected, actual)
}

func TestDefault(t *testing.T) {
actual, err := cli.Parse([]string{"goverter", "gen", "pattern"})
require.NoError(t, err)

expected := &goverter.GenerateConfig{
expected := &cli.Generate{&goverter.GenerateConfig{
PackagePatterns: []string{"pattern"},
WorkingDir: "",
OutputBuildConstraint: "!goverter",
Expand All @@ -76,6 +102,6 @@ func TestDefault(t *testing.T) {
Location: "command line (-g, -global)",
Lines: nil,
},
}
}}
require.Equal(t, expected, actual)
}
30 changes: 22 additions & 8 deletions cli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cli
import (
"fmt"
"os"
"runtime/debug"

"github.com/jmattheis/goverter"
"github.com/jmattheis/goverter/enum"
Expand All @@ -14,20 +15,33 @@ type RunOpts struct {

// Run runs the goverter cli with the given args and customizations.
func Run(args []string, opts RunOpts) {
cfg, err := Parse(args)
cmd, err := Parse(args)
if err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}

if opts.EnumTransformers != nil {
for key, value := range opts.EnumTransformers {
cfg.EnumTransformers[key] = value
switch cmd := cmd.(type) {
case *Help:
_, _ = fmt.Fprintln(os.Stdout, cmd.Usage)
os.Exit(0)
case *Generate:
if opts.EnumTransformers != nil {
for key, value := range opts.EnumTransformers {
cmd.Config.EnumTransformers[key] = value
}
}
}

if err = goverter.GenerateConverters(cfg); err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
os.Exit(1)
if err = goverter.GenerateConverters(cmd.Config); err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
case *Version:
b, ok := debug.ReadBuildInfo()
if ok {
fmt.Println(b)
}
default:
panic("unknown command")
}
}
2 changes: 1 addition & 1 deletion codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ coverage:
target: 90%
patch:
default:
target: 90%
target: 50%
1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import GH from './GH.vue';
- Error when the settings [`enum`](reference/enum.md) and
[`useUnderlyingTypeMethods`](reference/useUnderlyingTypeMethods.md) conflict.
<GH issue="141" pr="142"/>
- Add [CLI](./reference/cli.md) commands `help` and `version`. <GH issue="144" pr="145"/>

## v1.4.0

Expand Down
7 changes: 3 additions & 4 deletions docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ The CLI allows you to specify package paths with converter interfaces and
applied to all converters.

```
$ goverter gen --help
$ goverter help
Usage:
goverter gen [OPTIONS] PACKAGE...
goverter help
goverter version
PACKAGE(s):
Define the import paths goverter will use to search for converter interfaces.
Expand All @@ -27,9 +29,6 @@ OPTIONS:
apply settings to all defined converters. For a list of available
settings see: https://goverter.jmattheis.de/reference/settings
-h, --help:
display this help page
-output-constraint [constraint]: (default: !goverter)
A build constraint added to all files generated by goverter.
Can be disabled by supplying an empty string.
Expand Down

0 comments on commit ae1b2c8

Please sign in to comment.