1use std::path::Path;
10
11use derive_builder::Builder;
12use git_checks_core::impl_prelude::*;
13use itertools::Itertools;
14use rayon::prelude::*;
15
16#[derive(Debug, Clone)]
18pub enum ChangelogStyle {
19 Directory {
21 path: String,
23 extension: Option<String>,
25 },
26 File {
28 path: String,
30 },
31 Files {
33 paths: Vec<String>,
35 },
36}
37
38impl ChangelogStyle {
39 pub fn file<P>(path: P) -> Self
41 where
42 P: Into<String>,
43 {
44 ChangelogStyle::File {
45 path: path.into(),
46 }
47 }
48
49 pub fn directory<P>(path: P, ext: Option<String>) -> Self
53 where
54 P: Into<String>,
55 {
56 ChangelogStyle::Directory {
57 path: path.into(),
58 extension: ext,
59 }
60 }
61
62 pub fn files<P, I>(paths: I) -> Self
64 where
65 I: IntoIterator<Item = P>,
66 P: Into<String>,
67 {
68 ChangelogStyle::Files {
69 paths: paths.into_iter().map(Into::into).collect(),
70 }
71 }
72
73 fn describe(&self) -> String {
75 match *self {
76 ChangelogStyle::Directory {
77 ref path,
78 ref extension,
79 } => {
80 if let Some(ext) = extension.as_ref() {
81 format!("a file ending with `.{}` in `{}`", ext, path)
82 } else {
83 format!("a file in `{}`", path)
84 }
85 },
86 ChangelogStyle::File {
87 ref path,
88 } => format!("the `{}` file", path),
89 ChangelogStyle::Files {
90 ref paths,
91 } => format!("one of the `{}` files", paths.iter().format("`, `")),
92 }
93 }
94
95 fn applies(&self, diff_path: &Path) -> bool {
97 match *self {
98 ChangelogStyle::Directory {
99 ref path,
100 ref extension,
101 } => {
102 let ext_ok = extension.as_ref().map_or(true, |ext| {
103 diff_path
104 .extension()
105 .is_some_and(|diff_ext| diff_ext == (ext.as_ref() as &Path))
106 });
107
108 ext_ok && diff_path.starts_with(path)
109 },
110 ChangelogStyle::File {
111 ref path,
112 } => diff_path == (path.as_ref() as &Path),
113 ChangelogStyle::Files {
114 ref paths,
115 } => {
116 paths
117 .iter()
118 .any(|path| diff_path == (path.as_ref() as &Path))
119 },
120 }
121 }
122
123 #[allow(clippy::match_like_matches_macro)]
125 fn is_ok(&self, status: StatusChange) -> bool {
126 match *self {
127 ChangelogStyle::Directory {
128 ..
129 } => {
130 match status {
131 StatusChange::Added
133 | StatusChange::Modified(_)
135 | StatusChange::Deleted => true,
137 _ => false,
138 }
139 },
140 ChangelogStyle::File {
141 ..
142 }
143 | ChangelogStyle::Files {
144 ..
145 } => {
146 match status {
147 StatusChange::Added
149 | StatusChange::Modified(_) => true,
151 _ => false,
153 }
154 },
155 }
156 }
157}
158
159#[derive(Builder, Debug, Clone)]
164#[builder(field(private))]
165pub struct Changelog {
166 style: ChangelogStyle,
170 #[builder(default = "false")]
175 required: bool,
176}
177
178impl Changelog {
179 pub fn builder() -> ChangelogBuilder {
181 Default::default()
182 }
183}
184
185impl ContentCheck for Changelog {
186 fn name(&self) -> &str {
187 "changelog"
188 }
189
190 fn check(
191 &self,
192 _: &CheckGitContext,
193 content: &dyn Content,
194 ) -> Result<CheckResult, Box<dyn Error>> {
195 let mut result = CheckResult::new();
196
197 let changelog_changes = content
198 .diffs()
199 .par_iter()
200 .filter(|diff| {
201 diff.old_blob != diff.new_blob
202 && self.style.applies(diff.name.as_path())
203 && self.style.is_ok(diff.status)
204 })
205 .count();
206
207 if changelog_changes == 0 {
208 if self.required {
209 result.add_error(format!(
210 "{}missing a changelog entry in {}.",
211 commit_prefix_str(content, "not allowed;"),
212 self.style.describe(),
213 ));
214 } else {
215 result.add_warning(format!(
216 "{}please consider adding a changelog entry in {}.",
217 commit_prefix_str(content, "is missing a changelog entry;"),
218 self.style.describe(),
219 ));
220 };
221 }
222
223 Ok(result)
224 }
225}
226
227#[cfg(feature = "config")]
228pub(crate) mod config {
229 use git_checks_config::{register_checks, CommitCheckConfig, IntoCheck, TopicCheckConfig};
230 use serde::Deserialize;
231 #[cfg(test)]
232 use serde_json::json;
233
234 #[cfg(test)]
235 use crate::test;
236 use crate::Changelog;
237 use crate::ChangelogStyle;
238
239 #[derive(Deserialize, Debug)]
282 #[serde(tag = "style")]
283 pub enum ChangelogConfig {
284 #[serde(rename = "directory")]
285 #[doc(hidden)]
286 Directory {
287 path: String,
288 #[serde(default)]
289 extension: Option<String>,
290
291 required: Option<bool>,
292 },
293 #[serde(rename = "file")]
294 #[doc(hidden)]
295 File {
296 path: String,
297
298 required: Option<bool>,
299 },
300 #[serde(rename = "files")]
301 #[doc(hidden)]
302 Files {
303 paths: Vec<String>,
304
305 required: Option<bool>,
306 },
307 }
308
309 impl IntoCheck for ChangelogConfig {
310 type Check = Changelog;
311
312 fn into_check(self) -> Self::Check {
313 let (style, required) = match self {
314 ChangelogConfig::Directory {
315 path,
316 extension,
317 required,
318 } => (ChangelogStyle::directory(path, extension), required),
319 ChangelogConfig::File {
320 path,
321 required,
322 } => (ChangelogStyle::file(path), required),
323 ChangelogConfig::Files {
324 paths,
325 required,
326 } => (ChangelogStyle::files(paths), required),
327 };
328
329 let mut builder = Changelog::builder();
330 builder.style(style);
331
332 if let Some(required) = required {
333 builder.required(required);
334 }
335
336 builder
337 .build()
338 .expect("configuration mismatch for `Changelog`")
339 }
340 }
341
342 register_checks! {
343 ChangelogConfig {
344 "changelog" => CommitCheckConfig,
345 "changelog/topic" => TopicCheckConfig,
346 },
347 }
348
349 #[test]
350 fn test_changelog_config_empty() {
351 let json = json!({});
352 let err = serde_json::from_value::<ChangelogConfig>(json).unwrap_err();
353 test::check_missing_json_field(err, "style");
354 }
355
356 #[test]
357 fn test_changelog_config_directory_path_is_required() {
358 let json = json!({
359 "style": "directory",
360 });
361 let err = serde_json::from_value::<ChangelogConfig>(json).unwrap_err();
362 test::check_missing_json_field(err, "path");
363 }
364
365 #[test]
366 fn test_changelog_config_directory_minimum_fields() {
367 let exp_path = "path/to/directory";
368 let json = json!({
369 "style": "directory",
370 "path": exp_path,
371 });
372 let check: ChangelogConfig = serde_json::from_value(json).unwrap();
373
374 if let ChangelogConfig::Directory {
375 ref path,
376 ref extension,
377 required,
378 } = &check
379 {
380 assert_eq!(path, exp_path);
381 assert_eq!(extension, &None);
382 assert_eq!(required, &None);
383 } else {
384 panic!("did not create a directory config: {:?}", check);
385 }
386
387 let check = check.into_check();
388
389 assert!(!check.required);
390 if let ChangelogStyle::Directory {
391 path,
392 extension,
393 } = &check.style
394 {
395 assert_eq!(path, exp_path);
396 assert_eq!(extension, &None);
397 } else {
398 panic!("did not create a directory style: {:?}", check);
399 }
400 }
401
402 #[test]
403 fn test_changelog_config_directory_all_fields() {
404 let exp_path = "path/to/directory";
405 let exp_ext: String = "md".into();
406 let json = json!({
407 "style": "directory",
408 "path": exp_path,
409 "extension": exp_ext,
410 "required": true,
411 });
412 let check: ChangelogConfig = serde_json::from_value(json).unwrap();
413
414 if let ChangelogConfig::Directory {
415 ref path,
416 ref extension,
417 required,
418 } = &check
419 {
420 assert_eq!(path, exp_path);
421 assert_eq!(extension, &Some(exp_ext.clone()));
422 assert_eq!(required, &Some(true));
423 } else {
424 panic!("did not create a directory config: {:?}", check);
425 }
426
427 let check = check.into_check();
428
429 assert!(check.required);
430 if let ChangelogStyle::Directory {
431 path,
432 extension,
433 } = &check.style
434 {
435 assert_eq!(path, exp_path);
436 assert_eq!(extension, &Some(exp_ext));
437 } else {
438 panic!("did not create a directory style: {:?}", check);
439 }
440 }
441
442 #[test]
443 fn test_changelog_config_file_path_is_required() {
444 let json = json!({
445 "style": "file",
446 });
447 let err = serde_json::from_value::<ChangelogConfig>(json).unwrap_err();
448 test::check_missing_json_field(err, "path");
449 }
450
451 #[test]
452 fn test_changelog_config_file_minimum_fields() {
453 let exp_path = "path/to/changelog.file";
454 let json = json!({
455 "style": "file",
456 "path": exp_path,
457 });
458 let check: ChangelogConfig = serde_json::from_value(json).unwrap();
459
460 if let ChangelogConfig::File {
461 ref path,
462 required,
463 } = &check
464 {
465 assert_eq!(path, exp_path);
466 assert_eq!(required, &None);
467 } else {
468 panic!("did not create a file config: {:?}", check);
469 }
470
471 let check = check.into_check();
472
473 assert!(!check.required);
474 if let ChangelogStyle::File {
475 path,
476 } = &check.style
477 {
478 assert_eq!(path, exp_path);
479 } else {
480 panic!("did not create a file style: {:?}", check);
481 }
482 }
483
484 #[test]
485 fn test_changelog_config_file_all_fields() {
486 let exp_path = "path/to/changelog.file";
487 let json = json!({
488 "style": "file",
489 "path": exp_path,
490 "required": true,
491 });
492 let check: ChangelogConfig = serde_json::from_value(json).unwrap();
493
494 if let ChangelogConfig::File {
495 ref path,
496 required,
497 } = &check
498 {
499 assert_eq!(path, exp_path);
500 assert_eq!(required, &Some(true));
501 } else {
502 panic!("did not create a file config: {:?}", check);
503 }
504
505 let check = check.into_check();
506
507 assert!(check.required);
508 if let ChangelogStyle::File {
509 path,
510 } = &check.style
511 {
512 assert_eq!(path, exp_path);
513 } else {
514 panic!("did not create a file style: {:?}", check);
515 }
516 }
517
518 #[test]
519 fn test_changelog_config_files_paths_is_required() {
520 let json = json!({
521 "style": "files",
522 });
523 let err = serde_json::from_value::<ChangelogConfig>(json).unwrap_err();
524 test::check_missing_json_field(err, "paths");
525 }
526
527 #[test]
528 fn test_changelog_config_files_minimum_fields() {
529 let exp_path1 = "path/to/first/changelog.file";
530 let exp_path2 = "path/to/second/changelog.file";
531 let json = json!({
532 "style": "files",
533 "paths": &[exp_path1, exp_path2],
534 });
535 let check: ChangelogConfig = serde_json::from_value(json).unwrap();
536
537 if let ChangelogConfig::Files {
538 ref paths,
539 required,
540 } = &check
541 {
542 assert_eq!(paths, &[exp_path1, exp_path2]);
543 assert_eq!(required, &None);
544 } else {
545 panic!("did not create a files config: {:?}", check);
546 }
547
548 let check = check.into_check();
549
550 assert!(!check.required);
551 if let ChangelogStyle::Files {
552 paths,
553 } = &check.style
554 {
555 assert_eq!(paths, &[exp_path1, exp_path2]);
556 } else {
557 panic!("did not create a files style: {:?}", check);
558 }
559 }
560
561 #[test]
562 fn test_changelog_config_files_all_fields() {
563 let exp_path1 = "path/to/first/changelog.file";
564 let exp_path2 = "path/to/second/changelog.file";
565 let json = json!({
566 "style": "files",
567 "paths": &[exp_path1, exp_path2],
568 "required": true,
569 });
570 let check: ChangelogConfig = serde_json::from_value(json).unwrap();
571
572 if let ChangelogConfig::Files {
573 ref paths,
574 required,
575 } = &check
576 {
577 assert_eq!(paths, &[exp_path1, exp_path2]);
578 assert_eq!(required, &Some(true));
579 } else {
580 panic!("did not create a files config: {:?}", check);
581 }
582
583 let check = check.into_check();
584
585 assert!(check.required);
586 if let ChangelogStyle::Files {
587 paths,
588 } = &check.style
589 {
590 assert_eq!(paths, &[exp_path1, exp_path2]);
591 } else {
592 panic!("did not create a files style: {:?}", check);
593 }
594 }
595
596 #[test]
597 fn test_changelog_config_invalid() {
598 let json = json!({
599 "style": "invalid",
600 });
601 let err = serde_json::from_value::<ChangelogConfig>(json).unwrap_err();
602
603 assert!(!err.is_io());
604 assert!(!err.is_syntax());
605 assert!(err.is_data());
606 assert!(!err.is_eof());
607
608 let msg = err.to_string();
609 if msg != "unknown variant `invalid`, expected `directory` or `file`" {
610 println!(
611 "Error message doesn't match. Was a new style added? ({})",
612 msg,
613 );
614 }
615 }
616}
617
618#[cfg(test)]
619mod tests {
620 use git_checks_core::{Check, TopicCheck};
621
622 use crate::builders::ChangelogBuilder;
623 use crate::test::*;
624 use crate::Changelog;
625 use crate::ChangelogStyle;
626
627 const CHANGELOG_DELETE: &str = "e86c0859ed36311c2ebce1ff50790eb21eabba78";
628 const CHANGELOG_MISSING: &str = "66953d52f3ec6f6e4d731e7f2f70dc4000ab13ae";
629 const CHANGELOG_MISSING_FIXED: &str = "a1020529e12fab5f1f7c87c60247d0068e0c9d8c";
630 const CHANGELOG_MISSING_FIXED_BAD_EXT: &str = "72c4a5ead2fcb5ce6017a391a1767294944c3e9c";
631 const CHANGELOG_MODE_CHANGE_BASE: &str = "254882cfbc4004a678d992818b49d08dd416528e";
632 const CHANGELOG_MODE_CHANGE: &str = "98644c64aee43d327383254e36eeda477c341938";
633 const FILE_CHANGELOG_INIT: &str = "3cd51c974845ff0c120e87a8e20ad5cf44798321";
634 const FILE_CHANGELOG_ADDED: &str = "34762d3ec96e2a302a30842ccbb5765c2b4a61d5";
635 const DIRECTORY_CHANGELOG_ADD: &str = "ff67b91112f4af4861528ac11b1797490ce18fc4";
636 const DIRECTORY_CHANGELOG_DELETE: &str = "114c724c1def28ecc96f10a8dab462879c80580a";
637 const DIRECTORY_CHANGELOG_MODIFY: &str = "f2719062d6c9e7c3835b397bd9553fb7b68cce5f";
638 const DIRECTORY_CHANGELOG_PREFIX: &str = "5f5442e33b6d0dfe01a14d98476d14e54c4d590e";
639 const DIRECTORY_CHANGELOG_BAD_EXT: &str = "93e235f10a76d58581f2d6056faa9d796156c3ea";
640
641 #[test]
642 fn test_changelog_builder_default() {
643 assert!(Changelog::builder().build().is_err());
644 }
645
646 #[test]
647 fn test_changelog_builder_minimum_fields() {
648 assert!(Changelog::builder()
649 .style(ChangelogStyle::file("changelog.md"))
650 .build()
651 .is_ok());
652 }
653
654 #[test]
655 fn test_changelog_name_commit() {
656 let check = Changelog::builder()
657 .style(ChangelogStyle::file("changelog.md"))
658 .build()
659 .unwrap();
660 assert_eq!(Check::name(&check), "changelog");
661 }
662
663 #[test]
664 fn test_changelog_name_topic() {
665 let check = Changelog::builder()
666 .style(ChangelogStyle::file("changelog.md"))
667 .build()
668 .unwrap();
669 assert_eq!(TopicCheck::name(&check), "changelog");
670 }
671
672 fn file_changelog() -> ChangelogBuilder {
673 let mut builder = Changelog::builder();
674 builder.style(ChangelogStyle::file("changelog.md"));
675 builder
676 }
677
678 fn files_changelog() -> ChangelogBuilder {
679 let mut builder = Changelog::builder();
680 builder.style(ChangelogStyle::files(
681 ["changelog.md", "other.md"].iter().cloned(),
682 ));
683 builder
684 }
685
686 fn directory_changelog() -> ChangelogBuilder {
687 let mut builder = Changelog::builder();
688 builder.style(ChangelogStyle::directory("changes", None));
689 builder
690 }
691
692 fn directory_changelog_ext() -> ChangelogBuilder {
693 let mut builder = Changelog::builder();
694 builder.style(ChangelogStyle::directory("changes", Some("md".into())));
695 builder
696 }
697
698 #[test]
699 fn test_changelog_file() {
700 let check = file_changelog().required(true).build().unwrap();
701 let result = run_check("test_changelog_file", CHANGELOG_MISSING, check);
702 test_result_errors(
703 result,
704 &[
705 "commit 66953d52f3ec6f6e4d731e7f2f70dc4000ab13ae not allowed; missing a changelog \
706 entry in the `changelog.md` file.",
707 ],
708 );
709 }
710
711 #[test]
712 fn test_changelog_file_mode_change() {
713 let check = file_changelog().required(true).build().unwrap();
714 let conf = make_check_conf(&check);
715 let result = test_check_base(
716 "test_changelog_file_mode_change",
717 CHANGELOG_MODE_CHANGE,
718 CHANGELOG_MODE_CHANGE_BASE,
719 &conf,
720 );
721 test_result_errors(
722 result,
723 &[
724 "commit 98644c64aee43d327383254e36eeda477c341938 not allowed; missing a changelog \
725 entry in the `changelog.md` file.",
726 ],
727 );
728 }
729
730 #[test]
731 fn test_changelog_file_init() {
732 let check = file_changelog().required(true).build().unwrap();
733 run_check_ok("test_changelog_file_init", FILE_CHANGELOG_INIT, check);
734 }
735
736 #[test]
737 fn test_changelog_file_ok() {
738 let check = file_changelog().required(true).build().unwrap();
739 run_check_ok("test_changelog_file_ok", FILE_CHANGELOG_ADDED, check);
740 }
741
742 #[test]
743 fn test_changelog_file_delete() {
744 let check = file_changelog().required(true).build().unwrap();
745 let result = run_check("test_changelog_file_delete", CHANGELOG_DELETE, check);
746 test_result_errors(
747 result,
748 &[
749 "commit e86c0859ed36311c2ebce1ff50790eb21eabba78 not allowed; missing a changelog \
750 entry in the `changelog.md` file.",
751 ],
752 );
753 }
754
755 #[test]
756 fn test_changelog_files() {
757 let check = files_changelog().required(true).build().unwrap();
758 let result = run_check("test_changelog_files", CHANGELOG_MISSING, check);
759 test_result_errors(
760 result,
761 &[
762 "commit 66953d52f3ec6f6e4d731e7f2f70dc4000ab13ae not allowed; missing a changelog \
763 entry in one of the `changelog.md`, `other.md` files.",
764 ],
765 );
766 }
767
768 #[test]
769 fn test_changelog_files_mode_change() {
770 let check = files_changelog().required(true).build().unwrap();
771 let conf = make_check_conf(&check);
772 let result = test_check_base(
773 "test_changelog_files_mode_change",
774 CHANGELOG_MODE_CHANGE,
775 CHANGELOG_MODE_CHANGE_BASE,
776 &conf,
777 );
778 test_result_errors(
779 result,
780 &[
781 "commit 98644c64aee43d327383254e36eeda477c341938 not allowed; missing a changelog \
782 entry in one of the `changelog.md`, `other.md` files.",
783 ],
784 );
785 }
786
787 #[test]
788 fn test_changelog_files_init() {
789 let check = files_changelog().required(true).build().unwrap();
790 run_check_ok("test_changelog_files_init", FILE_CHANGELOG_INIT, check);
791 }
792
793 #[test]
794 fn test_changelog_files_ok() {
795 let check = files_changelog().required(true).build().unwrap();
796 run_check_ok("test_changelog_files_ok", FILE_CHANGELOG_ADDED, check);
797 }
798
799 #[test]
800 fn test_changelog_files_delete() {
801 let check = files_changelog().required(true).build().unwrap();
802 let result = run_check("test_changelog_files_delete", CHANGELOG_DELETE, check);
803 test_result_errors(
804 result,
805 &[
806 "commit e86c0859ed36311c2ebce1ff50790eb21eabba78 not allowed; missing a changelog \
807 entry in one of the `changelog.md`, `other.md` files.",
808 ],
809 );
810 }
811
812 #[test]
813 fn test_changelog_directory() {
814 let check = directory_changelog().required(true).build().unwrap();
815 let result = run_check("test_changelog_directory", CHANGELOG_MISSING, check);
816 test_result_errors(
817 result,
818 &[
819 "commit 66953d52f3ec6f6e4d731e7f2f70dc4000ab13ae not allowed; missing a changelog \
820 entry in a file in `changes`.",
821 ],
822 );
823 }
824
825 #[test]
826 fn test_changelog_directory_mode_change() {
827 let check = directory_changelog().required(true).build().unwrap();
828 let conf = make_check_conf(&check);
829 let result = test_check_base(
830 "test_changelog_directory_mode_change",
831 CHANGELOG_MODE_CHANGE,
832 CHANGELOG_MODE_CHANGE_BASE,
833 &conf,
834 );
835 test_result_errors(
836 result,
837 &[
838 "commit 98644c64aee43d327383254e36eeda477c341938 not allowed; missing a changelog \
839 entry in a file in `changes`.",
840 ],
841 );
842 }
843
844 #[test]
845 fn test_changelog_directory_bad_extension() {
846 let check = directory_changelog_ext().required(true).build().unwrap();
847 let result = run_check(
848 "test_changelog_directory_bad_extension",
849 DIRECTORY_CHANGELOG_BAD_EXT,
850 check,
851 );
852 test_result_errors(
853 result,
854 &[
855 "commit 93e235f10a76d58581f2d6056faa9d796156c3ea not allowed; missing a changelog \
856 entry in a file ending with `.md` in `changes`.",
857 ],
858 );
859 }
860
861 #[test]
862 fn test_changelog_directory_delete() {
863 let check = directory_changelog().required(true).build().unwrap();
864 let conf = make_check_conf(&check);
865 let result = test_check_base(
866 "test_changelog_directory_delete",
867 DIRECTORY_CHANGELOG_DELETE,
868 CHANGELOG_MISSING_FIXED_BAD_EXT,
869 &conf,
870 );
871 test_result_ok(result);
872 }
873
874 #[test]
875 fn test_changelog_directory_modify() {
876 let check = directory_changelog().required(true).build().unwrap();
877 let conf = make_check_conf(&check);
878 let result = test_check_base(
879 "test_changelog_directory_modify",
880 DIRECTORY_CHANGELOG_MODIFY,
881 CHANGELOG_MISSING_FIXED_BAD_EXT,
882 &conf,
883 );
884 test_result_ok(result);
885 }
886
887 #[test]
888 fn test_changelog_directory_prefix() {
889 let check = directory_changelog().required(true).build().unwrap();
890 let result = run_check(
891 "test_changelog_directory_prefix",
892 DIRECTORY_CHANGELOG_PREFIX,
893 check,
894 );
895 test_result_errors(
896 result,
897 &[
898 "commit 5f5442e33b6d0dfe01a14d98476d14e54c4d590e not allowed; missing a changelog \
899 entry in a file in `changes`.",
900 ],
901 );
902 }
903
904 #[test]
905 fn test_changelog_directory_ok() {
906 let check = directory_changelog().required(true).build().unwrap();
907 run_check_ok(
908 "test_changelog_directory_ok",
909 DIRECTORY_CHANGELOG_ADD,
910 check,
911 );
912 }
913
914 #[test]
915 fn test_changelog_directory_ok_extension() {
916 let check = directory_changelog_ext().required(true).build().unwrap();
917 run_check_ok(
918 "test_changelog_directory_ok_extension",
919 DIRECTORY_CHANGELOG_ADD,
920 check,
921 );
922 }
923
924 #[test]
925 fn test_changelog_warning_file() {
926 let check = file_changelog().build().unwrap();
927 let result = run_check("test_changelog_warning_file", CHANGELOG_MISSING, check);
928 test_result_warnings(result, &[
929 "commit 66953d52f3ec6f6e4d731e7f2f70dc4000ab13ae is missing a changelog entry; please \
930 consider adding a changelog entry in the `changelog.md` file.",
931 ]);
932 }
933
934 #[test]
935 fn test_changelog_warning_files() {
936 let check = files_changelog().build().unwrap();
937 let result = run_check("test_changelog_warning_files", CHANGELOG_MISSING, check);
938 test_result_warnings(result, &[
939 "commit 66953d52f3ec6f6e4d731e7f2f70dc4000ab13ae is missing a changelog entry; please \
940 consider adding a changelog entry in one of the `changelog.md`, `other.md` files.",
941 ]);
942 }
943
944 #[test]
945 fn test_changelog_warning_directory() {
946 let check = directory_changelog().build().unwrap();
947 let result = run_check("test_changelog_warning_directory", CHANGELOG_MISSING, check);
948 test_result_warnings(result, &[
949 "commit 66953d52f3ec6f6e4d731e7f2f70dc4000ab13ae is missing a changelog entry; please \
950 consider adding a changelog entry in a file in `changes`.",
951 ]);
952 }
953
954 #[test]
955 fn test_changelog_topic_file() {
956 let check = file_changelog().required(true).build().unwrap();
957 let result = run_topic_check("test_changelog_topic_file", CHANGELOG_MISSING, check);
958 test_result_errors(
959 result,
960 &["missing a changelog entry in the `changelog.md` file."],
961 );
962 }
963
964 #[test]
965 fn test_changelog_topic_file_warning() {
966 let check = file_changelog().build().unwrap();
967 let result = run_topic_check(
968 "test_changelog_topic_file_warning",
969 CHANGELOG_MISSING,
970 check,
971 );
972 test_result_warnings(
973 result,
974 &["please consider adding a changelog entry in the `changelog.md` file."],
975 );
976 }
977
978 #[test]
979 fn test_changelog_topic_files() {
980 let check = files_changelog().required(true).build().unwrap();
981 let result = run_topic_check("test_changelog_topic_files", CHANGELOG_MISSING, check);
982 test_result_errors(
983 result,
984 &["missing a changelog entry in one of the `changelog.md`, `other.md` files."],
985 );
986 }
987
988 #[test]
989 fn test_changelog_topic_files_warning() {
990 let check = files_changelog().build().unwrap();
991 let result = run_topic_check(
992 "test_changelog_topic_files_warning",
993 CHANGELOG_MISSING,
994 check,
995 );
996 test_result_warnings(result, &[
997 "please consider adding a changelog entry in one of the `changelog.md`, `other.md` files.",
998 ]);
999 }
1000
1001 #[test]
1002 fn test_changelog_topic_directory() {
1003 let check = directory_changelog().required(true).build().unwrap();
1004 let result = run_topic_check("test_changelog_topic_directory", CHANGELOG_MISSING, check);
1005 test_result_errors(
1006 result,
1007 &["missing a changelog entry in a file in `changes`."],
1008 );
1009 }
1010
1011 #[test]
1012 fn test_changelog_topic_directory_warning() {
1013 let check = directory_changelog().build().unwrap();
1014 let result = run_topic_check(
1015 "test_changelog_topic_directory_warning",
1016 CHANGELOG_MISSING,
1017 check,
1018 );
1019 test_result_warnings(
1020 result,
1021 &["please consider adding a changelog entry in a file in `changes`."],
1022 );
1023 }
1024
1025 #[test]
1026 fn test_changelog_topic_directory_bad_ext() {
1027 let check = directory_changelog_ext().required(true).build().unwrap();
1028 let result = run_topic_check(
1029 "test_changelog_topic_directory_bad_ext",
1030 CHANGELOG_MISSING_FIXED,
1031 check,
1032 );
1033 test_result_errors(
1034 result,
1035 &["missing a changelog entry in a file ending with `.md` in `changes`."],
1036 );
1037 }
1038
1039 #[test]
1040 fn test_changelog_topic_directory_warning_bad_ext() {
1041 let check = directory_changelog_ext().build().unwrap();
1042 let result = run_topic_check(
1043 "test_changelog_topic_directory_warning_bad_ext",
1044 CHANGELOG_MISSING_FIXED,
1045 check,
1046 );
1047 test_result_warnings(result, &[
1048 "please consider adding a changelog entry in a file ending with `.md` in `changes`.",
1049 ]);
1050 }
1051
1052 #[test]
1053 fn test_changelog_topic_fixed_file() {
1054 let check = file_changelog().required(true).build().unwrap();
1055 run_topic_check_ok(
1056 "test_changelog_topic_fixed_file",
1057 CHANGELOG_MISSING_FIXED,
1058 check,
1059 );
1060 }
1061
1062 #[test]
1063 fn test_changelog_topic_fixed_files() {
1064 let check = files_changelog().required(true).build().unwrap();
1065 run_topic_check_ok(
1066 "test_changelog_topic_fixed_files",
1067 CHANGELOG_MISSING_FIXED,
1068 check,
1069 );
1070 }
1071
1072 #[test]
1073 fn test_changelog_topic_fixed_directory() {
1074 let check = directory_changelog().required(true).build().unwrap();
1075 run_topic_check_ok(
1076 "test_changelog_topic_fixed_directory",
1077 CHANGELOG_MISSING_FIXED,
1078 check,
1079 );
1080 }
1081
1082 #[test]
1083 fn test_changelog_topic_fixed_directory_bad_ext() {
1084 let check = directory_changelog().required(true).build().unwrap();
1085 run_topic_check_ok(
1086 "test_changelog_topic_fixed_directory_bad_ext",
1087 CHANGELOG_MISSING_FIXED_BAD_EXT,
1088 check,
1089 );
1090 }
1091}