Skip to content

Commit ab6deb0

Browse files
committed
feat: migrate mail errors to typed contract
1 parent 33de28f commit ab6deb0

53 files changed

Lines changed: 1370 additions & 595 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.golangci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,20 +65,20 @@ linters:
6565
- forbidigo
6666
# errs-typed-only enforced on paths already migrated to errs.NewXxxError.
6767
# Add a path when its migration is complete.
68-
- 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/calendar/helpers\.go|shortcuts/drive/)
68+
- 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/calendar/helpers\.go|shortcuts/drive/|shortcuts/mail/)
6969
text: errs-typed-only
7070
linters:
7171
- forbidigo
7272
# errs-no-bare-wrap enforced on paths fully migrated to typed final
7373
# errors. Scoped separately from errs-typed-only because cmd/auth/,
7474
# cmd/config/ still have residual fmt.Errorf and must not be caught.
75-
- path-except: (shortcuts/drive/|shortcuts/calendar/helpers\.go|shortcuts/common/mcp_client\.go)
75+
- path-except: (shortcuts/drive/|shortcuts/mail/|shortcuts/calendar/helpers\.go|shortcuts/common/mcp_client\.go)
7676
text: errs-no-bare-wrap
7777
linters:
7878
- forbidigo
7979
# errs-no-legacy-helper is drive-only: the shared helpers it bans are
8080
# still used by other domains until their later migration phase.
81-
- path-except: (shortcuts/drive/)
81+
- path-except: (shortcuts/drive/|shortcuts/mail/)
8282
text: errs-no-legacy-helper
8383
linters:
8484
- forbidigo

internal/errclass/classify.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,8 @@ func APIHint(subtype errs.Subtype) string {
244244
return "operate on source and target within the same tenant and region/unit"
245245
case errs.SubtypeCrossBrand:
246246
return "operate on source and target within the same brand environment"
247+
case errs.SubtypeQuotaExceeded:
248+
return "reduce the request volume or free quota, then retry after the relevant quota resets"
247249
}
248250
return ""
249251
}

internal/errclass/codemeta_mail.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
2+
// SPDX-License-Identifier: MIT
3+
4+
package errclass
5+
6+
import "github.com/larksuite/cli/errs"
7+
8+
// mailCodeMeta holds mail-service Lark code -> CodeMeta mappings.
9+
// Only codes whose meaning is verifiable from repo evidence are registered;
10+
// ambiguous codes fall back to CategoryAPI via BuildAPIError.
11+
var mailCodeMeta = map[int]CodeMeta{
12+
1234013: {Category: errs.CategoryAPI, Subtype: errs.SubtypeNotFound}, // mailbox not found or not active
13+
1236007: {Category: errs.CategoryAPI, Subtype: errs.SubtypeQuotaExceeded}, // user daily send count exceeded
14+
1236008: {Category: errs.CategoryAPI, Subtype: errs.SubtypeQuotaExceeded}, // user daily external recipient count exceeded
15+
1236009: {Category: errs.CategoryAPI, Subtype: errs.SubtypeQuotaExceeded}, // tenant daily external recipient count exceeded
16+
1236010: {Category: errs.CategoryAPI, Subtype: errs.SubtypeQuotaExceeded}, // mail quota limit
17+
1236013: {Category: errs.CategoryAPI, Subtype: errs.SubtypeQuotaExceeded}, // tenant storage limit exceeded
18+
}
19+
20+
func init() { mergeCodeMeta(mailCodeMeta, "mail") }

lint/errscontract/rule_no_legacy_envelope_literal.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
// appending their path prefix here.
1818
var migratedEnvelopePaths = []string{
1919
"shortcuts/drive/",
20+
"shortcuts/mail/",
2021
}
2122

2223
// legacyOutputImportPath is the import path of the package that declares the

shortcuts/mail/body_file.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"strings"
99

1010
"github.com/larksuite/cli/extension/fileio"
11-
"github.com/larksuite/cli/internal/output"
1211
"github.com/larksuite/cli/shortcuts/common"
1312
)
1413

