feat: subtext under pr title
This commit is contained in:
@@ -6,6 +6,17 @@ query PullRequestQuery($id: ID!) {
|
||||
body
|
||||
state
|
||||
isDraft
|
||||
baseRef {
|
||||
name
|
||||
}
|
||||
headRef {
|
||||
name
|
||||
}
|
||||
author {
|
||||
__typename
|
||||
login
|
||||
avatarUrl(size: 32)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,9 @@ pub(crate) struct DetailedPullRequest {
|
||||
pub(crate) state: PullRequestState,
|
||||
pub(crate) is_draft: bool,
|
||||
pub(crate) body: String,
|
||||
pub(crate) author: Option<super::user::Actor>,
|
||||
pub(crate) base_branch_name: Option<String>,
|
||||
pub(crate) head_branch_name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@@ -285,8 +288,8 @@ impl query::QueryFn for ListPullRequests {
|
||||
}
|
||||
|
||||
let query_string = match self.filter {
|
||||
Some(filter) => format!("is:pr archived:false sort:updated-desc {}", filter),
|
||||
None => "is:pr archived:false sort:updated-desc".into(),
|
||||
| Some(filter) => format!("is:pr archived:false sort:updated-desc {}", filter),
|
||||
| None => "is:pr archived:false sort:updated-desc".into(),
|
||||
};
|
||||
|
||||
let gql =
|
||||
@@ -308,19 +311,19 @@ impl query::QueryFn for ListPullRequests {
|
||||
.flatten()
|
||||
.filter_map(|edge| {
|
||||
edge.node.and_then(|n| match n {
|
||||
PullRequestPaginationQuerySearchEdgesNode::PullRequest(p) => {
|
||||
Some(PullRequest {
|
||||
id: p.id.into(),
|
||||
title: p.title,
|
||||
state: p.state,
|
||||
is_draft: p.is_draft,
|
||||
repo_slug: format!(
|
||||
"{}/{}",
|
||||
p.repository.owner.login, p.repository.name
|
||||
),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
| PullRequestPaginationQuerySearchEdgesNode::PullRequest(p) => {
|
||||
Some(PullRequest {
|
||||
id: p.id.into(),
|
||||
title: p.title,
|
||||
state: p.state,
|
||||
is_draft: p.is_draft,
|
||||
repo_slug: format!(
|
||||
"{}/{}",
|
||||
p.repository.owner.login, p.repository.name
|
||||
),
|
||||
})
|
||||
}
|
||||
| _ => None,
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
@@ -365,15 +368,21 @@ impl query::QueryFn for FetchPullRequest {
|
||||
"missing 'node' field on PullRequestQuery response".into(),
|
||||
))
|
||||
.and_then(|n| match n {
|
||||
PullRequestQueryNode::PullRequest(p) => Ok(DetailedPullRequest {
|
||||
title: p.title,
|
||||
state: p.state,
|
||||
is_draft: p.is_draft,
|
||||
body: p.body,
|
||||
| PullRequestQueryNode::PullRequest(p) => Ok(DetailedPullRequest {
|
||||
title: p.title,
|
||||
state: p.state,
|
||||
is_draft: p.is_draft,
|
||||
body: p.body,
|
||||
author: p.author.map(|it| api::user::Actor {
|
||||
login: it.login,
|
||||
avatar_url: it.avatar_url,
|
||||
}),
|
||||
_ => Err(api::Error::MalformedResponse(
|
||||
"unexpected node type on PullRequestQuery".into(),
|
||||
)),
|
||||
base_branch_name: p.base_ref.map(|r| r.name),
|
||||
head_branch_name: p.head_ref.map(|r| r.name),
|
||||
}),
|
||||
| _ => Err(api::Error::MalformedResponse(
|
||||
"unexpected node type on PullRequestQuery".into(),
|
||||
)),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -416,11 +425,11 @@ impl query::QueryFn for FetchPullRequestTimeline {
|
||||
|
||||
TimelineActor {
|
||||
kind: match on {
|
||||
actorFieldsOn::Bot => "Bot",
|
||||
actorFieldsOn::EnterpriseUserAccount => "EnterpriseUserAccount",
|
||||
actorFieldsOn::Mannequin => "Mannequin",
|
||||
actorFieldsOn::Organization => "Organization",
|
||||
actorFieldsOn::User => "User",
|
||||
| actorFieldsOn::Bot => "Bot",
|
||||
| actorFieldsOn::EnterpriseUserAccount => "EnterpriseUserAccount",
|
||||
| actorFieldsOn::Mannequin => "Mannequin",
|
||||
| actorFieldsOn::Organization => "Organization",
|
||||
| actorFieldsOn::User => "User",
|
||||
}
|
||||
.into(),
|
||||
name: login,
|
||||
@@ -430,62 +439,62 @@ impl query::QueryFn for FetchPullRequestTimeline {
|
||||
|
||||
fn normalize_assignee(actor: assigneeFields) -> TimelineActor {
|
||||
match actor {
|
||||
assigneeFields::Bot(actor) => TimelineActor {
|
||||
kind: "Bot".into(),
|
||||
name: actor.login,
|
||||
avatar_url: Some(actor.avatar_url),
|
||||
},
|
||||
assigneeFields::Mannequin(actor) => TimelineActor {
|
||||
kind: "Mannequin".into(),
|
||||
name: actor.login,
|
||||
avatar_url: Some(actor.avatar_url),
|
||||
},
|
||||
assigneeFields::Organization(actor) => TimelineActor {
|
||||
kind: "Organization".into(),
|
||||
name: actor.login,
|
||||
avatar_url: Some(actor.avatar_url),
|
||||
},
|
||||
assigneeFields::User(actor) => TimelineActor {
|
||||
kind: "User".into(),
|
||||
name: actor.login,
|
||||
avatar_url: Some(actor.avatar_url),
|
||||
},
|
||||
| assigneeFields::Bot(actor) => TimelineActor {
|
||||
kind: "Bot".into(),
|
||||
name: actor.login,
|
||||
avatar_url: Some(actor.avatar_url),
|
||||
},
|
||||
| assigneeFields::Mannequin(actor) => TimelineActor {
|
||||
kind: "Mannequin".into(),
|
||||
name: actor.login,
|
||||
avatar_url: Some(actor.avatar_url),
|
||||
},
|
||||
| assigneeFields::Organization(actor) => TimelineActor {
|
||||
kind: "Organization".into(),
|
||||
name: actor.login,
|
||||
avatar_url: Some(actor.avatar_url),
|
||||
},
|
||||
| assigneeFields::User(actor) => TimelineActor {
|
||||
kind: "User".into(),
|
||||
name: actor.login,
|
||||
avatar_url: Some(actor.avatar_url),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_requested_reviewer(actor: requestedReviewerFields) -> TimelineActor {
|
||||
match actor {
|
||||
requestedReviewerFields::Bot(actor) => TimelineActor {
|
||||
kind: "Bot".into(),
|
||||
name: actor.login,
|
||||
avatar_url: Some(actor.avatar_url),
|
||||
},
|
||||
requestedReviewerFields::Mannequin(actor) => TimelineActor {
|
||||
kind: "Mannequin".into(),
|
||||
name: actor.login,
|
||||
avatar_url: Some(actor.avatar_url),
|
||||
},
|
||||
requestedReviewerFields::Team(actor) => TimelineActor {
|
||||
kind: "Team".into(),
|
||||
name: actor.name,
|
||||
avatar_url: None,
|
||||
},
|
||||
requestedReviewerFields::User(actor) => TimelineActor {
|
||||
kind: "User".into(),
|
||||
name: actor.login,
|
||||
avatar_url: Some(actor.avatar_url),
|
||||
},
|
||||
| requestedReviewerFields::Bot(actor) => TimelineActor {
|
||||
kind: "Bot".into(),
|
||||
name: actor.login,
|
||||
avatar_url: Some(actor.avatar_url),
|
||||
},
|
||||
| requestedReviewerFields::Mannequin(actor) => TimelineActor {
|
||||
kind: "Mannequin".into(),
|
||||
name: actor.login,
|
||||
avatar_url: Some(actor.avatar_url),
|
||||
},
|
||||
| requestedReviewerFields::Team(actor) => TimelineActor {
|
||||
kind: "Team".into(),
|
||||
name: actor.name,
|
||||
avatar_url: None,
|
||||
},
|
||||
| requestedReviewerFields::User(actor) => TimelineActor {
|
||||
kind: "User".into(),
|
||||
name: actor.login,
|
||||
avatar_url: Some(actor.avatar_url),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_review_state(state: PullRequestReviewState) -> String {
|
||||
match state {
|
||||
PullRequestReviewState::PENDING => "PENDING",
|
||||
PullRequestReviewState::COMMENTED => "COMMENTED",
|
||||
PullRequestReviewState::APPROVED => "APPROVED",
|
||||
PullRequestReviewState::CHANGES_REQUESTED => "CHANGES_REQUESTED",
|
||||
PullRequestReviewState::DISMISSED => "DISMISSED",
|
||||
_ => "OTHER",
|
||||
| PullRequestReviewState::PENDING => "PENDING",
|
||||
| PullRequestReviewState::COMMENTED => "COMMENTED",
|
||||
| PullRequestReviewState::APPROVED => "APPROVED",
|
||||
| PullRequestReviewState::CHANGES_REQUESTED => "CHANGES_REQUESTED",
|
||||
| PullRequestReviewState::DISMISSED => "DISMISSED",
|
||||
| _ => "OTHER",
|
||||
}
|
||||
.into()
|
||||
}
|
||||
@@ -705,10 +714,10 @@ impl query::QueryFn for FetchPullRequestTimeline {
|
||||
"missing 'node' field on PullRequestTimelineQuery response".into(),
|
||||
))
|
||||
.and_then(|node| match node {
|
||||
PullRequestTimelineQueryNode::PullRequest(pull_request) => Ok(pull_request),
|
||||
_ => Err(api::Error::MalformedResponse(
|
||||
"unexpected node type on PullRequestTimelineQuery".into(),
|
||||
)),
|
||||
| PullRequestTimelineQueryNode::PullRequest(pull_request) => Ok(pull_request),
|
||||
| _ => Err(api::Error::MalformedResponse(
|
||||
"unexpected node type on PullRequestTimelineQuery".into(),
|
||||
)),
|
||||
})?;
|
||||
|
||||
let timeline = pull_request.timeline_items;
|
||||
|
||||
@@ -133,15 +133,80 @@ mod tests {
|
||||
.expect("closed pull request fixture should parse");
|
||||
let dashboard_markdown = fetch_pull_request(&issues::Id::from("PR_kwDONovem84"))
|
||||
.expect("dashboard pull request fixture should parse");
|
||||
let cached_repo_picker = fetch_pull_request(&issues::Id::from("PR_kwDONovem85"))
|
||||
.expect("repo picker pull request fixture should parse");
|
||||
let worker_split = fetch_pull_request(&issues::Id::from("PR_kwDOAgent47"))
|
||||
.expect("worker split pull request fixture should parse");
|
||||
let spacing_tokens = fetch_pull_request(&issues::Id::from("PR_kwDODesign31"))
|
||||
.expect("spacing token pull request fixture should parse");
|
||||
|
||||
assert_eq!(merged.state, issues::PullRequestState::Merged);
|
||||
assert!(merged.body.contains("| Stage | Owner | Status |"));
|
||||
assert_eq!(
|
||||
merged.author.as_ref().map(|author| author.login.as_str()),
|
||||
Some("rorycraft")
|
||||
);
|
||||
assert_eq!(merged.base_branch_name.as_deref(), Some("main"));
|
||||
assert_eq!(
|
||||
merged.head_branch_name.as_deref(),
|
||||
Some("feat/release-handoff-checklist")
|
||||
);
|
||||
assert!(
|
||||
documented_failover
|
||||
.body
|
||||
.contains("./scripts/failover promote-standby")
|
||||
);
|
||||
assert_eq!(
|
||||
documented_failover
|
||||
.author
|
||||
.as_ref()
|
||||
.map(|author| author.login.as_str()),
|
||||
Some("kennethnym")
|
||||
);
|
||||
assert_eq!(documented_failover.base_branch_name.as_deref(), Some("main"));
|
||||
assert_eq!(
|
||||
documented_failover.head_branch_name.as_deref(),
|
||||
Some("docs/manual-failover-steps")
|
||||
);
|
||||
assert!(dashboard_markdown.body.contains("```rust"));
|
||||
assert_eq!(dashboard_markdown.base_branch_name.as_deref(), Some("main"));
|
||||
assert_eq!(
|
||||
dashboard_markdown.head_branch_name.as_deref(),
|
||||
Some("feat/cached-issue-pane")
|
||||
);
|
||||
assert_eq!(
|
||||
cached_repo_picker
|
||||
.author
|
||||
.as_ref()
|
||||
.map(|author| author.login.as_str()),
|
||||
Some("kennethnym")
|
||||
);
|
||||
assert_eq!(cached_repo_picker.base_branch_name.as_deref(), Some("main"));
|
||||
assert_eq!(
|
||||
cached_repo_picker.head_branch_name.as_deref(),
|
||||
Some("feat/cached-repo-picker")
|
||||
);
|
||||
assert_eq!(
|
||||
worker_split.author.as_ref().map(|author| author.login.as_str()),
|
||||
Some("leaferiksen")
|
||||
);
|
||||
assert_eq!(worker_split.base_branch_name.as_deref(), Some("main"));
|
||||
assert_eq!(
|
||||
worker_split.head_branch_name.as_deref(),
|
||||
Some("feat/worker-context-envelope")
|
||||
);
|
||||
assert_eq!(
|
||||
spacing_tokens
|
||||
.author
|
||||
.as_ref()
|
||||
.map(|author| author.login.as_str()),
|
||||
Some("mariahops")
|
||||
);
|
||||
assert_eq!(spacing_tokens.base_branch_name.as_deref(), Some("main"));
|
||||
assert_eq!(
|
||||
spacing_tokens.head_branch_name.as_deref(),
|
||||
Some("chore/dashboard-spacing-scale")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -20,6 +20,12 @@ pub struct User {
|
||||
pub email: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct Actor {
|
||||
pub(crate) login: String,
|
||||
pub(crate) avatar_url: String,
|
||||
}
|
||||
|
||||
impl Deref for Id {
|
||||
type Target = u64;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user