In a multi-module project, this value applies to individual modules, not the parent(s). 143 | * 144 | *
Note: If you are using this in a project's pom.xml then you may accidentally cause issues 145 | * when e.g. rebuilding older branches. Instead, it may make more sense to use this as a command 146 | * line plugin execution flag in CI or in a Maven profile used for building releases. 147 | * 148 | * @since 1.0. 149 | */ 150 | @Parameter(property = "maxLibYears", defaultValue = "0.0") 151 | private float maxLibYears; 152 | 153 | /** 154 | * Only take these artifacts into consideration. 155 | * 156 | *
Comma-separated list of extended GAV patterns. 157 | * 158 | *
Extended GAV: groupId:artifactId:version:type:classifier:scope 159 | * 160 | *
The wildcard "*" can be used as the only, first, last or both characters in each token. 161 | * The version token does support version ranges. 162 | * 163 | *
Example: {@code "mygroup:artifact:*,*:*:*:*:*:compile"}
164 | *
165 | * @since 1.0.0
166 | */
167 | @Parameter(property = "pluginManagementDependencyIncludes", defaultValue = WildcardMatcher.WILDCARD)
168 | private List The wildcard "*" can be used as the only, first, last or both characters in each token.
175 | * The version token does support version ranges.
176 | *
177 | * Example: {@code "mygroup:artifact:*,othergroup:*,anothergroup"}
178 | *
179 | * @since 1.0.0
180 | */
181 | @Parameter(property = "pluginManagementDependencyExcludes")
182 | private List The wildcard "*" can be used as the only, first, last or both characters in each token.
224 | * The version token does support version ranges.
225 | *
226 | * Example: {@code "mygroup:artifact:*,othergroup:*,anothergroup"}
227 | *
228 | * @since 1.0.0
229 | */
230 | @Parameter(property = "pluginDependencyIncludes", defaultValue = WildcardMatcher.WILDCARD)
231 | private List The wildcard "*" can be used as the only, first, last or both characters in each token.
238 | * The version token does support version ranges.
239 | *
240 | * Example: {@code "mygroup:artifact:*,othergroup:*,anothergroup"}
241 | *
242 | * @since 1.0.0
243 | */
244 | @Parameter(property = "pluginDependencyExcludes")
245 | private List Comma-separated list of extended GAV patterns.
251 | *
252 | * Extended GAV: groupId:artifactId:version:type:classifier:scope
253 | *
254 | * The wildcard "*" can be used as the only, first, last or both characters in each token.
255 | * The version token does support version ranges.
256 | *
257 | * Example: {@code "mygroup:artifact:*,*:*:*:*:*:compile"}
258 | *
259 | * @since 1.0.0
260 | */
261 | @Parameter(property = "dependencyIncludes", defaultValue = WildcardMatcher.WILDCARD)
262 | private List Comma-separated list of extended GAV patterns.
268 | *
269 | * Extended GAV: groupId:artifactId:version:type:classifier:scope
270 | *
271 | * The wildcard "*" can be used as the only, first, last or both characters in each token.
272 | * The version token does support version ranges.
273 | *
274 | * Example: {@code "mygroup:artifact:*,*:*:*:*:*:provided,*:*:*:*:*:system"}
275 | *
276 | * @since 1.0.0
277 | */
278 | @Parameter(property = "dependencyExcludes")
279 | private List Comma-separated list of extended GAV patterns.
285 | *
286 | * Extended GAV: groupId:artifactId:version:type:classifier:scope
287 | *
288 | * The wildcard "*" can be used as the only, first, last or both characters in each token.
289 | * The version token does support version ranges.
290 | *
291 | * Example: {@code "mygroup:artifact:*,*:*:*:*:*:compile"}
292 | *
293 | * @since 1.0.0
294 | */
295 | @Parameter(property = "dependencyManagementIncludes", defaultValue = WildcardMatcher.WILDCARD)
296 | private List Comma-separated list of extended GAV patterns.
302 | *
303 | * Extended GAV: groupId:artifactId:version:type:classifier:scope
304 | *
305 | * The wildcard "*" can be used as the only, first, last or both characters in each token.
306 | * The version token does support version ranges.
307 | *
308 | * Example: {@code "mygroup:artifact:*,*:*:*:*:*:provided,*:*:*:*:*:system"}
309 | *
310 | * @since 1.0.0
311 | */
312 | @Parameter(property = "dependencyManagementExcludes")
313 | private List We ensure that the proposed change is the libyears between 1.1.0 and 2.0.0.
606 | */
607 | @Test
608 | public void dependencyUpdateAvailableDependencyDefinedInDependencyManagement() throws Exception {
609 | LibYearMojo mojo =
610 | new LibYearMojo(mockRepositorySystem(), mockAetherRepositorySystem(new HashMap<>() {
611 | {
612 | put("default-dependency", new String[] {"1.0.0", "1.1.0", "2.0.0"});
613 | }
614 | })) {
615 | {
616 | MavenProject project = new MavenProjectBuilder()
617 | .withDependencies(singletonList(DependencyBuilder.newBuilder()
618 | .withGroupId("default-group")
619 | .withArtifactId("default-dependency")
620 | .withVersion("1.0.0")
621 | .build()))
622 | .withDependencyManagementDependencyList(singletonList(DependencyBuilder.newBuilder()
623 | .withGroupId("default-group")
624 | .withArtifactId("default-dependency")
625 | .withVersion("1.1.0")
626 | .build()))
627 | .build();
628 |
629 | setProject(project);
630 | allowProcessingAllDependencies(this);
631 | setPluginContext(new HashMap<>());
632 |
633 | setSession(mockMavenSession(project));
634 | setSearchUri("http://localhost:8080");
635 |
636 | setLog(new InMemoryTestLogger());
637 | }
638 | };
639 |
640 | LocalDateTime now = LocalDateTime.now();
641 |
642 | // Mark version 2.0.0 as a year newer. The current dependency version is 1.1.0,
643 | // overridden from
644 | // 1.0.0 by
645 | // dependencyManagement
646 |
647 | // TODO: This first stub probably shouldn't be needed as we shouldn't need to
648 | // fetch the release
649 | // year of this version
650 | // but without it, the test fails.
651 | stubResponseFor("default-group", "default-dependency", "1.0.0", now.minusYears(10));
652 | stubResponseFor("default-group", "default-dependency", "1.1.0", now.minusYears(1));
653 | stubResponseFor("default-group", "default-dependency", "2.0.0", now);
654 |
655 | mojo.execute();
656 |
657 | assertTrue(((InMemoryTestLogger) mojo.getLog())
658 | .infoLogs.stream()
659 | .anyMatch(
660 | (l) -> l.contains("default-group:default-dependency") && l.contains("1.00 libyears")));
661 | assertTrue(((InMemoryTestLogger) mojo.getLog()).errorLogs.isEmpty());
662 | }
663 |
664 | @Test
665 | public void pluginVersionUpdateAvailable() throws Exception {
666 | Plugin plugin = pluginOf("default-plugin", "default-group", "1.0.0");
667 | plugin.setDependencies(singletonList(dependencyFor("default-group", "default-dependency", "1.0.0")));
668 |
669 | LibYearMojo mojo =
670 | new LibYearMojo(mockRepositorySystem(), mockAetherRepositorySystem(new HashMap<>() {
671 | {
672 | put("default-dependency", new String[] {"1.0.0", "1.1.0", "2.0.0"});
673 | }
674 | })) {
675 | {
676 | MavenProject project = new MavenProjectBuilder()
677 | .withPlugins(singletonList(plugin))
678 | .build();
679 |
680 | setProject(project);
681 |
682 | allowProcessingAllDependencies(this);
683 | setPluginContext(new HashMap<>());
684 |
685 | setSession(mockMavenSession(project));
686 | setSearchUri("http://localhost:8080");
687 |
688 | setLog(new InMemoryTestLogger());
689 | }
690 | };
691 |
692 | LocalDateTime now = LocalDateTime.now();
693 |
694 | // Mark version 2.0.0 as a year newer
695 | stubResponseFor("default-group", "default-dependency", "1.0.0", now.minusYears(1));
696 | stubResponseFor("default-group", "default-dependency", "2.0.0", now);
697 |
698 | mojo.execute();
699 |
700 | assertTrue(((InMemoryTestLogger) mojo.getLog())
701 | .infoLogs.stream()
702 | .anyMatch(
703 | (l) -> l.contains("default-group:default-dependency") && l.contains("1.00 libyears")));
704 | assertTrue(((InMemoryTestLogger) mojo.getLog()).errorLogs.isEmpty());
705 | }
706 |
707 | /**
708 | * This test has a plugin version 1.0.0 which has a dependency on another artifact version
709 | * 1.0.1. That version is overridden in dependency management to 1.1.0. Version 2.0.0 is
710 | * available.
711 | *
712 | * This test ensures we suggest the libyears between 1.1.0 and 2.0.0.
713 | */
714 | @Test
715 | public void pluginVersionUpdateAvailableDependencyDefinedInDependencyManagement() throws Exception {
716 | Plugin plugin = pluginOf("default-plugin", "default-group", "1.0.0");
717 | plugin.setDependencies(singletonList(dependencyFor("default-group", "default-dependency", "1.0.1")));
718 |
719 | LibYearMojo mojo =
720 | new LibYearMojo(mockRepositorySystem(), mockAetherRepositorySystem(new HashMap<>() {
721 | {
722 | put("default-dependency", new String[] {"1.0.0", "1.1.0", "2.0.0"});
723 | }
724 | })) {
725 | {
726 | MavenProject project = new MavenProjectBuilder()
727 | .withPlugins(singletonList(plugin))
728 | .withDependencyManagementDependencyList(singletonList(DependencyBuilder.newBuilder()
729 | .withGroupId("default-group")
730 | .withArtifactId("default-dependency")
731 | .withVersion("1.1.0")
732 | .build()))
733 | .build();
734 |
735 | setProject(project);
736 |
737 | allowProcessingAllDependencies(this);
738 | setPluginContext(new HashMap<>());
739 |
740 | setSession(mockMavenSession(project));
741 | setSearchUri("http://localhost:8080");
742 |
743 | setLog(new InMemoryTestLogger());
744 | }
745 | };
746 |
747 | LocalDateTime now = LocalDateTime.now();
748 |
749 | // Mark version 2.0.0 as a year newer
750 | stubResponseFor("default-group", "default-dependency", "1.0.1", now.minusYears(2));
751 | stubResponseFor("default-group", "default-dependency", "1.1.0", now.minusYears(1));
752 | stubResponseFor("default-group", "default-dependency", "2.0.0", now);
753 |
754 | mojo.execute();
755 |
756 | assertTrue(((InMemoryTestLogger) mojo.getLog())
757 | .infoLogs.stream()
758 | .anyMatch(
759 | (l) -> l.contains("default-group:default-dependency") && l.contains("1.00 libyears")));
760 | assertTrue(((InMemoryTestLogger) mojo.getLog()).errorLogs.isEmpty());
761 | }
762 |
763 | /**
764 | * This test has a plugin version 1.0.0. That version is overridden in plugin management to
765 | * 1.1.0. Version 2.0.0 is available.
766 | *
767 | * This test ensures we suggest the libyears between 1.1.0 and 2.0.0.
768 | */
769 | @Test
770 | public void pluginVersionUpdateAvailableDependencyDefinedInPluginManagement() throws Exception {
771 | Plugin plugin = pluginOf("default-plugin", "default-group", "1.0.0");
772 | plugin.setDependencies(singletonList(dependencyFor("default-group", "default-dependency", "1.0.1")));
773 |
774 | Plugin managedPlugin = pluginOf("default-plugin", "default-group", "1.0.0");
775 | plugin.setDependencies(singletonList(dependencyFor("default-group", "default-dependency", "1.1.0")));
776 |
777 | LibYearMojo mojo =
778 | new LibYearMojo(mockRepositorySystem(), mockAetherRepositorySystem(new HashMap<>() {
779 | {
780 | put("default-dependency", new String[] {"1.0.0", "1.1.0", "2.0.0"});
781 | }
782 | })) {
783 | {
784 | MavenProject project = new MavenProjectBuilder()
785 | .withPlugins(singletonList(plugin))
786 | .withPluginManagementPluginList(singletonList(managedPlugin))
787 | .build();
788 |
789 | setProject(project);
790 |
791 | allowProcessingAllDependencies(this);
792 |
793 | setPluginContext(new HashMap<>());
794 |
795 | setSession(mockMavenSession(project));
796 | setSearchUri("http://localhost:8080");
797 |
798 | setLog(new InMemoryTestLogger());
799 | }
800 | };
801 |
802 | LocalDateTime now = LocalDateTime.now();
803 |
804 | // Mark version 2.0.0 as a year newer
805 | stubResponseFor("default-group", "default-dependency", "1.1.0", now.minusYears(1));
806 | stubResponseFor("default-group", "default-dependency", "2.0.0", now);
807 |
808 | mojo.execute();
809 |
810 | assertTrue(((InMemoryTestLogger) mojo.getLog())
811 | .infoLogs.stream()
812 | .anyMatch(
813 | (l) -> l.contains("default-group:default-dependency") && l.contains("1.00 libyears")));
814 | assertTrue(((InMemoryTestLogger) mojo.getLog()).errorLogs.isEmpty());
815 | }
816 |
817 | private Dependency dependencyFor(String groupID, String artifactId, String version) {
818 | Dependency dep = new Dependency();
819 | dep.setGroupId(groupID);
820 | dep.setArtifactId(artifactId);
821 | dep.setVersion(version);
822 | return dep;
823 | }
824 |
825 | /**
826 | * Stub the Maven search API response that looks for release information for a particular
827 | * version of a particular artifact
828 | */
829 | private void stubResponseFor(String groupId, String artifactId, String version, LocalDateTime time) {
830 | stubFor(get(urlPathEqualTo("/solrsearch/select"))
831 | .withQueryParam("q", equalTo(String.format("g:%s AND a:%s AND v:%s", groupId, artifactId, version)))
832 | .withQueryParam("wt", equalTo("json"))
833 | .willReturn(ok(getJSONResponseForVersion(groupId, artifactId, version, time))));
834 | }
835 |
836 | /**
837 | * Simulate the JSON response from the Maven Central repository search API. Docs available at here.
839 | */
840 | private String getJSONResponseForVersion(
841 | String groupId, String artifactId, String version, LocalDateTime releaseDate) {
842 | JSONObject root = new JSONObject();
843 | JSONObject response = new JSONObject();
844 | JSONArray versions = new JSONArray();
845 | JSONObject newVersion = new JSONObject();
846 |
847 | newVersion.put("id", String.format("%s:%s:%s", groupId, artifactId, version));
848 | newVersion.put("g", groupId);
849 | newVersion.put("a", artifactId);
850 | newVersion.put("v", version);
851 | newVersion.put("p", "jar");
852 | newVersion.put("timestamp", releaseDate.toEpochSecond(ZoneOffset.UTC) * 1000); // API response is in millis
853 |
854 | versions.put(newVersion);
855 | response.put("docs", versions);
856 | response.put("numFound", 1);
857 | root.put("response", response);
858 |
859 | return root.toString();
860 | }
861 |
862 | @Test
863 | public void apiCallToMavenFails() throws Exception {
864 | LibYearMojo mojo =
865 | new LibYearMojo(mockRepositorySystem(), mockAetherRepositorySystem(new HashMap<>() {
866 | {
867 | put("default-dependency", new String[] {"1.0.0", "2.0.0"});
868 | }
869 | })) {
870 | {
871 | MavenProject project = new MavenProjectBuilder()
872 | .withDependencies(singletonList(DependencyBuilder.newBuilder()
873 | .withGroupId("default-group")
874 | .withArtifactId("default-dependency")
875 | .withVersion("1.0.0")
876 | .build()))
877 | .build();
878 |
879 | setProject(project);
880 | allowProcessingAllDependencies(this);
881 | setPluginContext(new HashMap<>());
882 |
883 | setSession(mockMavenSession(project));
884 | setSearchUri("http://localhost:8080");
885 |
886 | setLog(new InMemoryTestLogger());
887 | }
888 | };
889 |
890 | stubFor(get(urlPathEqualTo("/solrsearch/select")).willReturn(serverError()));
891 |
892 | mojo.execute();
893 |
894 | assertTrue(((InMemoryTestLogger) mojo.getLog())
895 | .errorLogs.stream()
896 | .anyMatch((l) -> l.contains(
897 | "Failed to fetch release date for" + " default-group:default-dependency" + " 1.0.0")));
898 | assertTrue(((InMemoryTestLogger) mojo.getLog())
899 | .errorLogs.stream()
900 | .anyMatch((l) -> l.contains(
901 | "Failed to fetch release date for" + " default-group:default-dependency" + " 2.0.0")));
902 | }
903 |
904 | @Test
905 | public void apiCallToMavenTimesOut() throws Exception {
906 | LibYearMojo mojo =
907 | new LibYearMojo(mockRepositorySystem(), mockAetherRepositorySystem(new HashMap<>() {
908 | {
909 | put("default-dependency", new String[] {"1.0.0", "2.0.0"});
910 | }
911 | })) {
912 | {
913 | MavenProject project = new MavenProjectBuilder()
914 | .withDependencies(singletonList(DependencyBuilder.newBuilder()
915 | .withGroupId("default-group")
916 | .withArtifactId("default-dependency")
917 | .withVersion("1.0.0")
918 | .build()))
919 | .build();
920 |
921 | setProject(project);
922 | allowProcessingAllDependencies(this);
923 | setPluginContext(new HashMap<>());
924 |
925 | setSession(mockMavenSession(project));
926 | setSearchUri("http://localhost:8080");
927 | setHttpTimeout(1);
928 | setFetchRetryCount(0);
929 |
930 | setLog(new InMemoryTestLogger());
931 | }
932 | };
933 |
934 | stubFor(get(urlPathEqualTo("/solrsearch/select")).willReturn(ok().withFixedDelay(10_000 /* ms */)));
935 |
936 | mojo.execute();
937 |
938 | assertTrue(((InMemoryTestLogger) mojo.getLog())
939 | .errorLogs.stream()
940 | .anyMatch((l) -> l.contains("Failed to fetch release date for"
941 | + " default-group:default-dependency"
942 | + " 1.0.0 (request timed out)")));
943 | assertTrue(((InMemoryTestLogger) mojo.getLog())
944 | .errorLogs.stream()
945 | .anyMatch((l) -> l.contains("Failed to fetch release date for"
946 | + " default-group:default-dependency"
947 | + " 2.0.0 (request timed out)")));
948 | assertEquals(2, ((InMemoryTestLogger) mojo.getLog()).errorLogs.size());
949 | }
950 |
951 | @Test
952 | public void apiCallToMavenRetriesOnFailure() throws Exception {
953 | LibYearMojo mojo =
954 | new LibYearMojo(mockRepositorySystem(), mockAetherRepositorySystem(new HashMap<>() {
955 | {
956 | put("default-dependency", new String[] {"1.0.0", "2.0.0"});
957 | }
958 | })) {
959 | {
960 | MavenProject project = new MavenProjectBuilder()
961 | .withDependencies(singletonList(DependencyBuilder.newBuilder()
962 | .withGroupId("default-group")
963 | .withArtifactId("default-dependency")
964 | .withVersion("1.0.0")
965 | .build()))
966 | .build();
967 |
968 | setProject(project);
969 | allowProcessingAllDependencies(this);
970 | setPluginContext(new HashMap<>());
971 |
972 | setSession(mockMavenSession(project));
973 | setSearchUri("http://localhost:8080");
974 |
975 | setFetchRetryCount(2);
976 |
977 | setLog(new InMemoryTestLogger());
978 | }
979 | };
980 |
981 | LocalDateTime now = LocalDateTime.now();
982 |
983 | // The first dependency should fail twice and return OK on the second retry
984 | stubFor(get(urlPathEqualTo("/solrsearch/select"))
985 | .withQueryParam(
986 | "q",
987 | equalTo(String.format(
988 | "g:%s AND a:%s AND v:%s", "default-group", "default-dependency", "1.0.0")))
989 | .inScenario("Failure chain")
990 | .whenScenarioStateIs("Started")
991 | .willReturn(serverError())
992 | .willSetStateTo("First failure"));
993 |
994 | stubFor(get(urlPathEqualTo("/solrsearch/select"))
995 | .inScenario("Failure chain")
996 | .whenScenarioStateIs("First failure")
997 | .willReturn(serverError())
998 | .willSetStateTo("Second failure"));
999 |
1000 | stubFor(get(urlPathEqualTo("/solrsearch/select"))
1001 | .inScenario("Failure chain")
1002 | .whenScenarioStateIs("Second failure")
1003 | .willReturn(ok(
1004 | getJSONResponseForVersion("default-group", "default-dependency", "1.0.0", now.minusYears(1)))));
1005 |
1006 | // The second request will succeed first time
1007 | stubResponseFor("default-group", "default-dependency", "2.0.0", now);
1008 |
1009 | mojo.execute();
1010 |
1011 | assertTrue(((InMemoryTestLogger) mojo.getLog())
1012 | .infoLogs.stream()
1013 | .anyMatch(
1014 | (l) -> l.contains("default-group:default-dependency") && l.contains("1.00 libyears")));
1015 | }
1016 |
1017 | @Test
1018 | public void dependencyUpdateAvailableButFetchingReleaseDateOfNewerVersionFails() throws Exception {
1019 | LibYearMojo mojo =
1020 | new LibYearMojo(mockRepositorySystem(), mockAetherRepositorySystem(new HashMap<>() {
1021 | {
1022 | put("default-dependency", new String[] {"1.0.0", "1.1.0", "2.0.0"});
1023 | }
1024 | })) {
1025 | {
1026 | MavenProject project = new MavenProjectBuilder()
1027 | .withDependencies(singletonList(DependencyBuilder.newBuilder()
1028 | .withGroupId("default-group")
1029 | .withArtifactId("default-dependency")
1030 | .withVersion("1.0.0")
1031 | .build()))
1032 | .build();
1033 |
1034 | setProject(project);
1035 |
1036 | allowProcessingAllDependencies(this);
1037 |
1038 | setPluginContext(new HashMap<>());
1039 |
1040 | setSession(mockMavenSession(project));
1041 | setSearchUri("http://localhost:8080");
1042 |
1043 | setLog(new InMemoryTestLogger());
1044 | }
1045 | };
1046 |
1047 | LocalDateTime now = LocalDateTime.now();
1048 |
1049 | stubResponseFor("default-group", "default-dependency", "1.0.0", now.minusYears(1));
1050 | stubFor(get(urlPathEqualTo("/solrsearch/select"))
1051 | .withQueryParam(
1052 | "q",
1053 | equalTo(String.format(
1054 | "g:%s AND a:%s AND v:%s", "default-group", "default-dependency", "2.0.0")))
1055 | .withQueryParam("wt", equalTo("json"))
1056 | .willReturn(serverError()));
1057 |
1058 | mojo.execute();
1059 |
1060 | assertFalse(((InMemoryTestLogger) mojo.getLog())
1061 | .infoLogs.stream().anyMatch((l) -> l.contains("default-group:default-dependency")));
1062 | assertTrue(((InMemoryTestLogger) mojo.getLog())
1063 | .errorLogs.contains(
1064 | "Failed to fetch release date for default-group:default-dependency" + " 2.0.0: Server Error"));
1065 | }
1066 |
1067 | @Test
1068 | public void dependencyUpdateAvailableButAPISearchDoesNotContainLatestVersion() throws Exception {
1069 | LibYearMojo mojo =
1070 | new LibYearMojo(mockRepositorySystem(), mockAetherRepositorySystem(new HashMap<>() {
1071 | {
1072 | put("default-dependency", new String[] {"1.0.0", "1.1.0", "2.0.0"});
1073 | }
1074 | })) {
1075 | {
1076 | MavenProject project = new MavenProjectBuilder()
1077 | .withDependencies(singletonList(DependencyBuilder.newBuilder()
1078 | .withGroupId("default-group")
1079 | .withArtifactId("default-dependency")
1080 | .withVersion("1.0.0")
1081 | .build()))
1082 | .build();
1083 |
1084 | setProject(project);
1085 | allowProcessingAllDependencies(this);
1086 | setPluginContext(new HashMap<>());
1087 |
1088 | setSession(mockMavenSession(project));
1089 | setSearchUri("http://localhost:8080");
1090 |
1091 | setLog(new InMemoryTestLogger());
1092 | }
1093 | };
1094 |
1095 | LocalDateTime now = LocalDateTime.now();
1096 |
1097 | stubResponseFor("default-group", "default-dependency", "1.0.0", now.minusYears(1));
1098 | stubFor(get(urlPathEqualTo("/solrsearch/select"))
1099 | .withQueryParam(
1100 | "q",
1101 | equalTo(String.format(
1102 | "g:%s AND a:%s AND v:%s", "default-group", "default-dependency", "2.0.0")))
1103 | .withQueryParam("wt", equalTo("json"))
1104 | .willReturn(ok("{\"response\":{\"docs\":[],\"numFound\":0}}")));
1105 |
1106 | mojo.execute();
1107 |
1108 | assertFalse(((InMemoryTestLogger) mojo.getLog())
1109 | .infoLogs.stream().anyMatch((l) -> l.contains("default-group:default-dependency")));
1110 | assertTrue(((InMemoryTestLogger) mojo.getLog())
1111 | .debugLogs.contains("Could not find artifact for default-group:default-dependency" + " 2.0.0"));
1112 | }
1113 |
1114 | @Test
1115 | public void multipleDependenciesWithUpdatesAreSortedAlphabetically() throws Exception {
1116 | LibYearMojo mojo =
1117 | new LibYearMojo(mockRepositorySystem(), mockAetherRepositorySystem(new HashMap<>() {
1118 | {
1119 | put("default-dependency", new String[] {"1.0.0", "2.0.0"});
1120 | put("second-dependency", new String[] {"5.0.0", "6.0.0"});
1121 | }
1122 | })) {
1123 | {
1124 | MavenProject project = new MavenProjectBuilder()
1125 | .withDependencies(List.of(
1126 | DependencyBuilder.newBuilder()
1127 | .withGroupId("default-group")
1128 | .withArtifactId("second-dependency")
1129 | .withVersion("5.0.0")
1130 | .build(),
1131 | DependencyBuilder.newBuilder()
1132 | .withGroupId("default-group")
1133 | .withArtifactId("default-dependency")
1134 | .withVersion("1.0.0")
1135 | .build()))
1136 | .build();
1137 |
1138 | setProject(project);
1139 | allowProcessingAllDependencies(this);
1140 | setPluginContext(new HashMap<>());
1141 |
1142 | setSession(mockMavenSession(project));
1143 | setSearchUri("http://localhost:8080");
1144 |
1145 | setLog(new InMemoryTestLogger());
1146 | }
1147 | };
1148 |
1149 | LocalDateTime now = LocalDateTime.now();
1150 |
1151 | // Mark version 2.0.0 as a year newer
1152 | // Don't stub 1.1.0, there's no need to check its version
1153 | stubResponseFor("default-group", "default-dependency", "1.0.0", now.minusYears(1));
1154 | stubResponseFor("default-group", "default-dependency", "2.0.0", now);
1155 | stubResponseFor("default-group", "second-dependency", "5.0.0", now.minusYears(5));
1156 | stubResponseFor("default-group", "second-dependency", "6.0.0", now.minusYears(3));
1157 |
1158 | mojo.execute();
1159 |
1160 | List
172 | * Comma-separated list of {@code groupId:[artifactId[:version]]} patterns
173 | *
174 | *
221 | * Comma-separated list of {@code groupId:[artifactId[:version]]} patterns
222 | *
223 | *
235 | * Comma-separated list of {@code groupId:[artifactId[:version]]} patterns
236 | *
237 | *
622 | * mygroup:myartifact ................ 1.0 years
623 | * mygroup:myartifactwithlonglonglongname
624 | * ................................... 2.0 years
625 | *
626 | *
627 | * @param dep The dependency
628 | * @param libYearsOutdated How many libyears behind it is
629 | */
630 | private void logDependencyAge(Map.EntryStrictness.LENIENT
because some mocks are set up by the
65 | * versions-maven-plugin and these use an older version of Mockito.
66 | */
67 | @ExtendWith(MockitoExtension.class)
68 | @MockitoSettings(strictness = Strictness.LENIENT)
69 | @WireMockTest(httpPort = 8080)
70 | public class LibYearMojoTest {
71 | // TODO: Tests with version numbers being referenced by variables
72 | // TODO: Test with version ranges
73 |
74 | /**
75 | * Test factory method. Generates a Plugin object representing the specified parameters.
76 | *
77 | * @param artifactId The Maven artifact ID
78 | * @param groupId The Maven group ID
79 | * @param version The Maven version
80 | * @return The Plugin object
81 | */
82 | private static Plugin pluginOf(String artifactId, String groupId, String version) {
83 | Plugin plugin = new Plugin();
84 | plugin.setGroupId(groupId);
85 | plugin.setArtifactId(artifactId);
86 | plugin.setVersion(version);
87 | return plugin;
88 | }
89 |
90 | @AfterEach
91 | public void reset() {
92 | // TODO: Make these private and add a reset method in the mojo
93 | LibYearMojo.libWeeksOutDated.set(0);
94 | LibYearMojo.dependencyVersionReleaseDates.clear();
95 | }
96 |
97 | /**
98 | * This is a basic test to ensure that a project with a single dependency correctly shows
99 | * nothing when no updates are available.
100 | */
101 | @Test
102 | public void dependencyIsAlreadyOnTheLatestVersion() throws Exception {
103 | LibYearMojo mojo =
104 | new LibYearMojo(mockRepositorySystem(), mockAetherRepositorySystem(new HashMap<>() {
105 | {
106 | put("default-dependency", new String[] {"1.0.0"});
107 | }
108 | })) {
109 | {
110 | MavenProject project = new MavenProjectBuilder()
111 | .withDependencies(singletonList(DependencyBuilder.newBuilder()
112 | .withGroupId("default-group")
113 | .withArtifactId("default-dependency")
114 | .withVersion("1.0.0")
115 | .build()))
116 | .build();
117 |
118 | setProject(project);
119 | allowProcessingAllDependencies(this);
120 | setPluginContext(new HashMap<>());
121 |
122 | setSession(mockMavenSession(project));
123 | setSearchUri("http://localhost:8080");
124 |
125 | setLog(new InMemoryTestLogger());
126 | }
127 | };
128 |
129 | LocalDateTime now = LocalDateTime.now();
130 | stubResponseFor("default-group", "default-dependency", "1.0.0", now.minusYears(1));
131 |
132 | mojo.execute();
133 |
134 | assertTrue(((InMemoryTestLogger) mojo.getLog()).infoLogs.isEmpty());
135 | assertTrue(((InMemoryTestLogger) mojo.getLog()).errorLogs.isEmpty());
136 | }
137 |
138 | /**
139 | * This is a basic test to ensure that a project with a single dependency correctly shows
140 | * available updates.
141 | */
142 | @Test
143 | public void dependencyUpdateAvailable() throws Exception {
144 | LibYearMojo mojo =
145 | new LibYearMojo(mockRepositorySystem(), mockAetherRepositorySystem(new HashMap<>() {
146 | {
147 | put("default-dependency", new String[] {"1.0.0", "1.1.0", "2.0.0"});
148 | }
149 | })) {
150 | {
151 | MavenProject project = new MavenProjectBuilder()
152 | .withDependencies(singletonList(DependencyBuilder.newBuilder()
153 | .withGroupId("default-group")
154 | .withArtifactId("default-dependency")
155 | .withVersion("1.0.0")
156 | .build()))
157 | .build();
158 |
159 | setProject(project);
160 | allowProcessingAllDependencies(this);
161 | setPluginContext(new HashMap<>());
162 |
163 | setSession(mockMavenSession(project));
164 | setSearchUri("http://localhost:8080");
165 |
166 | setLog(new InMemoryTestLogger());
167 | }
168 | };
169 |
170 | LocalDateTime now = LocalDateTime.now();
171 |
172 | // Mark version 2.0.0 as a year newer
173 | // Don't stub 1.1.0, there's no need to check its version
174 | stubResponseFor("default-group", "default-dependency", "1.0.0", now.minusYears(1));
175 | stubResponseFor("default-group", "default-dependency", "2.0.0", now);
176 |
177 | mojo.execute();
178 |
179 | assertTrue(((InMemoryTestLogger) mojo.getLog())
180 | .infoLogs.stream()
181 | .anyMatch(
182 | (l) -> l.contains("default-group:default-dependency") && l.contains("1.00 libyears")));
183 | assertTrue(((InMemoryTestLogger) mojo.getLog()).errorLogs.isEmpty());
184 | }
185 |
186 | /** This test checks that the output for dependencies with long names is formatted correctly. */
187 | @Test
188 | public void dependencyUpdateWithLongNameAvailable() throws Exception {
189 | LibYearMojo mojo =
190 | new LibYearMojo(mockRepositorySystem(), mockAetherRepositorySystem(new HashMap<>() {
191 | {
192 | put("default-dependency-with-very-very-long-name", new String[] {"1.0.0", "1.1.0", "2.0.0"});
193 | }
194 | })) {
195 | {
196 | MavenProject project = new MavenProjectBuilder()
197 | .withDependencies(singletonList(DependencyBuilder.newBuilder()
198 | .withGroupId("default-group")
199 | .withArtifactId("default-dependency-with-very-very-long-name")
200 | .withVersion("1.0.0")
201 | .build()))
202 | .build();
203 | setProject(project);
204 | allowProcessingAllDependencies(this);
205 | setPluginContext(new HashMap<>());
206 |
207 | setSession(mockMavenSession(project));
208 | setSearchUri("http://localhost:8080");
209 |
210 | setLog(new InMemoryTestLogger());
211 | }
212 | };
213 |
214 | LocalDateTime now = LocalDateTime.now();
215 |
216 | // Mark version 2.0.0 as a year newer
217 | stubResponseFor("default-group", "default-dependency-with-very-very-long-name", "1.0.0", now.minusYears(1));
218 | stubResponseFor("default-group", "default-dependency-with-very-very-long-name", "2.0.0", now);
219 |
220 | mojo.execute();
221 |
222 | List