Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b42596214d | ||
|
|
f684c412ea | ||
|
|
415d962371 | ||
|
|
26253a4eeb | ||
|
|
8549a90402 | ||
|
|
a5dbd2e049 | ||
|
|
b1a6f9e20c | ||
|
|
0fae9dd8b3 |
@@ -54,6 +54,8 @@ The format is inspired by [Keep a Changelog](https://keepachangelog.com/) and th
|
||||
|
||||
- **Sheet revision changesets** — adds read-only commands for querying the current workbook revision and reviewing Agent-readable changes between revisions, with guidance for distinguishing revisions from saved history versions and safely selecting rollback targets.
|
||||
|
||||
- **Sheet floating images** — supports creating or replacing a floating image directly from a local file with `create-float-image --file` and `update-float-image --file`, while retaining the existing `--src` workflow.
|
||||
|
||||
### Changed
|
||||
|
||||
- **AiSearch and Contact shortcuts** (#1083) — adds strict people search and reviewed unified results; people results must use the live-reviewed `person` source, and exact mobile lookups normalize accepted formatting before calling the dedicated mobile interface. Agent/public discovery keeps `contact +list-roles`, `contact +list-roster-fields`, `contact +get-roster`, and incomplete Live routes unavailable rather than publishing ambiguous results, while the historical Contact CLI commands retain legacy MCP execution and real error propagation. The legacy role-list projection preserves the service's reviewed null placeholder without exposing that ambiguous row through Agent Result contracts.
|
||||
|
||||
@@ -148,7 +148,7 @@ var paramAliasCompleteCommands = map[string][]string{
|
||||
"contact +resolve-dept": {"contact", "+resolve-dept", "--name", "Fixture Dept"},
|
||||
"contact +search-user": {"contact", "+search-user", "--query", "Fixture User"},
|
||||
"contact dept list-children": {"contact", "dept", "list-children", "--dept", "1"},
|
||||
"contact user profile get": {"contact", "user", "profile", "get", "--staff-id", "user-1"},
|
||||
"contact user profile get": {"contact", "user", "profile", "get", "--staff-id", "user-1", "--fields", "name,userId"},
|
||||
"dev app get": {"dev", "app", "get", "--unified-app-id", "app-1"},
|
||||
"devdoc article search": {"devdoc", "article", "search", "--query", "fixture", "--page", "2", "--size", "7"},
|
||||
"ding +receiver-status": {"ding", "+receiver-status", "--ding-id", "ding-1"},
|
||||
@@ -237,52 +237,106 @@ var paramAliasCompleteCommands = map[string][]string{
|
||||
// param_concepts.json: inactive candidate templates are ignored, while every
|
||||
// command becomes mandatory as soon as one of its reviewed aliases is active.
|
||||
var paramAliasCandidateCompleteCommands = map[string][]string{
|
||||
"attendance +check-record": {"attendance", "+check-record", "--users", "user-1,user-2", "--start", "2026-03-10 00:00:00", "--end", "2026-03-10 23:59:59"},
|
||||
"attendance +get-adjustment-rule": {"attendance", "+get-adjustment-rule", "--adjustment-id", "adjustment-1"},
|
||||
"attendance +get-approve-template": {"attendance", "+get-approve-template", "--type", "leave"},
|
||||
"attendance +get-checkin-record": {"attendance", "+get-checkin-record", "--operator-corp-id", "corp-1", "--operator-staff-id", "staff-operator", "--staff-ids", "staff-1,staff-2", "--start", "2026-03-10 00:00:00", "--end", "2026-03-10 23:59:59"},
|
||||
"attendance +get-leave-records": {"attendance", "+get-leave-records", "--user", "user-1", "--start", "2026-03-01", "--end", "2026-03-31", "--leave-code", "annual_leave"},
|
||||
"attendance +get-overtime-rule": {"attendance", "+get-overtime-rule", "--overtime-id", "overtime-1"},
|
||||
"attendance +get-schedule": {"attendance", "+get-schedule", "--users", "user-1,user-2", "--start", "2026-03-10", "--end", "2026-03-11"},
|
||||
"attendance +get-self-setting": {"attendance", "+get-self-setting", "--user", "user-1", "--setting-scene", "checkRemind"},
|
||||
"attendance +get-summary": {"attendance", "+get-summary", "--user", "user-1", "--date", "2026-03-10", "--stats-type", "week"},
|
||||
"attendance +list-approve": {"attendance", "+list-approve", "--users", "user-1,user-2", "--types", "leave", "--start", "2026-03-01", "--end", "2026-03-31"},
|
||||
"attendance +query-report-data": {"attendance", "+query-report-data", "--users", "user-1,user-2", "--columns", "attendance_days,late_count", "--start", "2026-03-01", "--end", "2026-03-31"},
|
||||
"attendance +search-adjustment-rule": {"attendance", "+search-adjustment-rule", "--query", "fixture", "--page", "2", "--limit", "7"},
|
||||
"attendance +search-class": {"attendance", "+search-class", "--filter-type", "name", "--query", "fixture"},
|
||||
"attendance +search-group": {"attendance", "+search-group", "--type", "FIXED"},
|
||||
"attendance +search-overtime-rule": {"attendance", "+search-overtime-rule", "--query", "fixture", "--page", "2", "--limit", "7"},
|
||||
"ding +list": {"ding", "+list", "--cursor", "0", "--type", "ALL"},
|
||||
"ding +recall-personal": {"ding", "+recall-personal", "--id", "ding-1", "--yes"},
|
||||
"ding +send-personal": {"ding", "+send-personal", "--users", appFixtureCurrentDOpenID, "--content", "fixture", "--yes"},
|
||||
"mail +contact-list": {"mail", "+contact-list", "--email", "fixture@example.com", "--limit", "7", "--cursor", "cursor-1"},
|
||||
"mail +folder-list": {"mail", "+folder-list", "--email", "fixture@example.com", "--folder", "folder-1"},
|
||||
"mail +message": {"mail", "+message", "--email", "fixture@example.com", "--id", "message-1"},
|
||||
"mail +messages": {"mail", "+messages", "--email", "fixture@example.com", "--ids", "message-1,message-2"},
|
||||
"mail +recent-mail": {"mail", "+recent-mail", "--limit", "7", "--cursor", "cursor-1"},
|
||||
"mail +search-mail": {"mail", "+search-mail", "--query", "fixture", "--size", "7", "--cursor", "cursor-1"},
|
||||
"mail +template-list": {"mail", "+template-list", "--email", "fixture@example.com", "--limit", "7", "--cursor", "cursor-1"},
|
||||
"mail +thread": {"mail", "+thread", "--email", "fixture@example.com", "--id", "thread-1"},
|
||||
"mail +thread-list": {"mail", "+thread-list", "--email", "fixture@example.com", "--folder", "folder-1", "--cursor", "cursor-1"},
|
||||
"mail +triage": {"mail", "+triage", "--query", "fixture", "--limit", "7", "--cursor", "cursor-1"},
|
||||
"mail +unread-mail": {"mail", "+unread-mail", "--size", "7", "--cursor", "cursor-1"},
|
||||
"mail +user-search": {"mail", "+user-search", "--keyword", "fixture", "--cursor", "cursor-1"},
|
||||
"markdown create": {"markdown", "create", "--content", "# Fixture", "--name", "fixture.md", "--space-id", "space-1"},
|
||||
"markdown diff": {"markdown", "diff", "--node", "node-1", "--version", "1", "--version2", "2", "--context", "3"},
|
||||
"markdown fetch": {"markdown", "fetch", "--node", "node-1", "--space-id", "space-1", "--output", "/tmp/dws-markdown-fixture.md"},
|
||||
"markdown overwrite": {"markdown", "overwrite", "--node", "node-1", "--content", "# Fixture", "--name", "fixture.md", "--space-id", "space-1", "--yes"},
|
||||
"markdown patch": {"markdown", "patch", "--node", "node-1", "--pattern", "old", "--content", "new", "--regex", "--space-id", "space-1", "--yes"},
|
||||
"oa +list-cc": {"oa", "+list-cc", "--page", "2"},
|
||||
"oa +list-executed": {"oa", "+list-executed", "--limit", "7", "--page", "2"},
|
||||
"oa +list-forms": {"oa", "+list-forms", "--cursor", "2"},
|
||||
"oa +list-pending": {"oa", "+list-pending", "--start", "1773072000000", "--end", "1773158399000", "--page", "2"},
|
||||
"oa +list-submitted": {"oa", "+list-submitted", "--page", "2"},
|
||||
"oa +my-initiated": {"oa", "+my-initiated", "--page", "2"},
|
||||
"report +outbox-list": {"report", "+outbox-list", "--size", "7"},
|
||||
"report +report-latest": {"report", "+report-latest", "--keyword", "Fixture", "--start", "2026-03-01T00:00:00+08:00", "--end", "2026-03-10T00:00:00+08:00"},
|
||||
"report +template-search": {"report", "+template-search", "--query", "fixture"},
|
||||
"sheet +list-sheets": {"sheet", "+list-sheets", "--node", "node-1"},
|
||||
"sheet +read": {"sheet", "+read", "--node", "node-1", "--sheet-id", "Sheet1"},
|
||||
"aisearch": {"aisearch", "--query", "Fixture User", "--dimension", "name"},
|
||||
"aisearch +search-person": {"aisearch", "+search-person", "--query", "Fixture User", "--dimensions", "name"},
|
||||
"aisearch behavior": {"aisearch", "behavior", "--queries", "fixture", "--types", "im", "--behavior-type", "send", "--chat-scope", "Fixture Group", "--direction", "我->Fixture User", "--time-range", "本周"},
|
||||
"aisearch enterprise": {"aisearch", "enterprise", "--queries", "fixture", "--types", "document", "--time-range", "本周"},
|
||||
"aisearch person": {"aisearch", "person", "--query", "Fixture User", "--dimension", "name"},
|
||||
"contact +by-mobile": {"contact", "+by-mobile", "--mobile", "13800138000"},
|
||||
"contact +list-dept-members": {"contact", "+list-dept-members", "--depts", "1,2"},
|
||||
"contact +list-followings": {"contact", "+list-followings", "--open-id", "open-fixture-1"},
|
||||
"contact +list-role-members": {"contact", "+list-role-members", "--id", "12345"},
|
||||
"contact +lookup": {"contact", "+lookup", "--name", "Fixture User"},
|
||||
"contact +org": {"contact", "+org", "--name", "Fixture User"},
|
||||
"contact +search-mobile": {"contact", "+search-mobile", "--mobile", "13800138000"},
|
||||
"contact +team": {"contact", "+team", "--name", "Fixture User"},
|
||||
"contact account create": {"contact", "account", "create", "--login-id", "fixture-login", "--org-user-name", "Fixture User", "--dept-ids", "1,2"},
|
||||
"contact account update": {"contact", "account", "update", "--user-id", "user-1", "--org-user-name", "Fixture User", "--depts", `[{"deptId":1}]`, "--avatar-file-id", "file-1", "--yes"},
|
||||
"contact dept create": {"contact", "dept", "create", "--name", "Fixture Dept", "--parent", "1", "--create-dept-group", "--yes"},
|
||||
"contact dept get-info": {"contact", "dept", "get-info", "--dept", "1"},
|
||||
"contact dept list-members": {"contact", "dept", "list-members", "--depts", "1,2"},
|
||||
"contact dept search": {"contact", "dept", "search", "--query", "Fixture Dept"},
|
||||
"contact dept update": {"contact", "dept", "update", "--dept", "2", "--name", "Fixture Dept", "--parent", "1", "--yes"},
|
||||
"contact label get": {"contact", "label", "get", "--names", "Fixture Role"},
|
||||
"contact org create": {"contact", "org", "create", "--org-name", "Fixture Org", "--creator-username", "Fixture Creator"},
|
||||
"contact user dismission search": {"contact", "user", "dismission", "search", "--depts", "1,2", "--start", "2026-03-01", "--end", "2026-03-31", "--page", "2", "--limit", "7"},
|
||||
"contact user get": {"contact", "user", "get", "--ids", "user-1,user-2"},
|
||||
"contact user invite": {"contact", "user", "invite", "--org-user-mobile", "13800138000", "--org-user-name", "Fixture User", "--depts", `[{"deptId":1}]`},
|
||||
"contact user search": {"contact", "user", "search", "--query", "Fixture User"},
|
||||
"contact user search-mobile": {"contact", "user", "search-mobile", "--mobile", "13800138000"},
|
||||
"contact user update": {"contact", "user", "update", "--user-id", "user-1", "--org-user-name", "Fixture User", "--depts", `[{"deptId":1}]`, "--yes"},
|
||||
"contact user update-ownness": {"contact", "user", "update-ownness", "--user-id", "user-1", "--ownness-text", "Fixture Status", "--yes"},
|
||||
"contact user update-self": {"contact", "user", "update-self", "--avatar-file-id", "file-1", "--nick", "Fixture Nick", "--yes"},
|
||||
"devdoc +search-docs": {"devdoc", "+search-docs", "--query", "fixture", "--page", "2", "--size", "7"},
|
||||
"hrbrain +get-pool": {"hrbrain", "+get-pool", "--pool-code", "pool-1"},
|
||||
"hrbrain +list-pool-employees": {"hrbrain", "+list-pool-employees", "--pool-code", "pool-1", "--page", "2", "--page-size", "7"},
|
||||
"hrbrain +list-pools": {"hrbrain", "+list-pools", "--keyword", "fixture", "--labels", "label-a,label-b", "--page", "2", "--page-size", "7"},
|
||||
"hrbrain +profile-career": {"hrbrain", "+profile-career", "--work-no", "work-1"},
|
||||
"hrbrain +profile-labels": {"hrbrain", "+profile-labels", "--staff-ids", "work-1,work-2", "--all-label"},
|
||||
"hrbrain +profile-metadata": {"hrbrain", "+profile-metadata", "--work-no", "work-1"},
|
||||
"hrbrain +profile-performance": {"hrbrain", "+profile-performance", "--work-no", "work-1"},
|
||||
"hrbrain +query-profile": {"hrbrain", "+query-profile", "--work-no", "work-1", "--data-queries", `[{"modelCode":"basic","fields":["name"]}]`},
|
||||
"hrbrain +search-employees": {"hrbrain", "+search-employees", "--keyword", "fixture", "--dept-name", "Fixture Dept", "--position-name", "Engineer", "--job-level", "P7", "--pool-code", "pool-1", "--page", "2", "--page-size", "7"},
|
||||
"hrbrain +search-employees-structured": {"hrbrain", "+search-employees-structured", "--origin-json", `{"rules":[],"combinator":"and"}`, "--fields", `[{"label":"name","value":"name"}]`, "--order-by", "name", "--page", "2", "--page-size", "7"},
|
||||
"hrbrain profile career": {"hrbrain", "profile", "career", "--work-no", "work-1"},
|
||||
"hrbrain profile labels": {"hrbrain", "profile", "labels", "--staff-ids", "work-1,work-2", "--all-label"},
|
||||
"hrbrain profile metadata": {"hrbrain", "profile", "metadata", "--work-no", "work-1"},
|
||||
"hrbrain profile performance": {"hrbrain", "profile", "performance", "--work-no", "work-1"},
|
||||
"hrbrain profile query": {"hrbrain", "profile", "query", "--work-no", "work-1", "--data-queries", `[{"modelCode":"basic","fields":["name"]}]`},
|
||||
"hrbrain search employees": {"hrbrain", "search", "employees", "--keyword", "fixture", "--dept-name", "Fixture Dept", "--position-name", "Engineer", "--job-level", "P7", "--pool-code", "pool-1", "--page", "2", "--page-size", "7"},
|
||||
"hrbrain search employees-structured": {"hrbrain", "search", "employees-structured", "--origin-json", `{"rules":[],"combinator":"and"}`, "--fields", `[{"label":"name","value":"name"}]`, "--order-by", "name", "--page", "2", "--page-size", "7"},
|
||||
"hrbrain talent-pool detail": {"hrbrain", "talent-pool", "detail", "--pool-code", "pool-1"},
|
||||
"hrbrain talent-pool employees": {"hrbrain", "talent-pool", "employees", "--pool-code", "pool-1", "--page", "2", "--page-size", "7"},
|
||||
"hrbrain talent-pool list": {"hrbrain", "talent-pool", "list", "--keyword", "fixture", "--labels", "label-a,label-b", "--page", "2", "--page-size", "7"},
|
||||
"pat +browser-policy": {"pat", "+browser-policy", "--enabled=false", "--agent-code", "fixture-agent", "--dry-run"},
|
||||
"pat browser-policy": {"pat", "browser-policy", "--enabled=false", "--agentCode", "fixture-agent"},
|
||||
"pat chmod": {"pat", "chmod", "--product", "calendar", "--products", "aitable", "--domain", "chat", "--domains", "mail", "--grant-type", "session", "--session-id", "session-1", "--recommend", "--agentCode", "fixture-agent", "--dry-run"},
|
||||
"attendance +check-record": {"attendance", "+check-record", "--users", "user-1,user-2", "--start", "2026-03-10 00:00:00", "--end", "2026-03-10 23:59:59"},
|
||||
"attendance +get-adjustment-rule": {"attendance", "+get-adjustment-rule", "--adjustment-id", "adjustment-1"},
|
||||
"attendance +get-approve-template": {"attendance", "+get-approve-template", "--type", "leave"},
|
||||
"attendance +get-checkin-record": {"attendance", "+get-checkin-record", "--operator-corp-id", "corp-1", "--operator-staff-id", "staff-operator", "--staff-ids", "staff-1,staff-2", "--start", "2026-03-10 00:00:00", "--end", "2026-03-10 23:59:59"},
|
||||
"attendance +get-leave-records": {"attendance", "+get-leave-records", "--user", "user-1", "--start", "2026-03-01", "--end", "2026-03-31", "--leave-code", "annual_leave"},
|
||||
"attendance +get-overtime-rule": {"attendance", "+get-overtime-rule", "--overtime-id", "overtime-1"},
|
||||
"attendance +get-schedule": {"attendance", "+get-schedule", "--users", "user-1,user-2", "--start", "2026-03-10", "--end", "2026-03-11"},
|
||||
"attendance +get-self-setting": {"attendance", "+get-self-setting", "--user", "user-1", "--setting-scene", "checkRemind"},
|
||||
"attendance +get-summary": {"attendance", "+get-summary", "--user", "user-1", "--date", "2026-03-10", "--stats-type", "week"},
|
||||
"attendance +list-approve": {"attendance", "+list-approve", "--users", "user-1,user-2", "--types", "leave", "--start", "2026-03-01", "--end", "2026-03-31"},
|
||||
"attendance +query-report-data": {"attendance", "+query-report-data", "--users", "user-1,user-2", "--columns", "attendance_days,late_count", "--start", "2026-03-01", "--end", "2026-03-31"},
|
||||
"attendance +search-adjustment-rule": {"attendance", "+search-adjustment-rule", "--query", "fixture", "--page", "2", "--limit", "7"},
|
||||
"attendance +search-class": {"attendance", "+search-class", "--filter-type", "name", "--query", "fixture"},
|
||||
"attendance +search-group": {"attendance", "+search-group", "--type", "FIXED"},
|
||||
"attendance +search-overtime-rule": {"attendance", "+search-overtime-rule", "--query", "fixture", "--page", "2", "--limit", "7"},
|
||||
"ding +list": {"ding", "+list", "--cursor", "0", "--type", "ALL"},
|
||||
"ding +recall-personal": {"ding", "+recall-personal", "--id", "ding-1", "--yes"},
|
||||
"ding +send-personal": {"ding", "+send-personal", "--users", appFixtureCurrentDOpenID, "--content", "fixture", "--yes"},
|
||||
"mail +contact-list": {"mail", "+contact-list", "--email", "fixture@example.com", "--limit", "7", "--cursor", "cursor-1"},
|
||||
"mail +folder-list": {"mail", "+folder-list", "--email", "fixture@example.com", "--folder", "folder-1"},
|
||||
"mail +message": {"mail", "+message", "--email", "fixture@example.com", "--id", "message-1"},
|
||||
"mail +messages": {"mail", "+messages", "--email", "fixture@example.com", "--ids", "message-1,message-2"},
|
||||
"mail +recent-mail": {"mail", "+recent-mail", "--limit", "7", "--cursor", "cursor-1"},
|
||||
"mail +search-mail": {"mail", "+search-mail", "--query", "fixture", "--size", "7", "--cursor", "cursor-1"},
|
||||
"mail +template-list": {"mail", "+template-list", "--email", "fixture@example.com", "--limit", "7", "--cursor", "cursor-1"},
|
||||
"mail +thread": {"mail", "+thread", "--email", "fixture@example.com", "--id", "thread-1"},
|
||||
"mail +thread-list": {"mail", "+thread-list", "--email", "fixture@example.com", "--folder", "folder-1", "--cursor", "cursor-1"},
|
||||
"mail +triage": {"mail", "+triage", "--query", "fixture", "--limit", "7", "--cursor", "cursor-1"},
|
||||
"mail +unread-mail": {"mail", "+unread-mail", "--size", "7", "--cursor", "cursor-1"},
|
||||
"mail +user-search": {"mail", "+user-search", "--keyword", "fixture", "--cursor", "cursor-1"},
|
||||
"markdown create": {"markdown", "create", "--content", "# Fixture", "--name", "fixture.md", "--space-id", "space-1"},
|
||||
"markdown diff": {"markdown", "diff", "--node", "node-1", "--version", "1", "--version2", "2", "--context", "3"},
|
||||
"markdown fetch": {"markdown", "fetch", "--node", "node-1", "--space-id", "space-1", "--output", "/tmp/dws-markdown-fixture.md"},
|
||||
"markdown overwrite": {"markdown", "overwrite", "--node", "node-1", "--content", "# Fixture", "--name", "fixture.md", "--space-id", "space-1", "--yes"},
|
||||
"markdown patch": {"markdown", "patch", "--node", "node-1", "--pattern", "old", "--content", "new", "--regex", "--space-id", "space-1", "--yes"},
|
||||
"oa +list-cc": {"oa", "+list-cc", "--page", "2"},
|
||||
"oa +list-executed": {"oa", "+list-executed", "--limit", "7", "--page", "2"},
|
||||
"oa +list-forms": {"oa", "+list-forms", "--cursor", "2"},
|
||||
"oa +list-pending": {"oa", "+list-pending", "--start", "1773072000000", "--end", "1773158399000", "--page", "2"},
|
||||
"oa +list-submitted": {"oa", "+list-submitted", "--page", "2"},
|
||||
"oa +my-initiated": {"oa", "+my-initiated", "--page", "2"},
|
||||
"report +outbox-list": {"report", "+outbox-list", "--size", "7"},
|
||||
"report +report-latest": {"report", "+report-latest", "--keyword", "Fixture", "--start", "2026-03-01T00:00:00+08:00", "--end", "2026-03-10T00:00:00+08:00"},
|
||||
"report +template-search": {"report", "+template-search", "--query", "fixture"},
|
||||
"sheet +list-sheets": {"sheet", "+list-sheets", "--node", "node-1"},
|
||||
"sheet +read": {"sheet", "+read", "--node", "node-1", "--sheet-id", "Sheet1"},
|
||||
|
||||
"minutes +detail": {"minutes", "+detail", "--ids", "u1,u2"},
|
||||
"minutes +latest": {"minutes", "+latest", "--keyword", "fixture"},
|
||||
@@ -1030,14 +1084,14 @@ func assertParamAliasCannotBypassConfirmation(t *testing.T, aliasArgs []string)
|
||||
}
|
||||
}
|
||||
|
||||
// TestCrossPlatformCoverageEightProductTemplatedParamAliasesCannotBypassConfirmation
|
||||
// TestCrossPlatformCoverageReviewedProductTemplatedParamAliasesCannotBypassConfirmation
|
||||
// exercises every distinct reviewed mutating complete-command template in the
|
||||
// eight-product Shortcut expansion. The fixture gate already proves every
|
||||
// reviewed product expansions. The fixture gate already proves every
|
||||
// alias resolves through PreParse; this gate removes the confirmation flag
|
||||
// from one active alias invocation per distinct template and requires the
|
||||
// runtime boundary to stop it before the first transport call. An explicit
|
||||
// --dry-run is a reviewed preview path and must not carry a bypass flag.
|
||||
func TestCrossPlatformCoverageEightProductTemplatedParamAliasesCannotBypassConfirmation(t *testing.T) {
|
||||
func TestCrossPlatformCoverageReviewedProductTemplatedParamAliasesCannotBypassConfirmation(t *testing.T) {
|
||||
concepts, err := cli.LoadParamConcepts()
|
||||
if err != nil {
|
||||
t.Fatalf("LoadParamConcepts() error = %v", err)
|
||||
@@ -1051,7 +1105,8 @@ func TestCrossPlatformCoverageEightProductTemplatedParamAliasesCannotBypassConfi
|
||||
}
|
||||
product, _, _ := strings.Cut(fixture.Command, " ")
|
||||
switch product {
|
||||
case "attendance", "mail", "oa", "ding", "report", "sheet", "whiteboard", "markdown":
|
||||
case "attendance", "mail", "oa", "ding", "report", "sheet", "whiteboard", "markdown",
|
||||
"aisearch", "contact", "live", "devdoc", "hrbrain", "pat":
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -10,6 +10,102 @@ package cli
|
||||
// generatedParamAliases is the per-command parameter-alias table reduced from
|
||||
// the reviewed concept dictionary. Each entry binds one runnable Cobra leaf.
|
||||
var generatedParamAliases = []ParamAliasEntry{
|
||||
{
|
||||
CLIPath: "aisearch",
|
||||
Aliases: map[string]string{
|
||||
"dimensions": "dimension",
|
||||
"person-dimension": "dimension",
|
||||
"person-name": "query",
|
||||
"person-query": "query",
|
||||
"search-by": "dimension",
|
||||
"search-dimension": "dimension",
|
||||
"search-term": "query",
|
||||
},
|
||||
Blocked: []string{"action-type", "behavior-type", "category", "chat-scope", "department-id", "direction", "employee-number", "field", "job-number", "mobile", "open-dingtalk-id", "phone-number", "queries", "search-types", "time-range", "types", "user-id"},
|
||||
Ambiguous: []string{"department", "duty", "employee", "id", "phone", "position", "scope", "target"},
|
||||
},
|
||||
{
|
||||
CLIPath: "aisearch +search-person",
|
||||
Aliases: map[string]string{
|
||||
"dimension": "dimensions",
|
||||
"keyword": "query",
|
||||
"keywords": "query",
|
||||
"person-dimension": "dimensions",
|
||||
"person-name": "query",
|
||||
"person-query": "query",
|
||||
"q": "query",
|
||||
"search-by": "dimensions",
|
||||
"search-dimension": "dimensions",
|
||||
"search-term": "query",
|
||||
"search-word": "query",
|
||||
},
|
||||
Blocked: []string{"action-type", "behavior-type", "category", "chat-scope", "department-id", "direction", "employee-number", "field", "ids", "job-number", "mobile", "name", "open-dingtalk-id", "phone-number", "position-id", "queries", "search-types", "subject", "text", "time-range", "title", "type", "types", "user-id"},
|
||||
Ambiguous: []string{"department", "duty", "employee", "id", "phone", "position", "scope", "target"},
|
||||
},
|
||||
{
|
||||
CLIPath: "aisearch behavior",
|
||||
Aliases: map[string]string{
|
||||
"action-type": "behavior-type",
|
||||
"activity-type": "behavior-type",
|
||||
"behavior-action": "behavior-type",
|
||||
"chat-name": "chat-scope",
|
||||
"content-queries": "queries",
|
||||
"content-query": "queries",
|
||||
"content-types": "types",
|
||||
"conversation-name": "chat-scope",
|
||||
"date-range": "time-range",
|
||||
"group-name": "chat-scope",
|
||||
"im-scope": "chat-scope",
|
||||
"interaction-direction": "direction",
|
||||
"interaction-flow": "direction",
|
||||
"message-flow": "direction",
|
||||
"period": "time-range",
|
||||
"resource-types": "types",
|
||||
"search-categories": "types",
|
||||
"search-period": "time-range",
|
||||
"search-terms": "queries",
|
||||
"search-type-list": "types",
|
||||
"time-window": "time-range",
|
||||
"topic-queries": "queries",
|
||||
"topics": "queries",
|
||||
},
|
||||
Blocked: []string{"chat-id", "conversation-id", "created-at", "dimension", "dimensions", "document-id", "end", "file-id", "from", "group-id", "natural-language", "node-id", "open-conversation-id", "open-dingtalk-id", "question", "receiver", "sender", "since", "start", "to", "until", "update", "updated-at", "user-id", "write"},
|
||||
Ambiguous: []string{"action", "actor", "category", "chat", "conversation", "date", "destination", "group", "range", "scope", "source", "target", "time", "type"},
|
||||
},
|
||||
{
|
||||
CLIPath: "aisearch enterprise",
|
||||
Aliases: map[string]string{
|
||||
"content-queries": "queries",
|
||||
"content-query": "queries",
|
||||
"content-types": "types",
|
||||
"date-range": "time-range",
|
||||
"period": "time-range",
|
||||
"resource-types": "types",
|
||||
"search-categories": "types",
|
||||
"search-period": "time-range",
|
||||
"search-terms": "queries",
|
||||
"search-type-list": "types",
|
||||
"time-window": "time-range",
|
||||
"topic-queries": "queries",
|
||||
"topics": "queries",
|
||||
},
|
||||
Blocked: []string{"action-type", "behavior-type", "chat-scope", "created-at", "dimension", "dimensions", "direction", "document-id", "end", "file-id", "from", "group-name", "node-id", "open-dingtalk-id", "receiver", "sender", "since", "start", "to", "until", "update", "updated-at", "user-id", "write"},
|
||||
Ambiguous: []string{"category", "date", "natural-language", "question", "range", "scope", "source", "time", "type"},
|
||||
},
|
||||
{
|
||||
CLIPath: "aisearch person",
|
||||
Aliases: map[string]string{
|
||||
"dimensions": "dimension",
|
||||
"person-dimension": "dimension",
|
||||
"person-name": "query",
|
||||
"person-query": "query",
|
||||
"search-by": "dimension",
|
||||
"search-dimension": "dimension",
|
||||
"search-term": "query",
|
||||
},
|
||||
Blocked: []string{"action-type", "behavior-type", "category", "chat-scope", "department-id", "direction", "employee-number", "field", "ids", "job-number", "mobile", "open-dingtalk-id", "phone-number", "position-id", "queries", "search-types", "time-range", "types", "user-id"},
|
||||
Ambiguous: []string{"department", "duty", "employee", "id", "phone", "position", "scope", "target"},
|
||||
},
|
||||
{
|
||||
CLIPath: "aitable +advperm-disable",
|
||||
Aliases: map[string]string{
|
||||
@@ -4128,6 +4224,13 @@ var generatedParamAliases = []ParamAliasEntry{
|
||||
},
|
||||
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "id", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact +by-mobile",
|
||||
Aliases: map[string]string{
|
||||
"org-user-mobile": "mobile",
|
||||
},
|
||||
Blocked: []string{"email", "login-id", "user-id"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact +dept-members",
|
||||
Aliases: map[string]string{
|
||||
@@ -4148,6 +4251,23 @@ var generatedParamAliases = []ParamAliasEntry{
|
||||
},
|
||||
Blocked: []string{"department-id", "dept", "dept-id", "name", "query"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact +list-followings",
|
||||
Aliases: map[string]string{
|
||||
"open-dingtalk-id": "open-id",
|
||||
"open-dingtalkid": "open-id",
|
||||
},
|
||||
Blocked: []string{"email", "mobile", "name", "open-dingtalk-ids", "phone", "query", "staff-id", "user-id", "userid"},
|
||||
Ambiguous: []string{"id", "person", "user"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact +list-role-members",
|
||||
Aliases: map[string]string{
|
||||
"label-id": "id",
|
||||
"role-id": "id",
|
||||
},
|
||||
Blocked: []string{"dept", "dept-id", "ids", "names", "staff-id", "user-id"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact +list-sub-depts",
|
||||
Aliases: map[string]string{
|
||||
@@ -4159,6 +4279,28 @@ var generatedParamAliases = []ParamAliasEntry{
|
||||
},
|
||||
Blocked: []string{"department-ids", "dept-ids", "depts", "name", "query"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact +lookup",
|
||||
Aliases: map[string]string{
|
||||
"employee-name": "name",
|
||||
"flower-name": "name",
|
||||
"person-name": "name",
|
||||
"staff-name": "name",
|
||||
"user-name": "name",
|
||||
},
|
||||
Blocked: []string{"department-id", "dept", "dept-id", "org-name", "role-name"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact +org",
|
||||
Aliases: map[string]string{
|
||||
"employee-name": "name",
|
||||
"flower-name": "name",
|
||||
"person-name": "name",
|
||||
"staff-name": "name",
|
||||
"user-name": "name",
|
||||
},
|
||||
Blocked: []string{"department-id", "dept", "dept-id", "org-name", "role-name"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact +resolve-dept",
|
||||
Aliases: map[string]string{
|
||||
@@ -4170,6 +4312,13 @@ var generatedParamAliases = []ParamAliasEntry{
|
||||
},
|
||||
Blocked: []string{"subject", "text", "title"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact +search-mobile",
|
||||
Aliases: map[string]string{
|
||||
"org-user-mobile": "mobile",
|
||||
},
|
||||
Blocked: []string{"email", "login-id", "user-id"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact +search-user",
|
||||
Aliases: map[string]string{
|
||||
@@ -4180,6 +4329,65 @@ var generatedParamAliases = []ParamAliasEntry{
|
||||
},
|
||||
Blocked: []string{"name", "subject", "text", "title"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact +team",
|
||||
Aliases: map[string]string{
|
||||
"employee-name": "name",
|
||||
"flower-name": "name",
|
||||
"person-name": "name",
|
||||
"staff-name": "name",
|
||||
"user-name": "name",
|
||||
},
|
||||
Blocked: []string{"department-id", "dept", "dept-id", "org-name", "role-name"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact account create",
|
||||
Aliases: map[string]string{
|
||||
"account-login-id": "login-id",
|
||||
"department-ids": "dept-ids",
|
||||
"depts": "dept-ids",
|
||||
"email-address": "email",
|
||||
"employee-name": "org-user-name",
|
||||
"login-account": "login-id",
|
||||
"mail-address": "email",
|
||||
"mobile": "org-user-mobile",
|
||||
"organization-user-name": "org-user-name",
|
||||
"staff-name": "org-user-name",
|
||||
},
|
||||
Blocked: []string{"creator-username", "department-id", "department-memberships-json", "dept", "dept-id", "depts-json", "name", "nick", "org-name", "query", "staff-id", "user-id"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact account update",
|
||||
Aliases: map[string]string{
|
||||
"department-assignments-json": "depts",
|
||||
"department-memberships-json": "depts",
|
||||
"employee-name": "org-user-name",
|
||||
"organization-user-name": "org-user-name",
|
||||
"profile-image-file-id": "avatar-file-id",
|
||||
"staff-id": "user-id",
|
||||
"staff-name": "org-user-name",
|
||||
"uid": "user-id",
|
||||
"user": "user-id",
|
||||
},
|
||||
Blocked: []string{"at-user-ids", "creator-username", "department-id", "department-ids", "dept", "dept-id", "dept-ids", "file", "name", "node-id", "org-name", "ownness-text", "parent", "parent-id", "to-user", "user-ids", "users"},
|
||||
Ambiguous: []string{"manager", "owner-id"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact dept create",
|
||||
Aliases: map[string]string{
|
||||
"new-parent-dept-id": "parent",
|
||||
"parent-department-id": "parent",
|
||||
"parent-dept-id": "parent",
|
||||
},
|
||||
Blocked: []string{"department-ids", "dept", "dept-id", "dept-ids", "depts"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact dept get-info",
|
||||
Aliases: map[string]string{
|
||||
"department-id": "dept",
|
||||
},
|
||||
Blocked: []string{"department", "department-ids", "depts", "parent", "parent-id"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact dept list-children",
|
||||
Aliases: map[string]string{
|
||||
@@ -4190,18 +4398,180 @@ var generatedParamAliases = []ParamAliasEntry{
|
||||
},
|
||||
Blocked: []string{"department-ids", "depts", "name", "query"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact dept list-members",
|
||||
Aliases: map[string]string{
|
||||
"department-ids": "depts",
|
||||
},
|
||||
Blocked: []string{"department-id", "dept", "name", "query"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact dept search",
|
||||
Aliases: map[string]string{
|
||||
"keywords": "query",
|
||||
"q": "query",
|
||||
"search-word": "query",
|
||||
},
|
||||
Blocked: []string{"subject", "text", "title"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact dept update",
|
||||
Aliases: map[string]string{
|
||||
"new-parent-dept-id": "parent",
|
||||
"parent-department-id": "parent",
|
||||
"parent-dept-id": "parent",
|
||||
"target-department-id": "dept",
|
||||
"target-dept-id": "dept",
|
||||
},
|
||||
Blocked: []string{"department-ids", "depts"},
|
||||
Ambiguous: []string{"department", "target-id"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact label get",
|
||||
Aliases: map[string]string{
|
||||
"label-names": "names",
|
||||
"role-names": "names",
|
||||
},
|
||||
Blocked: []string{"dept-id", "id", "label-id", "role-id", "user-id"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact label list-members",
|
||||
Blocked: []string{"dept", "dept-id", "ids", "names", "staff-id", "user-id"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact org create",
|
||||
Aliases: map[string]string{
|
||||
"company-name": "org-name",
|
||||
"corp-name": "org-name",
|
||||
"creator-name": "creator-username",
|
||||
"founder-name": "creator-username",
|
||||
"organization-name": "org-name",
|
||||
},
|
||||
Blocked: []string{"login-id", "user-id"},
|
||||
Ambiguous: []string{"name"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact user dismission search",
|
||||
Aliases: map[string]string{
|
||||
"begin": "start",
|
||||
"current-page": "page",
|
||||
"department-ids": "depts",
|
||||
"dept-ids": "depts",
|
||||
"employee-name": "name",
|
||||
"end-date": "end",
|
||||
"end-time": "end",
|
||||
"flower-name": "name",
|
||||
"from": "start",
|
||||
"from-date": "start",
|
||||
"max-result": "limit",
|
||||
"max-results": "limit",
|
||||
"max-time": "end",
|
||||
"min-time": "start",
|
||||
"page-no": "page",
|
||||
"page-num": "page",
|
||||
"page-size": "limit",
|
||||
"per-page": "limit",
|
||||
"person-name": "name",
|
||||
"since": "start",
|
||||
"size": "limit",
|
||||
"staff-name": "name",
|
||||
"start-date": "start",
|
||||
"start-time": "start",
|
||||
"take": "limit",
|
||||
"time-max": "end",
|
||||
"time-min": "start",
|
||||
"top": "limit",
|
||||
"user-name": "name",
|
||||
},
|
||||
Blocked: []string{"count", "cursor", "date", "department-id", "department-memberships-json", "dept", "dept-id", "dept-list-json", "offset", "page-index", "page-token", "query", "time"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact user get",
|
||||
Aliases: map[string]string{
|
||||
"member-user-ids": "ids",
|
||||
"staff-ids": "ids",
|
||||
"users": "ids",
|
||||
},
|
||||
Blocked: []string{"at-user-ids", "staff-id", "uid", "user"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact user invite",
|
||||
Aliases: map[string]string{
|
||||
"department-assignments-json": "depts",
|
||||
"department-memberships-json": "depts",
|
||||
"employee-name": "org-user-name",
|
||||
"mobile": "org-user-mobile",
|
||||
"organization-user-name": "org-user-name",
|
||||
"staff-name": "org-user-name",
|
||||
},
|
||||
Blocked: []string{"creator-username", "department-id", "department-ids", "dept", "dept-id", "dept-ids", "email", "login-id", "nick", "org-name", "parent", "parent-id", "user-id"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact user profile get",
|
||||
Aliases: map[string]string{
|
||||
"id": "staff-id",
|
||||
"ids": "staff-id",
|
||||
"uid": "staff-id",
|
||||
"user": "staff-id",
|
||||
"user-id": "staff-id",
|
||||
"userid": "staff-id",
|
||||
"field-code-list": "fields",
|
||||
"field-codes": "fields",
|
||||
"id": "staff-id",
|
||||
"ids": "staff-id",
|
||||
"profile-fields": "fields",
|
||||
"roster-fields": "fields",
|
||||
"uid": "staff-id",
|
||||
"user": "staff-id",
|
||||
"user-id": "staff-id",
|
||||
"userid": "staff-id",
|
||||
},
|
||||
Blocked: []string{"at-user-ids", "name", "output-fields", "staff-ids", "to-user", "user-ids", "users"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact user search",
|
||||
Aliases: map[string]string{
|
||||
"keywords": "query",
|
||||
"q": "query",
|
||||
"search-word": "query",
|
||||
},
|
||||
Blocked: []string{"subject", "text", "title"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact user search-mobile",
|
||||
Aliases: map[string]string{
|
||||
"org-user-mobile": "mobile",
|
||||
},
|
||||
Blocked: []string{"email", "login-id", "user-id"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact user update",
|
||||
Aliases: map[string]string{
|
||||
"department-assignments-json": "depts",
|
||||
"department-memberships-json": "depts",
|
||||
"employee-name": "org-user-name",
|
||||
"organization-user-name": "org-user-name",
|
||||
"staff-id": "user-id",
|
||||
"staff-name": "org-user-name",
|
||||
"uid": "user-id",
|
||||
"user": "user-id",
|
||||
},
|
||||
Blocked: []string{"at-user-ids", "creator-username", "department-id", "department-ids", "dept", "dept-id", "dept-ids", "name", "nick", "org-name", "parent", "parent-id", "to-user", "user-ids", "users"},
|
||||
Ambiguous: []string{"manager", "owner-id"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact user update-ownness",
|
||||
Aliases: map[string]string{
|
||||
"personal-status": "ownness-text",
|
||||
"staff-id": "user-id",
|
||||
"status": "ownness-text",
|
||||
"status-text": "ownness-text",
|
||||
"uid": "user-id",
|
||||
"user": "user-id",
|
||||
},
|
||||
Blocked: []string{"at-user-ids", "name", "to-user", "user-ids", "users"},
|
||||
},
|
||||
{
|
||||
CLIPath: "contact user update-self",
|
||||
Aliases: map[string]string{
|
||||
"profile-image-file-id": "avatar-file-id",
|
||||
},
|
||||
Blocked: []string{"file", "name", "node-id", "org-user-name", "ownness-text", "user-id"},
|
||||
},
|
||||
{
|
||||
CLIPath: "dev app get",
|
||||
Aliases: map[string]string{
|
||||
@@ -4213,18 +4583,26 @@ var generatedParamAliases = []ParamAliasEntry{
|
||||
{
|
||||
CLIPath: "devdoc article search",
|
||||
Aliases: map[string]string{
|
||||
"current-page": "page",
|
||||
"limit": "size",
|
||||
"max-result": "size",
|
||||
"max-results": "size",
|
||||
"page-no": "page",
|
||||
"page-num": "page",
|
||||
"page-size": "size",
|
||||
"per-page": "size",
|
||||
"take": "size",
|
||||
"top": "size",
|
||||
"current-page": "page",
|
||||
"keywords": "query",
|
||||
"limit": "size",
|
||||
"max-result": "size",
|
||||
"max-results": "size",
|
||||
"page-no": "page",
|
||||
"page-num": "page",
|
||||
"page-number": "page",
|
||||
"page-size": "size",
|
||||
"per-page": "size",
|
||||
"q": "query",
|
||||
"query-text": "query",
|
||||
"results-per-page": "size",
|
||||
"search-term": "query",
|
||||
"search-word": "query",
|
||||
"take": "size",
|
||||
"top": "size",
|
||||
},
|
||||
Blocked: []string{"count", "cursor", "page-index", "page-token"},
|
||||
Blocked: []string{"context", "count", "cursor", "doc-id", "document-id", "error-code", "error-message", "file-id", "name", "next-cursor", "next-token", "node-id", "offset", "page-index", "page-token", "request-id", "space-id", "subject", "text", "title", "total", "trace-id", "workspace-id"},
|
||||
Ambiguous: []string{"id", "type"},
|
||||
},
|
||||
{
|
||||
CLIPath: "ding +list",
|
||||
@@ -6352,6 +6730,166 @@ var generatedParamAliases = []ParamAliasEntry{
|
||||
},
|
||||
Blocked: []string{"knowledge-base-id", "limit", "page-size", "part-size", "size", "space", "wiki-workspace-id", "workspace", "workspace-id"},
|
||||
},
|
||||
{
|
||||
CLIPath: "hrbrain profile career",
|
||||
Aliases: map[string]string{
|
||||
"employee-no": "work-no",
|
||||
"employee-number": "work-no",
|
||||
"staff-no": "work-no",
|
||||
},
|
||||
Blocked: []string{"employee-id", "end", "end-date", "job-level", "position", "staff-id", "staff-ids", "start", "start-date", "user-id", "work-nos", "year"},
|
||||
Ambiguous: []string{"date", "employee", "id", "name", "time", "user"},
|
||||
},
|
||||
{
|
||||
CLIPath: "hrbrain profile labels",
|
||||
Aliases: map[string]string{
|
||||
"all-labels": "all-label",
|
||||
"employee-nos": "staff-ids",
|
||||
"staff-nos": "staff-ids",
|
||||
"work-nos": "staff-ids",
|
||||
},
|
||||
Blocked: []string{"employee-id", "employee-ids", "employee-no", "staff-id", "staff-no", "user-id", "user-ids", "work-no"},
|
||||
Ambiguous: []string{"employee", "id", "label", "name", "tag", "user"},
|
||||
},
|
||||
{
|
||||
CLIPath: "hrbrain profile metadata",
|
||||
Aliases: map[string]string{
|
||||
"employee-no": "work-no",
|
||||
"employee-number": "work-no",
|
||||
"staff-no": "work-no",
|
||||
},
|
||||
Blocked: []string{"data-queries", "employee-id", "model-code", "module", "section", "staff-id", "staff-ids", "user-id", "work-nos"},
|
||||
Ambiguous: []string{"employee", "field", "id", "name", "user"},
|
||||
},
|
||||
{
|
||||
CLIPath: "hrbrain profile performance",
|
||||
Aliases: map[string]string{
|
||||
"employee-no": "work-no",
|
||||
"employee-number": "work-no",
|
||||
"staff-no": "work-no",
|
||||
},
|
||||
Blocked: []string{"cycle", "employee-id", "end", "end-date", "rating", "score", "staff-id", "staff-ids", "start", "start-date", "user-id", "work-nos", "year"},
|
||||
Ambiguous: []string{"date", "employee", "id", "level", "name", "time", "user"},
|
||||
},
|
||||
{
|
||||
CLIPath: "hrbrain profile query",
|
||||
Aliases: map[string]string{
|
||||
"employee-no": "work-no",
|
||||
"employee-number": "work-no",
|
||||
"module-queries": "data-queries",
|
||||
"profile-queries": "data-queries",
|
||||
"staff-no": "work-no",
|
||||
},
|
||||
Blocked: []string{"data-query", "employee-id", "model-code", "module", "section", "staff-id", "staff-ids", "user-id", "work-nos"},
|
||||
Ambiguous: []string{"employee", "field", "id", "name", "query", "user"},
|
||||
},
|
||||
{
|
||||
CLIPath: "hrbrain search employees",
|
||||
Aliases: map[string]string{
|
||||
"current-page": "page",
|
||||
"department-name": "dept-name",
|
||||
"job-title": "position-name",
|
||||
"keywords": "keyword",
|
||||
"limit": "page-size",
|
||||
"max-result": "page-size",
|
||||
"max-results": "page-size",
|
||||
"page-no": "page",
|
||||
"page-num": "page",
|
||||
"per-page": "page-size",
|
||||
"position-level": "job-level",
|
||||
"q": "keyword",
|
||||
"query": "keyword",
|
||||
"search-word": "keyword",
|
||||
"size": "page-size",
|
||||
"take": "page-size",
|
||||
"talent-pool-code": "pool-code",
|
||||
"top": "page-size",
|
||||
},
|
||||
Blocked: []string{"count", "cursor", "data-queries", "department-id", "dept-id", "employee-id", "order-by", "origin-json", "page-index", "page-token", "pool-id", "staff-id", "staff-ids", "subject", "talent-pool-id", "text", "user-id", "work-no"},
|
||||
Ambiguous: []string{"code", "department", "grade", "id", "level", "name", "pool", "position", "title", "user"},
|
||||
},
|
||||
{
|
||||
CLIPath: "hrbrain search employees-structured",
|
||||
Aliases: map[string]string{
|
||||
"criteria-json": "origin-json",
|
||||
"current-page": "page",
|
||||
"filter-json": "origin-json",
|
||||
"limit": "page-size",
|
||||
"max-result": "page-size",
|
||||
"max-results": "page-size",
|
||||
"page-no": "page",
|
||||
"page-num": "page",
|
||||
"per-page": "page-size",
|
||||
"result-fields-json": "fields",
|
||||
"return-fields-json": "fields",
|
||||
"search-json": "origin-json",
|
||||
"size": "page-size",
|
||||
"sort-by": "order-by",
|
||||
"sort-fields": "order-by",
|
||||
"take": "page-size",
|
||||
"top": "page-size",
|
||||
},
|
||||
Blocked: []string{"count", "cursor", "department-name", "dept-name", "field-name", "job-level", "keyword", "operator", "operators", "page-index", "page-token", "pool-code", "position-name", "query", "staff-ids", "work-no"},
|
||||
Ambiguous: []string{"criteria", "field", "filter", "id", "name", "order", "sort", "type"},
|
||||
},
|
||||
{
|
||||
CLIPath: "hrbrain search fields",
|
||||
Blocked: []string{"dept-name", "field-name", "job-level", "keyword", "operator", "operators", "order-by", "origin-json", "page", "page-size", "pool-code", "position-name", "query", "staff-ids", "work-no"},
|
||||
Ambiguous: []string{"criteria", "field", "filter", "id", "name", "type"},
|
||||
},
|
||||
{
|
||||
CLIPath: "hrbrain talent-pool detail",
|
||||
Aliases: map[string]string{
|
||||
"talent-pool-code": "pool-code",
|
||||
},
|
||||
Blocked: []string{"creator", "employee-id", "keyword", "labels", "page", "page-size", "pool-id", "query", "staff-ids", "talent-pool-id", "work-no"},
|
||||
Ambiguous: []string{"code", "id", "name", "pool", "type"},
|
||||
},
|
||||
{
|
||||
CLIPath: "hrbrain talent-pool employees",
|
||||
Aliases: map[string]string{
|
||||
"current-page": "page",
|
||||
"limit": "page-size",
|
||||
"max-result": "page-size",
|
||||
"max-results": "page-size",
|
||||
"page-no": "page",
|
||||
"page-num": "page",
|
||||
"per-page": "page-size",
|
||||
"size": "page-size",
|
||||
"take": "page-size",
|
||||
"talent-pool-code": "pool-code",
|
||||
"top": "page-size",
|
||||
},
|
||||
Blocked: []string{"count", "creator", "cursor", "dept-name", "employee-id", "job-level", "keyword", "labels", "page-index", "page-token", "pool-id", "position-name", "query", "staff-ids", "talent-pool-id", "work-no"},
|
||||
Ambiguous: []string{"code", "id", "name", "pool", "status"},
|
||||
},
|
||||
{
|
||||
CLIPath: "hrbrain talent-pool list",
|
||||
Aliases: map[string]string{
|
||||
"current-page": "page",
|
||||
"keywords": "keyword",
|
||||
"label-list": "labels",
|
||||
"limit": "page-size",
|
||||
"max-result": "page-size",
|
||||
"max-results": "page-size",
|
||||
"page-no": "page",
|
||||
"page-num": "page",
|
||||
"per-page": "page-size",
|
||||
"q": "keyword",
|
||||
"query": "keyword",
|
||||
"search-word": "keyword",
|
||||
"size": "page-size",
|
||||
"take": "page-size",
|
||||
"top": "page-size",
|
||||
},
|
||||
Blocked: []string{"count", "cursor", "employee-id", "name", "page-index", "page-token", "pool-code", "pool-id", "staff-ids", "subject", "talent-pool-id", "text", "title", "user-id", "work-no"},
|
||||
Ambiguous: []string{"code", "creator-id", "id", "label-name", "pool", "type", "user"},
|
||||
},
|
||||
{
|
||||
CLIPath: "live stream list",
|
||||
Blocked: []string{"anchor-id", "conversation-id", "cover-url", "create", "creator-id", "cursor", "end", "end-live", "end-time", "from", "group-id", "keyword", "limit", "live-id", "offset", "order", "page", "page-size", "page-token", "playback", "query", "record", "room-id", "size", "sort", "start", "start-live", "start-time", "state", "status", "stream-id", "title", "to", "user-id"},
|
||||
Ambiguous: []string{"date", "id", "owner", "time", "type", "user"},
|
||||
},
|
||||
{
|
||||
CLIPath: "mail +contact-list",
|
||||
Aliases: map[string]string{
|
||||
@@ -7457,6 +7995,42 @@ var generatedParamAliases = []ParamAliasEntry{
|
||||
},
|
||||
Blocked: []string{"name", "subject", "text", "title"},
|
||||
},
|
||||
{
|
||||
CLIPath: "pat +browser-policy",
|
||||
Aliases: map[string]string{
|
||||
"allow-browser": "enabled",
|
||||
"browser-enabled": "enabled",
|
||||
"open-browser": "enabled",
|
||||
},
|
||||
Blocked: []string{"api-scope", "app-id", "app-key", "app-secret", "block-browser", "browser-disabled", "deny-browser", "disable-browser", "domain", "domains", "grant-mode", "grant-type", "oauth-scope", "permission", "permissions", "product", "products", "recommend", "recommended", "scope", "scopes", "session-id"},
|
||||
Ambiguous: []string{"agent", "agent-id", "browser", "mode", "policy", "state", "value"},
|
||||
},
|
||||
{
|
||||
CLIPath: "pat browser-policy",
|
||||
Aliases: map[string]string{
|
||||
"allow-browser": "enabled",
|
||||
"browser-enabled": "enabled",
|
||||
"open-browser": "enabled",
|
||||
},
|
||||
Blocked: []string{"api-scope", "app-id", "app-key", "app-secret", "block-browser", "browser-disabled", "deny-browser", "disable-browser", "domain", "domains", "grant-mode", "grant-type", "oauth-scope", "permission", "permissions", "product", "products", "recommend", "recommended", "scope", "scopes", "session-id"},
|
||||
Ambiguous: []string{"agent", "agent-id", "browser", "mode", "policy", "state", "value"},
|
||||
},
|
||||
{
|
||||
CLIPath: "pat chmod",
|
||||
Aliases: map[string]string{
|
||||
"authorization-mode": "grant-type",
|
||||
"authorization-session-id": "session-id",
|
||||
"domain-code": "domain",
|
||||
"domain-codes": "domains",
|
||||
"grant-mode": "grant-type",
|
||||
"pat-session-id": "session-id",
|
||||
"product-code": "product",
|
||||
"product-codes": "products",
|
||||
"recommended": "recommend",
|
||||
},
|
||||
Blocked: []string{"all", "all-scopes", "allow-browser", "api-scope", "app-id", "app-key", "app-secret", "browser-enabled", "browser-policy", "confirm", "confirmed", "disable-browser", "force", "oauth-scope", "open-browser", "permission", "permission-scope", "permission-scopes", "permissions", "scope", "scopes"},
|
||||
Ambiguous: []string{"action", "agent", "agent-id", "id", "mode", "resource", "service", "services", "session", "type"},
|
||||
},
|
||||
{
|
||||
CLIPath: "report +inbox-list",
|
||||
Aliases: map[string]string{
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -19,17 +19,172 @@ trap cleanup EXIT HUP INT TERM
|
||||
|
||||
git -C "$ROOT" diff --no-ext-diff --find-renames --name-status "$merge_base" "$head" >"$tmp_root/status"
|
||||
|
||||
normalize_notes() {
|
||||
awk '
|
||||
/^[[:space:]]*$/ && !started { next }
|
||||
{ started = 1; lines[++count] = $0 }
|
||||
END {
|
||||
while (count > 0 && lines[count] ~ /^[[:space:]]*$/) count--
|
||||
for (line_no = 1; line_no <= count; line_no++) print lines[line_no]
|
||||
}
|
||||
' "$1"
|
||||
}
|
||||
|
||||
extract_release_notes() {
|
||||
git -C "$ROOT" show "$1:CHANGELOG.md" |
|
||||
awk -v heading="## [$2] - " '
|
||||
index($0, heading) == 1 { found = 1; next }
|
||||
found && /^## / { exit }
|
||||
found { print }
|
||||
'
|
||||
}
|
||||
|
||||
release_heading() {
|
||||
git -C "$ROOT" show "$1:CHANGELOG.md" |
|
||||
awk -v heading="## [$2] - " 'index($0, heading) == 1 { print }'
|
||||
}
|
||||
|
||||
changelog_without_release_notes() {
|
||||
git -C "$ROOT" show "$1:CHANGELOG.md" |
|
||||
awk -v heading="## [$2] - " '
|
||||
index($0, heading) == 1 { print; skipped = 1; next }
|
||||
skipped && /^## / { skipped = 0 }
|
||||
!skipped { print }
|
||||
'
|
||||
}
|
||||
|
||||
# A pre-tag beta amendment must preserve the original seal verbatim except for
|
||||
# appending newly archived fragment bodies to their existing categories. These
|
||||
# helpers canonicalize the renderer's category format before comparing it.
|
||||
canonicalize_fragment_notes() {
|
||||
awk '
|
||||
BEGIN { order[1] = "Added"; order[2] = "Changed"; order[3] = "Deprecated"; order[4] = "Removed"; order[5] = "Fixed"; order[6] = "Security" }
|
||||
function trim(value) {
|
||||
sub(/^[\n]+/, "", value)
|
||||
sub(/[\n]+$/, "", value)
|
||||
return value
|
||||
}
|
||||
function flush() {
|
||||
if (category == "") return
|
||||
value = trim(body)
|
||||
if (value == "" || seen[category]++) invalid = 1
|
||||
blocks[category] = value
|
||||
category = ""
|
||||
body = ""
|
||||
}
|
||||
/^### / {
|
||||
flush()
|
||||
candidate = substr($0, 5)
|
||||
if (candidate !~ /^(Added|Changed|Deprecated|Removed|Fixed|Security)$/) {
|
||||
invalid = 1
|
||||
next
|
||||
}
|
||||
category = candidate
|
||||
next
|
||||
}
|
||||
{
|
||||
if (category == "") {
|
||||
if ($0 !~ /^[[:space:]]*$/) invalid = 1
|
||||
next
|
||||
}
|
||||
body = body $0 "\n"
|
||||
}
|
||||
END {
|
||||
flush()
|
||||
if (invalid) exit 1
|
||||
for (i = 1; i <= 6; i++) {
|
||||
category = order[i]
|
||||
if (category in blocks) printf "### %s\n\n%s\n\n", category, blocks[category]
|
||||
}
|
||||
}
|
||||
' "$1"
|
||||
}
|
||||
|
||||
merge_canonical_fragment_notes() {
|
||||
awk '
|
||||
BEGIN { order[1] = "Added"; order[2] = "Changed"; order[3] = "Deprecated"; order[4] = "Removed"; order[5] = "Fixed"; order[6] = "Security" }
|
||||
function trim(value) {
|
||||
sub(/^[\n]+/, "", value)
|
||||
sub(/[\n]+$/, "", value)
|
||||
return value
|
||||
}
|
||||
function flush() {
|
||||
if (category == "") return
|
||||
value = trim(body)
|
||||
if (value == "") invalid = 1
|
||||
if (part == 1) before[category] = value
|
||||
else if (part == 2) addition[category] = value
|
||||
else invalid = 1
|
||||
category = ""
|
||||
body = ""
|
||||
}
|
||||
FNR == 1 {
|
||||
if (started) flush()
|
||||
started = 1
|
||||
part++
|
||||
}
|
||||
/^### / {
|
||||
flush()
|
||||
category = substr($0, 5)
|
||||
if (category !~ /^(Added|Changed|Deprecated|Removed|Fixed|Security)$/) invalid = 1
|
||||
next
|
||||
}
|
||||
{ body = body $0 "\n" }
|
||||
END {
|
||||
flush()
|
||||
if (invalid || part != 2) exit 1
|
||||
for (i = 1; i <= 6; i++) {
|
||||
category = order[i]
|
||||
if (!(category in before) && !(category in addition)) continue
|
||||
printf "### %s\n\n", category
|
||||
if (category in before) printf "%s\n\n", before[category]
|
||||
if (category in addition) printf "%s\n\n", addition[category]
|
||||
}
|
||||
}
|
||||
' "$1" "$2"
|
||||
}
|
||||
|
||||
archive_changed=false
|
||||
if awk -F '\t' '{ for (field = 2; field <= NF; field++) if ($field ~ /^\.changes\/released\//) found = 1 } END { exit !found }' "$tmp_root/status"; then
|
||||
archive_changed=true
|
||||
fi
|
||||
|
||||
if [ "$archive_changed" = true ]; then
|
||||
release_version="$(git -C "$ROOT" diff --no-ext-diff --unified=0 "$merge_base" "$head" -- CHANGELOG.md | sed -n 's/^+## \[\([0-9][0-9.]*\(-beta\.[1-9][0-9]*\)\{0,1\}\)\] - .*/\1/p')"
|
||||
[ "$(printf '%s\n' "$release_version" | sed '/^$/d' | wc -l | tr -d '[:space:]')" -eq 1 ] || {
|
||||
printf '%s\n' 'error: release-fragment archival requires exactly one newly added versioned CHANGELOG section' >&2
|
||||
exit 1
|
||||
}
|
||||
new_release_version="$(git -C "$ROOT" diff --no-ext-diff --unified=0 "$merge_base" "$head" -- CHANGELOG.md | sed -n 's/^+## \[\([0-9][0-9.]*\(-beta\.[1-9][0-9]*\)\{0,1\}\)\] - .*/\1/p')"
|
||||
new_release_version_count="$(printf '%s\n' "$new_release_version" | sed '/^$/d' | wc -l | tr -d '[:space:]')"
|
||||
archival_mode=seal
|
||||
if [ "$new_release_version_count" -eq 1 ]; then
|
||||
release_version="$new_release_version"
|
||||
else
|
||||
# An amendment keeps the existing heading. Derive the one allowed target
|
||||
# from the literal archive directory, then verify every move below.
|
||||
release_version="$(awk -F '\t' '$1 == "R100" && NF == 3 && $3 ~ /^\.changes\/released\// { path = $3; sub(/^\.changes\/released\//, "", path); sub(/\/.*/, "", path); print path }' "$tmp_root/status" | sort -u)"
|
||||
[ "$(printf '%s\n' "$release_version" | sed '/^$/d' | wc -l | tr -d '[:space:]')" -eq 1 ] || {
|
||||
printf '%s\n' 'error: release-fragment archival requires exactly one newly added versioned CHANGELOG section or one untagged beta amendment target' >&2
|
||||
exit 1
|
||||
}
|
||||
printf '%s\n' "$release_version" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+-beta\.[1-9][0-9]*$' || {
|
||||
printf '%s\n' 'error: only an existing beta CHANGELOG section may receive a pre-tag fragment amendment' >&2
|
||||
exit 1
|
||||
}
|
||||
base_heading="$(release_heading "$merge_base" "$release_version")"
|
||||
head_heading="$(release_heading "$head" "$release_version")"
|
||||
[ "$(printf '%s\n' "$base_heading" | sed '/^$/d' | wc -l | tr -d '[:space:]')" -eq 1 ] && [ "$base_heading" = "$head_heading" ] || {
|
||||
printf '%s\n' 'error: beta fragment amendment requires one unchanged pre-existing CHANGELOG heading' >&2
|
||||
exit 1
|
||||
}
|
||||
changelog_without_release_notes "$merge_base" "$release_version" >"$tmp_root/base-changelog-without-amendment"
|
||||
changelog_without_release_notes "$head" "$release_version" >"$tmp_root/head-changelog-without-amendment"
|
||||
if ! cmp -s "$tmp_root/base-changelog-without-amendment" "$tmp_root/head-changelog-without-amendment"; then
|
||||
printf '%s\n' 'error: beta fragment amendment may change only its existing beta CHANGELOG section' >&2
|
||||
exit 1
|
||||
fi
|
||||
if git -C "$ROOT" rev-parse --verify --quiet "refs/tags/v$release_version^{commit}" >/dev/null; then
|
||||
printf 'error: beta fragment amendment is forbidden after tag v%s exists\n' "$release_version" >&2
|
||||
exit 1
|
||||
fi
|
||||
archival_mode=beta-amendment
|
||||
fi
|
||||
# The archive directory is matched as a literal prefix, never as a regex:
|
||||
# interpolating the version into one would make `.` match any character, so
|
||||
# `1.0.1-beta.1` would also admit `.changes/released/1x0x1-betaX1/` and break
|
||||
@@ -47,7 +202,7 @@ if [ "$archive_changed" = true ]; then
|
||||
{ invalid = 1 }
|
||||
END { exit !(changelog && moved > 0 && !invalid) }
|
||||
' "$tmp_root/status"; then
|
||||
printf '%s\n' 'error: release fragments must be unchanged R100 moves from .changes/<name>.md to .changes/released/<new-version>/<name>.md in the matching release-seal PR' >&2
|
||||
printf '%s\n' 'error: release fragments must be unchanged R100 moves from .changes/<name>.md to .changes/released/<new-version>/<name>.md in the matching release-seal or untagged beta-amendment PR' >&2
|
||||
exit 1
|
||||
fi
|
||||
source_changes="$tmp_root/source-changes"
|
||||
@@ -63,17 +218,25 @@ if [ "$archive_changed" = true ]; then
|
||||
esac
|
||||
done
|
||||
"$ROOT/scripts/release/render-release-fragments.sh" "$source_changes" >"$tmp_root/expected-notes"
|
||||
git -C "$ROOT" show "$head:CHANGELOG.md" |
|
||||
awk -v heading="## [$release_version] - " '
|
||||
index($0, heading) == 1 { found = 1; next }
|
||||
found && /^## / { exit }
|
||||
found { print }
|
||||
' >"$tmp_root/actual-section"
|
||||
case "$release_version" in
|
||||
*-beta.*)
|
||||
cp "$tmp_root/actual-section" "$tmp_root/actual-notes"
|
||||
;;
|
||||
*)
|
||||
if [ "$archival_mode" = beta-amendment ]; then
|
||||
extract_release_notes "$merge_base" "$release_version" >"$tmp_root/base-notes"
|
||||
extract_release_notes "$head" "$release_version" >"$tmp_root/head-notes"
|
||||
if ! canonicalize_fragment_notes "$tmp_root/base-notes" >"$tmp_root/base-notes.canonical" ||
|
||||
! canonicalize_fragment_notes "$tmp_root/expected-notes" >"$tmp_root/amendment-notes.canonical" ||
|
||||
! merge_canonical_fragment_notes "$tmp_root/base-notes.canonical" "$tmp_root/amendment-notes.canonical" >"$tmp_root/expected-notes.merged" ||
|
||||
! canonicalize_fragment_notes "$tmp_root/head-notes" >"$tmp_root/actual-notes.canonical"; then
|
||||
printf '%s\n' 'error: beta fragment amendment requires canonical rendered fragment categories' >&2
|
||||
exit 1
|
||||
fi
|
||||
normalize_notes "$tmp_root/expected-notes.merged" >"$tmp_root/expected-notes.normalized"
|
||||
normalize_notes "$tmp_root/actual-notes.canonical" >"$tmp_root/actual-notes.normalized"
|
||||
else
|
||||
extract_release_notes "$head" "$release_version" >"$tmp_root/actual-section"
|
||||
case "$release_version" in
|
||||
*-beta.*)
|
||||
cp "$tmp_root/actual-section" "$tmp_root/actual-notes"
|
||||
;;
|
||||
*)
|
||||
stable_beta="$(sed -n 's/^### Changes since `\(v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*-beta\.[1-9][0-9]*\)`$/\1/p' "$tmp_root/actual-section")"
|
||||
[ "$(printf '%s\n' "$stable_beta" | sed '/^$/d' | wc -l | tr -d '[:space:]')" -eq 1 ] || {
|
||||
printf '%s\n' 'error: stable release-seal with archived fragments requires exactly one ### Changes since `vX.Y.Z-beta.N` boundary' >&2
|
||||
@@ -88,22 +251,13 @@ if [ "$archive_changed" = true ]; then
|
||||
found { print }
|
||||
/^### Changes since `v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*-beta\.[1-9][0-9]*`$/ { found = 1 }
|
||||
' "$tmp_root/actual-section" >"$tmp_root/actual-notes"
|
||||
;;
|
||||
esac
|
||||
normalize_notes() {
|
||||
awk '
|
||||
/^[[:space:]]*$/ && !started { next }
|
||||
{ started = 1; lines[++count] = $0 }
|
||||
END {
|
||||
while (count > 0 && lines[count] ~ /^[[:space:]]*$/) count--
|
||||
for (line_no = 1; line_no <= count; line_no++) print lines[line_no]
|
||||
}
|
||||
' "$1"
|
||||
}
|
||||
normalize_notes "$tmp_root/expected-notes" >"$tmp_root/expected-notes.normalized"
|
||||
normalize_notes "$tmp_root/actual-notes" >"$tmp_root/actual-notes.normalized"
|
||||
;;
|
||||
esac
|
||||
normalize_notes "$tmp_root/expected-notes" >"$tmp_root/expected-notes.normalized"
|
||||
normalize_notes "$tmp_root/actual-notes" >"$tmp_root/actual-notes.normalized"
|
||||
fi
|
||||
if ! cmp -s "$tmp_root/expected-notes.normalized" "$tmp_root/actual-notes.normalized"; then
|
||||
printf '%s\n' 'error: release-seal CHANGELOG section does not exactly match the rendered active release fragments' >&2
|
||||
printf '%s\n' 'error: release CHANGELOG section does not exactly match the rendered active release fragments' >&2
|
||||
diff -u "$tmp_root/expected-notes.normalized" "$tmp_root/actual-notes.normalized" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -351,6 +351,79 @@ This release promotes the sealed `+"`v1.0.1-beta.1`"+` contents to stable.
|
||||
}
|
||||
}
|
||||
|
||||
func TestReleaseFragmentPolicyAcceptsOnlyUntaggedCanonicalBetaAmendments(t *testing.T) {
|
||||
newAmendmentRepo := func(t *testing.T) (*changelogGateRepo, string) {
|
||||
t.Helper()
|
||||
repo := newChangelogGateRepo(t)
|
||||
sealBase := repo.sealFragmentInto(t, "1.0.1-beta.1")
|
||||
if output, err := repo.runFragmentPolicy(t, sealBase, "HEAD"); err != nil {
|
||||
t.Fatalf("release fragment policy rejected initial beta seal: %v\noutput:\n%s", err, output)
|
||||
}
|
||||
changelogGateWrite(t, repo.root, ".changes/1235-sheet.md", "---\ncategory: Added\n---\n\n- Sheet accepts local float image files.\n", 0o644)
|
||||
repo.commit(t, "merge post-seal beta fragment")
|
||||
return repo, strings.TrimSpace(changelogGateGit(t, repo.root, "rev-parse", "HEAD"))
|
||||
}
|
||||
|
||||
stageCanonicalAmendment := func(t *testing.T, repo *changelogGateRepo) {
|
||||
t.Helper()
|
||||
changelogGateWrite(t, repo.root, "CHANGELOG.md", `# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.0.1-beta.1] - 2026-07-17
|
||||
|
||||
### Added
|
||||
|
||||
- Chat reply mentions.
|
||||
|
||||
- Sheet accepts local float image files.
|
||||
|
||||
## [1.0.0] - 2026-07-01
|
||||
|
||||
### Added
|
||||
|
||||
- Initial release.
|
||||
`, 0o644)
|
||||
archiveDir := filepath.Join(repo.root, ".changes", "released", "1.0.1-beta.1")
|
||||
if err := os.Rename(filepath.Join(repo.root, ".changes", "1235-sheet.md"), filepath.Join(archiveDir, "1235-sheet.md")); err != nil {
|
||||
t.Fatalf("Rename beta amendment fragment: %v", err)
|
||||
}
|
||||
repo.commit(t, "amend untagged beta release notes")
|
||||
}
|
||||
|
||||
t.Run("accepts exact pre-tag merge", func(t *testing.T) {
|
||||
repo, amendmentBase := newAmendmentRepo(t)
|
||||
stageCanonicalAmendment(t, repo)
|
||||
|
||||
if output, err := repo.runFragmentPolicy(t, amendmentBase, "HEAD"); err != nil {
|
||||
t.Fatalf("release fragment policy rejected canonical beta amendment: %v\noutput:\n%s", err, output)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("rejects tagged beta", func(t *testing.T) {
|
||||
repo, amendmentBase := newAmendmentRepo(t)
|
||||
stageCanonicalAmendment(t, repo)
|
||||
changelogGateGit(t, repo.root, "tag", "v1.0.1-beta.1")
|
||||
|
||||
output, err := repo.runFragmentPolicy(t, amendmentBase, "HEAD")
|
||||
if err == nil || !strings.Contains(output, "forbidden after tag v1.0.1-beta.1 exists") {
|
||||
t.Fatalf("tagged beta amendment passed: err=%v\noutput:\n%s", err, output)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("rejects rewritten sealed prose", func(t *testing.T) {
|
||||
repo, amendmentBase := newAmendmentRepo(t)
|
||||
stageCanonicalAmendment(t, repo)
|
||||
changelogGateWrite(t, repo.root, "CHANGELOG.md", strings.Replace(changelogGateSealedRelease, "Chat reply mentions.", "Rewritten sealed note.", 1), 0o644)
|
||||
repo.commit(t, "rewrite sealed beta prose")
|
||||
|
||||
output, err := repo.runFragmentPolicy(t, amendmentBase, "HEAD")
|
||||
if err == nil || !strings.Contains(output, "does not exactly match") {
|
||||
t.Fatalf("rewritten beta amendment passed: err=%v\noutput:\n%s", err, output)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestReleaseFragmentPolicyRejectsInvalidActiveFragmentAndWrongArchiveVersion(t *testing.T) {
|
||||
t.Run("invalid active fragment", func(t *testing.T) {
|
||||
repo := newChangelogGateRepo(t)
|
||||
|
||||
Reference in New Issue
Block a user