|
| 1 | +use std::borrow::Cow; |
| 2 | + |
1 | 3 | use anyhow::bail;
|
2 | 4 |
|
3 | 5 | use crate::{
|
@@ -34,65 +36,83 @@ async fn add_rendered_link(ctx: &Context, e: &IssuesEvent, prefix: &str) -> anyh
|
34 | 36 | if e.action == IssuesAction::Opened
|
35 | 37 | || e.action == IssuesAction::Closed
|
36 | 38 | || e.action == IssuesAction::Reopened
|
| 39 | + || e.action == IssuesAction::Synchronize |
37 | 40 | {
|
38 | 41 | let files = e.issue.files(&ctx.github).await?;
|
39 | 42 |
|
40 |
| - if let Some(file) = files.iter().find(|f| f.filename.starts_with(prefix)) { |
41 |
| - let head = e.issue.head.as_ref().unwrap(); |
42 |
| - let base = e.issue.base.as_ref().unwrap(); |
| 43 | + let rendered_link = files |
| 44 | + .iter() |
| 45 | + .find(|f| f.filename.starts_with(prefix)) |
| 46 | + .map(|file| { |
| 47 | + let head = e.issue.head.as_ref().unwrap(); |
| 48 | + let base = e.issue.base.as_ref().unwrap(); |
43 | 49 |
|
44 |
| - // This URL should be stable while the PR is open, even if the |
45 |
| - // user pushes new commits. |
46 |
| - // |
47 |
| - // It will go away if the user deletes their branch, or if |
48 |
| - // they reset it (such as if they created a PR from master). |
49 |
| - // That should usually only happen after the PR is closed |
50 |
| - // a which point we switch to a SHA-based url. |
51 |
| - // |
52 |
| - // If the PR is merged we use a URL that points to the actual |
53 |
| - // repository, as to be resilient to branch deletion, as well |
54 |
| - // be in sync with current "master" branch. |
55 |
| - // |
56 |
| - // For a PR "octocat:master" <- "Bob:patch-1", we generate, |
57 |
| - // - if merged: `https://github.com/octocat/REPO/blob/master/FILEPATH` |
58 |
| - // - if open: `https://github.com/Bob/REPO/blob/patch-1/FILEPATH` |
59 |
| - // - if closed: `https://github.com/octocat/REPO/blob/SHA/FILEPATH` |
60 |
| - let rendered_link = format!( |
61 |
| - "[Rendered](https://github.com/{}/blob/{}/{})", |
62 |
| - if e.issue.merged || e.action == IssuesAction::Closed { |
63 |
| - &e.repository.full_name |
64 |
| - } else { |
65 |
| - &head.repo.full_name |
66 |
| - }, |
67 |
| - if e.issue.merged { |
68 |
| - &base.git_ref |
69 |
| - } else if e.action == IssuesAction::Closed { |
70 |
| - &head.sha |
71 |
| - } else { |
72 |
| - &head.git_ref |
73 |
| - }, |
74 |
| - file.filename |
75 |
| - ); |
| 50 | + // This URL should be stable while the PR is open, even if the |
| 51 | + // user pushes new commits. |
| 52 | + // |
| 53 | + // It will go away if the user deletes their branch, or if |
| 54 | + // they reset it (such as if they created a PR from master). |
| 55 | + // That should usually only happen after the PR is closed |
| 56 | + // a which point we switch to a SHA-based url. |
| 57 | + // |
| 58 | + // If the PR is merged we use a URL that points to the actual |
| 59 | + // repository, as to be resilient to branch deletion, as well |
| 60 | + // be in sync with current "master" branch. |
| 61 | + // |
| 62 | + // For a PR "octocat:master" <- "Bob:patch-1", we generate, |
| 63 | + // - if merged: `https://github.com/octocat/REPO/blob/master/FILEPATH` |
| 64 | + // - if open: `https://github.com/Bob/REPO/blob/patch-1/FILEPATH` |
| 65 | + // - if closed: `https://github.com/octocat/REPO/blob/SHA/FILEPATH` |
| 66 | + format!( |
| 67 | + "[Rendered](https://github.com/{}/blob/{}/{})", |
| 68 | + if e.issue.merged || e.action == IssuesAction::Closed { |
| 69 | + &e.repository.full_name |
| 70 | + } else { |
| 71 | + &head.repo.full_name |
| 72 | + }, |
| 73 | + if e.issue.merged { |
| 74 | + &base.git_ref |
| 75 | + } else if e.action == IssuesAction::Closed { |
| 76 | + &head.sha |
| 77 | + } else { |
| 78 | + &head.git_ref |
| 79 | + }, |
| 80 | + file.filename |
| 81 | + ) |
| 82 | + }); |
76 | 83 |
|
77 |
| - let new_body = if !e.issue.body.contains("[Rendered]") { |
| 84 | + let new_body: Cow<'_, str> = if !e.issue.body.contains("[Rendered]") { |
| 85 | + if let Some(rendered_link) = rendered_link { |
78 | 86 | // add rendered link to the end of the body
|
79 |
| - format!("{}\n\n{rendered_link}", e.issue.body) |
80 |
| - } else if let Some(start_pos) = e.issue.body.find("[Rendered](") { |
81 |
| - let Some(end_offset) = &e.issue.body[start_pos..].find(')') else { |
82 |
| - bail!("no `)` after `[Rendered]` found") |
83 |
| - }; |
| 87 | + format!("{}\n\n{rendered_link}", e.issue.body).into() |
| 88 | + } else { |
| 89 | + // or return the original body since we don't have |
| 90 | + // a rendered link to add |
| 91 | + e.issue.body.as_str().into() |
| 92 | + } |
| 93 | + } else if let Some(start_pos) = e.issue.body.find("[Rendered](") { |
| 94 | + let Some(end_offset) = &e.issue.body[start_pos..].find(')') else { |
| 95 | + bail!("no `)` after `[Rendered]` found") |
| 96 | + }; |
84 | 97 |
|
85 |
| - // replace the current rendered link with the new one |
86 |
| - e.issue.body.replace( |
| 98 | + // replace the current rendered link with the new one or replace |
| 99 | + // it with an empty string if we don't have one |
| 100 | + e.issue |
| 101 | + .body |
| 102 | + .replace( |
87 | 103 | &e.issue.body[start_pos..=(start_pos + end_offset)],
|
88 |
| - &rendered_link, |
| 104 | + rendered_link.as_deref().unwrap_or(""), |
89 | 105 | )
|
90 |
| - } else { |
91 |
| - bail!( |
92 |
| - "found `[Rendered]` but not it's associated link, can't replace it, bailing out" |
93 |
| - ) |
94 |
| - }; |
| 106 | + .into() |
| 107 | + } else { |
| 108 | + bail!( |
| 109 | + "found `[Rendered]` but not it's associated link, can't replace it or remove it, bailing out" |
| 110 | + ) |
| 111 | + }; |
95 | 112 |
|
| 113 | + // avoid an expensive GitHub api call by first checking if we actually |
| 114 | + // edited the pull request body |
| 115 | + if e.issue.body != new_body { |
96 | 116 | e.issue.edit_body(&ctx.github, &new_body).await?;
|
97 | 117 | }
|
98 | 118 | }
|
|
0 commit comments