mirror of
https://github.com/larksuite/cli.git
synced 2026-07-03 14:02:43 +08:00
Emit structured validation, API, network, file, and internal error envelopes for Markdown shortcuts so users and agents can recover from failed markdown workflows using stable type, subtype, param, and code fields. Add Markdown domain errscontract and golangci guards to prevent legacy envelope and common helper regressions.
102 lines
3.3 KiB
Go
102 lines
3.3 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package markdown
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"strings"
|
|
|
|
"github.com/larksuite/cli/internal/validate"
|
|
"github.com/larksuite/cli/shortcuts/common"
|
|
)
|
|
|
|
var MarkdownOverwrite = common.Shortcut{
|
|
Service: "markdown",
|
|
Command: "+overwrite",
|
|
Description: "Overwrite an existing Markdown file in Drive",
|
|
Risk: "write",
|
|
Scopes: []string{"drive:file:upload", "drive:drive.metadata:readonly"},
|
|
AuthTypes: []string{"user", "bot"},
|
|
HasFormat: true,
|
|
Flags: []common.Flag{
|
|
{Name: "file-token", Desc: "target Markdown file token", Required: true},
|
|
{Name: "name", Desc: "optional file name with .md suffix; overrides the existing/local file name"},
|
|
{Name: "content", Desc: "new Markdown content", Input: []string{common.File, common.Stdin}},
|
|
{Name: "file", Desc: "local .md file path"},
|
|
},
|
|
Validate: func(ctx context.Context, runtime *common.RuntimeContext) error {
|
|
fileToken := strings.TrimSpace(runtime.Str("file-token"))
|
|
if err := validate.ResourceName(fileToken, "--file-token"); err != nil {
|
|
return markdownValidationParamError("--file-token", "%s", err).WithCause(err)
|
|
}
|
|
return validateMarkdownSpec(runtime, markdownUploadSpec{
|
|
FileToken: fileToken,
|
|
FileName: strings.TrimSpace(runtime.Str("name")),
|
|
FilePath: strings.TrimSpace(runtime.Str("file")),
|
|
FileSet: runtime.Changed("file"),
|
|
Content: runtime.Str("content"),
|
|
ContentSet: runtime.Changed("content"),
|
|
}, false)
|
|
},
|
|
DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI {
|
|
spec := markdownUploadSpec{
|
|
FileToken: strings.TrimSpace(runtime.Str("file-token")),
|
|
FileName: strings.TrimSpace(runtime.Str("name")),
|
|
FilePath: strings.TrimSpace(runtime.Str("file")),
|
|
FileSet: runtime.Changed("file"),
|
|
Content: runtime.Str("content"),
|
|
ContentSet: runtime.Changed("content"),
|
|
}
|
|
fileSize, err := markdownSourceSize(runtime, spec)
|
|
if err != nil {
|
|
return common.NewDryRunAPI().Set("error", err.Error())
|
|
}
|
|
return markdownOverwriteDryRun(spec, fileSize, fileSize > markdownSinglePartSizeLimit)
|
|
},
|
|
Execute: func(ctx context.Context, runtime *common.RuntimeContext) error {
|
|
fileToken := strings.TrimSpace(runtime.Str("file-token"))
|
|
spec := markdownUploadSpec{
|
|
FileToken: fileToken,
|
|
FileName: strings.TrimSpace(runtime.Str("name")),
|
|
FilePath: strings.TrimSpace(runtime.Str("file")),
|
|
FileSet: runtime.Changed("file"),
|
|
Content: runtime.Str("content"),
|
|
ContentSet: runtime.Changed("content"),
|
|
}
|
|
|
|
fileSize, err := markdownSourceSize(runtime, spec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fileName, err := resolveMarkdownOverwriteFileName(runtime, spec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
spec.FileName = fileName
|
|
|
|
var result markdownUploadResult
|
|
if spec.FileSet {
|
|
result, err = uploadMarkdownLocalFile(runtime, spec, fileSize)
|
|
} else {
|
|
result, err = uploadMarkdownContent(runtime, spec, []byte(spec.Content))
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
out := map[string]interface{}{
|
|
"file_token": result.FileToken,
|
|
"file_name": fileName,
|
|
"version": result.Version,
|
|
"size_bytes": fileSize,
|
|
}
|
|
runtime.OutFormat(out, nil, func(w io.Writer) {
|
|
prettyPrintMarkdownWrite(w, out)
|
|
})
|
|
return nil
|
|
},
|
|
}
|