From 872b39467990df7e23059a48e3b21b8cfdf057fb Mon Sep 17 00:00:00 2001 From: Masahiro Nagano Date: Sun, 6 Sep 2026 22:01:59 +0900 Subject: [PATCH] feat: add Validator option for additional argument validation --- README.md | 43 +++++++++++++++++++++++++++++++++++++++++ flagrun.go | 15 ++++++++++++++ flagrun_shipper_test.go | 20 +++++++++++++++++++ go.mod | 9 +++++---- 4 files changed, 83 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9efe3e2..efe6ec1 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,48 @@ func main() { } ``` +### `flagrun.Validator` — 引数の追加検証 + +`flagrun.Validator` を使うと、コマンドライン引数のパース後に追加の検証を行えます。検証関数は `func([]string) error` のシグネチャを持ち、エラーを返した場合は標準エラー出力にメッセージを出力して `UNKNOWN` で終了します。 + +```go +package main + +import ( + "fmt" + + "github.com/monitoring-forge/flagrun" +) + +type Opt struct { + Host string `short:"H" long:"host" default:"localhost" description:"Target host"` + Port int `short:"p" long:"port" default:"8080" description:"Target port"` + Version bool `short:"v" long:"version" description:"Show version"` +} + +func (p *Opt) Run(args []string) (string, int) { + return "ok\t1", flagrun.OK +} + +func (p *Opt) Validator(args []string) error { + if p.Port < 1 || p.Port > 65535 { + return fmt.Errorf("port must be between 1 and 65535: %d", p.Port) + } + return nil +} + +func main() { + opt := &Opt{} + os.Exit(flagrun.Go( + opt, + flagrun.Version(version), + flagrun.Validator(opt.Validator), + )) +} +``` + +検証は `go-flags` によるパース成功後、`Run` メソッドの呼び出し前に実行されます。`flagrun.Go` / `flagrun.Check` / `flagrun.Ship` のいずれでも利用できます。 + ## オプション | `flagrun.Go` / `flagrun.Check` / `flagrun.Ship` では、以下の関数を使って動作をカスタマイズできます。 @@ -131,6 +173,7 @@ func main() { | `flagrun.Commit(commit string)` | コミットハッシュなどを指定します(デフォルト: `dev`)。 | | `flagrun.ArgsRequired()` | コマンドライン引数を必須にします。引数がない場合は UNKNOWN で終了します。 | | `flagrun.AlwaysStdout()` | `Run` の戻り値を、終了コードに関係なく標準出力へ出力します。`flagrun.Check` では常に標準出力へ出力されるため、このオプションは不要です。 | +| `flagrun.Validator(validator func([]string) error)` | パース後の追加検証を行う関数を指定します。エラー時は UNKNOWN で終了します。 | ## 終了コード diff --git a/flagrun.go b/flagrun.go index 8dc8b66..4ba1da1 100644 --- a/flagrun.go +++ b/flagrun.go @@ -41,6 +41,7 @@ type Flagrun struct { Version string Commit string AlwaysStdout bool + Validator func([]string) error } type FlagrunOptions func(*Flagrun) @@ -73,6 +74,12 @@ func AlwaysStdout() FlagrunOptions { } } +func Validator(validator func([]string) error) FlagrunOptions { + return func(f *Flagrun) { + f.Validator = validator + } +} + func printLine(w io.Writer, s string) error { if w == nil { return nil @@ -178,6 +185,14 @@ func (f *Flagrun) parseArgs(argv []string, stdout, stderr io.Writer, opt any) ([ psr.WriteHelp(stderr) return nil, nullint(UNKNOWN) } + + if f.Validator != nil { + if err := f.Validator(args); err != nil { + fmt.Fprintf(stderr, "%v\n", err) + return nil, nullint(UNKNOWN) + } + } + return args, nil } diff --git a/flagrun_shipper_test.go b/flagrun_shipper_test.go index fd88aec..b553b86 100644 --- a/flagrun_shipper_test.go +++ b/flagrun_shipper_test.go @@ -2,6 +2,7 @@ package flagrun import ( "bytes" + "fmt" "os" "testing" @@ -10,6 +11,7 @@ import ( type testShipper struct { Version bool `short:"v" long:"version" description:"Show version"` + Valid bool `short:"V" long:"valid" description:"Valid parameter"` ran bool } @@ -17,6 +19,13 @@ func (s *testShipper) Run(_ []string) { s.ran = true } +func (s *testShipper) Validator(_ []string) error { + if !s.Valid { + return fmt.Errorf("Valid parameter is not set") + } + return nil +} + func TestInternalShipper(t *testing.T) { f := buildFlagrun() o := &testShipper{} @@ -63,3 +72,14 @@ func TestShip(t *testing.T) { assert.Equal(t, OK, code) assert.True(t, o.ran) } + +func TestInternalShipperValidator(t *testing.T) { + o := &testShipper{} + f := buildFlagrun(Validator(o.Validator)) + var stdout bytes.Buffer + var stderr bytes.Buffer + code := f.internalShipper([]string{}, &stdout, &stderr, o) + + assert.Equal(t, UNKNOWN, code) + assert.Contains(t, stderr.String(), "Valid parameter is not set") +} diff --git a/go.mod b/go.mod index de59621..874d385 100644 --- a/go.mod +++ b/go.mod @@ -2,12 +2,13 @@ module github.com/monitoring-forge/flagrun go 1.25.0 -require github.com/jessevdk/go-flags v1.6.1 - -require go.yaml.in/yaml/v3 v3.0.5 // indirect - require ( + github.com/jessevdk/go-flags v1.6.1 github.com/mackerelio/checkers v0.2.1 github.com/stretchr/testify v1.12.1 +) + +require ( + go.yaml.in/yaml/v3 v3.0.5 // indirect golang.org/x/sys v0.47.0 // indirect )