rustc_commits.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. use crate::db::rustc_commits;
  2. use crate::{
  3. github::{self, Event},
  4. handlers::Context,
  5. };
  6. use std::convert::TryInto;
  7. const BORS_GH_ID: i64 = 3372342;
  8. pub async fn handle(ctx: &Context, event: &Event) -> anyhow::Result<()> {
  9. let body = match event.comment_body() {
  10. Some(v) => v,
  11. // Skip events that don't have comment bodies associated
  12. None => return Ok(()),
  13. };
  14. let event = if let Event::IssueComment(e) = event {
  15. if e.action != github::IssueCommentAction::Created {
  16. return Ok(());
  17. }
  18. e
  19. } else {
  20. return Ok(());
  21. };
  22. if !body.contains("Test successful") {
  23. return Ok(());
  24. }
  25. if event.comment.user.id != Some(BORS_GH_ID) {
  26. log::trace!("Ignoring non-bors comment, user: {:?}", event.comment.user);
  27. return Ok(());
  28. }
  29. let repo = event.issue.repository();
  30. if !(repo.organization == "rust-lang" && repo.repository == "rust") {
  31. return Ok(());
  32. }
  33. let start = "<!-- homu: ";
  34. let start = body.find(start).map(|s| s + start.len());
  35. let end = body.find(" -->");
  36. let (start, end) = if let (Some(start), Some(end)) = (start, end) {
  37. (start, end)
  38. } else {
  39. log::warn!("Unable to extract build completion from comment {:?}", body);
  40. return Ok(());
  41. };
  42. let bors: BorsMessage = match serde_json::from_str(&body[start..end]) {
  43. Ok(bors) => bors,
  44. Err(e) => {
  45. log::error!(
  46. "failed to parse build completion from {:?}: {:?}",
  47. &body[start..end],
  48. e
  49. );
  50. return Ok(());
  51. }
  52. };
  53. if bors.type_ != "BuildCompleted" {
  54. log::trace!("Not build completion? {:?}", bors);
  55. }
  56. if bors.base_ref != "master" {
  57. log::trace!("Ignoring bors merge, not on master");
  58. return Ok(());
  59. }
  60. let mut sha = bors.merge_sha;
  61. let mut pr = Some(event.issue.number.try_into().unwrap());
  62. loop {
  63. // FIXME: ideally we would pull in all the commits here, but unfortunately
  64. // in rust-lang/rust's case there's bors-authored commits that aren't
  65. // actually from rust-lang/rust as they were merged into the clippy repo.
  66. let mut gc = match ctx.github.rust_commit(&sha).await {
  67. Some(c) => c,
  68. None => {
  69. log::error!("Could not find bors-reported sha: {:?}", sha);
  70. return Ok(());
  71. }
  72. };
  73. let parent_sha = gc.parents.remove(0).sha;
  74. if pr.is_none() {
  75. if let Some(tail) = gc.message.strip_prefix("Auto merge of #") {
  76. if let Some(end) = tail.find(' ') {
  77. if let Ok(number) = tail[..end].parse::<u32>() {
  78. pr = Some(number);
  79. }
  80. }
  81. }
  82. }
  83. let pr = match pr.take() {
  84. Some(number) => number,
  85. None => break,
  86. };
  87. let res = rustc_commits::record_commit(
  88. &ctx.db,
  89. rustc_commits::Commit {
  90. sha: gc.sha,
  91. parent_sha: parent_sha.clone(),
  92. time: gc.commit.author.date,
  93. pr: Some(pr),
  94. },
  95. )
  96. .await;
  97. match res {
  98. Ok(()) => {
  99. // proceed to the next commit once we've recorded this one.
  100. // We'll stop when we hit a duplicate commit, but this allows us
  101. // to backfill commits.
  102. sha = parent_sha;
  103. }
  104. Err(e) => {
  105. log::error!("Failed to record commit {:?}", e);
  106. break;
  107. }
  108. }
  109. }
  110. Ok(())
  111. }
  112. #[derive(Debug, serde::Deserialize)]
  113. struct BorsMessage {
  114. #[serde(rename = "type")]
  115. type_: String,
  116. base_ref: String,
  117. merge_sha: String,
  118. }