Compare commits
2 Commits
59088af2ab
...
16cc58b17f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16cc58b17f | ||
|
|
a10d870863 |
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
bd-23xb
|
bd-2i3z
|
||||||
|
|||||||
@@ -37,11 +37,10 @@
|
|||||||
| 29 | *help* | — | — | — | (clap built-in) |
|
| 29 | *help* | — | — | — | (clap built-in) |
|
||||||
| | **Hidden/deprecated:** | | | | |
|
| | **Hidden/deprecated:** | | | | |
|
||||||
| 30 | `list` | — | `<ENTITY>` | 14 | deprecated, use issues/mrs |
|
| 30 | `list` | — | `<ENTITY>` | 14 | deprecated, use issues/mrs |
|
||||||
| 31 | `show` | — | `<ENTITY> <IID>` | 1 | deprecated, use issues/mrs |
|
| 31 | `auth-test` | — | — | 0 | deprecated, use auth |
|
||||||
| 32 | `auth-test` | — | — | 0 | deprecated, use auth |
|
| 32 | `sync-status` | — | — | 0 | deprecated, use status |
|
||||||
| 33 | `sync-status` | — | — | 0 | deprecated, use status |
|
| 33 | `backup` | — | — | 0 | Stub (not implemented) |
|
||||||
| 34 | `backup` | — | — | 0 | Stub (not implemented) |
|
| 34 | `reset` | — | — | 1 | Stub (not implemented) |
|
||||||
| 35 | `reset` | — | — | 1 | Stub (not implemented) |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
1. **Make `gitlab_note_id` explicit in all note-level payloads without breaking existing consumers**
|
1. **Make `gitlab_note_id` explicit in all note-level payloads without breaking existing consumers**
|
||||||
Rationale: Your Bridge Contract already requires `gitlab_note_id`, but current plan keeps `gitlab_id` only in `notes` list while adding `gitlab_note_id` only in `show`. That forces agents to special-case commands. Add `gitlab_note_id` as an alias field everywhere note-level data appears, while keeping `gitlab_id` for compatibility.
|
Rationale: Your Bridge Contract already requires `gitlab_note_id`, but current plan keeps `gitlab_id` only in `notes` list while adding `gitlab_note_id` only in detail views. That forces agents to special-case commands. Add `gitlab_note_id` as an alias field everywhere note-level data appears, while keeping `gitlab_id` for compatibility.
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
@@ Bridge Contract (Cross-Cutting)
|
@@ Bridge Contract (Cross-Cutting)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ construct API calls without a separate project-ID lookup, even after path change
|
|||||||
**Back-compat rule**: Note payloads in the `notes` list command continue exposing `gitlab_id`
|
**Back-compat rule**: Note payloads in the `notes` list command continue exposing `gitlab_id`
|
||||||
for existing consumers, but **MUST also** expose `gitlab_note_id` with the same value. This
|
for existing consumers, but **MUST also** expose `gitlab_note_id` with the same value. This
|
||||||
ensures agents can use a single field name (`gitlab_note_id`) across all commands — `notes`,
|
ensures agents can use a single field name (`gitlab_note_id`) across all commands — `notes`,
|
||||||
`show`, and `discussions --include-notes` — without special-casing by command.
|
`issues <IID>`/`mrs <IID>`, and `discussions --include-notes` — without special-casing by command.
|
||||||
|
|
||||||
This contract exists so agents can deterministically construct `glab api` write calls without
|
This contract exists so agents can deterministically construct `glab api` write calls without
|
||||||
cross-referencing multiple commands. Each workstream below must satisfy these fields in its
|
cross-referencing multiple commands. Each workstream below must satisfy these fields in its
|
||||||
|
|||||||
@@ -107,12 +107,12 @@ Each criterion is independently testable. Implementation is complete when ALL pa
|
|||||||
|
|
||||||
### AC-7: Show Issue Display (E2E)
|
### AC-7: Show Issue Display (E2E)
|
||||||
|
|
||||||
**Human (`lore show issue 123`):**
|
**Human (`lore issues 123`):**
|
||||||
- [ ] New line after "State": `Status: In progress` (colored by `status_color` hex → nearest terminal color)
|
- [ ] New line after "State": `Status: In progress` (colored by `status_color` hex → nearest terminal color)
|
||||||
- [ ] Status line only shown when `status_name IS NOT NULL`
|
- [ ] Status line only shown when `status_name IS NOT NULL`
|
||||||
- [ ] Category shown in parens when available, lowercased: `Status: In progress (in_progress)`
|
- [ ] Category shown in parens when available, lowercased: `Status: In progress (in_progress)`
|
||||||
|
|
||||||
**Robot (`lore --robot show issue 123`):**
|
**Robot (`lore --robot issues 123`):**
|
||||||
- [ ] JSON includes `status_name`, `status_category`, `status_color`, `status_icon_name`, `status_synced_at` fields
|
- [ ] JSON includes `status_name`, `status_category`, `status_color`, `status_icon_name`, `status_synced_at` fields
|
||||||
- [ ] Fields are `null` (not absent) when status not available
|
- [ ] Fields are `null` (not absent) when status not available
|
||||||
- [ ] `status_synced_at` is integer (ms epoch UTC) or `null` — enables freshness checks by consumers
|
- [ ] `status_synced_at` is integer (ms epoch UTC) or `null` — enables freshness checks by consumers
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ fn handle_robot_docs(robot_mode: bool, brief: bool) -> Result<(), Box<dyn std::e
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"issues": {
|
"issues": {
|
||||||
"description": "List or show issues",
|
"description": "List issues, or view detail with <IID>",
|
||||||
"flags": ["<IID>", "-n/--limit", "--fields <list>", "-s/--state", "--status <name>", "-p/--project", "-a/--author", "-A/--assignee", "-l/--label", "-m/--milestone", "--since", "--due-before", "--has-due", "--no-has-due", "--sort", "--asc", "--no-asc", "-o/--open", "--no-open"],
|
"flags": ["<IID>", "-n/--limit", "--fields <list>", "-s/--state", "--status <name>", "-p/--project", "-a/--author", "-A/--assignee", "-l/--label", "-m/--milestone", "--since", "--due-before", "--has-due", "--no-has-due", "--sort", "--asc", "--no-asc", "-o/--open", "--no-open"],
|
||||||
"example": "lore --robot issues --state opened --limit 10",
|
"example": "lore --robot issues --state opened --limit 10",
|
||||||
"notes": {
|
"notes": {
|
||||||
@@ -128,7 +128,7 @@ fn handle_robot_docs(robot_mode: bool, brief: bool) -> Result<(), Box<dyn std::e
|
|||||||
"data": {"issues": "[{iid:int, title:string, state:string, author_username:string, labels:[string], assignees:[string], discussion_count:int, unresolved_count:int, created_at_iso:string, updated_at_iso:string, web_url:string?, project_path:string, status_name:string?}]", "total_count": "int", "showing": "int"},
|
"data": {"issues": "[{iid:int, title:string, state:string, author_username:string, labels:[string], assignees:[string], discussion_count:int, unresolved_count:int, created_at_iso:string, updated_at_iso:string, web_url:string?, project_path:string, status_name:string?}]", "total_count": "int", "showing": "int"},
|
||||||
"meta": {"elapsed_ms": "int", "available_statuses": "[string] — all distinct status names in the database, for use with --status filter"}
|
"meta": {"elapsed_ms": "int", "available_statuses": "[string] — all distinct status names in the database, for use with --status filter"}
|
||||||
},
|
},
|
||||||
"show": {
|
"detail": {
|
||||||
"ok": "bool",
|
"ok": "bool",
|
||||||
"data": "IssueDetail (full entity with description, discussions, notes, events)",
|
"data": "IssueDetail (full entity with description, discussions, notes, events)",
|
||||||
"meta": {"elapsed_ms": "int"}
|
"meta": {"elapsed_ms": "int"}
|
||||||
@@ -138,7 +138,7 @@ fn handle_robot_docs(robot_mode: bool, brief: bool) -> Result<(), Box<dyn std::e
|
|||||||
"fields_presets": {"minimal": ["iid", "title", "state", "updated_at_iso"]}
|
"fields_presets": {"minimal": ["iid", "title", "state", "updated_at_iso"]}
|
||||||
},
|
},
|
||||||
"mrs": {
|
"mrs": {
|
||||||
"description": "List or show merge requests",
|
"description": "List merge requests, or view detail with <IID>",
|
||||||
"flags": ["<IID>", "-n/--limit", "--fields <list>", "-s/--state", "-p/--project", "-a/--author", "-A/--assignee", "-r/--reviewer", "-l/--label", "--since", "-d/--draft", "-D/--no-draft", "--target", "--source", "--sort", "--asc", "--no-asc", "-o/--open", "--no-open"],
|
"flags": ["<IID>", "-n/--limit", "--fields <list>", "-s/--state", "-p/--project", "-a/--author", "-A/--assignee", "-r/--reviewer", "-l/--label", "--since", "-d/--draft", "-D/--no-draft", "--target", "--source", "--sort", "--asc", "--no-asc", "-o/--open", "--no-open"],
|
||||||
"example": "lore --robot mrs --state opened",
|
"example": "lore --robot mrs --state opened",
|
||||||
"response_schema": {
|
"response_schema": {
|
||||||
@@ -147,7 +147,7 @@ fn handle_robot_docs(robot_mode: bool, brief: bool) -> Result<(), Box<dyn std::e
|
|||||||
"data": {"mrs": "[{iid:int, title:string, state:string, author_username:string, labels:[string], draft:bool, target_branch:string, source_branch:string, discussion_count:int, unresolved_count:int, created_at_iso:string, updated_at_iso:string, web_url:string?, project_path:string, reviewers:[string]}]", "total_count": "int", "showing": "int"},
|
"data": {"mrs": "[{iid:int, title:string, state:string, author_username:string, labels:[string], draft:bool, target_branch:string, source_branch:string, discussion_count:int, unresolved_count:int, created_at_iso:string, updated_at_iso:string, web_url:string?, project_path:string, reviewers:[string]}]", "total_count": "int", "showing": "int"},
|
||||||
"meta": {"elapsed_ms": "int"}
|
"meta": {"elapsed_ms": "int"}
|
||||||
},
|
},
|
||||||
"show": {
|
"detail": {
|
||||||
"ok": "bool",
|
"ok": "bool",
|
||||||
"data": "MrDetail (full entity with description, discussions, notes, events)",
|
"data": "MrDetail (full entity with description, discussions, notes, events)",
|
||||||
"meta": {"elapsed_ms": "int"}
|
"meta": {"elapsed_ms": "int"}
|
||||||
@@ -780,42 +780,3 @@ async fn handle_list_compat(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_show_compat(
|
|
||||||
config_override: Option<&str>,
|
|
||||||
entity: &str,
|
|
||||||
iid: i64,
|
|
||||||
project_filter: Option<&str>,
|
|
||||||
robot_mode: bool,
|
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let start = std::time::Instant::now();
|
|
||||||
let config = Config::load(config_override)?;
|
|
||||||
let project_filter = config.effective_project(project_filter);
|
|
||||||
|
|
||||||
match entity {
|
|
||||||
"issue" => {
|
|
||||||
let result = run_show_issue(&config, iid, project_filter)?;
|
|
||||||
if robot_mode {
|
|
||||||
print_show_issue_json(&result, start.elapsed().as_millis() as u64);
|
|
||||||
} else {
|
|
||||||
print_show_issue(&result);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
"mr" => {
|
|
||||||
let result = run_show_mr(&config, iid, project_filter)?;
|
|
||||||
if robot_mode {
|
|
||||||
print_show_mr_json(&result, start.elapsed().as_millis() as u64);
|
|
||||||
} else {
|
|
||||||
print_show_mr(&result);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
eprintln!(
|
|
||||||
"{}",
|
|
||||||
Theme::error().render(&format!("Unknown entity: {entity}"))
|
|
||||||
);
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -290,7 +290,6 @@ const COMMAND_FLAGS: &[(&str, &[&str])] = &[
|
|||||||
"--source-branch",
|
"--source-branch",
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
("show", &["--project"]),
|
|
||||||
("reset", &["--yes"]),
|
("reset", &["--yes"]),
|
||||||
(
|
(
|
||||||
"me",
|
"me",
|
||||||
@@ -396,7 +395,6 @@ const CANONICAL_SUBCOMMANDS: &[&str] = &[
|
|||||||
"backup",
|
"backup",
|
||||||
"reset",
|
"reset",
|
||||||
"list",
|
"list",
|
||||||
"show",
|
|
||||||
"auth-test",
|
"auth-test",
|
||||||
"sync-status",
|
"sync-status",
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -381,17 +381,6 @@ pub enum Commands {
|
|||||||
source_branch: Option<String>,
|
source_branch: Option<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[command(hide = true)]
|
|
||||||
Show {
|
|
||||||
#[arg(value_parser = ["issue", "mr"])]
|
|
||||||
entity: String,
|
|
||||||
|
|
||||||
iid: i64,
|
|
||||||
|
|
||||||
#[arg(long)]
|
|
||||||
project: Option<String>,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[command(hide = true, name = "auth-test")]
|
#[command(hide = true, name = "auth-test")]
|
||||||
AuthTest,
|
AuthTest,
|
||||||
|
|
||||||
|
|||||||
27
src/main.rs
27
src/main.rs
@@ -365,33 +365,6 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
Some(Commands::Show {
|
|
||||||
entity,
|
|
||||||
iid,
|
|
||||||
project,
|
|
||||||
}) => {
|
|
||||||
if robot_mode {
|
|
||||||
eprintln!(
|
|
||||||
r#"{{"warning":{{"type":"DEPRECATED","message":"'lore show' is deprecated, use 'lore {entity}s {iid}'","successor":"{entity}s"}}}}"#
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
eprintln!(
|
|
||||||
"{}",
|
|
||||||
Theme::warning().render(&format!(
|
|
||||||
"warning: 'lore show' is deprecated, use 'lore {}s {}'",
|
|
||||||
entity, iid
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
handle_show_compat(
|
|
||||||
cli.config.as_deref(),
|
|
||||||
&entity,
|
|
||||||
iid,
|
|
||||||
project.as_deref(),
|
|
||||||
robot_mode,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
Some(Commands::AuthTest) => {
|
Some(Commands::AuthTest) => {
|
||||||
if robot_mode {
|
if robot_mode {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
|
|||||||
Reference in New Issue
Block a user