Skip to content
Merged
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
6 changes: 3 additions & 3 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,20 @@ linters:
- forbidigo
# errs-typed-only enforced on paths already migrated to errs.NewXxxError.
# Add a path when its migration is complete.
- path-except: (internal/auth/|internal/errcompat/|internal/errclass/|internal/client/|internal/cmdutil/factory\.go|cmd/auth/|cmd/config/|cmd/service/|shortcuts/common/mcp_client\.go|shortcuts/base/|shortcuts/calendar/|shortcuts/contact/|shortcuts/doc/|shortcuts/drive/|shortcuts/im/|shortcuts/mail/|shortcuts/minutes/|shortcuts/okr/|shortcuts/task/|shortcuts/vc/|shortcuts/whiteboard/|internal/event/consume/|cmd/event/|events/|shortcuts/event/)
- path-except: (internal/auth/|internal/errcompat/|internal/errclass/|internal/client/|internal/cmdutil/factory\.go|cmd/auth/|cmd/config/|cmd/service/|shortcuts/common/mcp_client\.go|shortcuts/base/|shortcuts/calendar/|shortcuts/contact/|shortcuts/doc/|shortcuts/drive/|shortcuts/im/|shortcuts/mail/|shortcuts/minutes/|shortcuts/okr/|shortcuts/sheets/|shortcuts/task/|shortcuts/vc/|shortcuts/whiteboard/|internal/event/consume/|cmd/event/|events/|shortcuts/event/)
text: errs-typed-only
linters:
- forbidigo
# errs-no-bare-wrap enforced on paths fully migrated to typed final
# errors. Scoped separately from errs-typed-only because cmd/auth/,
# cmd/config/ still have residual fmt.Errorf and must not be caught.
- path-except: (shortcuts/base/|shortcuts/calendar/|shortcuts/contact/|shortcuts/doc/|shortcuts/drive/|shortcuts/im/|shortcuts/mail/|shortcuts/minutes/|shortcuts/okr/|shortcuts/task/|shortcuts/vc/|shortcuts/whiteboard/|shortcuts/common/mcp_client\.go|cmd/event/|events/|shortcuts/event/)
- path-except: (shortcuts/base/|shortcuts/calendar/|shortcuts/contact/|shortcuts/doc/|shortcuts/drive/|shortcuts/im/|shortcuts/mail/|shortcuts/minutes/|shortcuts/okr/|shortcuts/sheets/|shortcuts/task/|shortcuts/vc/|shortcuts/whiteboard/|shortcuts/common/mcp_client\.go|cmd/event/|events/|shortcuts/event/)
text: errs-no-bare-wrap
linters:
- forbidigo
# errs-no-legacy-helper enforced on domains whose shared validation/save
# helpers have migrated to typed final errors.
- path-except: (shortcuts/base/|shortcuts/calendar/|shortcuts/contact/|shortcuts/doc/|shortcuts/drive/|shortcuts/im/|shortcuts/mail/|shortcuts/minutes/|shortcuts/okr/|shortcuts/task/|shortcuts/vc/|shortcuts/whiteboard/|cmd/event/|events/|shortcuts/event/)
- path-except: (shortcuts/base/|shortcuts/calendar/|shortcuts/contact/|shortcuts/doc/|shortcuts/drive/|shortcuts/im/|shortcuts/mail/|shortcuts/minutes/|shortcuts/okr/|shortcuts/sheets/|shortcuts/task/|shortcuts/vc/|shortcuts/whiteboard/|cmd/event/|events/|shortcuts/event/)
text: errs-no-legacy-helper
linters:
- forbidigo
Expand Down
1 change: 1 addition & 0 deletions lint/errscontract/rule_no_legacy_common_helper_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var migratedCommonHelperPaths = []string{
"shortcuts/mail/",
"shortcuts/minutes/",
"shortcuts/okr/",
"shortcuts/sheets/",
"shortcuts/task/",
"shortcuts/vc/",
"shortcuts/whiteboard/",
Expand Down
1 change: 1 addition & 0 deletions lint/errscontract/rule_no_legacy_envelope_literal.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var migratedEnvelopePaths = []string{
"shortcuts/mail/",
"shortcuts/minutes/",
"shortcuts/okr/",
"shortcuts/sheets/",
"shortcuts/task/",
"shortcuts/vc/",
"shortcuts/whiteboard/",
Expand Down
18 changes: 18 additions & 0 deletions lint/errscontract/rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,7 @@ func TestCheckNoLegacyCommonHelperCall_RejectsLegacyHelpersOnMigratedPath(t *tes
"shortcuts/drive/drive_search.go",
"shortcuts/mail/mail_send.go",
"shortcuts/okr/okr_progress_create.go",
"shortcuts/sheets/helpers.go",
"shortcuts/task/task_update.go",
"shortcuts/whiteboard/whiteboard_query.go",
}
Expand Down Expand Up @@ -1021,6 +1022,23 @@ func boom() {
}
}

func TestCheckNoLegacyCommonHelperCall_CoversSheetsPathWithAliasAndFunctionValue(t *testing.T) {
src := `package migrated

import c "github.com/larksuite/cli/shortcuts/common"

func boom() {
f := c.FlagErrorf
_ = f
c.WrapInputStatError(nil)
}
`
v := CheckNoLegacyCommonHelperCall("shortcuts/sheets/helpers.go", src)
if len(v) != 2 {
t.Fatalf("expected 2 violations for aliased/function-value legacy helpers on sheets path, got %d: %+v", len(v), v)
}
}

func TestCheckNoLegacyCommonHelperCall_AllowsNonMigratedPath(t *testing.T) {
src := `package contact

Expand Down
14 changes: 7 additions & 7 deletions shortcuts/sheets/backward/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"strconv"
"strings"

"github.com/larksuite/cli/internal/output"
"github.com/larksuite/cli/errs"
"github.com/larksuite/cli/internal/validate"
"github.com/larksuite/cli/shortcuts/common"
)
Expand All @@ -27,7 +27,7 @@

// getFirstSheetID queries the spreadsheet and returns the first sheet's ID.
func getFirstSheetID(runtime *common.RuntimeContext, spreadsheetToken string) (string, error) {
data, err := runtime.CallAPI("GET", fmt.Sprintf("/open-apis/sheets/v3/spreadsheets/%s/sheets/query", validate.EncodePathSegment(spreadsheetToken)), nil, nil)
data, err := runtime.CallAPITyped("GET", fmt.Sprintf("/open-apis/sheets/v3/spreadsheets/%s/sheets/query", validate.EncodePathSegment(spreadsheetToken)), nil, nil)

Check warning on line 30 in shortcuts/sheets/backward/helpers.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/sheets/backward/helpers.go#L30

Added line #L30 was not covered by tests
if err != nil {
return "", err
}
Expand All @@ -38,7 +38,7 @@
return id, nil
}
}
return "", output.Errorf(output.ExitAPI, "not_found", "no sheets found in this spreadsheet")
return "", errs.NewValidationError(errs.SubtypeFailedPrecondition, "no sheets found in this spreadsheet")

Check warning on line 41 in shortcuts/sheets/backward/helpers.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/sheets/backward/helpers.go#L41

Added line #L41 was not covered by tests
}

// extractSpreadsheetToken extracts spreadsheet token from URL.
Expand Down Expand Up @@ -104,7 +104,7 @@
return nil
}
if looksLikeRelativeRange(input) {
return common.FlagErrorf("--range %q requires --sheet-id or a <sheetId>! prefix", input)
return common.ValidationErrorf("--range %q requires --sheet-id or a <sheetId>! prefix", input).WithParam("--range")
}
return nil
}
Expand All @@ -127,7 +127,7 @@
if strings.EqualFold(parts[0], parts[1]) {
return nil
}
return common.FlagErrorf("--range %q must be a single cell (e.g. A1 or A1:A1), got a multi-cell span", input)
return common.ValidationErrorf("--range %q must be a single cell (e.g. A1 or A1:A1), got a multi-cell span", input).WithParam("--range")
}
return nil
}
Expand Down Expand Up @@ -197,11 +197,11 @@
func offsetCell(cell string, rowOffset, colOffset int) (string, error) {
matches := cellRefPattern.FindStringSubmatch(strings.TrimSpace(cell))
if len(matches) != 3 {
return "", fmt.Errorf("invalid cell reference: %s", cell)
return "", fmt.Errorf("invalid cell reference: %s", cell) //nolint:forbidigo // intermediate sentinel; sole caller buildRectRange discards it and falls back

Check warning on line 200 in shortcuts/sheets/backward/helpers.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/sheets/backward/helpers.go#L200

Added line #L200 was not covered by tests
}
colIndex := columnNameToIndex(matches[1])
if colIndex < 1 {
return "", fmt.Errorf("invalid column: %s", matches[1])
return "", fmt.Errorf("invalid column: %s", matches[1]) //nolint:forbidigo // intermediate sentinel; sole caller buildRectRange discards it and falls back

Check warning on line 204 in shortcuts/sheets/backward/helpers.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/sheets/backward/helpers.go#L204

Added line #L204 was not covered by tests
}
rowIndex, err := strconv.Atoi(matches[2])
if err != nil {
Expand Down
21 changes: 11 additions & 10 deletions shortcuts/sheets/backward/lark_sheets_cell_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@
"encoding/json"
"fmt"

"github.com/larksuite/cli/errs"
"github.com/larksuite/cli/internal/validate"
"github.com/larksuite/cli/shortcuts/common"
)

func parseValues2DJSON(raw string) ([][]interface{}, error) {
var rows [][]interface{}
if err := json.Unmarshal([]byte(raw), &rows); err != nil {
return nil, common.FlagErrorf("--values invalid JSON, must be a 2D array")
return nil, errs.NewValidationError(errs.SubtypeInvalidArgument, "--values invalid JSON, must be a 2D array").WithParam("--values")
}
if rows == nil {
return nil, common.FlagErrorf("--values invalid JSON, must be a 2D array")
return nil, errs.NewValidationError(errs.SubtypeInvalidArgument, "--values invalid JSON, must be a 2D array").WithParam("--values")
}
return rows, nil
}
Expand Down Expand Up @@ -46,7 +47,7 @@
}
if r := runtime.Str("range"); r != "" {
if rangeSheetID, _, ok := splitSheetRange(r); ok && runtime.Str("sheet-id") != "" && rangeSheetID != runtime.Str("sheet-id") {
return common.FlagErrorf("--range sheet ID %q does not match --sheet-id %q", rangeSheetID, runtime.Str("sheet-id"))
return errs.NewValidationError(errs.SubtypeInvalidArgument, "--range sheet ID %q does not match --sheet-id %q", rangeSheetID, runtime.Str("sheet-id")).WithParam("--range")

Check warning on line 50 in shortcuts/sheets/backward/lark_sheets_cell_data.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/sheets/backward/lark_sheets_cell_data.go#L50

Added line #L50 was not covered by tests
}
}
return nil
Expand Down Expand Up @@ -90,7 +91,7 @@
params["valueRenderOption"] = renderOption
}

data, err := runtime.CallAPI("GET", fmt.Sprintf("/open-apis/sheets/v2/spreadsheets/%s/values/%s", validate.EncodePathSegment(token), validate.EncodePathSegment(readRange)), params, nil)
data, err := runtime.CallAPITyped("GET", fmt.Sprintf("/open-apis/sheets/v2/spreadsheets/%s/values/%s", validate.EncodePathSegment(token), validate.EncodePathSegment(readRange)), params, nil)

Check warning on line 94 in shortcuts/sheets/backward/lark_sheets_cell_data.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/sheets/backward/lark_sheets_cell_data.go#L94

Added line #L94 was not covered by tests
if err != nil {
return err
}
Expand Down Expand Up @@ -167,7 +168,7 @@
writeRange = normalizeWriteRange(runtime.Str("sheet-id"), writeRange, values)
}

data, err := runtime.CallAPI("PUT", fmt.Sprintf("/open-apis/sheets/v2/spreadsheets/%s/values", validate.EncodePathSegment(token)), nil, map[string]interface{}{
data, err := runtime.CallAPITyped("PUT", fmt.Sprintf("/open-apis/sheets/v2/spreadsheets/%s/values", validate.EncodePathSegment(token)), nil, map[string]interface{}{

Check warning on line 171 in shortcuts/sheets/backward/lark_sheets_cell_data.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/sheets/backward/lark_sheets_cell_data.go#L171

Added line #L171 was not covered by tests
"valueRange": map[string]interface{}{
"range": writeRange,
"values": values,
Expand Down Expand Up @@ -247,7 +248,7 @@
appendRange = normalizePointRange(runtime.Str("sheet-id"), appendRange)
}

data, err := runtime.CallAPI("POST", fmt.Sprintf("/open-apis/sheets/v2/spreadsheets/%s/values_append", validate.EncodePathSegment(token)), nil, map[string]interface{}{
data, err := runtime.CallAPITyped("POST", fmt.Sprintf("/open-apis/sheets/v2/spreadsheets/%s/values_append", validate.EncodePathSegment(token)), nil, map[string]interface{}{

Check warning on line 251 in shortcuts/sheets/backward/lark_sheets_cell_data.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/sheets/backward/lark_sheets_cell_data.go#L251

Added line #L251 was not covered by tests
"valueRange": map[string]interface{}{
"range": appendRange,
"values": values,
Expand Down Expand Up @@ -288,7 +289,7 @@
}
if r := runtime.Str("range"); r != "" {
if rangeSheetID, _, ok := splitSheetRange(r); ok && runtime.Str("sheet-id") != "" && rangeSheetID != runtime.Str("sheet-id") {
return common.FlagErrorf("--range sheet ID %q does not match --sheet-id %q", rangeSheetID, runtime.Str("sheet-id"))
return errs.NewValidationError(errs.SubtypeInvalidArgument, "--range sheet ID %q does not match --sheet-id %q", rangeSheetID, runtime.Str("sheet-id")).WithParam("--range")
}
}
return nil
Expand Down Expand Up @@ -336,7 +337,7 @@
"find": findText,
}

data, err := runtime.CallAPI("POST", fmt.Sprintf("/open-apis/sheets/v3/spreadsheets/%s/sheets/%s/find", validate.EncodePathSegment(token), validate.EncodePathSegment(sheetID)), nil, reqData)
data, err := runtime.CallAPITyped("POST", fmt.Sprintf("/open-apis/sheets/v3/spreadsheets/%s/sheets/%s/find", validate.EncodePathSegment(token), validate.EncodePathSegment(sheetID)), nil, reqData)

Check warning on line 340 in shortcuts/sheets/backward/lark_sheets_cell_data.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/sheets/backward/lark_sheets_cell_data.go#L340

Added line #L340 was not covered by tests
if err != nil {
return err
}
Expand Down Expand Up @@ -373,7 +374,7 @@
}
if r := runtime.Str("range"); r != "" {
if rangeSheetID, _, ok := splitSheetRange(r); ok && runtime.Str("sheet-id") != "" && rangeSheetID != runtime.Str("sheet-id") {
return common.FlagErrorf("--range sheet ID %q does not match --sheet-id %q", rangeSheetID, runtime.Str("sheet-id"))
return errs.NewValidationError(errs.SubtypeInvalidArgument, "--range sheet ID %q does not match --sheet-id %q", rangeSheetID, runtime.Str("sheet-id")).WithParam("--range")
}
}
return nil
Expand Down Expand Up @@ -415,7 +416,7 @@
findCondition["range"] = normalizeSheetRange(sheetID, runtime.Str("range"))
}

data, err := runtime.CallAPI("POST",
data, err := runtime.CallAPITyped("POST",
fmt.Sprintf("/open-apis/sheets/v3/spreadsheets/%s/sheets/%s/replace",
validate.EncodePathSegment(token),
validate.EncodePathSegment(sheetID),
Expand Down
24 changes: 12 additions & 12 deletions shortcuts/sheets/backward/lark_sheets_cell_images.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"os"
"path/filepath"

"github.com/larksuite/cli/errs"
"github.com/larksuite/cli/extension/fileio"
"github.com/larksuite/cli/internal/output"
"github.com/larksuite/cli/internal/validate"
"github.com/larksuite/cli/shortcuts/common"
)
Expand All @@ -38,7 +38,7 @@
token = extractSpreadsheetToken(runtime.Str("url"))
}
if token == "" {
return common.FlagErrorf("specify --url or --spreadsheet-token")
return errs.NewValidationError(errs.SubtypeInvalidArgument, "specify --url or --spreadsheet-token").WithParams(errs.InvalidParam{Name: "--url", Reason: "required; specify one"}, errs.InvalidParam{Name: "--spreadsheet-token", Reason: "required; specify one"})
}
if err := validateSheetRangeInput(runtime.Str("sheet-id"), runtime.Str("range")); err != nil {
return err
Expand Down Expand Up @@ -91,7 +91,7 @@

imageBytes, err := io.ReadAll(imageFile)
if err != nil {
return output.ErrValidation("cannot read image file: %s", err)
return errs.NewValidationError(errs.SubtypeInvalidArgument, "cannot read image file: %s", err).WithParam("--image").WithCause(err)

Check warning on line 94 in shortcuts/sheets/backward/lark_sheets_cell_images.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/sheets/backward/lark_sheets_cell_images.go#L94

Added line #L94 was not covered by tests
}

imageName := runtime.Str("name")
Expand All @@ -101,7 +101,7 @@

fmt.Fprintf(runtime.IO().ErrOut, "Writing image: %s (%d bytes) → %s\n", imageName, stat.Size(), pointRange)

data, err := runtime.CallAPI("POST", fmt.Sprintf("/open-apis/sheets/v2/spreadsheets/%s/values_image", validate.EncodePathSegment(token)), nil, map[string]interface{}{
data, err := runtime.CallAPITyped("POST", fmt.Sprintf("/open-apis/sheets/v2/spreadsheets/%s/values_image", validate.EncodePathSegment(token)), nil, map[string]interface{}{
"range": pointRange,
"image": imageBytes,
"name": imageName,
Expand All @@ -116,35 +116,35 @@

func validateSheetWriteImageFile(fio fileio.FileIO, imagePath string) (fileio.FileInfo, error) {
if fio == nil {
return nil, output.ErrValidation("no file I/O provider registered")
return nil, errs.NewValidationError(errs.SubtypeInvalidArgument, "no file I/O provider registered")

Check warning on line 119 in shortcuts/sheets/backward/lark_sheets_cell_images.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/sheets/backward/lark_sheets_cell_images.go#L119

Added line #L119 was not covered by tests
}
stat, err := fio.Stat(imagePath)
if err != nil {
return nil, wrapSheetWriteImageStatError(err, imagePath)
}
if stat.IsDir() || !stat.Mode().IsRegular() {
return nil, output.ErrValidation("image must be a regular file: %s", imagePath)
return nil, errs.NewValidationError(errs.SubtypeInvalidArgument, "image must be a regular file: %s", imagePath).WithParam("--image")
}
const maxImageSize int64 = 20 * 1024 * 1024
if stat.Size() > maxImageSize {
return nil, output.ErrValidation("image %.1fMB exceeds 20MB limit", float64(stat.Size())/1024/1024)
return nil, errs.NewValidationError(errs.SubtypeInvalidArgument, "image %.1fMB exceeds 20MB limit", float64(stat.Size())/1024/1024).WithParam("--image")
}
return stat, nil
}

func wrapSheetWriteImageStatError(err error, imagePath string) error {
if errors.Is(err, fileio.ErrPathValidation) {
return output.ErrValidation("unsafe image path: %s", err)
return errs.NewValidationError(errs.SubtypeInvalidArgument, "unsafe image path: %s", err).WithParam("--image").WithCause(err)
}
if os.IsNotExist(err) {
return output.ErrValidation("image file not found: %s", imagePath)
return errs.NewValidationError(errs.SubtypeInvalidArgument, "image file not found: %s", imagePath).WithParam("--image").WithCause(err)
}
return output.ErrValidation("cannot stat image file: %s", err)
return errs.NewValidationError(errs.SubtypeInvalidArgument, "cannot stat image file: %s", err).WithParam("--image").WithCause(err)

Check warning on line 142 in shortcuts/sheets/backward/lark_sheets_cell_images.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/sheets/backward/lark_sheets_cell_images.go#L142

Added line #L142 was not covered by tests
}

func wrapSheetWriteImageOpenError(err error) error {
if errors.Is(err, fileio.ErrPathValidation) {
return output.ErrValidation("unsafe image path: %s", err)
return errs.NewValidationError(errs.SubtypeInvalidArgument, "unsafe image path: %s", err).WithParam("--image").WithCause(err)

Check warning on line 147 in shortcuts/sheets/backward/lark_sheets_cell_images.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/sheets/backward/lark_sheets_cell_images.go#L147

Added line #L147 was not covered by tests
}
return output.ErrValidation("cannot read image file: %s", err)
return errs.NewValidationError(errs.SubtypeInvalidArgument, "cannot read image file: %s", err).WithParam("--image").WithCause(err)

Check warning on line 149 in shortcuts/sheets/backward/lark_sheets_cell_images.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/sheets/backward/lark_sheets_cell_images.go#L149

Added line #L149 was not covered by tests
}
Loading
Loading