mirror of
https://github.com/larksuite/cli.git
synced 2026-07-03 14:02:43 +08:00
docs: drop Miaoda brand word from apps command help text (#1399)
This commit is contained in:
@@ -13,12 +13,12 @@ import (
|
||||
"github.com/larksuite/cli/shortcuts/common"
|
||||
)
|
||||
|
||||
// AppsAccessScopeGet reads the current access scope configuration of a Miaoda app.
|
||||
// AppsAccessScopeGet reads the current access scope configuration of an app.
|
||||
// 响应原样透传服务端契约(字符串 scope 枚举 All/Tenant/Range + 拆分的 users/departments/chats 数组)。
|
||||
var AppsAccessScopeGet = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+access-scope-get",
|
||||
Description: "Get Miaoda app access scope configuration",
|
||||
Description: "Get app access scope configuration",
|
||||
Risk: "read",
|
||||
Tips: []string{
|
||||
"Example: lark-cli apps +access-scope-get --app-id <app_id>",
|
||||
@@ -39,7 +39,7 @@ var AppsAccessScopeGet = common.Shortcut{
|
||||
appID := strings.TrimSpace(rctx.Str("app-id"))
|
||||
return common.NewDryRunAPI().
|
||||
GET(fmt.Sprintf("%s/apps/%s/access-scope", apiBasePath, validate.EncodePathSegment(appID))).
|
||||
Desc("Get Miaoda app access scope")
|
||||
Desc("Get app access scope")
|
||||
},
|
||||
Execute: func(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
appID := strings.TrimSpace(rctx.Str("app-id"))
|
||||
|
||||
@@ -24,7 +24,7 @@ var allowedAccessTargetTypes = map[string]bool{
|
||||
var AppsAccessScopeSet = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+access-scope-set",
|
||||
Description: "Set Miaoda app access scope (specific / public / tenant)",
|
||||
Description: "Set app access scope (specific / public / tenant)",
|
||||
Risk: "write",
|
||||
Tips: []string{
|
||||
`Example: lark-cli apps +access-scope-set --app-id <app_id> --scope tenant`,
|
||||
@@ -52,7 +52,7 @@ var AppsAccessScopeSet = common.Shortcut{
|
||||
appID := strings.TrimSpace(rctx.Str("app-id"))
|
||||
dry := common.NewDryRunAPI().
|
||||
PUT(fmt.Sprintf("%s/apps/%s/access-scope", apiBasePath, validate.EncodePathSegment(appID))).
|
||||
Desc("Set Miaoda app access scope")
|
||||
Desc("Set app access scope")
|
||||
body, bodyErr := buildAccessScopeBody(rctx)
|
||||
if bodyErr != nil {
|
||||
dry.Set("body_error", bodyErr.Error())
|
||||
|
||||
@@ -12,13 +12,13 @@ import (
|
||||
"github.com/larksuite/cli/shortcuts/common"
|
||||
)
|
||||
|
||||
const createHint = "verify --app-type is html or full_stack and --name is non-empty; if this is a permission error, confirm your account can create Miaoda apps"
|
||||
const createHint = "verify --app-type is html or full_stack and --name is non-empty; if this is a permission error, confirm your account can create apps"
|
||||
|
||||
// AppsCreate creates a new Miaoda app.
|
||||
// AppsCreate creates a new app.
|
||||
var AppsCreate = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+create",
|
||||
Description: "Create a new Miaoda app",
|
||||
Description: "Create a new app",
|
||||
Risk: "write",
|
||||
Tips: []string{
|
||||
`Example: lark-cli apps +create --name "审批系统" --app-type full_stack`,
|
||||
@@ -42,7 +42,7 @@ var AppsCreate = common.Shortcut{
|
||||
DryRun: func(ctx context.Context, rctx *common.RuntimeContext) *common.DryRunAPI {
|
||||
return common.NewDryRunAPI().
|
||||
POST(apiBasePath + "/apps").
|
||||
Desc("Create a Miaoda app").
|
||||
Desc("Create an app").
|
||||
Body(buildAppsCreateBody(rctx))
|
||||
},
|
||||
Execute: func(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
const dbEnvCreateHint = "verify --app-id is correct; if the app is already multi-env this is a conflict — inspect current tables with `lark-cli apps +db-table-list --app-id <app_id> --env dev`"
|
||||
|
||||
// AppsDBEnvCreate creates a DB environment for a Miaoda app(拆分单库为 dev/online 多环境)。
|
||||
// AppsDBEnvCreate creates a DB environment for an app(拆分单库为 dev/online 多环境)。
|
||||
//
|
||||
// 调 POST /apps/{app_id}/db_dev_init。--env 指定要创建的环境,由调用方传入,目前只支持 dev。
|
||||
// 不可逆:单库一旦拆成 dev/online 双库无法回退。Risk: high-risk-write 触发框架自动注入 --yes 确认关卡。
|
||||
@@ -30,7 +30,7 @@ var AppsDBEnvCreate = common.Shortcut{
|
||||
AuthTypes: []string{"user"},
|
||||
HasFormat: true,
|
||||
Flags: []common.Flag{
|
||||
{Name: "app-id", Desc: "Miaoda app id", Required: true},
|
||||
{Name: "app-id", Desc: "app id", Required: true},
|
||||
{Name: "env", Default: "dev", Enum: []string{"dev"}, Desc: "environment to create (only dev supported for now)"},
|
||||
{Name: "sync-data", Type: "bool", Desc: "copy existing online data into the new environment (default off)"},
|
||||
},
|
||||
@@ -42,7 +42,7 @@ var AppsDBEnvCreate = common.Shortcut{
|
||||
appID, _ := requireAppID(rctx.Str("app-id"))
|
||||
return common.NewDryRunAPI().
|
||||
POST(appDbEnvCreatePath(appID)).
|
||||
Desc("Create Miaoda app DB environment").
|
||||
Desc("Create app DB environment").
|
||||
Body(buildDBEnvCreateBody(rctx))
|
||||
},
|
||||
Execute: func(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/larksuite/cli/shortcuts/common"
|
||||
)
|
||||
|
||||
// AppsDBExecute executes SQL against a Miaoda app database.
|
||||
// AppsDBExecute executes SQL against an app database.
|
||||
//
|
||||
// POST /apps/{app_id}/sql_commands,CLI 永远带 ?transactional=false 进入 DBA 模式
|
||||
// (不默认包事务、支持 DDL、result 字符串内嵌结构化 JSON)。
|
||||
@@ -45,7 +45,7 @@ import (
|
||||
var AppsDBExecute = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+db-execute",
|
||||
Description: "Execute SQL (SELECT / DML / DDL) against a Miaoda app database",
|
||||
Description: "Execute SQL (SELECT / DML / DDL) against an app database",
|
||||
Risk: "high-risk-write",
|
||||
Tips: []string{
|
||||
`Example: lark-cli apps +db-execute --app-id <app_id> --sql "SELECT * FROM orders LIMIT 10" --yes`,
|
||||
@@ -56,7 +56,7 @@ var AppsDBExecute = common.Shortcut{
|
||||
AuthTypes: []string{"user"},
|
||||
HasFormat: true,
|
||||
Flags: []common.Flag{
|
||||
{Name: "app-id", Desc: "Miaoda app id", Required: true},
|
||||
{Name: "app-id", Desc: "app id", Required: true},
|
||||
{Name: "sql", Desc: "SQL text; use - to read stdin. Mutually exclusive with --file",
|
||||
Input: []string{common.Stdin}},
|
||||
{Name: "file", Desc: "path to a .sql file (relative to cwd). Mutually exclusive with --sql"},
|
||||
@@ -97,7 +97,7 @@ var AppsDBExecute = common.Shortcut{
|
||||
appID, _ := requireAppID(rctx.Str("app-id"))
|
||||
return common.NewDryRunAPI().
|
||||
POST(appSQLPath(appID)).
|
||||
Desc("Execute SQL on Miaoda app database").
|
||||
Desc("Execute SQL on app database").
|
||||
Params(buildDBSQLParams(rctx)).
|
||||
Body(buildDBSQLBody(rctx))
|
||||
},
|
||||
|
||||
@@ -35,7 +35,7 @@ var AppsDBTableGet = common.Shortcut{
|
||||
AuthTypes: []string{"user"},
|
||||
HasFormat: true,
|
||||
Flags: []common.Flag{
|
||||
{Name: "app-id", Desc: "Miaoda app id", Required: true},
|
||||
{Name: "app-id", Desc: "app id", Required: true},
|
||||
{Name: "table", Desc: "table name", Required: true},
|
||||
{Name: "env", Default: "online", Enum: []string{"dev", "online"}, Desc: "target db environment"},
|
||||
},
|
||||
@@ -52,7 +52,7 @@ var AppsDBTableGet = common.Shortcut{
|
||||
appID, _ := requireAppID(rctx.Str("app-id"))
|
||||
return common.NewDryRunAPI().
|
||||
GET(appTablePath(appID, strings.TrimSpace(rctx.Str("table")))).
|
||||
Desc("Get Miaoda app db table schema").
|
||||
Desc("Get app db table schema").
|
||||
Params(buildDBTableGetParams(rctx))
|
||||
},
|
||||
Execute: func(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
|
||||
const dbTableListHint = "verify --app-id is correct; if targeting --env dev, create it first with `lark-cli apps +db-env-create --app-id <app_id> --env dev`"
|
||||
|
||||
// AppsDBTableList lists tables in a Miaoda app's database.
|
||||
// AppsDBTableList lists tables in an app's database.
|
||||
//
|
||||
// GET /apps/{app_id}/tables(cursor 分页),response items[] 含 estimated_row_count /
|
||||
// size_bytes optional 字段,默认返回,不必额外传 query。
|
||||
@@ -29,7 +29,7 @@ const dbTableListHint = "verify --app-id is correct; if targeting --env dev, cre
|
||||
var AppsDBTableList = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+db-table-list",
|
||||
Description: "List tables in a Miaoda app database (cursor pagination)",
|
||||
Description: "List tables in an app database (cursor pagination)",
|
||||
Risk: "read",
|
||||
Tips: []string{
|
||||
"Example: lark-cli apps +db-table-list --app-id <app_id>",
|
||||
@@ -39,7 +39,7 @@ var AppsDBTableList = common.Shortcut{
|
||||
AuthTypes: []string{"user"},
|
||||
HasFormat: true,
|
||||
Flags: []common.Flag{
|
||||
{Name: "app-id", Desc: "Miaoda app id", Required: true},
|
||||
{Name: "app-id", Desc: "app id", Required: true},
|
||||
{Name: "env", Default: "online", Enum: []string{"dev", "online"}, Desc: "target db environment"},
|
||||
{Name: "page-size", Type: "int", Default: "20", Desc: "page size"},
|
||||
{Name: "page-token", Desc: "pagination cursor from previous response"},
|
||||
@@ -52,7 +52,7 @@ var AppsDBTableList = common.Shortcut{
|
||||
appID, _ := requireAppID(rctx.Str("app-id"))
|
||||
return common.NewDryRunAPI().
|
||||
GET(appTablesPath(appID)).
|
||||
Desc("List Miaoda app db tables").
|
||||
Desc("List app db tables").
|
||||
Params(buildDBTableListParams(rctx))
|
||||
},
|
||||
Execute: func(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
var AppsHTMLPublish = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+html-publish",
|
||||
Description: "Publish HTML to a Miaoda app (single multipart POST returns the access URL)",
|
||||
Description: "Publish HTML to an app (single multipart POST returns the access URL)",
|
||||
Risk: "write",
|
||||
Tips: []string{
|
||||
"Example: lark-cli apps +html-publish --app-id <app_id> --path ./dist",
|
||||
@@ -29,7 +29,7 @@ var AppsHTMLPublish = common.Shortcut{
|
||||
AuthTypes: []string{"user"},
|
||||
HasFormat: true,
|
||||
Flags: []common.Flag{
|
||||
{Name: "app-id", Desc: "Miaoda app ID", Required: true},
|
||||
{Name: "app-id", Desc: "app ID", Required: true},
|
||||
{Name: "path", Desc: "path to HTML file or directory", Required: true},
|
||||
{Name: "allow-sensitive", Type: "bool", Desc: "skip the credential-file scan (allow .env / .npmrc / .aws/credentials / etc. in the publish payload)"},
|
||||
},
|
||||
@@ -179,7 +179,7 @@ func ensureIndexHTML(candidates []htmlPublishCandidate) error {
|
||||
}
|
||||
}
|
||||
return appsFailedPreconditionParamError("--path", "--path is missing index.html").
|
||||
WithHint("Miaoda uses index.html as the app entrypoint; for a directory put index.html at the root, or pass a single file named index.html")
|
||||
WithHint("index.html is the app entrypoint; for a directory put index.html at the root, or pass a single file named index.html")
|
||||
}
|
||||
|
||||
func runHTMLPublish(ctx context.Context, fio fileio.FileIO, publisher appsHTMLPublishClient, spec appsHTMLPublishSpec) (map[string]interface{}, error) {
|
||||
|
||||
@@ -27,8 +27,8 @@ const defaultInitBranch = "sprint/default"
|
||||
// the non-empty (`app sync`) path stays a single commit.
|
||||
const (
|
||||
commitMsgAppCode = "chore: initialize app project code"
|
||||
commitMsgAppConfig = "chore: initialize miaoda app config"
|
||||
commitMsgUpgrade = "chore: initialize miaoda app repository"
|
||||
commitMsgAppConfig = "chore: initialize app config"
|
||||
commitMsgUpgrade = "chore: initialize app repository"
|
||||
)
|
||||
|
||||
// scaffold kinds returned by runScaffold and consumed by commitAndPushIfDirty.
|
||||
@@ -49,11 +49,11 @@ const (
|
||||
// can swap in a fakeCommandRunner. Production uses execCommandRunner.
|
||||
var initRunner commandRunner = execCommandRunner{}
|
||||
|
||||
// AppsInit initializes a Miaoda app's code and local development environment.
|
||||
// AppsInit initializes an app's code and local development environment.
|
||||
var AppsInit = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+init",
|
||||
Description: "Initialize a Miaoda app's code and local development environment",
|
||||
Description: "Initialize an app's code and local development environment",
|
||||
Risk: "write",
|
||||
Tips: []string{
|
||||
"Example: lark-cli apps +init --app-id <app_id> --dir <dir>",
|
||||
@@ -73,7 +73,7 @@ var AppsInit = common.Shortcut{
|
||||
// envelope. The spec and the E2E assert exit-2 + a structured
|
||||
// {"ok":false,"error":{...}} envelope for missing --app-id, so the empty
|
||||
// check lives in Validate (typed validation error -> exit 2).
|
||||
{Name: "app-id", Desc: "Miaoda app ID"},
|
||||
{Name: "app-id", Desc: "app ID"},
|
||||
{Name: "dir", Desc: "clone target directory; absolute or relative path (default ./<app-id>)"},
|
||||
{Name: "template", Desc: "code-init template for an empty repo; optional — if omitted, derived from the app's tech stack"},
|
||||
},
|
||||
@@ -87,7 +87,7 @@ var AppsInit = common.Shortcut{
|
||||
appID := strings.TrimSpace(rctx.Str("app-id"))
|
||||
template := resolveTemplate(rctx, appID)
|
||||
dry := common.NewDryRunAPI().
|
||||
Desc("Initialize Miaoda app code (credential-init, clone, checkout, npx code-init, optional commit/push)").
|
||||
Desc("Initialize app code (credential-init, clone, checkout, npx code-init, optional commit/push)").
|
||||
Set("credential_init", fmt.Sprintf("apps +git-credential-init --app-id %s --format json", appID)).
|
||||
Set("checkout", "git checkout "+defaultInitBranch).
|
||||
Set("scaffold", fmt.Sprintf("empty repo: npx -y --prefer-online %s app init --template %s --app-id %s; non-empty: npx -y --prefer-online %s app sync + .spark/meta.json app_id patch + conditional skills sync --local", miaodaCLIPkg, template, appID, miaodaCLIPkg)).
|
||||
@@ -191,7 +191,7 @@ func ensureEmptyDir(dir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// isAlreadyInitialized reports whether dir is an already-initialized Miaoda app
|
||||
// isAlreadyInitialized reports whether dir is an already-initialized app
|
||||
// repo, detected by the presence of <dir>/.spark/meta.json (regardless of its
|
||||
// app_id value). Used to short-circuit +init into a friendly no-op.
|
||||
func isAlreadyInitialized(dir string) bool {
|
||||
@@ -379,7 +379,7 @@ func appsInitExecute(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
}
|
||||
|
||||
// Already-initialized short-circuit: a dir containing .spark/meta.json is an
|
||||
// initialized Miaoda app repo -> skip clone/scaffold/commit, but still refresh
|
||||
// initialized app repo -> skip clone/scaffold/commit, but still refresh
|
||||
// the local env so a re-run picks up the latest startup env vars.
|
||||
if isAlreadyInitialized(dir) {
|
||||
initLogf(rctx, "Already initialized at %s — refreshing local environment", dir)
|
||||
@@ -556,7 +556,7 @@ func issueCredentials(ctx context.Context, rctx *common.RuntimeContext, appID st
|
||||
// commitAndPushIfDirty commits and pushes only when the working tree has
|
||||
// changes; a clean tree is a no-op (returns false,false). For the empty-repo
|
||||
// init path (scaffoldKind == "init") it splits the scaffolded tree into two
|
||||
// commits — app project code, then Miaoda config (.spark/.agent) — skipping
|
||||
// commits — app project code, then app config (.spark/.agent) — skipping
|
||||
// either commit when that group has no changes (no empty commits). Other paths
|
||||
// commit once. Push is a single `git push origin <branch>` for all commits.
|
||||
func commitAndPushIfDirty(ctx context.Context, dir, scaffoldKind string) (committed, pushed bool, err error) {
|
||||
@@ -621,7 +621,7 @@ func stageAndCommit(ctx context.Context, dir, message string, pathspecs ...strin
|
||||
|
||||
// classifyPorcelain parses `git status --porcelain` output and partitions the
|
||||
// changed paths into the "app code" group (anything outside .spark/ and .agent/)
|
||||
// and the "Miaoda config" group (.spark/ and .agent/). It returns the exact
|
||||
// and the "app config" group (.spark/ and .agent/). It returns the exact
|
||||
// porcelain paths so callers can stage them verbatim: porcelain never lists
|
||||
// gitignored files, so `git add -- <these paths>` never trips git's ignored-path
|
||||
// error. (Naming an ignored dir explicitly — or combining a "." pathspec with
|
||||
@@ -658,7 +658,7 @@ func porcelainPath(line string) string {
|
||||
return p
|
||||
}
|
||||
|
||||
// isConfigPath reports whether p is the Miaoda app-config group: the .spark or
|
||||
// isConfigPath reports whether p is the app-config group: the .spark or
|
||||
// .agent directory itself, or anything under them. ".sparkrc" is NOT config.
|
||||
func isConfigPath(p string) bool {
|
||||
return p == ".spark" || p == ".agent" ||
|
||||
|
||||
@@ -835,7 +835,7 @@ func TestAppsInit_EmptyRepo_TwoCommits(t *testing.T) {
|
||||
t.Fatalf("unexpected: %v", err)
|
||||
}
|
||||
msgs := commitMessages(f.calls)
|
||||
want := []string{"chore: initialize app project code", "chore: initialize miaoda app config"}
|
||||
want := []string{"chore: initialize app project code", "chore: initialize app config"}
|
||||
if len(msgs) != 2 || msgs[0] != want[0] || msgs[1] != want[1] {
|
||||
t.Fatalf("commit messages = %v, want %v", msgs, want)
|
||||
}
|
||||
@@ -896,7 +896,7 @@ func TestAppsInit_EmptyRepo_ConfigOnly_SingleCommit(t *testing.T) {
|
||||
t.Fatalf("unexpected: %v", err)
|
||||
}
|
||||
msgs := commitMessages(f.calls)
|
||||
if len(msgs) != 1 || msgs[0] != "chore: initialize miaoda app config" {
|
||||
if len(msgs) != 1 || msgs[0] != "chore: initialize app config" {
|
||||
t.Fatalf("commit messages = %v, want one config commit", msgs)
|
||||
}
|
||||
}
|
||||
@@ -916,7 +916,7 @@ func TestAppsInit_NonEmpty_SingleInitCommit(t *testing.T) {
|
||||
t.Fatalf("unexpected: %v", err)
|
||||
}
|
||||
msgs := commitMessages(f.calls)
|
||||
if len(msgs) != 1 || msgs[0] != "chore: initialize miaoda app repository" {
|
||||
if len(msgs) != 1 || msgs[0] != "chore: initialize app repository" {
|
||||
t.Fatalf("commit messages = %v, want one upgrade commit", msgs)
|
||||
}
|
||||
for _, c := range f.calls {
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/larksuite/cli/shortcuts/common"
|
||||
)
|
||||
|
||||
// AppsList lists Miaoda apps visible to the calling user (cursor pagination).
|
||||
// AppsList lists apps visible to the calling user (cursor pagination).
|
||||
//
|
||||
// Supports name fuzzy match (--keyword), ownership-dimension filter
|
||||
// (--ownership: all / mine / shared), and app-type filter (--app-type). See
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
var AppsList = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+list",
|
||||
Description: "List Miaoda apps visible to the calling user (cursor pagination)",
|
||||
Description: "List apps visible to the calling user (cursor pagination)",
|
||||
Risk: "read",
|
||||
Tips: []string{
|
||||
"Example: lark-cli apps +list",
|
||||
@@ -42,7 +42,7 @@ var AppsList = common.Shortcut{
|
||||
DryRun: func(ctx context.Context, rctx *common.RuntimeContext) *common.DryRunAPI {
|
||||
return common.NewDryRunAPI().
|
||||
GET(apiBasePath + "/apps").
|
||||
Desc("List Miaoda apps").
|
||||
Desc("List apps").
|
||||
Params(buildAppsListParams(rctx))
|
||||
},
|
||||
Execute: func(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
|
||||
@@ -13,11 +13,11 @@ import (
|
||||
"github.com/larksuite/cli/shortcuts/common"
|
||||
)
|
||||
|
||||
// AppsReleaseCreate creates a release for a Miaoda app.
|
||||
// AppsReleaseCreate creates a release for an app.
|
||||
var AppsReleaseCreate = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+release-create",
|
||||
Description: "Create a release for a Miaoda app (returns release_id for status polling)",
|
||||
Description: "Create a release for an app (returns release_id for status polling)",
|
||||
Risk: "write",
|
||||
Tips: []string{
|
||||
"Example: lark-cli apps +release-create --app-id <app_id>",
|
||||
@@ -27,7 +27,7 @@ var AppsReleaseCreate = common.Shortcut{
|
||||
AuthTypes: []string{"user"},
|
||||
HasFormat: true,
|
||||
Flags: []common.Flag{
|
||||
{Name: "app-id", Desc: "Miaoda app ID", Required: true},
|
||||
{Name: "app-id", Desc: "app ID", Required: true},
|
||||
{Name: "branch", Desc: "release branch (server uses default if omitted)"},
|
||||
},
|
||||
Validate: func(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
|
||||
@@ -26,7 +26,7 @@ var AppsReleaseGet = common.Shortcut{
|
||||
AuthTypes: []string{"user"},
|
||||
HasFormat: true,
|
||||
Flags: []common.Flag{
|
||||
{Name: "app-id", Desc: "Miaoda app ID", Required: true},
|
||||
{Name: "app-id", Desc: "app ID", Required: true},
|
||||
{Name: "release-id", Desc: "release ID (the release_id returned by +release-create)", Required: true},
|
||||
},
|
||||
Validate: func(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
|
||||
@@ -14,11 +14,11 @@ import (
|
||||
"github.com/larksuite/cli/shortcuts/common"
|
||||
)
|
||||
|
||||
// AppsReleaseList lists a Miaoda app's release history (most recent first).
|
||||
// AppsReleaseList lists an app's release history (most recent first).
|
||||
var AppsReleaseList = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+release-list",
|
||||
Description: "List a Miaoda app's release history (most recent first)",
|
||||
Description: "List an app's release history (most recent first)",
|
||||
Risk: "read",
|
||||
Tips: []string{
|
||||
"Example: lark-cli apps +release-list --app-id <app_id>",
|
||||
@@ -28,7 +28,7 @@ var AppsReleaseList = common.Shortcut{
|
||||
AuthTypes: []string{"user"},
|
||||
HasFormat: true,
|
||||
Flags: []common.Flag{
|
||||
{Name: "app-id", Desc: "Miaoda app ID", Required: true},
|
||||
{Name: "app-id", Desc: "app ID", Required: true},
|
||||
{Name: "status", Enum: []string{"publishing", "finished", "failed"}, Desc: "filter by release status: publishing | finished | failed"},
|
||||
{Name: "page-size", Type: "int", Default: "20", Desc: "page size (max 500)"},
|
||||
{Name: "page-token", Desc: "pagination cursor from a previous response"},
|
||||
|
||||
@@ -13,11 +13,11 @@ import (
|
||||
"github.com/larksuite/cli/shortcuts/common"
|
||||
)
|
||||
|
||||
// AppsSessionCreate creates a new session under an existing Miaoda app.
|
||||
// AppsSessionCreate creates a new session under an existing app.
|
||||
var AppsSessionCreate = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+session-create",
|
||||
Description: "Create a session under a Miaoda app",
|
||||
Description: "Create a session under an app",
|
||||
Risk: "write",
|
||||
Tips: []string{
|
||||
"Example: lark-cli apps +session-create --app-id <app_id>",
|
||||
@@ -37,7 +37,7 @@ var AppsSessionCreate = common.Shortcut{
|
||||
DryRun: func(ctx context.Context, rctx *common.RuntimeContext) *common.DryRunAPI {
|
||||
return common.NewDryRunAPI().
|
||||
POST(sessionsPath(rctx.Str("app-id"))).
|
||||
Desc("Create a session under a Miaoda app")
|
||||
Desc("Create a session under an app")
|
||||
},
|
||||
Execute: func(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
data, err := rctx.CallAPITyped("POST", sessionsPath(rctx.Str("app-id")), nil, nil)
|
||||
|
||||
@@ -12,11 +12,11 @@ import (
|
||||
"github.com/larksuite/cli/shortcuts/common"
|
||||
)
|
||||
|
||||
// AppsSessionList lists sessions under a Miaoda app (cursor pagination, single page).
|
||||
// AppsSessionList lists sessions under an app (cursor pagination, single page).
|
||||
var AppsSessionList = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+session-list",
|
||||
Description: "List sessions under a Miaoda app (cursor pagination)",
|
||||
Description: "List sessions under an app (cursor pagination)",
|
||||
Risk: "read",
|
||||
Tips: []string{
|
||||
"Example: lark-cli apps +session-list --app-id <app_id>",
|
||||
@@ -39,7 +39,7 @@ var AppsSessionList = common.Shortcut{
|
||||
DryRun: func(ctx context.Context, rctx *common.RuntimeContext) *common.DryRunAPI {
|
||||
return common.NewDryRunAPI().
|
||||
GET(sessionsPath(rctx.Str("app-id"))).
|
||||
Desc("List sessions under a Miaoda app").
|
||||
Desc("List sessions under an app").
|
||||
Params(buildSessionListParams(rctx))
|
||||
},
|
||||
Execute: func(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
|
||||
@@ -13,11 +13,11 @@ import (
|
||||
"github.com/larksuite/cli/shortcuts/common"
|
||||
)
|
||||
|
||||
// AppsUpdate partially updates a Miaoda app's name / description.
|
||||
// AppsUpdate partially updates an app's name / description.
|
||||
var AppsUpdate = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+update",
|
||||
Description: "Partially update a Miaoda app (only provided fields are sent)",
|
||||
Description: "Partially update an app (only provided fields are sent)",
|
||||
Risk: "write",
|
||||
Tips: []string{
|
||||
`Example: lark-cli apps +update --app-id <app_id> --name "新名称"`,
|
||||
@@ -49,7 +49,7 @@ var AppsUpdate = common.Shortcut{
|
||||
appID := strings.TrimSpace(rctx.Str("app-id"))
|
||||
return common.NewDryRunAPI().
|
||||
PATCH(fmt.Sprintf("%s/apps/%s", apiBasePath, validate.EncodePathSegment(appID))).
|
||||
Desc("Update a Miaoda app").
|
||||
Desc("Update an app").
|
||||
Body(buildAppsUpdateBody(rctx))
|
||||
},
|
||||
Execute: func(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
|
||||
@@ -12,12 +12,12 @@ import (
|
||||
// appsService 是 CLI 命令的 service 前缀(lark-cli apps ...)。
|
||||
const appsService = "apps"
|
||||
|
||||
// apiBasePath is the registered OAPI prefix for the Miaoda apps domain.
|
||||
// apiBasePath is the registered OAPI prefix for the apps domain.
|
||||
const apiBasePath = "/open-apis/spark/v1"
|
||||
|
||||
// appIDListHint is the shared recovery hint for commands whose most likely
|
||||
// failure cause is a wrong/inaccessible --app-id. It points at +list to find
|
||||
// the correct Miaoda app id. The app_/cli_ format rule is taught in
|
||||
// the correct app id. The app_/cli_ format rule is taught in
|
||||
// lark-apps SKILL.md ("app_id 获取"); the hint stays lean and does not repeat it.
|
||||
const appIDListHint = "verify --app-id is correct and you have access to the app; list your apps with `lark-cli apps +list`"
|
||||
|
||||
|
||||
@@ -35,12 +35,12 @@ const gitCredentialIssuePath = apiBasePath + "/apps/:app_id/git_info"
|
||||
|
||||
// gitCredentialIssueHint is the actionable next-step attached to a failed
|
||||
// Git-credential issuance. A 5xx is flagged retryable separately at the call site.
|
||||
const gitCredentialIssueHint = "failed to issue the Git credential: verify --app-id is correct and you have developer access to this Miaoda app; a 5xx is a transient server error and is safe to retry"
|
||||
const gitCredentialIssueHint = "failed to issue the Git credential: verify --app-id is correct and you have developer access to this app; a 5xx is a transient server error and is safe to retry"
|
||||
|
||||
var AppsGitCredentialInit = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+git-credential-init",
|
||||
Description: "Initialize Git credentials and a URL-scoped Git helper for a Miaoda app repository",
|
||||
Description: "Initialize Git credentials and a URL-scoped Git helper for an app repository",
|
||||
Risk: "write",
|
||||
Tips: []string{
|
||||
"Example: lark-cli apps +git-credential-init --app-id <app_id>",
|
||||
@@ -49,7 +49,7 @@ var AppsGitCredentialInit = common.Shortcut{
|
||||
AuthTypes: []string{"user"},
|
||||
HasFormat: true,
|
||||
Flags: []common.Flag{
|
||||
{Name: "app-id", Desc: "Miaoda app ID", Required: true},
|
||||
{Name: "app-id", Desc: "app ID", Required: true},
|
||||
},
|
||||
Validate: func(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
if strings.TrimSpace(rctx.Str("app-id")) == "" {
|
||||
@@ -64,7 +64,7 @@ var AppsGitCredentialInit = common.Shortcut{
|
||||
appID := strings.TrimSpace(rctx.Str("app-id"))
|
||||
return common.NewDryRunAPI().
|
||||
GET(gitCredentialIssuePath).
|
||||
Desc("Issue a Miaoda Git repository PAT").
|
||||
Desc("Issue an app Git repository PAT").
|
||||
Set("mode", "api-plus-local-setup").
|
||||
Set("action", "initialize_local_git_credential").
|
||||
Set("app_id", appID).
|
||||
@@ -81,7 +81,7 @@ var AppsGitCredentialInit = common.Shortcut{
|
||||
manager := newGitCredentialManager(appID, rctx.Factory.Keychain, runtimeIssuer{rctx: rctx})
|
||||
result, err := manager.Init(ctx, profileFromConfig(rctx.Config), appID)
|
||||
if err != nil {
|
||||
return gitCredentialLocalError("Initialize local Miaoda Git credential", err)
|
||||
return gitCredentialLocalError("Initialize local app Git credential", err)
|
||||
}
|
||||
payload := map[string]interface{}{
|
||||
"app_id": result.AppID,
|
||||
@@ -119,7 +119,7 @@ var AppsGitCredentialInit = common.Shortcut{
|
||||
var AppsGitCredentialRemove = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+git-credential-remove",
|
||||
Description: "Remove local Git credentials and the URL-scoped Git helper for a Miaoda app repository",
|
||||
Description: "Remove local Git credentials and the URL-scoped Git helper for an app repository",
|
||||
Risk: "write",
|
||||
Tips: []string{
|
||||
"Example: lark-cli apps +git-credential-remove --app-id <app_id>",
|
||||
@@ -128,7 +128,7 @@ var AppsGitCredentialRemove = common.Shortcut{
|
||||
AuthTypes: []string{"user"},
|
||||
HasFormat: true,
|
||||
Flags: []common.Flag{
|
||||
{Name: "app-id", Desc: "Miaoda app ID", Required: true},
|
||||
{Name: "app-id", Desc: "app ID", Required: true},
|
||||
},
|
||||
Validate: func(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
if strings.TrimSpace(rctx.Str("app-id")) == "" {
|
||||
@@ -159,7 +159,7 @@ var AppsGitCredentialRemove = common.Shortcut{
|
||||
manager := newGitCredentialManager(appID, rctx.Factory.Keychain, nil)
|
||||
result, err := manager.Remove(ctx, profileFromConfig(rctx.Config), appID)
|
||||
if err != nil {
|
||||
return gitCredentialLocalError("Remove local Miaoda Git credential", err)
|
||||
return gitCredentialLocalError("Remove local app Git credential", err)
|
||||
}
|
||||
payload := map[string]interface{}{
|
||||
"app_id": result.AppID,
|
||||
@@ -193,7 +193,7 @@ var AppsGitCredentialRemove = common.Shortcut{
|
||||
var AppsGitCredentialList = common.Shortcut{
|
||||
Service: appsService,
|
||||
Command: "+git-credential-list",
|
||||
Description: "List local Git credentials for Miaoda app repositories",
|
||||
Description: "List local Git credentials for app repositories",
|
||||
Risk: "read",
|
||||
Tips: []string{
|
||||
"Example: lark-cli apps +git-credential-list",
|
||||
@@ -215,7 +215,7 @@ var AppsGitCredentialList = common.Shortcut{
|
||||
Execute: func(ctx context.Context, rctx *common.RuntimeContext) error {
|
||||
records, err := listGitCredentialRecords(rctx.Factory.Keychain, time.Now)
|
||||
if err != nil {
|
||||
return gitCredentialLocalError("List local Miaoda Git credentials", err)
|
||||
return gitCredentialLocalError("List local app Git credentials", err)
|
||||
}
|
||||
payload := map[string]interface{}{
|
||||
"count": len(records),
|
||||
@@ -252,7 +252,7 @@ func InstallOnApps(parent *cobra.Command, f *cmdutil.Factory) {
|
||||
func newGitCredentialHelperCommand(f *cmdutil.Factory) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "git-credential-helper get|store|erase",
|
||||
Short: "Git credential helper for Miaoda app repositories",
|
||||
Short: "Git credential helper for app repositories",
|
||||
Hidden: true,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
@@ -260,7 +260,7 @@ func newGitCredentialHelperCommand(f *cmdutil.Factory) *cobra.Command {
|
||||
return runGitCredentialHelper(cmd.Context(), f, strings.TrimSpace(appID), args[0])
|
||||
},
|
||||
}
|
||||
cmd.Flags().String("app-id", "", "Miaoda app ID")
|
||||
cmd.Flags().String("app-id", "", "app ID")
|
||||
_ = cmd.Flags().MarkHidden("app-id")
|
||||
return cmd
|
||||
}
|
||||
@@ -457,10 +457,10 @@ func issuedFromData(appID string, data map[string]interface{}) (*gitcred.IssuedC
|
||||
issued.AppID = appID
|
||||
}
|
||||
if issued.GitHTTPURL == "" {
|
||||
return nil, errs.NewInternalError(errs.SubtypeInvalidResponse, "Issue Miaoda Git credential: response missing gitURL")
|
||||
return nil, errs.NewInternalError(errs.SubtypeInvalidResponse, "Issue app Git credential: response missing gitURL")
|
||||
}
|
||||
if issued.PAT == "" {
|
||||
return nil, errs.NewInternalError(errs.SubtypeInvalidResponse, "Issue Miaoda Git credential: response missing token")
|
||||
return nil, errs.NewInternalError(errs.SubtypeInvalidResponse, "Issue app Git credential: response missing token")
|
||||
}
|
||||
return issued, nil
|
||||
}
|
||||
@@ -479,7 +479,7 @@ func parseIssueCredentialData(resp *larkcore.ApiResp, err error, cc errclass.Cla
|
||||
detail := logIDDetail(resp)
|
||||
if resp == nil || len(resp.RawBody) == 0 {
|
||||
return nil, errs.NewInternalError(errs.SubtypeInvalidResponse,
|
||||
"Issue Miaoda Git credential: empty response body")
|
||||
"Issue app Git credential: empty response body")
|
||||
}
|
||||
var result map[string]any
|
||||
jsonErr := json.Unmarshal(resp.RawBody, &result)
|
||||
@@ -522,7 +522,7 @@ func checkGitInfoBaseResp(result map[string]any, logID string) error {
|
||||
if message == "" {
|
||||
message = "Git credential API returned non-zero BaseResp status"
|
||||
}
|
||||
baseErr := errs.NewAPIError(errs.SubtypeUnknown, "Issue Miaoda Git credential: %s", message).WithCode(int(code))
|
||||
baseErr := errs.NewAPIError(errs.SubtypeUnknown, "Issue app Git credential: %s", message).WithCode(int(code))
|
||||
if logID != "" {
|
||||
baseErr = baseErr.WithLogID(logID)
|
||||
}
|
||||
|
||||
@@ -699,7 +699,7 @@ func assertStringSliceEqual(t *testing.T, got, want []string) {
|
||||
|
||||
func TestGitCredentialLocalErrorWrapsOnlyPlainErrors(t *testing.T) {
|
||||
plain := errors.New("git config failed")
|
||||
wrapped := gitCredentialLocalError("List local Miaoda Git credentials", plain)
|
||||
wrapped := gitCredentialLocalError("List local app Git credentials", plain)
|
||||
var configErr *errs.ConfigError
|
||||
if !errors.As(wrapped, &configErr) {
|
||||
t.Fatalf("plain local error wrapped as %T, want *errs.ConfigError", wrapped)
|
||||
|
||||
@@ -458,19 +458,19 @@ func defaultUsername(username string) string {
|
||||
|
||||
func validateIssuedCredential(appID, normalizedURL string, issued *IssuedCredential, now int64) error {
|
||||
if issued == nil {
|
||||
return errs.NewInternalError(errs.SubtypeInvalidResponse, "Issue Miaoda Git credential: empty credential")
|
||||
return errs.NewInternalError(errs.SubtypeInvalidResponse, "Issue app Git credential: empty credential")
|
||||
}
|
||||
if issued.AppID != "" && issued.AppID != appID {
|
||||
return errs.NewInternalError(errs.SubtypeInvalidResponse, "Issue Miaoda Git credential: response app_id %q does not match requested app_id %q", issued.AppID, appID)
|
||||
return errs.NewInternalError(errs.SubtypeInvalidResponse, "Issue app Git credential: response app_id %q does not match requested app_id %q", issued.AppID, appID)
|
||||
}
|
||||
if normalizedURL == "" {
|
||||
return errs.NewInternalError(errs.SubtypeInvalidResponse, "Issue Miaoda Git credential: response missing gitURL")
|
||||
return errs.NewInternalError(errs.SubtypeInvalidResponse, "Issue app Git credential: response missing gitURL")
|
||||
}
|
||||
if strings.TrimSpace(issued.PAT) == "" {
|
||||
return errs.NewInternalError(errs.SubtypeInvalidResponse, "Issue Miaoda Git credential: response missing token")
|
||||
return errs.NewInternalError(errs.SubtypeInvalidResponse, "Issue app Git credential: response missing token")
|
||||
}
|
||||
if issued.ExpiresAt <= now {
|
||||
return errs.NewInternalError(errs.SubtypeInvalidResponse, "Issue Miaoda Git credential: response expiredTime must be in the future")
|
||||
return errs.NewInternalError(errs.SubtypeInvalidResponse, "Issue app Git credential: response expiredTime must be in the future")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ const (
|
||||
)
|
||||
|
||||
// CredentialFile is the app-scoped non-secret metadata persisted under the
|
||||
// Miaoda app storage directory.
|
||||
// app storage directory.
|
||||
type CredentialFile struct {
|
||||
Version int `json:"version"`
|
||||
CredentialRecord
|
||||
|
||||
@@ -53,7 +53,7 @@ func (api appsHTMLPublishAPI) HTMLPublish(ctx context.Context, appID string, tar
|
||||
return &htmlPublishResponse{URL: url}, nil
|
||||
}
|
||||
|
||||
// OAPI business error codes returned by the Miaoda
|
||||
// OAPI business error codes returned by the
|
||||
// /apps/{id}/upload_and_release_html_code endpoint. Owned by the backend
|
||||
// service; update when new codes are documented in the OAPI spec.
|
||||
const (
|
||||
@@ -66,7 +66,7 @@ func buildHTMLPublishFailureHint(code int) string {
|
||||
case errCodeBuildFailed:
|
||||
return "server-side build failed: run `lark-cli apps +html-publish --app-id <your-app-id> --path <path> --dry-run` to inspect the packaged file list"
|
||||
case errCodeAppNotFound:
|
||||
return "the app does not exist or the caller has no access; ask the user to confirm the app_id (extract it from the Miaoda app URL https://miaoda.feishu.cn/app/app_xxx after /app/, or take the app_xxx string directly)"
|
||||
return "the app does not exist or the caller has no access; ask the user to confirm the app_id (extract it from the app URL https://miaoda.feishu.cn/app/app_xxx after /app/, or take the app_xxx string directly)"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
- `TestAppsAccessScopeSetDryRun`: CLI input `specific`/`public`/`tenant` -> server enum `Range`/`All`/`Tenant`; `apply_config.approvers` shape; four mutex rejection paths.
|
||||
- `TestAppsAccessScopeGetDryRun`: URL shape; no body/params on GET; `--app-id` required.
|
||||
- `TestAppsHTMLPublishDryRun`: walker manifest for directory + single file; hidden files intentionally included (design decision); empty dir / missing `index.html` produce envelope `validation_error` field (dry-run exits 0 advisory, not blocking); both required-flag rejections.
|
||||
- `TestAppsGitCredentialInitDryRun`: URL shape for issuing a Miaoda Git PAT; no body; `app_id` query metadata included.
|
||||
- `TestAppsGitCredentialInitDryRun`: URL shape for issuing an app Git PAT; no body; `app_id` query metadata included.
|
||||
- `TestAppsGitCredentialListLocalE2E`: local-only command scans every app storage directory and reports repository URL and status without exposing PAT or expiry details.
|
||||
- `TestAppsGitCredentialRemoveLocalE2E`: local cleanup command removes app-scoped metadata under an isolated config dir.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user