autolabel.rs 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. use crate::{
  2. config::AutolabelConfig,
  3. github::{self, Event, Label},
  4. handlers::{Context, Handler},
  5. };
  6. use futures::future::{BoxFuture, FutureExt};
  7. pub(super) struct AutolabelInput {
  8. labels: Vec<Label>
  9. }
  10. pub(super) struct AutolabelHandler;
  11. impl Handler for AutolabelHandler {
  12. type Input = AutolabelInput;
  13. type Config = AutolabelConfig;
  14. fn parse_input(
  15. &self,
  16. _ctx: &Context,
  17. event: &Event,
  18. config: Option<&Self::Config>,
  19. ) -> Result<Option<Self::Input>, String> {
  20. if let Event::Issue(e) = event {
  21. if e.action == github::IssuesAction::Labeled {
  22. if let Some(config) = config {
  23. let mut autolabels = Vec::new();
  24. let applied_label = &e.label.as_ref().expect("label").name;
  25. 'outer: for (label, config) in config.get_by_trigger(applied_label) {
  26. let exclude_patterns: Vec<glob::Pattern> = config
  27. .exclude_labels
  28. .iter()
  29. .filter_map(|label| {
  30. match glob::Pattern::new(label) {
  31. Ok(exclude_glob) => {
  32. Some(exclude_glob)
  33. }
  34. Err(error) => {
  35. log::error!("Invalid glob pattern: {}", error);
  36. None
  37. }
  38. }
  39. })
  40. .collect();
  41. for label in event.issue().unwrap().labels() {
  42. for pat in &exclude_patterns {
  43. if pat.matches(&label.name) {
  44. // If we hit an excluded label, ignore this autolabel and check the next
  45. continue 'outer;
  46. }
  47. }
  48. }
  49. // If we reach here, no excluded labels were found, so we should apply the autolabel.
  50. autolabels.push(Label { name: label.to_owned() });
  51. }
  52. if !autolabels.is_empty() {
  53. return Ok(Some(AutolabelInput { labels: autolabels }));
  54. }
  55. }
  56. }
  57. }
  58. Ok(None)
  59. }
  60. fn handle_input<'a>(
  61. &self,
  62. ctx: &'a Context,
  63. config: &'a Self::Config,
  64. event: &'a Event,
  65. input: Self::Input,
  66. ) -> BoxFuture<'a, anyhow::Result<()>> {
  67. handle_input(ctx, config, event, input).boxed()
  68. }
  69. }
  70. async fn handle_input(
  71. ctx: &Context,
  72. _config: &AutolabelConfig,
  73. event: &Event,
  74. input: AutolabelInput,
  75. ) -> anyhow::Result<()> {
  76. let issue = event.issue().unwrap();
  77. let mut labels = issue.labels().to_owned();
  78. for label in input.labels {
  79. // Don't add the label if it's already there
  80. if !labels.contains(&label) {
  81. labels.push(label);
  82. }
  83. }
  84. issue.set_labels(&ctx.github, labels).await?;
  85. Ok(())
  86. }