Skip to content

Commit 7aae6e9

Browse files
committed
feat: add docs history shortcuts
Add docs +history-list, +history-revert, and +history-revert-status backed by docs_ai history OpenAPI endpoints. Document the safe history workflow and extend dry-run/live E2E coverage for the new shortcuts.
1 parent 3595356 commit 7aae6e9

11 files changed

Lines changed: 1021 additions & 52 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ Thumbs.db
2727
# Go
2828
docs/ref
2929
docs/
30+
!tests/cli_e2e/docs/
31+
!tests/cli_e2e/docs/*.go
32+
!tests/cli_e2e/docs/*.md
3033
vendor/
3134

3235

cmd/api/api_test.go

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,28 @@ import (
2020
"github.com/spf13/cobra"
2121
)
2222

23+
func newTestApiCmd(f *cmdutil.Factory, runF func(*APIOptions) error) *cobra.Command {
24+
cmd := NewCmdApi(f, runF)
25+
cmd.SilenceErrors = true
26+
cmd.SilenceUsage = true
27+
return cmd
28+
}
29+
30+
func newTestRootCmd() *cobra.Command {
31+
return &cobra.Command{
32+
Use: "lark-cli",
33+
SilenceErrors: true,
34+
SilenceUsage: true,
35+
}
36+
}
37+
2338
func TestApiCmd_FlagParsing(t *testing.T) {
2439
f, _, _, _ := cmdutil.TestFactory(t, &core.CliConfig{
2540
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
2641
})
2742

2843
var gotOpts *APIOptions
29-
cmd := NewCmdApi(f, func(opts *APIOptions) error {
44+
cmd := newTestApiCmd(f, func(opts *APIOptions) error {
3045
gotOpts = opts
3146
return nil
3247
})
@@ -54,7 +69,7 @@ func TestApiCmd_DryRun(t *testing.T) {
5469
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
5570
})
5671

57-
cmd := NewCmdApi(f, nil)
72+
cmd := newTestApiCmd(f, nil)
5873
cmd.SetArgs([]string{"GET", "/open-apis/test", "--as", "bot", "--dry-run"})
5974
err := cmd.Execute()
6075
if err != nil {
@@ -77,7 +92,7 @@ func TestApiCmd_NullParamsWithPageSize(t *testing.T) {
7792
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
7893
})
7994

80-
cmd := NewCmdApi(f, nil)
95+
cmd := newTestApiCmd(f, nil)
8196
cmd.SetArgs([]string{"GET", "/open-apis/test", "--params", "null", "--page-size", "50", "--as", "bot", "--dry-run"})
8297
if err := cmd.Execute(); err != nil {
8398
t.Fatalf("--params null with --page-size should not error, got: %v", err)
@@ -98,7 +113,7 @@ func TestApiCmd_BotMode(t *testing.T) {
98113
Body: map[string]interface{}{"code": 0, "msg": "ok", "data": map[string]interface{}{"result": "success"}},
99114
})
100115

101-
cmd := NewCmdApi(f, nil)
116+
cmd := newTestApiCmd(f, nil)
102117
cmd.SetArgs([]string{"GET", "/open-apis/test", "--as", "bot"})
103118
err := cmd.Execute()
104119
if err != nil {
@@ -125,7 +140,7 @@ func TestApiCmd_MissingArgs(t *testing.T) {
125140
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
126141
})
127142

128-
cmd := NewCmdApi(f, nil)
143+
cmd := newTestApiCmd(f, nil)
129144
cmd.SetArgs([]string{"GET"}) // missing path
130145
err := cmd.Execute()
131146
if err == nil {
@@ -138,7 +153,7 @@ func TestApiCmd_InvalidParamsJSON(t *testing.T) {
138153
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
139154
})
140155

141-
cmd := NewCmdApi(f, nil)
156+
cmd := newTestApiCmd(f, nil)
142157
cmd.SetArgs([]string{"GET", "/open-apis/test", "--as", "bot", "--params", "{bad"})
143158
err := cmd.Execute()
144159
if err == nil {
@@ -151,7 +166,7 @@ func TestApiValidArgsFunction(t *testing.T) {
151166
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
152167
})
153168

154-
cmd := NewCmdApi(f, nil)
169+
cmd := newTestApiCmd(f, nil)
155170
fn := cmd.ValidArgsFunction
156171

157172
tests := []struct {
@@ -217,7 +232,7 @@ func TestNewCmdApi_StrictModeHidesAsFlag(t *testing.T) {
217232
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu, SupportedIdentities: 2,
218233
})
219234

220-
cmd := NewCmdApi(f, nil)
235+
cmd := newTestApiCmd(f, nil)
221236
flag := cmd.Flags().Lookup("as")
222237
if flag == nil {
223238
t.Fatal("expected --as flag to be registered")
@@ -236,7 +251,7 @@ func TestApiCmd_PageLimitDefault(t *testing.T) {
236251
})
237252

238253
var gotOpts *APIOptions
239-
cmd := NewCmdApi(f, func(opts *APIOptions) error {
254+
cmd := newTestApiCmd(f, func(opts *APIOptions) error {
240255
gotOpts = opts
241256
return nil
242257
})
@@ -255,7 +270,7 @@ func TestApiCmd_ParamsAndDataBothStdinConflict(t *testing.T) {
255270
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
256271
})
257272

258-
cmd := NewCmdApi(f, nil)
273+
cmd := newTestApiCmd(f, nil)
259274
cmd.SetArgs([]string{"POST", "/open-apis/test", "--as", "bot", "--params", "-", "--data", "-"})
260275
err := cmd.Execute()
261276
if err == nil {
@@ -272,7 +287,7 @@ func TestApiCmd_OutputAndPageAllConflict(t *testing.T) {
272287
})
273288

274289
var gotOpts *APIOptions
275-
cmd := NewCmdApi(f, func(opts *APIOptions) error {
290+
cmd := newTestApiCmd(f, func(opts *APIOptions) error {
276291
gotOpts = opts
277292
return apiRun(opts)
278293
})
@@ -297,7 +312,7 @@ func TestApiCmd_BinaryResponse_AutoSave(t *testing.T) {
297312
ContentType: "application/octet-stream",
298313
})
299314

300-
cmd := NewCmdApi(f, nil)
315+
cmd := newTestApiCmd(f, nil)
301316
cmd.SetArgs([]string{"GET", "/open-apis/drive/v1/files/xxx/download", "--as", "bot"})
302317
err := cmd.Execute()
303318
if err != nil {
@@ -328,7 +343,7 @@ func TestApiCmd_PageAll_NonBatchAPI_FallbackToJSON(t *testing.T) {
328343
},
329344
})
330345

331-
cmd := NewCmdApi(f, nil)
346+
cmd := newTestApiCmd(f, nil)
332347
cmd.SetArgs([]string{"GET", "/open-apis/contact/v3/users/u123", "--as", "bot", "--page-all", "--format", "ndjson"})
333348
err := cmd.Execute()
334349
if err != nil {
@@ -368,7 +383,7 @@ func TestApiCmd_PageAll_NonBatchAPI_ErrorStillOutputsJSON(t *testing.T) {
368383
},
369384
})
370385

371-
cmd := NewCmdApi(f, nil)
386+
cmd := newTestApiCmd(f, nil)
372387
cmd.SetArgs([]string{"GET", "/open-apis/im/v1/chats/oc_xxx/announcement", "--as", "bot", "--page-all"})
373388
err := cmd.Execute()
374389
// Should return an error
@@ -409,7 +424,7 @@ func TestApiCmd_PageAll_BatchAPI_StreamsItems(t *testing.T) {
409424
},
410425
})
411426

412-
cmd := NewCmdApi(f, nil)
427+
cmd := newTestApiCmd(f, nil)
413428
cmd.SetArgs([]string{"GET", "/open-apis/contact/v3/users", "--as", "bot", "--page-all", "--format", "ndjson"})
414429
err := cmd.Execute()
415430
if err != nil {
@@ -448,7 +463,7 @@ func TestApiCmd_PageAll_StreamBusinessErrorDoesNotDumpJSON(t *testing.T) {
448463
},
449464
})
450465

451-
cmd := NewCmdApi(f, nil)
466+
cmd := newTestApiCmd(f, nil)
452467
cmd.SetArgs([]string{"GET", "/open-apis/contact/v3/users", "--as", "bot", "--page-all", "--format", "ndjson"})
453468
err := cmd.Execute()
454469
if err == nil {
@@ -483,7 +498,7 @@ func TestApiCmd_PageAll_BatchAPI_DefaultJSONEnvelope(t *testing.T) {
483498
},
484499
})
485500

486-
cmd := NewCmdApi(f, nil)
501+
cmd := newTestApiCmd(f, nil)
487502
cmd.SetArgs([]string{"GET", "/open-apis/contact/v3/users", "--as", "bot", "--page-all"})
488503
if err := cmd.Execute(); err != nil {
489504
t.Fatalf("unexpected error: %v", err)
@@ -549,8 +564,8 @@ func TestApiCmd_PageAll_DefaultJSONRunsContentSafety(t *testing.T) {
549564
},
550565
})
551566

552-
root := &cobra.Command{Use: "lark-cli"}
553-
root.AddCommand(NewCmdApi(f, nil))
567+
root := newTestRootCmd()
568+
root.AddCommand(newTestApiCmd(f, nil))
554569
root.SetArgs([]string{"api", "GET", "/open-apis/contact/v3/users", "--as", "bot", "--page-all"})
555570
if err := root.Execute(); err != nil {
556571
t.Fatalf("unexpected error: %v", err)
@@ -600,8 +615,8 @@ func TestApiCmd_PageAll_StreamFormatRunsContentSafety(t *testing.T) {
600615
},
601616
})
602617

603-
root := &cobra.Command{Use: "lark-cli"}
604-
root.AddCommand(NewCmdApi(f, nil))
618+
root := newTestRootCmd()
619+
root.AddCommand(newTestApiCmd(f, nil))
605620
root.SetArgs([]string{"api", "GET", "/open-apis/contact/v3/users", "--as", "bot", "--page-all", "--format", "ndjson"})
606621
if err := root.Execute(); err != nil {
607622
t.Fatalf("unexpected error: %v", err)
@@ -656,8 +671,8 @@ func TestApiCmd_PageAll_StreamFormatBlockSkipsBlockedPage(t *testing.T) {
656671
},
657672
})
658673

659-
root := &cobra.Command{Use: "lark-cli"}
660-
root.AddCommand(NewCmdApi(f, nil))
674+
root := newTestRootCmd()
675+
root.AddCommand(newTestApiCmd(f, nil))
661676
root.SetArgs([]string{"api", "GET", "/open-apis/contact/v3/users", "--as", "bot", "--page-all", "--format", "ndjson"})
662677
err := root.Execute()
663678
if err == nil {
@@ -721,7 +736,7 @@ func TestApiCmd_JqFlag_Parsing(t *testing.T) {
721736
})
722737

723738
var gotOpts *APIOptions
724-
cmd := NewCmdApi(f, func(opts *APIOptions) error {
739+
cmd := newTestApiCmd(f, func(opts *APIOptions) error {
725740
gotOpts = opts
726741
return nil
727742
})
@@ -741,7 +756,7 @@ func TestApiCmd_JqFlag_ShortForm(t *testing.T) {
741756
})
742757

743758
var gotOpts *APIOptions
744-
cmd := NewCmdApi(f, func(opts *APIOptions) error {
759+
cmd := newTestApiCmd(f, func(opts *APIOptions) error {
745760
gotOpts = opts
746761
return nil
747762
})
@@ -760,7 +775,7 @@ func TestApiCmd_JqAndOutputConflict(t *testing.T) {
760775
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
761776
})
762777

763-
cmd := NewCmdApi(f, func(opts *APIOptions) error {
778+
cmd := newTestApiCmd(f, func(opts *APIOptions) error {
764779
return apiRun(opts)
765780
})
766781
cmd.SetArgs([]string{"GET", "/open-apis/test", "--as", "bot", "--jq", ".data", "--output", "file.bin"})
@@ -791,7 +806,7 @@ func TestApiCmd_JqFilter_AppliesExpression(t *testing.T) {
791806
},
792807
})
793808

794-
cmd := NewCmdApi(f, nil)
809+
cmd := newTestApiCmd(f, nil)
795810
cmd.SetArgs([]string{"GET", "/open-apis/test/jq", "--as", "bot", "--jq", ".data.items[].name"})
796811
err := cmd.Execute()
797812
if err != nil {
@@ -812,7 +827,7 @@ func TestApiCmd_JqAndFormatConflict(t *testing.T) {
812827
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
813828
})
814829

815-
cmd := NewCmdApi(f, func(opts *APIOptions) error {
830+
cmd := newTestApiCmd(f, func(opts *APIOptions) error {
816831
return apiRun(opts)
817832
})
818833
cmd.SetArgs([]string{"GET", "/open-apis/test", "--as", "bot", "--jq", ".data", "--format", "ndjson"})
@@ -830,7 +845,7 @@ func TestApiCmd_JqInvalidExpression(t *testing.T) {
830845
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
831846
})
832847

833-
cmd := NewCmdApi(f, func(opts *APIOptions) error {
848+
cmd := newTestApiCmd(f, func(opts *APIOptions) error {
834849
return apiRun(opts)
835850
})
836851
cmd.SetArgs([]string{"GET", "/open-apis/test", "--as", "bot", "--jq", "invalid["})
@@ -859,7 +874,7 @@ func TestApiCmd_PageAll_WithJq(t *testing.T) {
859874
},
860875
})
861876

862-
cmd := NewCmdApi(f, nil)
877+
cmd := newTestApiCmd(f, nil)
863878
cmd.SetArgs([]string{"GET", "/open-apis/contact/v3/users", "--as", "bot", "--page-all", "--jq", ".data.items[].id"})
864879
err := cmd.Execute()
865880
if err != nil {
@@ -880,7 +895,7 @@ func TestApiCmd_MethodUppercase(t *testing.T) {
880895
})
881896

882897
var gotOpts *APIOptions
883-
cmd := NewCmdApi(f, func(opts *APIOptions) error {
898+
cmd := newTestApiCmd(f, func(opts *APIOptions) error {
884899
gotOpts = opts
885900
return nil
886901
})
@@ -899,7 +914,7 @@ func TestApiCmd_FileFlagParsing(t *testing.T) {
899914
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
900915
})
901916
var gotOpts *APIOptions
902-
cmd := NewCmdApi(f, func(opts *APIOptions) error {
917+
cmd := newTestApiCmd(f, func(opts *APIOptions) error {
903918
gotOpts = opts
904919
return nil
905920
})
@@ -917,7 +932,7 @@ func TestApiCmd_FileAndOutputConflict(t *testing.T) {
917932
f, _, _, _ := cmdutil.TestFactory(t, &core.CliConfig{
918933
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
919934
})
920-
cmd := NewCmdApi(f, func(opts *APIOptions) error {
935+
cmd := newTestApiCmd(f, func(opts *APIOptions) error {
921936
return apiRun(opts)
922937
})
923938
cmd.SetArgs([]string{"POST", "/open-apis/test", "--as", "bot", "--file", "photo.jpg", "--output", "out.json"})
@@ -934,7 +949,7 @@ func TestApiCmd_FileWithGET(t *testing.T) {
934949
f, _, _, _ := cmdutil.TestFactory(t, &core.CliConfig{
935950
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
936951
})
937-
cmd := NewCmdApi(f, func(opts *APIOptions) error {
952+
cmd := newTestApiCmd(f, func(opts *APIOptions) error {
938953
return apiRun(opts)
939954
})
940955
cmd.SetArgs([]string{"GET", "/open-apis/test", "--as", "bot", "--file", "photo.jpg"})
@@ -951,7 +966,7 @@ func TestApiCmd_FileStdinConflictWithData(t *testing.T) {
951966
f, _, _, _ := cmdutil.TestFactory(t, &core.CliConfig{
952967
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
953968
})
954-
cmd := NewCmdApi(f, func(opts *APIOptions) error {
969+
cmd := newTestApiCmd(f, func(opts *APIOptions) error {
955970
return apiRun(opts)
956971
})
957972
cmd.SetArgs([]string{"POST", "/open-apis/test", "--as", "bot", "--file", "-", "--data", "-"})
@@ -974,7 +989,7 @@ func TestApiCmd_DryRunWithFile(t *testing.T) {
974989
f, stdout, _, _ := cmdutil.TestFactory(t, &core.CliConfig{
975990
AppID: "test-app", AppSecret: "test-secret", Brand: core.BrandFeishu,
976991
})
977-
cmd := NewCmdApi(f, nil)
992+
cmd := newTestApiCmd(f, nil)
978993
cmd.SetArgs([]string{"POST", "/open-apis/im/v1/images", "--file", "image=" + tmpFile, "--data", `{"image_type":"message"}`, "--dry-run", "--as", "bot"})
979994
err := cmd.Execute()
980995
if err != nil {
@@ -1015,7 +1030,7 @@ func TestApiCmd_PermissionError_DerivesFirstClassFields(t *testing.T) {
10151030
},
10161031
})
10171032

1018-
cmd := NewCmdApi(f, nil)
1033+
cmd := newTestApiCmd(f, nil)
10191034
cmd.SetArgs([]string{"GET", "/open-apis/docx/v1/documents/test", "--as", "bot"})
10201035
err := cmd.Execute()
10211036
if err == nil {
@@ -1041,7 +1056,7 @@ func TestApiCmd_JsonFlag_Accepted(t *testing.T) {
10411056
})
10421057

10431058
var gotOpts *APIOptions
1044-
cmd := NewCmdApi(f, func(opts *APIOptions) error {
1059+
cmd := newTestApiCmd(f, func(opts *APIOptions) error {
10451060
gotOpts = opts
10461061
return nil
10471062
})

0 commit comments

Comments
 (0)