From f28435efddcbfe1ab1ae8690d88df7d15ff729e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Bustarret?= Date: Fri, 6 Feb 2026 10:25:06 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(input):=20send=20a=20raw=20JSO?= =?UTF-8?q?N=20document?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++++++ cmd/helpers_test.go | 2 +- cmd/oapi_test.go | 7 +++++++ main.go | 2 +- pkg/runner/runner.go | 21 +++++++++++++++++---- 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3e148c1..5520116 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,12 @@ Commands may be chained, and attributes returned by a command can be reinjected gli oapi CreateNic --SubnetId subnet-foo | gli oapi LinkNic -v --NicId {{.Nic.NicId}} --VmId i-foo --DeviceNumber 7 ``` +### Sending raw JSON + +```shell +echo '{"SubnetId":"subnet-foo"}' | gli oapi CreateNic +``` + ### Using jq filters ```shell diff --git a/cmd/helpers_test.go b/cmd/helpers_test.go index 281bc3d..b2111d4 100644 --- a/cmd/helpers_test.go +++ b/cmd/helpers_test.go @@ -31,7 +31,7 @@ func run(t *testing.T, args []string, input []byte) []byte { os.Stdout, err = os.Create(filepath.Join(dir, "stdout")) //nolint require.NoError(t, err) - err = runner.Prefilter() + err = runner.CheckStdin() require.NoError(t, err) cmd.Execute() diff --git a/cmd/oapi_test.go b/cmd/oapi_test.go index cd4fefe..e8182c0 100644 --- a/cmd/oapi_test.go +++ b/cmd/oapi_test.go @@ -34,4 +34,11 @@ func TestOAPI(t *testing.T) { require.NotNil(t, resp.Subnet) assert.NotEmpty(t, resp.Subnet.SubnetId) }) + t.Run("JSON can be injected", func(t *testing.T) { + in := `{"IpRange":"10.0.0.0/16"}` + resp := osc.CreateNetResponse{} + runJSON(t, []string{"oapi", "CreateNet"}, []byte(in), &resp) + require.NotNil(t, resp.Net) + assert.NotEmpty(t, resp.Net.NetId) + }) } diff --git a/main.go b/main.go index b36912d..2870eb5 100644 --- a/main.go +++ b/main.go @@ -12,7 +12,7 @@ import ( ) func main() { - err := runner.Prefilter() + err := runner.CheckStdin() if err != nil { errors.ExitErr(err) } diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index 9b68abb..5686bfe 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -23,16 +23,24 @@ import ( "github.com/spf13/pflag" ) -var Input []byte +var ( + stdinChecked bool + stdin []byte +) + +func Stdin() ([]byte, bool) { + return stdin, stdinChecked && len(stdin) > 0 +} -func Prefilter() error { +func CheckStdin() error { + stdinChecked = true if isatty.IsTerminal(os.Stdin.Fd()) { debug.Println("terminal, skipping stdin") return nil } debug.Println("reading stdin") var err error - Input, err = io.ReadAll(os.Stdin) + stdin, err = io.ReadAll(os.Stdin) if err != nil { return fmt.Errorf("unable to read stdin: %w", err) } @@ -43,7 +51,7 @@ func Prefilter() error { } debug.Println("templating args") var input map[string]any - err = json.Unmarshal(Input, &input) + err = json.Unmarshal(stdin, &input) if err != nil { return fmt.Errorf("input is not a JSON object: %w", err) } @@ -73,14 +81,19 @@ func ToStruct(cmd *cobra.Command, arg reflect.Value, prefix string) error { fs := cmd.Flags() debug.Println(reflect.Indirect(arg).Type().Name()) var err error + noneset := true fs.VisitAll(func(f *pflag.Flag) { if f.Changed { // skipping default values + noneset = false debug.Println(f.Name, "=>", f.Value) if serr := set(arg, fs, f.Name, f.Name); serr != nil { err = serr } } }) + if stdin, ok := Stdin(); ok && noneset { + err = json.Unmarshal(stdin, arg.Interface()) + } return err }