From 53b7216775b3cf64e78e0f61afe5a1daf03c18b1 Mon Sep 17 00:00:00 2001 From: Ryo Kitagawa Date: Wed, 20 Mar 2024 17:59:37 +0900 Subject: [PATCH] feat: add ignore tag images option (#39) --- src/config.rs | 8 ++++ src/main.rs | 7 +++- src/parser.rs | 114 ++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 116 insertions(+), 13 deletions(-) diff --git a/src/config.rs b/src/config.rs index f433be7..17f83f3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,6 +23,7 @@ pub struct Config { pub ci: ci::CIKind, pub notifier: notifier::NotifierKind, pub suppress_skaffold: bool, + pub ignore_tag_images: Vec, pub patch: bool, } @@ -35,11 +36,13 @@ impl Config { let ci = ci::CIKind::from_str(ci_kind)?; let notifier = notifier::NotifierKind::from_str(notifier_kind)?; let suppress_skaffold = cli.suppress_skaffold; + let ignore_tag_images = cli.ignore_tag_images.clone(); let patch = cli.patch; return Ok(Self { ci, notifier, suppress_skaffold, + ignore_tag_images, patch, }); } @@ -62,11 +65,16 @@ impl Config { let ci = ci::CIKind::from_str(&env::var("KSNOTIFY_CI")?)?; let notifier = notifier::NotifierKind::from_str(&env::var("KSNOTIFY_NOTIFIER")?)?; let suppress_skaffold = env::var("KSNOTIFY_SUPPRESS_SKAFFOLD").is_ok(); + let ignore_tag_images = env::var("KSNOTIFY_IGNORE_TAG_IMAGES")? + .split(',') + .map(String::from) + .collect(); let patch = env::var("KSNOTIFY_PATCH").is_ok(); Ok(Self { ci, notifier, suppress_skaffold, + ignore_tag_images, patch, }) } diff --git a/src/main.rs b/src/main.rs index 2e5e251..e30d512 100755 --- a/src/main.rs +++ b/src/main.rs @@ -43,6 +43,10 @@ pub struct Cli { #[arg(long, value_name = "FILE")] pub config: Option, + /// Image names to ignore tag differences. + #[arg(long)] + pub ignore_tag_images: Vec, + #[clap(flatten)] verbose: Verbosity, } @@ -95,7 +99,8 @@ fn process( ) -> Result { let mut body = String::new(); io::stdin().read_to_string(&mut body)?; - let parser = parser::DiffParser::new(config.suppress_skaffold)?; + let parser = + parser::DiffParser::new(config.suppress_skaffold, config.ignore_tag_images.clone())?; let result = parser.parse(&body)?; let link = url.unwrap_or_default(); let template = template::Template::new(result.kind_result, link, target); diff --git a/src/parser.rs b/src/parser.rs index 3715d1b..ec76e77 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -18,10 +18,11 @@ pub struct DiffParser { skaffold: Regex, suppress_skaffold: bool, generation: Regex, + ignore_tag_images: Vec, } impl DiffParser { - pub fn new(suppress_skaffold: bool) -> Result { + pub fn new(suppress_skaffold: bool, ignore_tag_images: Vec) -> Result { let kind = Regex::new(r"(?m)^diff -u -N\s.*/(?P[^/\s]+)\s.*/([^/\s]+)$")?; // matches line like "diff -u -N /var/folders/fl/blahblah/[apiVersion].[kind].[namespace].[name] /var/folders/fl/blahblah/[apiVersion].[kind].[namespace].[name]" let header = Regex::new(r"(?m)^((diff -u -N)|(\-\-\-)|(\+\+\+)).*$")?; // matches diff header that starts with "diff -u -N" or "---" or "+++" let diff = Regex::new(r"(?m)^[\-\+].*$")?; @@ -34,6 +35,7 @@ impl DiffParser { skaffold, suppress_skaffold, generation, + ignore_tag_images, }) } @@ -73,6 +75,18 @@ impl DiffParser { .collect() } + fn suppress_image_tags(&self, mut result: HashMap) -> HashMap { + for image_name in self.ignore_tag_images.iter() { + result = result + .iter() + .map(|(kind, diff)| (kind, self.remove_image_tags(diff, image_name))) + .filter(|(_kind, diff)| self.is_there_any_diff(diff)) + .map(|(kind, diff)| (kind.to_string(), diff)) + .collect(); + } + result + } + fn remove_skaffold_labels(&self, diff: &str) -> String { self.skaffold.replace_all(diff, "").to_string() } @@ -81,6 +95,22 @@ impl DiffParser { self.generation.replace_all(diff, "").to_string() } + fn remove_image_tags(&self, diff: &str, image_name: &str) -> String { + let escaped_image_name = regex::escape(image_name); + let regexp = Regex::new( + format!( + r"- *image: {}(:.*)?\n\+ *image: {}(:.*)?\n", + escaped_image_name, escaped_image_name + ) + .as_str(), + ); + if let Err(e) = regexp { + eprintln!("Failed to create regex: {:?}", e); + return diff.to_string(); + } + regexp.unwrap().replace_all(diff, "").to_string() + } + fn is_there_any_diff(&self, body: &str) -> bool { self.diff.is_match(body) } @@ -104,6 +134,7 @@ impl Parsable for DiffParser { if self.suppress_skaffold { result = self.suppress_skaffold_labels(result); } + result = self.suppress_image_tags(result); debug!("result: {:?}", result); Ok(ParseResult { @@ -128,7 +159,7 @@ diff -u -N /var/folders/fl/blahblah/v1.Service.test.test-app2 /var/folders/fl/bl +++ /var/folders/fl/blahblah/v1.Service.test.test-app 2022-02-22 22:00:00.000000000 +0900 - 12345 + 67890"; - let parser = self::DiffParser::new(false).unwrap(); + let parser = self::DiffParser::new(false, Vec::new()).unwrap(); let actual = parser.parse(diff).unwrap(); assert_eq!(actual.kind_result.len(), 2); @@ -152,7 +183,7 @@ diff -u -N /var/folders/fl/blahblah/v1.Service.test.test-app2 /var/folders/fl/bl 12345 67890"; - let parser = self::DiffParser::new(false).unwrap(); + let parser = self::DiffParser::new(false, Vec::new()).unwrap(); let actual = parser.parse_kinds(diff); let expected = vec!["v1.Service.test.test-app1", "v1.Service.test.test-app2"]; assert_eq!(&actual[..], &expected[..]); @@ -170,7 +201,7 @@ diff -u -N /var/folders/fl/blahblah/v1.Service.test.test-app2 /var/folders/fl/bl +++ /var/folders/fl/blahblah/v1.Service.test.test-app 2022-02-22 22:00:00.000000000 +0900 12345 67890"; - let parser = self::DiffParser::new(false).unwrap(); + let parser = self::DiffParser::new(false, Vec::new()).unwrap(); let actual = parser.parse_diff(diff); let expected = vec!["ABCDE\nFGHIJ", "12345\n67890"]; assert_eq!(&actual[..], &expected[..]); @@ -182,7 +213,7 @@ diff -u -N /var/folders/fl/blahblah/v1.Service.test.test-app2 /var/folders/fl/bl def - hij + klm"; - let parser = self::DiffParser::new(false).unwrap(); + let parser = self::DiffParser::new(false, Vec::new()).unwrap(); let actual = parser.is_there_any_diff(diff); assert!(actual); } @@ -192,7 +223,7 @@ def let diff = "abc def hij"; - let parser = self::DiffParser::new(false).unwrap(); + let parser = self::DiffParser::new(false, Vec::new()).unwrap(); let actual = parser.is_there_any_diff(diff); assert!(!actual); } @@ -208,7 +239,7 @@ hij"; name: test-app namespace: test "; - let parser = self::DiffParser::new(true).unwrap(); + let parser = self::DiffParser::new(true, Vec::new()).unwrap(); let actual = parser.remove_skaffold_labels(diff); let expected = " @@ -5,7 +5,6 @@ @@ -231,7 +262,7 @@ hij"; name: test-app namespace: test "; - let parser = self::DiffParser::new(true).unwrap(); + let parser = self::DiffParser::new(true, Vec::new()).unwrap(); let actual = parser.remove_skaffold_labels(diff); let expected = " @@ -5,7 +5,6 @@ @@ -257,7 +288,7 @@ hij"; namespace: test spec: "; - let parser = self::DiffParser::new(true).unwrap(); + let parser = self::DiffParser::new(true, Vec::new()).unwrap(); let actual = parser.remove_skaffold_labels(diff); let expected = " @@ -1,8 +1,6 @@ @@ -289,7 +320,7 @@ hij"; spec: containers: "; - let parser = self::DiffParser::new(true).unwrap(); + let parser = self::DiffParser::new(true, Vec::new()).unwrap(); let actual = parser.remove_skaffold_labels(diff); let expected = " @@ -1,8 +1,6 @@ @@ -316,7 +347,7 @@ hij"; name: test-app namespace: test "; - let parser = self::DiffParser::new(true).unwrap(); + let parser = self::DiffParser::new(true, Vec::new()).unwrap(); let actual = parser.remove_generation_fields(diff); let expected = " @@ -5,9 +5,7 @@ @@ -333,12 +364,71 @@ hij"; name: test-app namespace: test "; - let parser = self::DiffParser::new(true).unwrap(); + let parser = self::DiffParser::new(true, Vec::new()).unwrap(); let actual = parser.remove_generation_fields(diff); let expected = " @@ -5,9 +5,7 @@ name: test-app namespace: test +"; + assert_eq!(actual, expected); + } + + #[test] + fn test_ignore_image_tags() { + let diff = " +@@ -50,7 +48,7 @@ + - configMapRef: + name: configmap +- image: image:latest@sha256:19adf91 ++ image: image:latest +"; + let parser = self::DiffParser::new(true, Vec::new()).unwrap(); + let actual = parser.remove_image_tags(diff, "image"); + let expected = " +@@ -50,7 +48,7 @@ + - configMapRef: + name: configmap +"; + assert_eq!(actual, expected); + } + + #[test] + fn test_ignore_image_tags_with_no_label() { + let diff = " +@@ -50,7 +48,7 @@ + - configMapRef: + name: configmap +- image: image:latest@sha256:19adf91 ++ image: image +"; + let parser = self::DiffParser::new(true, Vec::new()).unwrap(); + let actual = parser.remove_image_tags(diff, "image"); + let expected = " +@@ -50,7 +48,7 @@ + - configMapRef: + name: configmap +"; + assert_eq!(actual, expected); + } + + #[test] + fn test_donot_ignore_image_tags_when_image_was_changed() { + let diff = " +@@ -50,7 +48,7 @@ + - configMapRef: + name: configmap +- image: image:latest ++ image: other:latest +"; + let parser = self::DiffParser::new(true, Vec::new()).unwrap(); + let actual = parser.remove_image_tags(diff, "image"); + let expected = " +@@ -50,7 +48,7 @@ + - configMapRef: + name: configmap +- image: image:latest ++ image: other:latest "; assert_eq!(actual, expected); }