@@ -51,11 +50,15 @@ const maxBodyFileSize = 32 * 1024 * 1024 // 32 MB
5150
func validateBodyFileMutex(bodyFlag, bodyFile string, validatePath func(string) error) error {
5251
bodyEmpty := strings.TrimSpace(bodyFlag) == ""
5352
if !bodyEmpty && bodyFile != "" {
54-
return output.ErrValidation("--body and --body-file are mutually exclusive; pass exactly one")
53+
return mailValidationError("--body and --body-file are mutually exclusive; pass exactly one").
54+
WithParams(
55+
mailInvalidParam("--body", "mutually exclusive with --body-file"),
56+
mailInvalidParam("--body-file", "mutually exclusive with --body"),
57+
)
5558
}
5659
if bodyFile != "" {
5760
if err := validatePath(bodyFile); err != nil {
58-
return output.ErrValidation("--body-file: %v", err)
61+
return mailValidationParamError("--body-file", "--body-file: %v", err).WithCause(err)
5962
}
6063
}
6164
return nil
@@ -79,7 +82,7 @@ func resolveBodyFromFlags(runtime *common.RuntimeContext) (string, error) {
7982

8083
func validateRequiredResolvedBody(body string, hasTemplate bool, message string) error {
8184
if !hasTemplate && strings.TrimSpace(body) == "" {
82-
return output.ErrValidation(message)
85+
return mailValidationError("%s", message)
8386
}
8487
return nil
8588
}
@@ -95,15 +98,15 @@ func validateRequiredResolvedBody(body string, hasTemplate bool, message string)
9598
func readBodyFile(fio fileio.FileIO, path string) (string, error) {
9699
f, err := fio.Open(path)
97100
if err != nil {
98-
return "", output.ErrValidation("open --body-file %s: %v", path, err)
101+
return "", mailValidationParamError("--body-file", "open --body-file %s: %v", path, err).WithCause(mailInputStatError(err))
99102
}
100103
defer f.Close()
101104
buf, err := io.ReadAll(io.LimitReader(f, maxBodyFileSize+1))
102105
if err != nil {
103-
return "", output.ErrValidation("read --body-file %s: %v", path, err)
106+
return "", mailValidationParamError("--body-file", "read --body-file %s: %v", path, err).WithCause(err)
104107
}
105108
if len(buf) > maxBodyFileSize {
106-
return "", output.ErrValidation("--body-file: file exceeds %d MB limit", maxBodyFileSize/1024/1024)
109+
return "", mailValidationParamError("--body-file", "--body-file: file exceeds %d MB limit", maxBodyFileSize/1024/1024)
107110
}
108111
return string(buf), nil
109112
}

shortcuts/mail/draft/charset.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
22
// SPDX-License-Identifier: MIT
33

4+
//nolint:forbidigo // intermediate draft charset errors; mail command layer wraps into typed ValidationError.
45
package draft
56

67
import (

shortcuts/mail/draft/large_attachment_parse.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
22
// SPDX-License-Identifier: MIT
33

4+
//nolint:forbidigo // intermediate draft large-attachment parser errors; mail command layer wraps into typed ValidationError.
45
package draft
56

67
import (

shortcuts/mail/draft/limits.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
22
// SPDX-License-Identifier: MIT
33

4+
//nolint:forbidigo // intermediate draft attachment limit errors; mail command layer wraps into typed ValidationError.
45
package draft
56

67
import (

shortcuts/mail/draft/model.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
22
// SPDX-License-Identifier: MIT
33

4+
//nolint:forbidigo // intermediate draft patch model errors; mail command layer wraps into typed ValidationError.
45
package draft
56

67
import (

shortcuts/mail/draft/parse.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
22
// SPDX-License-Identifier: MIT
33

4+
//nolint:forbidigo // intermediate draft EML parser errors; mail command layer wraps into typed ValidationError.
45
package draft
56

67
import (

0 commit comments

Comments
 (0)