Skip to content

Commit 6d1a55b

Browse files
Merge pull request #1646 from ehuss/rfc-rendered
Fix RFC rendered linkifier.
2 parents 42dba1d + 7e85b63 commit 6d1a55b

File tree

4 files changed

+114
-28
lines changed

4 files changed

+114
-28
lines changed

src/github.rs

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -231,39 +231,63 @@ pub struct Label {
231231
pub name: String,
232232
}
233233

234-
#[derive(Debug, serde::Deserialize)]
235-
pub struct PullRequestDetails {
236-
// none for now
237-
}
238-
234+
/// An issue or pull request.
235+
///
236+
/// For convenience, since issues and pull requests share most of their
237+
/// fields, this struct is used for both. The `pull_request` field can be used
238+
/// to determine which it is. Some fields are only available on pull requests
239+
/// (but not always, check the GitHub API for details).
239240
#[derive(Debug, serde::Deserialize)]
240241
pub struct Issue {
241242
pub number: u64,
242243
#[serde(deserialize_with = "opt_string")]
243244
pub body: String,
244245
created_at: chrono::DateTime<Utc>,
245246
pub updated_at: chrono::DateTime<Utc>,
247+
/// The SHA for a merge commit.
248+
///
249+
/// This field is complicated, see the [Pull Request
250+
/// docs](https://docs.github.com/en/rest/pulls/pulls#get-a-pull-request)
251+
/// for details.
246252
#[serde(default)]
247253
pub merge_commit_sha: Option<String>,
248254
pub title: String,
255+
/// The common URL for viewing this issue or PR.
256+
///
257+
/// Example: `https://github.com/octocat/Hello-World/pull/1347`
249258
pub html_url: String,
250259
pub user: User,
251260
pub labels: Vec<Label>,
252261
pub assignees: Vec<User>,
253-
pub pull_request: Option<PullRequestDetails>,
262+
/// This is true if this is a pull request.
263+
///
264+
/// Note that this field does not come from GitHub. This is manually added
265+
/// when the webhook arrives to help differentiate between an event
266+
/// related to an issue versus a pull request.
267+
#[serde(default)]
268+
pub pull_request: bool,
269+
/// Whether or not the pull request was merged.
254270
#[serde(default)]
255271
pub merged: bool,
256272
#[serde(default)]
257273
pub draft: bool,
258-
// API URL
274+
/// The API URL for discussion comments.
275+
///
276+
/// Example: `https://api.github.com/repos/octocat/Hello-World/issues/1347/comments`
259277
comments_url: String,
278+
/// The repository for this issue.
279+
///
280+
/// Note that this is constructed via the [`Issue::repository`] method.
281+
/// It is not deserialized from the GitHub API.
260282
#[serde(skip)]
261283
repository: OnceCell<IssueRepository>,
262284

285+
/// The base commit for a PR (the branch of the destination repo).
263286
#[serde(default)]
264-
base: Option<CommitBase>,
287+
pub base: Option<CommitBase>,
288+
/// The head commit for a PR (the branch from the source repo).
265289
#[serde(default)]
266-
head: Option<CommitBase>,
290+
pub head: Option<CommitBase>,
267291
}
268292

269293
/// Contains only the parts of `Issue` that are needed for turning the issue title into a Zulip
@@ -431,7 +455,7 @@ impl Issue {
431455
}
432456

433457
pub fn is_pr(&self) -> bool {
434-
self.pull_request.is_some()
458+
self.pull_request
435459
}
436460

