Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.0.1"
".": "0.1.0"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 236
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/increase%2Fincrease-57310f0e57b0996b79f938ef778b40e54f5b62cefb78c3e6405cefacfa704c66.yml
openapi_spec_hash: c6d65e9ebf76cb81a5395b8ab4251a95
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/increase%2Fincrease-c8283ca199163ab2079f2cafac18348f54e96e9049864f39cd7e89958e80db0d.yml
openapi_spec_hash: a4f32a1c462a8ad1380f6a7a1d7b75ec
config_hash: 4945e03affdf289484733306e4797f81
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Changelog

## 0.1.0 (2026-04-02)

Full Changelog: [v0.0.1...v0.1.0](https://github.com/Increase/increase-cli/compare/v0.0.1...v0.1.0)

### Features

* **api:** api update ([a75f6ba](https://github.com/Increase/increase-cli/commit/a75f6ba67337b21db18d53f3726b3be54047b6a5))
* **api:** api update ([b802215](https://github.com/Increase/increase-cli/commit/b802215033456369742d20124d3077a12e61bc8d))
* **api:** api update ([44a8c16](https://github.com/Increase/increase-cli/commit/44a8c166b0bc930afa2eba1e1244b468696bd5f6))
* **api:** api update ([b9c0732](https://github.com/Increase/increase-cli/commit/b9c073243aa91a766a7db4a604401f52f4431c38))
* binary-only parameters become CLI flags that take filenames only ([cc21dff](https://github.com/Increase/increase-cli/commit/cc21dffca52f9ff543a3a38555742a7ed3cd926a))


### Bug Fixes

* fix for off-by-one error in pagination logic ([d5b8428](https://github.com/Increase/increase-cli/commit/d5b842883d1201fef0db3f2adb768fddbf53c27f))
* handle empty data set using `--format explore` ([ff538ca](https://github.com/Increase/increase-cli/commit/ff538ca7d15fd6f362c169b2f89c3dc9e25a64bc))
* use `RawJSON` when iterating items with `--format explore` in the CLI ([67340d0](https://github.com/Increase/increase-cli/commit/67340d0d26af534f125883c29686fbc5f48470ad))


### Chores

* **internal:** codegen related update ([49ec4a1](https://github.com/Increase/increase-cli/commit/49ec4a16ff861bd0fa104c75a4d63bf40c506847))
* **internal:** codegen related update ([ec2fc1e](https://github.com/Increase/increase-cli/commit/ec2fc1e9a4e0510f30b06632e5f0ce3d6e1ef284))
* **tests:** bump steady to v0.20.1 ([9445bc1](https://github.com/Increase/increase-cli/commit/9445bc1d6dc5c611e1aa90d126e4340c3b62de45))
* **tests:** bump steady to v0.20.2 ([5a976f1](https://github.com/Increase/increase-cli/commit/5a976f142db86f917109f88b06bfd2fc7f0c6e1a))
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/Increase/increase-cli
go 1.25

require (
github.com/Increase/increase-go v0.524.0
github.com/Increase/increase-go v0.529.0
github.com/charmbracelet/bubbles v0.21.0
github.com/charmbracelet/bubbletea v1.3.6
github.com/charmbracelet/lipgloss v1.1.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/Increase/increase-go v0.524.0 h1:zTFXedEOuVxTBNV6LLXY5FaCYJrP1BGp1s0cuhLVZ68=
github.com/Increase/increase-go v0.524.0/go.mod h1:GOsK6Rh57nWpcfykcdHSIccIQJc7Fq0qitViNGbS4RM=
github.com/Increase/increase-go v0.529.0 h1:2br1Fa68WNRuesiP6m/gFZEihpdsCQEjKYoua7sLTP0=
github.com/Increase/increase-go v0.529.0/go.mod h1:GOsK6Rh57nWpcfykcdHSIccIQJc7Fq0qitViNGbS4RM=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
Expand Down
38 changes: 35 additions & 3 deletions internal/jsonview/explorer.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package jsonview

import (
"bytes"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -309,6 +310,10 @@ func ExploreJSON(title string, json gjson.Result) error {
return err
}

type hasRawJSON interface {
RawJSON() string
}

// ExploreJSONStream explores JSON data loaded incrementally via an iterator
func ExploreJSONStream[T any](title string, it Iterator[T]) error {
anyIt := genericToAnyIterator(it)
Expand All @@ -327,12 +332,12 @@ func ExploreJSONStream[T any](title string, it Iterator[T]) error {
return err
}

// Convert items to JSON array
jsonBytes, err := json.Marshal(items)
arrayJSONBytes, err := marshalItemsToJSONArray(items)
if err != nil {
return err
}
arrayJSON := gjson.ParseBytes(jsonBytes)

arrayJSON := gjson.ParseBytes(arrayJSONBytes)
view, err := newTableView("", arrayJSON, false)
if err != nil {
return err
Expand All @@ -352,6 +357,29 @@ func ExploreJSONStream[T any](title string, it Iterator[T]) error {
return err
}

func marshalItemsToJSONArray(items []any) ([]byte, error) {
var buf bytes.Buffer
buf.WriteByte('[')

for i, item := range items {
if i > 0 {
buf.WriteByte(',')
}
if hasRaw, ok := item.(hasRawJSON); ok {
buf.WriteString(hasRaw.RawJSON())
} else {
jsonData, err := json.Marshal(item)
if err != nil {
return nil, err
}
buf.Write(jsonData)
}
}

buf.WriteByte(']')
return buf.Bytes(), nil
}

func (v *JSONViewer) current() JSONView { return v.stack[len(v.stack)-1] }
func (v *JSONViewer) Init() tea.Cmd { return nil }

Expand Down Expand Up @@ -406,6 +434,10 @@ func (v *JSONViewer) navigateForward() (tea.Model, tea.Cmd) {
return v, nil
}

if len(tableView.rowData) < 1 {
return v, nil
}

cursor := tableView.table.Cursor()
selected := tableView.rowData[cursor]
if !v.canNavigateInto(selected) {
Expand Down
60 changes: 60 additions & 0 deletions internal/jsonview/explorer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package jsonview

import (
"testing"

"github.com/charmbracelet/bubbles/help"
"github.com/tidwall/gjson"

"github.com/stretchr/testify/require"
)

func TestNavigateForward_EmptyRowData(t *testing.T) {
// An empty JSON array produces a TableView with no rows.
emptyArray := gjson.Parse("[]")
view, err := newTableView("", emptyArray, false)
require.NoError(t, err)

viewer := &JSONViewer{
stack: []JSONView{view},
root: "test",
help: help.New(),
}

// Should return without panicking despite the empty data set.
model, cmd := viewer.navigateForward()
require.Equal(t, model, viewer, "expected same viewer model returned")
require.Nil(t, cmd)

// Stack should remain unchanged (no new view pushed).
require.Equal(t, 1, len(viewer.stack), "expected stack length 1, got %d", len(viewer.stack))
}

// rawJSONItem implements HasRawJSON, returning pre-built JSON.
type rawJSONItem struct {
raw string
}

func (r rawJSONItem) RawJSON() string { return r.raw }

func TestMarshalItemsToJSONArray_WithHasRawJSON(t *testing.T) {
items := []any{
rawJSONItem{raw: `{"id":1,"name":"alice"}`},
rawJSONItem{raw: `{"id":2,"name":"bob"}`},
}

got, err := marshalItemsToJSONArray(items)
require.NoError(t, err)
require.JSONEq(t, `[{"id":1,"name":"alice"},{"id":2,"name":"bob"}]`, string(got))
}

func TestMarshalItemsToJSONArray_WithoutHasRawJSON(t *testing.T) {
items := []any{
map[string]any{"id": 1, "name": "alice"},
map[string]any{"id": 2, "name": "bob"},
}

got, err := marshalItemsToJSONArray(items)
require.NoError(t, err)
require.JSONEq(t, `[{"id":1,"name":"alice"},{"id":2,"name":"bob"}]`, string(got))
}
10 changes: 10 additions & 0 deletions internal/requestflag/requestflag.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ type Flag[
// parameters.
Const bool

// FileInput, when true, indicates that the flag value is always treated as a file path. The file is read
// automatically without requiring the "@" prefix. This is used for parameters with `type: string, format:
// binary` in the OpenAPI spec.
FileInput bool

// unexported fields for internal use
count int // number of times the flag has been set
hasBeenSet bool // whether the flag has been set from env or file
Expand All @@ -59,6 +64,7 @@ type InRequest interface {
GetHeaderPath() string
GetBodyPath() string
IsBodyRoot() bool
IsFileInput() bool
}

func (f Flag[T]) GetQueryPath() string {
Expand All @@ -77,6 +83,10 @@ func (f Flag[T]) IsBodyRoot() bool {
return f.BodyRoot
}

func (f Flag[T]) IsFileInput() bool {
return f.FileInput
}

// The values that will be sent in different parts of a request.
type RequestContents struct {
Queries map[string]any
Expand Down
6 changes: 3 additions & 3 deletions pkg/cmd/cmdutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ func countTerminalLines(data []byte, terminalWidth int) int {
return bytes.Count([]byte(wrap.String(string(data), terminalWidth)), []byte("\n"))
}

type HasRawJSON interface {
type hasRawJSON interface {
RawJSON() string
}

Expand All @@ -413,7 +413,7 @@ func ShowJSONIterator[T any](stdout *os.File, title string, iter jsonview.Iterat
for itemsToDisplay != 0 && iter.Next() {
item := iter.Current()
var obj gjson.Result
if hasRaw, ok := any(item).(HasRawJSON); ok {
if hasRaw, ok := any(item).(hasRawJSON); ok {
obj = gjson.Parse(hasRaw.RawJSON())
} else {
jsonData, err := json.Marshal(item)
Expand Down Expand Up @@ -460,7 +460,7 @@ func ShowJSONIterator[T any](stdout *os.File, title string, iter jsonview.Iterat
}
item := iter.Current()
var obj gjson.Result
if hasRaw, ok := any(item).(HasRawJSON); ok {
if hasRaw, ok := any(item).(hasRawJSON); ok {
obj = gjson.Parse(hasRaw.RawJSON())
} else {
jsonData, err := json.Marshal(item)
Expand Down
9 changes: 5 additions & 4 deletions pkg/cmd/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ var filesCreate = cli.Command{
Suggest: true,
Flags: []cli.Flag{
&requestflag.Flag[string]{
Name: "file",
Usage: "The file contents. This should follow the specifications of [RFC 7578](https://datatracker.ietf.org/doc/html/rfc7578) which defines file transfers for the multipart/form-data protocol.",
Required: true,
BodyPath: "file",
Name: "file",
Usage: "The file contents. This should follow the specifications of [RFC 7578](https://datatracker.ietf.org/doc/html/rfc7578) which defines file transfers for the multipart/form-data protocol.",
Required: true,
BodyPath: "file",
FileInput: true,
},
&requestflag.Flag[string]{
Name: "purpose",
Expand Down
10 changes: 7 additions & 3 deletions pkg/cmd/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package cmd

import (
"strings"
"testing"

"github.com/Increase/increase-cli/internal/mocktest"
Expand All @@ -15,18 +16,21 @@ func TestFilesCreate(t *testing.T) {
t,
"--api-key", "string",
"files", "create",
"--file", "Example data",
"--file", mocktest.TestFile(t, "Example data"),
"--purpose", "check_image_front",
"--description", "x",
)
})

t.Run("piping data", func(t *testing.T) {
testFile := mocktest.TestFile(t, "Example data")
// Test piping YAML data over stdin
pipeData := []byte("" +
pipeDataStr := "" +
"file: Example data\n" +
"purpose: check_image_front\n" +
"description: x\n")
"description: x\n"
pipeDataStr = strings.ReplaceAll(pipeDataStr, "Example data", testFile)
pipeData := []byte(pipeDataStr)
mocktest.TestRunMockTestWithPipeAndFlags(
t, pipeData,
"--api-key", "string",
Expand Down
Loading
Loading