fix(show): include gitlab_id on notes in issue/MR detail views

The show command's NoteDetail and MrNoteDetail structs were missing
gitlab_id, making individual notes unaddressable in robot mode output.
This was inconsistent with the notes list command which already exposed
gitlab_id. Without an identifier, agents consuming show output could
not construct GitLab web URLs or reference specific notes for follow-up
operations via glab.

Added gitlab_id to:
- NoteDetail / NoteDetailJson (issue discussions)
- MrNoteDetail / MrNoteDetailJson (MR discussions)
- Both SQL queries (shifted column indices accordingly)
- Both From<&T> conversion impls

Deliberately scoped to show command only — me/timeline/trace structs
were evaluated and intentionally left unchanged because they serve
different consumption patterns where note-level identity is not needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
teernisse
2026-03-10 11:40:23 -04:00
parent d94bcbfbe7
commit cab8c540da
3 changed files with 23 additions and 15 deletions

View File

@@ -44,6 +44,7 @@ pub struct DiscussionDetail {
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct NoteDetail { pub struct NoteDetail {
pub gitlab_id: i64,
pub author_username: String, pub author_username: String,
pub body: String, pub body: String,
pub created_at: i64, pub created_at: i64,
@@ -277,7 +278,7 @@ fn get_issue_discussions(conn: &Connection, issue_id: i64) -> Result<Vec<Discuss
.collect::<std::result::Result<Vec<_>, _>>()?; .collect::<std::result::Result<Vec<_>, _>>()?;
let mut note_stmt = conn.prepare( let mut note_stmt = conn.prepare(
"SELECT author_username, body, created_at, is_system "SELECT gitlab_id, author_username, body, created_at, is_system
FROM notes FROM notes
WHERE discussion_id = ? WHERE discussion_id = ?
ORDER BY position", ORDER BY position",
@@ -287,11 +288,12 @@ fn get_issue_discussions(conn: &Connection, issue_id: i64) -> Result<Vec<Discuss
for (disc_id, individual_note) in disc_rows { for (disc_id, individual_note) in disc_rows {
let notes: Vec<NoteDetail> = note_stmt let notes: Vec<NoteDetail> = note_stmt
.query_map([disc_id], |row| { .query_map([disc_id], |row| {
let is_system: i64 = row.get(3)?; let is_system: i64 = row.get(4)?;
Ok(NoteDetail { Ok(NoteDetail {
author_username: row.get(0)?, gitlab_id: row.get(0)?,
body: row.get(1)?, author_username: row.get(1)?,
created_at: row.get(2)?, body: row.get(2)?,
created_at: row.get(3)?,
is_system: is_system == 1, is_system: is_system == 1,
}) })
})? })?

View File

@@ -29,6 +29,7 @@ pub struct MrDiscussionDetail {
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct MrNoteDetail { pub struct MrNoteDetail {
pub gitlab_id: i64,
pub author_username: String, pub author_username: String,
pub body: String, pub body: String,
pub created_at: i64, pub created_at: i64,
@@ -224,7 +225,7 @@ fn get_mr_discussions(conn: &Connection, mr_id: i64) -> Result<Vec<MrDiscussionD
.collect::<std::result::Result<Vec<_>, _>>()?; .collect::<std::result::Result<Vec<_>, _>>()?;
let mut note_stmt = conn.prepare( let mut note_stmt = conn.prepare(
"SELECT author_username, body, created_at, is_system, "SELECT gitlab_id, author_username, body, created_at, is_system,
position_old_path, position_new_path, position_old_line, position_old_path, position_new_path, position_old_line,
position_new_line, position_type position_new_line, position_type
FROM notes FROM notes
@@ -236,12 +237,12 @@ fn get_mr_discussions(conn: &Connection, mr_id: i64) -> Result<Vec<MrDiscussionD
for (disc_id, individual_note) in disc_rows { for (disc_id, individual_note) in disc_rows {
let notes: Vec<MrNoteDetail> = note_stmt let notes: Vec<MrNoteDetail> = note_stmt
.query_map([disc_id], |row| { .query_map([disc_id], |row| {
let is_system: i64 = row.get(3)?; let is_system: i64 = row.get(4)?;
let old_path: Option<String> = row.get(4)?; let old_path: Option<String> = row.get(5)?;
let new_path: Option<String> = row.get(5)?; let new_path: Option<String> = row.get(6)?;
let old_line: Option<i64> = row.get(6)?; let old_line: Option<i64> = row.get(7)?;
let new_line: Option<i64> = row.get(7)?; let new_line: Option<i64> = row.get(8)?;
let position_type: Option<String> = row.get(8)?; let position_type: Option<String> = row.get(9)?;
let position = if old_path.is_some() let position = if old_path.is_some()
|| new_path.is_some() || new_path.is_some()
@@ -260,9 +261,10 @@ fn get_mr_discussions(conn: &Connection, mr_id: i64) -> Result<Vec<MrDiscussionD
}; };
Ok(MrNoteDetail { Ok(MrNoteDetail {
author_username: row.get(0)?, gitlab_id: row.get(0)?,
body: row.get(1)?, author_username: row.get(1)?,
created_at: row.get(2)?, body: row.get(2)?,
created_at: row.get(3)?,
is_system: is_system == 1, is_system: is_system == 1,
position, position,
}) })

View File

@@ -398,6 +398,7 @@ pub struct DiscussionDetailJson {
#[derive(Serialize)] #[derive(Serialize)]
pub struct NoteDetailJson { pub struct NoteDetailJson {
pub gitlab_id: i64,
pub author_username: String, pub author_username: String,
pub body: String, pub body: String,
pub created_at: String, pub created_at: String,
@@ -458,6 +459,7 @@ impl From<&DiscussionDetail> for DiscussionDetailJson {
impl From<&NoteDetail> for NoteDetailJson { impl From<&NoteDetail> for NoteDetailJson {
fn from(note: &NoteDetail) -> Self { fn from(note: &NoteDetail) -> Self {
Self { Self {
gitlab_id: note.gitlab_id,
author_username: note.author_username.clone(), author_username: note.author_username.clone(),
body: note.body.clone(), body: note.body.clone(),
created_at: ms_to_iso(note.created_at), created_at: ms_to_iso(note.created_at),
@@ -497,6 +499,7 @@ pub struct MrDiscussionDetailJson {
#[derive(Serialize)] #[derive(Serialize)]
pub struct MrNoteDetailJson { pub struct MrNoteDetailJson {
pub gitlab_id: i64,
pub author_username: String, pub author_username: String,
pub body: String, pub body: String,
pub created_at: String, pub created_at: String,
@@ -542,6 +545,7 @@ impl From<&MrDiscussionDetail> for MrDiscussionDetailJson {
impl From<&MrNoteDetail> for MrNoteDetailJson { impl From<&MrNoteDetail> for MrNoteDetailJson {
fn from(note: &MrNoteDetail) -> Self { fn from(note: &MrNoteDetail) -> Self {
Self { Self {
gitlab_id: note.gitlab_id,
author_username: note.author_username.clone(), author_username: note.author_username.clone(),
body: note.body.clone(), body: note.body.clone(),
created_at: ms_to_iso(note.created_at), created_at: ms_to_iso(note.created_at),