437461
pub async fn get_comment(&self, client: &GithubClient, id: usize) -> anyhow::Result<Comment> {
@@ -798,6 +822,9 @@ pub enum PullRequestReviewAction {
798822
Dismissed,
799823
}
800824

825+
/// A pull request review event.
826+
///
827+
/// <https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#pull_request_review>
801828
#[derive(Debug, serde::Deserialize)]
802829
pub struct PullRequestReviewEvent {
803830
pub action: PullRequestReviewAction,
@@ -877,6 +904,9 @@ struct PullRequestEventFields {}
877904
#[derive(Clone, Debug, serde::Deserialize)]
878905
pub struct CommitBase {
879906
sha: String,
907+
#[serde(rename = "ref")]
908+
pub git_ref: String,
909+
pub repo: Repository,
880910
}
881911

882912
pub fn files_changed(diff: &str) -> Vec<&str> {
@@ -1215,11 +1245,24 @@ pub struct PushEvent {
12151245
sender: User,
12161246
}
12171247

1248+
/// An event triggered by a webhook.
12181249
#[derive(Debug)]
12191250
pub enum Event {
1251+
/// A Git branch or tag is created.
12201252
Create(CreateEvent),
1253+
/// A comment on an issue or PR.
1254+
///
1255+
/// Can be:
1256+
/// - Regular comment on an issue or PR.
1257+
/// - A PR review.
1258+
/// - A comment on a PR review.
1259+
///
1260+
/// These different scenarios are unified into the `IssueComment` variant
1261+
/// when triagebot receives the corresponding webhook event.
12211262
IssueComment(IssueCommentEvent),
1263+
/// Activity on an issue or PR.
12221264
Issue(IssuesEvent),
1265+
/// One or more commits are pushed to a repository branch or tag.
12231266
Push(PushEvent),
12241267
}
12251268

src/handlers/review_submitted.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ pub(crate) async fn handle(
1010
event @ IssueCommentEvent {
1111
action: IssueCommentAction::Created,
1212
issue: Issue {
13-
pull_request: Some(_),
14-
..
13+
pull_request: true, ..
1514
},
1615
..
1716
},

src/handlers/rfc_helper.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,29 @@ pub async fn handle(ctx: &Context, event: &Event) -> anyhow::Result<()> {
2323
}
2424

2525
async fn add_rendered_link(ctx: &Context, e: &IssuesEvent) -> anyhow::Result<()> {
26-
if e.action == IssuesAction::Opened || e.action == IssuesAction::Synchronize {
26+
if e.action == IssuesAction::Opened {
2727
let files = e.issue.files(&ctx.github).await?;
2828

2929
if let Some(file) = files.iter().find(|f| f.filename.starts_with("text/")) {
3030
if !e.issue.body.contains("[Rendered]") {
31+
// This URL should be stable while the PR is open, even if the
32+
// user pushes new commits.
33+
//
34+
// It will go away if the user deletes their branch, or if
35+
// they reset it (such as if they created a PR from master).
36+
// That should usually only happen after the PR is closed.
37+
// During the closing process, the closer should update the
38+
// Rendered link to the new location (which we should
39+
// automate!).
40+
let head = e.issue.head.as_ref().unwrap();
41+
let url = format!(
42+
"https://github.com/{}/blob/{}/{}",
43+
head.repo.full_name, head.git_ref, file.filename
44+
);
3145
e.issue
3246
.edit_body(
3347
&ctx.github,
34-
&format!("{}\n\n[Rendered]({})", e.issue.body, file.blob_url),
48+
&format!("{}\n\n[Rendered]({})", e.issue.body, url),
3549
)
3650
.await?;
3751
}

src/lib.rs

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ use interactions::ErrorComment;
99
use std::fmt;
1010
use tracing as log;
1111

12-
use crate::github::PullRequestDetails;
13-
1412
pub mod actions;
1513
pub mod agenda;
1614
mod changelogs;
@@ -28,15 +26,52 @@ mod team_data;
2826
pub mod triage;
2927
pub mod zulip;
3028

29+
/// The name of a webhook event.
3130
#[derive(Debug)]
3231
pub enum EventName {
32+
/// Pull request activity.
33+
///
34+
/// This gets translated to [`github::Event::Issue`] when sent to a handler.
35+
///
36+
/// <https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#pull_request>
3337
PullRequest,
38+
/// Pull request review activity.
39+
///
40+
/// This gets translated to [`github::Event::IssueComment`] when sent to a handler.
41+
///
42+
/// <https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#pull_request_review>
3443
PullRequestReview,
44+
/// A comment on a pull request review.
45+
///
46+
/// This gets translated to [`github::Event::IssueComment`] when sent to a handler.
47+
///
48+
/// <https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#pull_request_review_comment>
3549
PullRequestReviewComment,
50+
/// An issue or PR comment.
51+
///
52+
/// This gets translated to [`github::Event::IssueComment`] when sent to a handler.
53+
///
54+
/// <https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#issue_comment>
3655
IssueComment,
56+
/// Issue activity.
57+
///
58+
/// This gets translated to [`github::Event::Issue`] when sent to a handler.
59+
///
60+
/// <https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#issues>
3761
Issue,
62+
/// One or more commits are pushed to a repository branch or tag.
63+
///
64+
/// This gets translated to [`github::Event::Push`] when sent to a handler.
65+
///
66+
/// <https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#push>
3867
Push,
68+
/// A Git branch or tag is created.
69+
///
70+
/// This gets translated to [`github::Event::Create`] when sent to a handler.
71+
///
72+
/// <https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#create>
3973
Create,
74+
/// All other unhandled webhooks.
4075
Other,
4176
}
4277

@@ -108,12 +143,7 @@ pub async fn webhook(
108143
.map_err(anyhow::Error::from)?;
109144

110145
log::info!("handling pull request review comment {:?}", payload);
111-
112-
// Github doesn't send a pull_request field nested into the
113-
// pull_request field, so we need to adjust the deserialized result
114-
// to preserve that this event came from a pull request (since it's
115-
// a PR review, that's obviously the case).
116-
payload.pull_request.pull_request = Some(PullRequestDetails {});
146+
payload.pull_request.pull_request = true;
117147

118148
// Treat pull request review comments exactly like pull request
119149
// review comments.
@@ -138,11 +168,7 @@ pub async fn webhook(
138168
.context("PullRequestReview(Comment) failed to deserialize")
139169
.map_err(anyhow::Error::from)?;
140170

141-
// Github doesn't send a pull_request field nested into the
142-
// pull_request field, so we need to adjust the deserialized result
143-
// to preserve that this event came from a pull request (since it's
144-
// a PR review, that's obviously the case).
145-
payload.issue.pull_request = Some(PullRequestDetails {});
171+
payload.issue.pull_request = true;
146172

147173
log::info!("handling pull request review comment {:?}", payload);
148174

@@ -166,10 +192,14 @@ pub async fn webhook(
166192
github::Event::IssueComment(payload)
167193
}
168194
EventName::Issue | EventName::PullRequest => {
169-
let payload = deserialize_payload::<github::IssuesEvent>(&payload)
195+
let mut payload = deserialize_payload::<github::IssuesEvent>(&payload)
170196
.context(format!("{:?} failed to deserialize", event))
171197
.map_err(anyhow::Error::from)?;
172198

199+
if matches!(event, EventName::PullRequest) {
200+
payload.issue.pull_request = true;
201+
}
202+
173203
log::info!("handling issue event {:?}", payload);
174204

175205
github::Event::Issue(payload)

0 commit comments

Comments
 (0)