From 2773dcf6c4df2cc8d701e229e26adc6114f88c6e Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sun, 23 Jul 2023 22:04:56 +0530 Subject: [PATCH 01/44] Fetched issue tracker from update center --- .../pluginhealth/scoring/model/Plugin.java | 11 +- .../scoring/model/updatecenter/Plugin.java | 5 +- .../scoring/probes/OpenIssuesProbe.java | 70 ++++++++++++ .../scoring/probes/OpenIssuesProbeTest.java | 102 ++++++++++++++++++ ...pdateCenterPluginPublicationProbeTest.java | 2 +- 5 files changed, 186 insertions(+), 4 deletions(-) create mode 100644 core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java create mode 100644 core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/Plugin.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/Plugin.java index 68ad0a862..9d9bd8262 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/Plugin.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/Plugin.java @@ -26,6 +26,7 @@ import java.time.ZonedDateTime; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -61,6 +62,13 @@ public class Plugin { @Column(name = "release_timestamp") private ZonedDateTime releaseTimestamp; + public List> getIssueTracker() { + return issueTracker; + } + + @Column(name = "issue_tracker") + private List> issueTracker; + @Column(columnDefinition = "jsonb") @Type(value = JsonType.class) private final Map details = new HashMap<>(); @@ -68,11 +76,12 @@ public class Plugin { public Plugin() { } - public Plugin(String name, VersionNumber version, String scm, ZonedDateTime releaseTimestamp) { + public Plugin(String name, VersionNumber version, String scm, ZonedDateTime releaseTimestamp, List> issueTrackers) { this.name = name; this.version = version; this.scm = scm; this.releaseTimestamp = releaseTimestamp; + this.issueTracker = issueTrackers; } public String getName() { diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java index 6c51489e7..ac9fe1360 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java @@ -26,13 +26,14 @@ import java.time.ZonedDateTime; import java.util.List; +import java.util.Map; import hudson.util.VersionNumber; public record Plugin(String name, VersionNumber version, String scm, ZonedDateTime releaseTimestamp, List labels, - int popularity, String requiredCore, String defaultBranch) { + int popularity, String requiredCore, String defaultBranch, List> issueTrackers) { public io.jenkins.pluginhealth.scoring.model.Plugin toPlugin() { - return new io.jenkins.pluginhealth.scoring.model.Plugin(this.name(), this.version(), this.scm(), this.releaseTimestamp()); + return new io.jenkins.pluginhealth.scoring.model.Plugin(this.name(), this.version(), this.scm(), this.releaseTimestamp(), this.issueTrackers()); } } diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java new file mode 100644 index 000000000..fbe018344 --- /dev/null +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java @@ -0,0 +1,70 @@ +package io.jenkins.pluginhealth.scoring.probes; + +import java.util.*; +import java.util.stream.Collectors; + +import io.jenkins.pluginhealth.scoring.model.Plugin; +import io.jenkins.pluginhealth.scoring.model.ProbeResult; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +@Component +@Order(value = OpenIssuesProbe.ORDER) +public class OpenIssuesProbe extends Probe { + private static final Logger LOGGER = LoggerFactory.getLogger(OpenIssuesProbe.class); + + public static final String KEY = "open-issue"; + public static final int ORDER = UpdateCenterPluginPublicationProbe.ORDER + 100; + + @Override + protected ProbeResult doApply(Plugin plugin, ProbeContext context) { + List issueTracker = getIssueTracker(plugin, context); + for (String type: issueTracker) { + if(type.equals("jira")) { + return ProbeResult.success(key(), String.format("%d open issues found", getJiraIssues())); + } + else if (type.equals("github")) { + return ProbeResult.success(key(), String.format("%d open issues found", getGitHubIssues())); + } + } + return ProbeResult.failure(key(), String.format("Update center issue tracker could not be found")); + } + + private static List getIssueTracker(Plugin plugin, ProbeContext context) { + return context.getUpdateCenter().plugins() + .get(plugin.getIssueTracker()) + .issueTrackers().stream() + .flatMap(map -> map.entrySet().stream()) + .filter(entry -> entry.getKey().equals("type")) + .map(Map.Entry::getValue) + .collect(Collectors.toList()); + } + + private static int getJiraIssues() { + return 0; + } + + private static int getGitHubIssues() { + return 0; + } + + + @Override + public String key() { + return KEY; + } + + @Override + public String getDescription() { + return "Returns the number of issues open in a plugin"; + } + + @Override + public String[] getProbeResultRequirement() { + return new String[]{UpdateCenterPluginPublicationProbe.KEY}; + } + +} diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java new file mode 100644 index 000000000..63d20a131 --- /dev/null +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java @@ -0,0 +1,102 @@ +package io.jenkins.pluginhealth.scoring.probes; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.*; + +import java.util.Map; + +import io.jenkins.pluginhealth.scoring.model.Plugin; +import io.jenkins.pluginhealth.scoring.model.ProbeResult; + +import org.junit.jupiter.api.Test; + +public class OpenIssuesProbeTest extends AbstractProbeTest { + @Override + OpenIssuesProbe getSpy() { + return spy(OpenIssuesProbe.class); + } + + @Test + void shouldNotRunWithInvalidUpdateCenter() { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = mock(ProbeContext.class); + + when(plugin.getDetails()).thenReturn( + Map.of(), + Map.of( + UpdateCenterPluginPublicationProbe.KEY, ProbeResult.failure(UpdateCenterPluginPublicationProbe.KEY, "") + ) + ); + + final OpenIssuesProbe probe = getSpy(); + for (int i = 0; i < 2; i++) { + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status") + .isEqualTo(ProbeResult.error(OpenIssuesProbe.KEY, "")); + verify(probe, never()).doApply(plugin, ctx); + } + + } + + @Test + void shouldBeAbleToFindOpenIssuesInBothJiraGH() { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = mock(ProbeContext.class); + + when(plugin.getDetails()).thenReturn( + Map.of( + UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") + ) + ); + + final OpenIssuesProbe probe = getSpy(); + when(plugin.getScm()).thenReturn("https://github.com/jenkinsci/accurev-plugin"); + + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.error(DocumentationMigrationProbe.KEY, "0 open issues found")); + } + + @Test + void shouldBeAbleToFindOpenIssuesInJira() { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = mock(ProbeContext.class); + + when(plugin.getDetails()).thenReturn( + Map.of( + UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") + ) + ); + + final OpenIssuesProbe probe = getSpy(); + when(plugin.getScm()).thenReturn("https://github.com/jenkinsci/active-directory-plugin"); + + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.error(DocumentationMigrationProbe.KEY, "0 open issues found")); + + } + + @Test + void shouldBeAbleToFindOpenIssuesInGH() { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = mock(ProbeContext.class); + + when(plugin.getDetails()).thenReturn( + Map.of( + UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") + ) + ); + + final OpenIssuesProbe probe = getSpy(); + when(plugin.getScm()).thenReturn("https://github.com/jenkinsci/advanced-installer-msi-builder-plugin"); + + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.error(DocumentationMigrationProbe.KEY, "0 open issues found")); + } +} diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java index 59ff0bd49..0a9c6cf52 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java @@ -81,7 +81,7 @@ void shouldSucceedIfPluginIsInUpdateCenterMap() { when(plugin.getName()).thenReturn(pluginName); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( - pluginName, null, null, null, List.of(), 0, "2.361.1", "main" + pluginName, null, null, null, List.of(), 0, "2.361.1", "main", null )), Map.of(), List.of() From 68aa5056dc68c33ff02204ecea7b498697f646fb Mon Sep 17 00:00:00 2001 From: Jagruti Date: Mon, 24 Jul 2023 14:33:51 +0530 Subject: [PATCH 02/44] Removed issueTracker from models --- .../io/jenkins/pluginhealth/scoring/model/Plugin.java | 10 +--------- .../scoring/model/updatecenter/Plugin.java | 4 ++-- .../scoring/model/updatecenter/UpdateCenter.java | 4 +++- .../pluginhealth/scoring/probes/OpenIssuesProbe.java | 3 +-- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/Plugin.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/Plugin.java index 9d9bd8262..b5ddfb83e 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/Plugin.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/Plugin.java @@ -62,13 +62,6 @@ public class Plugin { @Column(name = "release_timestamp") private ZonedDateTime releaseTimestamp; - public List> getIssueTracker() { - return issueTracker; - } - - @Column(name = "issue_tracker") - private List> issueTracker; - @Column(columnDefinition = "jsonb") @Type(value = JsonType.class) private final Map details = new HashMap<>(); @@ -76,12 +69,11 @@ public List> getIssueTracker() { public Plugin() { } - public Plugin(String name, VersionNumber version, String scm, ZonedDateTime releaseTimestamp, List> issueTrackers) { + public Plugin(String name, VersionNumber version, String scm, ZonedDateTime releaseTimestamp) { this.name = name; this.version = version; this.scm = scm; this.releaseTimestamp = releaseTimestamp; - this.issueTracker = issueTrackers; } public String getName() { diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java index ac9fe1360..5e68de37c 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java @@ -32,8 +32,8 @@ public record Plugin(String name, VersionNumber version, String scm, ZonedDateTime releaseTimestamp, List labels, - int popularity, String requiredCore, String defaultBranch, List> issueTrackers) { + int popularity, String requiredCore, String defaultBranch) { public io.jenkins.pluginhealth.scoring.model.Plugin toPlugin() { - return new io.jenkins.pluginhealth.scoring.model.Plugin(this.name(), this.version(), this.scm(), this.releaseTimestamp(), this.issueTrackers()); + return new io.jenkins.pluginhealth.scoring.model.Plugin(this.name(), this.version(), this.scm(), this.releaseTimestamp()); } } diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/UpdateCenter.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/UpdateCenter.java index 9d5b6f89e..3bd7f673f 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/UpdateCenter.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/UpdateCenter.java @@ -29,6 +29,8 @@ public record UpdateCenter(Map plugins, Map deprecations, - List warnings + List warnings, + List> issueTrackers + ) { } diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java index fbe018344..fe67741c9 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java @@ -34,8 +34,7 @@ else if (type.equals("github")) { } private static List getIssueTracker(Plugin plugin, ProbeContext context) { - return context.getUpdateCenter().plugins() - .get(plugin.getIssueTracker()) + return context.getUpdateCenter() .issueTrackers().stream() .flatMap(map -> map.entrySet().stream()) .filter(entry -> entry.getKey().equals("type")) From 54a82a31274347141ab12ecb74782ff58a6332b4 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Mon, 24 Jul 2023 21:21:00 +0530 Subject: [PATCH 03/44] Modified the existing test cases that were affected and updated then new ones --- .../scoring/probes/OpenIssuesProbe.java | 3 +- .../scoring/probes/CodeCoverageProbeTest.java | 7 ++ .../probes/DeprecatedPluginProbeTest.java | 4 + .../probes/InstallationStatProbeTest.java | 1 + .../scoring/probes/JenkinsCoreProbeTest.java | 2 + .../KnownSecurityVulnerabilityProbeTest.java | 22 +++-- .../scoring/probes/OpenIssuesProbeTest.java | 87 +++++++++++++++---- .../scoring/probes/SpotBugsProbeTest.java | 3 + .../probes/UpForAdoptionProbeTest.java | 3 + ...pdateCenterPluginPublicationProbeTest.java | 4 +- .../scoring/probes/ProbeEngineTest.java | 1 + 11 files changed, 112 insertions(+), 25 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java index fe67741c9..46ba7b7ae 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java @@ -15,7 +15,6 @@ @Order(value = OpenIssuesProbe.ORDER) public class OpenIssuesProbe extends Probe { private static final Logger LOGGER = LoggerFactory.getLogger(OpenIssuesProbe.class); - public static final String KEY = "open-issue"; public static final int ORDER = UpdateCenterPluginPublicationProbe.ORDER + 100; @@ -30,7 +29,7 @@ else if (type.equals("github")) { return ProbeResult.success(key(), String.format("%d open issues found", getGitHubIssues())); } } - return ProbeResult.failure(key(), String.format("Update center issue tracker could not be found")); + return ProbeResult.failure(key(), "Update center issue tracker could not be found"); } private static List getIssueTracker(Plugin plugin, ProbeContext context) { diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java index 540d488ce..c5efd234b 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java @@ -118,6 +118,7 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), + List.of(), List.of() )); when(ctx.getRepositoryName(plugin.getScm())).thenReturn(Optional.empty()); @@ -162,6 +163,7 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), + List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); @@ -219,6 +221,7 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), + List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); @@ -276,6 +279,7 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), + List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); @@ -333,6 +337,7 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), + List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); @@ -390,6 +395,7 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), + List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); @@ -447,6 +453,7 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), + List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java index 94f1c6b41..c2990ef18 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java @@ -64,6 +64,7 @@ void shouldBeAbleToDetectNonDeprecatedPlugin() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main")), Map.of("bar", new Deprecation("find-the-reason-here")), + Collections.emptyList(), Collections.emptyList() )); @@ -82,6 +83,7 @@ void shouldBeAbleToDetectDeprecatedPlugin() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main")), Map.of("bar", new Deprecation("find-the-reason-here"), "foo", new Deprecation("this-is-the-reason")), + Collections.emptyList(), Collections.emptyList() )); @@ -103,6 +105,7 @@ void shouldBeAbleToDetectDeprecatedPluginFromLabels() { pluginName, new Plugin(pluginName, new VersionNumber("1.0"), "", ZonedDateTime.now(), List.of("deprecated"), 0, "2.361", "main") ), Map.of(), + Collections.emptyList(), Collections.emptyList() )); @@ -125,6 +128,7 @@ void shouldSurviveIfPluginIsNotInUpdateCenter() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of(), Map.of(), + Collections.emptyList(), Collections.emptyList() )); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java index 985d0dd39..593773547 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java @@ -95,6 +95,7 @@ void shouldBeAbleToFindInstallationCountInUpdateCenter() { new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin(pluginName, null, null, null, List.of(), 100, "", "main") ), Map.of(), + List.of(), List.of() )); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java index 761e0a083..e007048d7 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java @@ -67,6 +67,7 @@ void shouldFailIfPluginNotInUpdateCenter() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of(), Map.of(), + List.of(), List.of() )); @@ -99,6 +100,7 @@ void shouldBeAbleToExtractJenkinsVersionFromUpdateCenter() { ) ), Map.of(), + List.of(), List.of() )); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java index 90cf1e042..47bfba82b 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java @@ -65,6 +65,7 @@ void shouldBeOKWithNoSecurityWarning() { new UpdateCenter( Collections.emptyMap(), Collections.emptyMap(), + Collections.emptyList(), Collections.emptyList() ) ); @@ -89,7 +90,8 @@ void shouldBeOKWithWarningOnDifferentPlugin() { Collections.emptyMap(), List.of( new SecurityWarning("SECURITY-1", "wiz", List.of(new SecurityWarningVersion(null, ".*"))) - ) + ), + List.of() ) ); @@ -117,7 +119,8 @@ void shouldBeOKWithWarningOnOlderVersion() { new SecurityWarning("SECURITY-1", pluginName, List.of( new SecurityWarningVersion(new VersionNumber("1.0"), "0\\.*") )) - ) + ), + List.of() ) ); @@ -144,7 +147,8 @@ void shouldNotBeOKWithWarningOnCurrentVersion() { Collections.emptyMap(), List.of( new SecurityWarning(warningId, pluginName, List.of(new SecurityWarningVersion(pluginVersion, "1.0"))) - ) + ), + List.of() ) ); @@ -172,7 +176,8 @@ void shouldNotBeOKWithWarningWithoutLastVersion() { Collections.emptyMap(), List.of( new SecurityWarning(warningId, pluginName, List.of(new SecurityWarningVersion(null, ".*"))) - ) + ), + List.of() ) ); @@ -202,7 +207,8 @@ void shouldNotBeOKWithMultipleWarningsWithoutLastVersion() { List.of( new SecurityWarning(warningId1, pluginName, List.of(new SecurityWarningVersion(null, ".*"))), new SecurityWarning(warningId2, pluginName, List.of(new SecurityWarningVersion(null, ".*"))) - ) + ), + List.of() ) ); @@ -232,7 +238,8 @@ void shouldNotBeOKWithWarningWithoutLastVersionAndOneResolved() { List.of( new SecurityWarning(warningId1, pluginName, List.of(new SecurityWarningVersion(null, ".*"))), new SecurityWarning(warningId2, pluginName, List.of(new SecurityWarningVersion(new VersionNumber("1.1"), ".*"))) - ) + ), + List.of() ) ); @@ -259,7 +266,8 @@ void shouldBeOKWithWarningWithoutLastVersionButOutOfPattern() { Collections.emptyMap(), List.of( new SecurityWarning("SECURITY-1", pluginName, List.of(new SecurityWarningVersion(null, "[0-1]\\..*"))) - ) + ), + List.of() ) ); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java index 63d20a131..969896749 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java @@ -3,10 +3,12 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; +import java.util.List; import java.util.Map; import io.jenkins.pluginhealth.scoring.model.Plugin; import io.jenkins.pluginhealth.scoring.model.ProbeResult; +import io.jenkins.pluginhealth.scoring.model.updatecenter.UpdateCenter; import org.junit.jupiter.api.Test; @@ -29,18 +31,15 @@ void shouldNotRunWithInvalidUpdateCenter() { ); final OpenIssuesProbe probe = getSpy(); - for (int i = 0; i < 2; i++) { - assertThat(probe.apply(plugin, ctx)) - .usingRecursiveComparison() - .comparingOnlyFields("id", "status") - .isEqualTo(ProbeResult.error(OpenIssuesProbe.KEY, "")); - verify(probe, never()).doApply(plugin, ctx); - } - + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.error(OpenIssuesProbe.KEY, "open-issue does not meet the criteria to be executed on null")); + verify(probe, never()).doApply(plugin, ctx); } @Test - void shouldBeAbleToFindOpenIssuesInBothJiraGH() { + void shouldBeAbleToFindNumberOfOpenIssuesInBothJiraGH() { final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); @@ -50,17 +49,42 @@ void shouldBeAbleToFindOpenIssuesInBothJiraGH() { ) ); + when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( + Map.of(), + Map.of(), + List.of(), + List.of( + Map.of( + "reportUrl", + "https://www.jenkins.io/participate/report-issue/redirect/#15525", + "type", + "jira", + "viewUrl", + "https://issues.jenkins.io/issues/?jql=component=15525" + ), + Map.of( + "reportUrl", + "https://github.com/jenkinsci/accurev-plugin/issues/new/choose", + "type", + "github", + "viewUrl", + "https://github.com/jenkinsci/accurev-plugin/issues" + ) + ) + )); + final OpenIssuesProbe probe = getSpy(); when(plugin.getScm()).thenReturn("https://github.com/jenkinsci/accurev-plugin"); assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.error(DocumentationMigrationProbe.KEY, "0 open issues found")); + .isEqualTo(ProbeResult.success(OpenIssuesProbe.KEY, "0 open issues found")); + verify(probe, atMostOnce()).doApply(plugin, ctx); } @Test - void shouldBeAbleToFindOpenIssuesInJira() { + void shouldBeAbleToFindNumberOfOpenIssuesInJira() { final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); @@ -70,18 +94,34 @@ void shouldBeAbleToFindOpenIssuesInJira() { ) ); + when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( + Map.of(), + Map.of(), + List.of(), + List.of( + Map.of( + "reportUrl", + "https://www.jenkins.io/participate/report-issue/redirect/#22024", + "type", + "jira", + "viewUrl", + "https://issues.jenkins.io/issues/?jql=component=22024" + ) + ) + )); + final OpenIssuesProbe probe = getSpy(); when(plugin.getScm()).thenReturn("https://github.com/jenkinsci/active-directory-plugin"); assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.error(DocumentationMigrationProbe.KEY, "0 open issues found")); - + .isEqualTo(ProbeResult.success(OpenIssuesProbe.KEY, "0 open issues found")); + verify(probe, atMostOnce()).doApply(plugin, ctx); } @Test - void shouldBeAbleToFindOpenIssuesInGH() { + void shouldBeAbleToFindNumberOfOpenIssuesInGH() { final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); @@ -91,12 +131,29 @@ void shouldBeAbleToFindOpenIssuesInGH() { ) ); + when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( + Map.of(), + Map.of(), + List.of(), + List.of( + Map.of( + "reportUrl", + "https://github.com/jenkinsci/advanced-installer-msi-builder-plugin/issues/new/choose", + "type", + "github", + "viewUrl", + "https://github.com/jenkinsci/advanced-installer-msi-builder-plugin/issues" + ) + ) + )); + final OpenIssuesProbe probe = getSpy(); when(plugin.getScm()).thenReturn("https://github.com/jenkinsci/advanced-installer-msi-builder-plugin"); assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.error(DocumentationMigrationProbe.KEY, "0 open issues found")); + .isEqualTo(ProbeResult.success(OpenIssuesProbe.KEY, "0 open issues found")); + verify(probe, atMostOnce()).doApply(plugin, ctx); } } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java index 241bf51f3..b818d37cc 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java @@ -91,6 +91,7 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), + List.of(), List.of() )); when(ctx.getRepositoryName(plugin.getScm())).thenReturn(Optional.empty()); @@ -133,6 +134,7 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), + List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); @@ -185,6 +187,7 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), + List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java index dc673db6d..40b09713c 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java @@ -63,6 +63,7 @@ void shouldBeAbleToDetectPluginForAdoption() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder", "adopt-this-plugin"), 0, "", "main")), Collections.emptyMap(), + Collections.emptyList(), Collections.emptyList() )); @@ -81,6 +82,7 @@ void shouldBeAbleToDetectPluginNotForAdoption() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder"), 0, "", "main")), Collections.emptyMap(), + Collections.emptyList(), Collections.emptyList() )); @@ -99,6 +101,7 @@ void shouldFailWhenPluginNotPresentInUpdateCenter() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of(), Map.of(), + List.of(), List.of() )); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java index 0a9c6cf52..12bd78c10 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java @@ -60,6 +60,7 @@ void shouldFailIfPluginIsNotInUpdateCenterMap() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of(), Map.of(), + Collections.emptyList(), Collections.emptyList() )); @@ -81,9 +82,10 @@ void shouldSucceedIfPluginIsInUpdateCenterMap() { when(plugin.getName()).thenReturn(pluginName); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( - pluginName, null, null, null, List.of(), 0, "2.361.1", "main", null + pluginName, null, null, null, List.of(), 0, "2.361.1", "main" )), Map.of(), + List.of(), List.of() )); diff --git a/war/src/test/java/io/jenkins/pluginhealth/scoring/probes/ProbeEngineTest.java b/war/src/test/java/io/jenkins/pluginhealth/scoring/probes/ProbeEngineTest.java index 6e06c2091..36504ab92 100644 --- a/war/src/test/java/io/jenkins/pluginhealth/scoring/probes/ProbeEngineTest.java +++ b/war/src/test/java/io/jenkins/pluginhealth/scoring/probes/ProbeEngineTest.java @@ -71,6 +71,7 @@ void setup() throws IOException { when(updateCenterService.fetchUpdateCenter()).thenReturn(new UpdateCenter( Map.of(), Map.of(), + List.of(), List.of() )); } From abb1001db0f144411e320a24f9747409fd710e55 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Mon, 24 Jul 2023 21:29:42 +0530 Subject: [PATCH 04/44] Fixing checkstyle issues --- .../java/io/jenkins/pluginhealth/scoring/model/Plugin.java | 1 - .../pluginhealth/scoring/probes/OpenIssuesProbe.java | 7 ++++--- .../pluginhealth/scoring/probes/OpenIssuesProbeTest.java | 7 ++++++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/Plugin.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/Plugin.java index b5ddfb83e..68ad0a862 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/Plugin.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/Plugin.java @@ -26,7 +26,6 @@ import java.time.ZonedDateTime; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Objects; diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java index 46ba7b7ae..93b32b8de 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java @@ -1,6 +1,7 @@ package io.jenkins.pluginhealth.scoring.probes; -import java.util.*; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import io.jenkins.pluginhealth.scoring.model.Plugin; @@ -21,8 +22,8 @@ public class OpenIssuesProbe extends Probe { @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { List issueTracker = getIssueTracker(plugin, context); - for (String type: issueTracker) { - if(type.equals("jira")) { + for (String type : issueTracker) { + if (type.equals("jira")) { return ProbeResult.success(key(), String.format("%d open issues found", getJiraIssues())); } else if (type.equals("github")) { diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java index 969896749..e09499c7c 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java @@ -1,7 +1,12 @@ package io.jenkins.pluginhealth.scoring.probes; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.atMostOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.util.List; import java.util.Map; From 4d8ae5d98f2d4a4859900c297341d43c6dd785e6 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Mon, 24 Jul 2023 21:38:19 +0530 Subject: [PATCH 05/44] Fixing checkstyle issues --- .../jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java index 5e68de37c..6c51489e7 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java @@ -26,7 +26,6 @@ import java.time.ZonedDateTime; import java.util.List; -import java.util.Map; import hudson.util.VersionNumber; From c4c1605bc05c2f31a38fabd0edc84bc89bffbebc Mon Sep 17 00:00:00 2001 From: Jagruti Date: Mon, 24 Jul 2023 21:56:17 +0530 Subject: [PATCH 06/44] Updated probe names and added java docs --- ...robe.java => NumberOfOpenIssuesProbe.java} | 25 +++++++++++++++---- ....java => NumberOfOpenIssuesProbeTest.java} | 22 ++++++++-------- 2 files changed, 31 insertions(+), 16 deletions(-) rename core/src/main/java/io/jenkins/pluginhealth/scoring/probes/{OpenIssuesProbe.java => NumberOfOpenIssuesProbe.java} (72%) rename core/src/test/java/io/jenkins/pluginhealth/scoring/probes/{OpenIssuesProbeTest.java => NumberOfOpenIssuesProbeTest.java} (86%) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java similarity index 72% rename from core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java rename to core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java index 93b32b8de..a2a89daee 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java @@ -12,16 +12,19 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; +/** + * This probe counts the total number of open issues in GitHub and JIRA + */ @Component -@Order(value = OpenIssuesProbe.ORDER) -public class OpenIssuesProbe extends Probe { - private static final Logger LOGGER = LoggerFactory.getLogger(OpenIssuesProbe.class); +@Order(value = NumberOfOpenIssuesProbe.ORDER) +public class NumberOfOpenIssuesProbe extends Probe { + private static final Logger LOGGER = LoggerFactory.getLogger(NumberOfOpenIssuesProbe.class); public static final String KEY = "open-issue"; public static final int ORDER = UpdateCenterPluginPublicationProbe.ORDER + 100; @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { - List issueTracker = getIssueTracker(plugin, context); + List issueTracker = getIssueTracker(context); for (String type : issueTracker) { if (type.equals("jira")) { return ProbeResult.success(key(), String.format("%d open issues found", getJiraIssues())); @@ -33,7 +36,13 @@ else if (type.equals("github")) { return ProbeResult.failure(key(), "Update center issue tracker could not be found"); } - private static List getIssueTracker(Plugin plugin, ProbeContext context) { + /** + * Get issueTracker data from UpdateCenter and filter the type + * + * @param {@link io.jenkins.pluginhealth.scoring.probes#ProbeContext} the context data for the probe + * @return a list which contains a map of issue tracker type + */ + private static List getIssueTracker(ProbeContext context) { return context.getUpdateCenter() .issueTrackers().stream() .flatMap(map -> map.entrySet().stream()) @@ -42,10 +51,16 @@ private static List getIssueTracker(Plugin plugin, ProbeContext context) .collect(Collectors.toList()); } + /** + * Get total number of JIRA issues in a plugin + * */ private static int getJiraIssues() { return 0; } + /** + * Get total number of GitHub issues in a plugin + * */ private static int getGitHubIssues() { return 0; } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java similarity index 86% rename from core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java rename to core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java index e09499c7c..6fa9fde06 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/OpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java @@ -17,10 +17,10 @@ import org.junit.jupiter.api.Test; -public class OpenIssuesProbeTest extends AbstractProbeTest { +public class NumberOfOpenIssuesProbeTest extends AbstractProbeTest { @Override - OpenIssuesProbe getSpy() { - return spy(OpenIssuesProbe.class); + NumberOfOpenIssuesProbe getSpy() { + return spy(NumberOfOpenIssuesProbe.class); } @Test @@ -35,11 +35,11 @@ void shouldNotRunWithInvalidUpdateCenter() { ) ); - final OpenIssuesProbe probe = getSpy(); + final NumberOfOpenIssuesProbe probe = getSpy(); assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.error(OpenIssuesProbe.KEY, "open-issue does not meet the criteria to be executed on null")); + .isEqualTo(ProbeResult.error(NumberOfOpenIssuesProbe.KEY, "open-issue does not meet the criteria to be executed on null")); verify(probe, never()).doApply(plugin, ctx); } @@ -78,13 +78,13 @@ void shouldBeAbleToFindNumberOfOpenIssuesInBothJiraGH() { ) )); - final OpenIssuesProbe probe = getSpy(); + final NumberOfOpenIssuesProbe probe = getSpy(); when(plugin.getScm()).thenReturn("https://github.com/jenkinsci/accurev-plugin"); assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(OpenIssuesProbe.KEY, "0 open issues found")); + .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "0 open issues found")); verify(probe, atMostOnce()).doApply(plugin, ctx); } @@ -115,13 +115,13 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() { ) )); - final OpenIssuesProbe probe = getSpy(); + final NumberOfOpenIssuesProbe probe = getSpy(); when(plugin.getScm()).thenReturn("https://github.com/jenkinsci/active-directory-plugin"); assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(OpenIssuesProbe.KEY, "0 open issues found")); + .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "0 open issues found")); verify(probe, atMostOnce()).doApply(plugin, ctx); } @@ -152,13 +152,13 @@ void shouldBeAbleToFindNumberOfOpenIssuesInGH() { ) )); - final OpenIssuesProbe probe = getSpy(); + final NumberOfOpenIssuesProbe probe = getSpy(); when(plugin.getScm()).thenReturn("https://github.com/jenkinsci/advanced-installer-msi-builder-plugin"); assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(OpenIssuesProbe.KEY, "0 open issues found")); + .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "0 open issues found")); verify(probe, atMostOnce()).doApply(plugin, ctx); } } From 99d9cf5e20eccf0d654cbffa9af04e8437b6f098 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sat, 29 Jul 2023 20:44:38 +0530 Subject: [PATCH 07/44] Added test and code to count open GitHub issues --- .../probes/NumberOfOpenIssuesProbe.java | 51 +++++++++++-------- .../probes/NumberOfOpenIssuesProbeTest.java | 36 ++++++++++--- 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java index a2a89daee..2c43c22f0 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java @@ -1,12 +1,15 @@ package io.jenkins.pluginhealth.scoring.probes; +import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import io.jenkins.pluginhealth.scoring.model.Plugin; import io.jenkins.pluginhealth.scoring.model.ProbeResult; +import org.kohsuke.github.GHRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; @@ -20,20 +23,20 @@ public class NumberOfOpenIssuesProbe extends Probe { private static final Logger LOGGER = LoggerFactory.getLogger(NumberOfOpenIssuesProbe.class); public static final String KEY = "open-issue"; - public static final int ORDER = UpdateCenterPluginPublicationProbe.ORDER + 100; + public static final int ORDER = SCMLinkValidationProbe.ORDER + 100; @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { - List issueTracker = getIssueTracker(context); - for (String type : issueTracker) { - if (type.equals("jira")) { - return ProbeResult.success(key(), String.format("%d open issues found", getJiraIssues())); - } - else if (type.equals("github")) { - return ProbeResult.success(key(), String.format("%d open issues found", getGitHubIssues())); - } - } - return ProbeResult.failure(key(), "Update center issue tracker could not be found"); + List issueTracker = getIssueTrackerType(context); + return issueTracker.stream() + .filter(type -> type.equals("jira")) + .findFirst() + .map(type -> getJiraIssues()) + .orElseGet(() -> issueTracker.stream() + .filter(type -> type.equals("github")) + .findFirst() + .map(type -> getGitHubIssues(context, plugin.getScm())) + .orElse(ProbeResult.failure(key(), "Update center issue tracker could not be found"))); } /** @@ -42,7 +45,7 @@ else if (type.equals("github")) { * @param {@link io.jenkins.pluginhealth.scoring.probes#ProbeContext} the context data for the probe * @return a list which contains a map of issue tracker type */ - private static List getIssueTracker(ProbeContext context) { + private List getIssueTrackerType(ProbeContext context) { return context.getUpdateCenter() .issueTrackers().stream() .flatMap(map -> map.entrySet().stream()) @@ -52,20 +55,28 @@ private static List getIssueTracker(ProbeContext context) { } /** - * Get total number of JIRA issues in a plugin + * Get total number of open JIRA issues in a plugin * */ - private static int getJiraIssues() { - return 0; + private ProbeResult getJiraIssues() { + return null; } /** - * Get total number of GitHub issues in a plugin + * Get total number of open GitHub issues in a plugin * */ - private static int getGitHubIssues() { - return 0; + private ProbeResult getGitHubIssues(ProbeContext context, String scm) { + try { + final Optional repositoryName = context.getRepositoryName(scm); + if (repositoryName.isPresent()) { + final GHRepository ghRepository = context.getGitHub().getRepository(repositoryName.get()); + return ProbeResult.success(key(), String.format("%d open issues found", ghRepository.getOpenIssueCount())); + } + } catch (IOException ex) { + return ProbeResult.error(key(), "Could not read GitHub open issues"); + } + return ProbeResult.failure(key(), String.format("GitHub repository could not be found")); } - @Override public String key() { return KEY; @@ -78,7 +89,7 @@ public String getDescription() { @Override public String[] getProbeResultRequirement() { - return new String[]{UpdateCenterPluginPublicationProbe.KEY}; + return new String[]{SCMLinkValidationProbe.KEY, UpdateCenterPluginPublicationProbe.KEY}; } } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java index 6fa9fde06..4e660189a 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java @@ -8,16 +8,21 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.Optional; import io.jenkins.pluginhealth.scoring.model.Plugin; import io.jenkins.pluginhealth.scoring.model.ProbeResult; import io.jenkins.pluginhealth.scoring.model.updatecenter.UpdateCenter; import org.junit.jupiter.api.Test; +import org.kohsuke.github.GHRepository; +import org.kohsuke.github.GitHub; public class NumberOfOpenIssuesProbeTest extends AbstractProbeTest { + @Override NumberOfOpenIssuesProbe getSpy() { return spy(NumberOfOpenIssuesProbe.class); @@ -106,11 +111,11 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() { List.of( Map.of( "reportUrl", - "https://www.jenkins.io/participate/report-issue/redirect/#22024", + "https://www.jenkins.io/participate/report-issue/redirect/#18331", "type", "jira", "viewUrl", - "https://issues.jenkins.io/issues/?jql=component=22024" + "https://issues.jenkins.io/issues/?jql=component=18331" ) ) )); @@ -126,16 +131,26 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() { } @Test - void shouldBeAbleToFindNumberOfOpenIssuesInGH() { + void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { + final String pluginName = "cloudevents"; + final String repository = "jenkinsci/" + pluginName + "-plugin"; + final String scmLink = "https://github.com/" + repository; + final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); + final GitHub gh = mock(GitHub.class); + final GHRepository ghRepository = mock(GHRepository.class); + + when(plugin.getName()).thenReturn(pluginName); when(plugin.getDetails()).thenReturn( Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, ""), UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") ) ); + when(plugin.getScm()).thenReturn(scmLink); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of(), Map.of(), @@ -143,22 +158,29 @@ void shouldBeAbleToFindNumberOfOpenIssuesInGH() { List.of( Map.of( "reportUrl", - "https://github.com/jenkinsci/advanced-installer-msi-builder-plugin/issues/new/choose", + "https://github.com/" + repository + "/issues/new/choose", "type", "github", "viewUrl", - "https://github.com/jenkinsci/advanced-installer-msi-builder-plugin/issues" + "https://github.com/" + repository + "/issues" ) ) )); + when(ctx.getGitHub()).thenReturn(gh); + when(ctx.getRepositoryName(plugin.getScm())).thenReturn(Optional.of(repository)); + when(gh.getRepository(repository)).thenReturn(ghRepository); + when(ghRepository.getOpenIssueCount()).thenReturn(6); final NumberOfOpenIssuesProbe probe = getSpy(); - when(plugin.getScm()).thenReturn("https://github.com/jenkinsci/advanced-installer-msi-builder-plugin"); assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "0 open issues found")); + .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "6 open issues found")); verify(probe, atMostOnce()).doApply(plugin, ctx); + } } + + + From 719c57dd96fa718c57351a7b1463047aeb56dd2d Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sun, 30 Jul 2023 19:14:24 +0530 Subject: [PATCH 08/44] Added test code and completed the test case --- core/pom.xml | 4 + .../probes/NumberOfOpenIssuesProbe.java | 95 +++++++++++++++---- .../probes/NumberOfOpenIssuesProbeTest.java | 79 ++++++++++++--- pom.xml | 5 + war/pom.xml | 8 +- 5 files changed, 155 insertions(+), 36 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 024955b15..bcb27e3d4 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -102,5 +102,9 @@ postgresql test + + org.springframework + spring-web + diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java index 2c43c22f0..4e02b7534 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java @@ -1,19 +1,48 @@ +/* + * MIT License + * + * Copyright (c) 2023 Jenkins Infra + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package io.jenkins.pluginhealth.scoring.probes; import java.io.IOException; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import io.jenkins.pluginhealth.scoring.model.Plugin; import io.jenkins.pluginhealth.scoring.model.ProbeResult; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import org.kohsuke.github.GHRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; /** * This probe counts the total number of open issues in GitHub and JIRA @@ -21,60 +50,87 @@ @Component @Order(value = NumberOfOpenIssuesProbe.ORDER) public class NumberOfOpenIssuesProbe extends Probe { - private static final Logger LOGGER = LoggerFactory.getLogger(NumberOfOpenIssuesProbe.class); public static final String KEY = "open-issue"; - public static final int ORDER = SCMLinkValidationProbe.ORDER + 100; + public static final int ORDER = UpdateCenterPluginPublicationProbe.ORDER + 100; + public static final String JIRA_HOST = "https://issues.jenkins.io/"; + public static final String JIRA_API_PATH = "rest/api/latest/search"; + private static final Logger LOGGER = LoggerFactory.getLogger(NumberOfOpenIssuesProbe.class); @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { List issueTracker = getIssueTrackerType(context); + + if (issueTracker.size() > 1) { + return ProbeResult.success(key(), + getJiraIssues(context, plugin.getScm(), plugin.getName()).message().concat(" ") + + getGitHubIssues(context, plugin.getScm(), plugin.getName()).message()); + } return issueTracker.stream() - .filter(type -> type.equals("jira")) + .filter(item -> item.equals("jira")) .findFirst() - .map(type -> getJiraIssues()) + .map(entry -> getJiraIssues(context, plugin.getScm(), plugin.getName())) .orElseGet(() -> issueTracker.stream() - .filter(type -> type.equals("github")) + .filter(item -> item.equals("github")) .findFirst() - .map(type -> getGitHubIssues(context, plugin.getScm())) - .orElse(ProbeResult.failure(key(), "Update center issue tracker could not be found"))); + .map(entry -> getGitHubIssues(context, plugin.getScm(), plugin.getName())) + .orElse(ProbeResult.failure(key(), String.format("Cannot find issue tracker for %s in update center", plugin.getName())))); } /** * Get issueTracker data from UpdateCenter and filter the type * - * @param {@link io.jenkins.pluginhealth.scoring.probes#ProbeContext} the context data for the probe + * @param context the probe context data * @return a list which contains a map of issue tracker type */ private List getIssueTrackerType(ProbeContext context) { return context.getUpdateCenter() .issueTrackers().stream() .flatMap(map -> map.entrySet().stream()) - .filter(entry -> entry.getKey().equals("type")) - .map(Map.Entry::getValue) + .filter(map -> map.getKey().equals("type")) + .map(map -> map.getValue()) .collect(Collectors.toList()); } /** * Get total number of open JIRA issues in a plugin - * */ - private ProbeResult getJiraIssues() { - return null; + */ + private ProbeResult getJiraIssues(ProbeContext context, String scm, String pluginName) { + try { + Optional repository = context.getRepositoryName(scm); + String api = JIRA_HOST + JIRA_API_PATH + "?jql=component=" + + (repository.isPresent() ? context.getRepositoryName(scm).get().split("/")[1] : "") + + " AND status=open"; + + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity response = restTemplate.getForEntity(api, String.class); + ObjectMapper objectMapper = new ObjectMapper(); + String jsonResponse = response.getBody(); + JsonNode jsonNode = objectMapper.readTree(jsonResponse); + int openJIRAIssues = jsonNode.get("total").asInt(); + return ProbeResult.success(key(), String.format("%d open issues found in JIRA.", openJIRAIssues)); + } catch (JsonMappingException e) { + LOGGER.error("Cannot map JSON returned by JIRA API for plugin {}.", pluginName, e); + } catch (JsonProcessingException e) { + LOGGER.error("Cannot process JSON returned by JIRA API for plugin {}.", pluginName, e); + } + return ProbeResult.failure(key(), String.format("Cannot fetch information from JIRA API for plugin %s.", pluginName)); } /** * Get total number of open GitHub issues in a plugin - * */ - private ProbeResult getGitHubIssues(ProbeContext context, String scm) { + */ + private ProbeResult getGitHubIssues(ProbeContext context, String scm, String pluginName) { try { final Optional repositoryName = context.getRepositoryName(scm); if (repositoryName.isPresent()) { final GHRepository ghRepository = context.getGitHub().getRepository(repositoryName.get()); - return ProbeResult.success(key(), String.format("%d open issues found", ghRepository.getOpenIssueCount())); + int openGitHubIssues = ghRepository.getOpenIssueCount(); + return ProbeResult.success(key(), String.format("%d open issues found in GitHub.", openGitHubIssues)); } } catch (IOException ex) { - return ProbeResult.error(key(), "Could not read GitHub open issues"); + return ProbeResult.error(key(), String.format("Cannot not read open issues on GitHub for plugin %s.", pluginName)); } - return ProbeResult.failure(key(), String.format("GitHub repository could not be found")); + return ProbeResult.failure(key(), String.format("Cannot find GitHub repository for plugin %s.", pluginName)); } @Override @@ -91,5 +147,4 @@ public String getDescription() { public String[] getProbeResultRequirement() { return new String[]{SCMLinkValidationProbe.KEY, UpdateCenterPluginPublicationProbe.KEY}; } - } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java index 4e660189a..a6f8d3594 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java @@ -1,6 +1,7 @@ package io.jenkins.pluginhealth.scoring.probes; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.atMostOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -17,11 +18,16 @@ import io.jenkins.pluginhealth.scoring.model.ProbeResult; import io.jenkins.pluginhealth.scoring.model.updatecenter.UpdateCenter; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; import org.kohsuke.github.GHRepository; import org.kohsuke.github.GitHub; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; -public class NumberOfOpenIssuesProbeTest extends AbstractProbeTest { +class NumberOfOpenIssuesProbeTest extends AbstractProbeTest { @Override NumberOfOpenIssuesProbe getSpy() { @@ -29,14 +35,29 @@ NumberOfOpenIssuesProbe getSpy() { } @Test - void shouldNotRunWithInvalidUpdateCenter() { + void shouldNotRunWithInvalidProbeResultRequirement() { final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); when(plugin.getDetails()).thenReturn( Map.of(), Map.of( + UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") + ), + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, "") + ), + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.failure(SCMLinkValidationProbe.KEY, ""), UpdateCenterPluginPublicationProbe.KEY, ProbeResult.failure(UpdateCenterPluginPublicationProbe.KEY, "") + ), + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, ""), + UpdateCenterPluginPublicationProbe.KEY, ProbeResult.failure(UpdateCenterPluginPublicationProbe.KEY, "") + ), + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.failure(SCMLinkValidationProbe.KEY, ""), + UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") ) ); @@ -49,12 +70,19 @@ void shouldNotRunWithInvalidUpdateCenter() { } @Test - void shouldBeAbleToFindNumberOfOpenIssuesInBothJiraGH() { + void shouldBeAbleToFindNumberOfOpenIssuesInBothJiraGH() throws IOException { + final String pluginName = "maven-repo-cleaner"; + final String repository = "jenkinsci/" + pluginName + "-plugin"; + final String scmLink = "https://github.com/" + repository; + final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); + final GitHub gh = mock(GitHub.class); + final GHRepository ghRepository = mock(GHRepository.class); when(plugin.getDetails()).thenReturn( Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, ""), UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") ) ); @@ -66,40 +94,56 @@ void shouldBeAbleToFindNumberOfOpenIssuesInBothJiraGH() { List.of( Map.of( "reportUrl", - "https://www.jenkins.io/participate/report-issue/redirect/#15525", + "https://www.jenkins.io/participate/report-issue/redirect/#15979", "type", "jira", "viewUrl", - "https://issues.jenkins.io/issues/?jql=component=15525" + "https://issues.jenkins.io/issues/?jql=component=15979" ), Map.of( "reportUrl", - "https://github.com/jenkinsci/accurev-plugin/issues/new/choose", + "https://github.com/jenkinsci/maven-repo-cleaner-plugin/issues/new/choose", "type", "github", "viewUrl", - "https://github.com/jenkinsci/accurev-plugin/issues" + "https://github.com/jenkinsci/maven-repo-cleaner-plugin/issues" ) ) )); + when(plugin.getName()).thenReturn(pluginName); + when(plugin.getScm()).thenReturn(scmLink); + + when(ctx.getGitHub()).thenReturn(gh); + when(ctx.getRepositoryName(scmLink)).thenReturn(Optional.of(repository)); + when(gh.getRepository(repository)).thenReturn(ghRepository); + when(ghRepository.getOpenIssueCount()).thenReturn(10); final NumberOfOpenIssuesProbe probe = getSpy(); - when(plugin.getScm()).thenReturn("https://github.com/jenkinsci/accurev-plugin"); assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "0 open issues found")); + .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "6 open issues found in JIRA. 10 open issues found in GitHub.")); verify(probe, atMostOnce()).doApply(plugin, ctx); } @Test - void shouldBeAbleToFindNumberOfOpenIssuesInJira() { + void shouldBeAbleToFindNumberOfOpenIssuesOnlyInJira() throws JsonProcessingException { + final String pluginName = "mailer"; + final String repository = "jenkinsci/" + pluginName + "-plugin"; + final String scmLink = "https://github.com/" + repository; + final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); + JsonNode jsonNode = mock(JsonNode.class); + RestTemplate restTemplate = mock(RestTemplate.class); + ResponseEntity responseEntity = mock(ResponseEntity.class); + + final String jsonString = "{\"expand\":\"names,schema\",\"startAt\":0,\"maxResults\":50,\"total\":1,\"issues\":[]}"; when(plugin.getDetails()).thenReturn( Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, ""), UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") ) ); @@ -120,25 +164,30 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() { ) )); + when(plugin.getName()).thenReturn(pluginName); + when(plugin.getScm()).thenReturn(scmLink); + when(ctx.getRepositoryName(scmLink)).thenReturn(Optional.of(repository)); + when(restTemplate.getForEntity(anyString(), anyString().getClass())).thenReturn(responseEntity); + when(responseEntity.getBody()).thenReturn(jsonString); + when(jsonNode.get(anyString())).thenReturn(new ObjectMapper().readTree(jsonString)); + final NumberOfOpenIssuesProbe probe = getSpy(); - when(plugin.getScm()).thenReturn("https://github.com/jenkinsci/active-directory-plugin"); assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "0 open issues found")); + .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "67 open issues found in JIRA.")); verify(probe, atMostOnce()).doApply(plugin, ctx); } @Test - void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { + void shouldBeAbleToFindNumberOfOpenIssuesOnlyInGH() throws IOException { final String pluginName = "cloudevents"; final String repository = "jenkinsci/" + pluginName + "-plugin"; final String scmLink = "https://github.com/" + repository; final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); - final GitHub gh = mock(GitHub.class); final GHRepository ghRepository = mock(GHRepository.class); @@ -176,7 +225,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "6 open issues found")); + .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "6 open issues found in GitHub.")); verify(probe, atMostOnce()).doApply(plugin, ctx); } diff --git a/pom.xml b/pom.xml index 64c94a2b2..51eeb7474 100644 --- a/pom.xml +++ b/pom.xml @@ -154,6 +154,11 @@ pom import + + org.springframework + spring-web + 3.0.2.RELEASE + diff --git a/war/pom.xml b/war/pom.xml index 305820a17..4d72dbbb6 100644 --- a/war/pom.xml +++ b/war/pom.xml @@ -151,7 +151,13 @@ postgresql test - + + org.springframework + spring-web + 5.3.22 + test + + plugin-health-scoring From 925afa374b6f0ebea43f13566086283a4069e752 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sun, 30 Jul 2023 20:33:54 +0530 Subject: [PATCH 09/44] Removed conficting dependencies --- core/pom.xml | 6 +++--- pom.xml | 5 ----- war/pom.xml | 8 +------- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index bcb27e3d4..3317777e0 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -63,7 +63,7 @@ org.springframework.boot - spring-boot-starter-validation + :qboot-starter-validation com.vladmihalcea @@ -103,8 +103,8 @@ test - org.springframework - spring-web + org.springframework.boot + spring-boot-starter-web diff --git a/pom.xml b/pom.xml index 51eeb7474..64c94a2b2 100644 --- a/pom.xml +++ b/pom.xml @@ -154,11 +154,6 @@ pom import - - org.springframework - spring-web - 3.0.2.RELEASE - diff --git a/war/pom.xml b/war/pom.xml index 4d72dbbb6..305820a17 100644 --- a/war/pom.xml +++ b/war/pom.xml @@ -151,13 +151,7 @@ postgresql test - - org.springframework - spring-web - 5.3.22 - test - - + plugin-health-scoring From 58b135af0e40a3858bdd80e6a256175bd89660fa Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sun, 30 Jul 2023 20:35:24 +0530 Subject: [PATCH 10/44] Fixed incorrect artifact name --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index 3317777e0..ef38c2d37 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -63,7 +63,7 @@ org.springframework.boot - :qboot-starter-validation + spring-boot-starter-validation com.vladmihalcea From 5fd8b2deab1b29377489ffb5fa8d0bef73dd430c Mon Sep 17 00:00:00 2001 From: Jagruti Date: Tue, 1 Aug 2023 17:18:10 +0530 Subject: [PATCH 11/44] Fixed JIRA API calling --- .../probes/NumberOfOpenIssuesProbe.java | 44 ++++++++++++++----- .../probes/NumberOfOpenIssuesProbeTest.java | 14 +++--- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java index 4e02b7534..35dafe499 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java @@ -25,6 +25,8 @@ package io.jenkins.pluginhealth.scoring.probes; import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -52,23 +54,23 @@ public class NumberOfOpenIssuesProbe extends Probe { public static final String KEY = "open-issue"; public static final int ORDER = UpdateCenterPluginPublicationProbe.ORDER + 100; - public static final String JIRA_HOST = "https://issues.jenkins.io/"; - public static final String JIRA_API_PATH = "rest/api/latest/search"; + private static final String JIRA_HOST = "https://issues.jenkins.io/rest/api/latest/search?"; private static final Logger LOGGER = LoggerFactory.getLogger(NumberOfOpenIssuesProbe.class); @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { - List issueTracker = getIssueTrackerType(context); + List issueTracker = getIssueTrackerData(context, IssueTrackerKeysEnum.TYPE.getKey()); if (issueTracker.size() > 1) { return ProbeResult.success(key(), - getJiraIssues(context, plugin.getScm(), plugin.getName()).message().concat(" ") + + getJiraIssues(issueTracker, plugin.getScm(), plugin.getName()).message().concat(" ") + getGitHubIssues(context, plugin.getScm(), plugin.getName()).message()); } + return issueTracker.stream() .filter(item -> item.equals("jira")) .findFirst() - .map(entry -> getJiraIssues(context, plugin.getScm(), plugin.getName())) + .map(entry -> getJiraIssues(getIssueTrackerData(context, IssueTrackerKeysEnum.VIEW.getKey()), plugin.getScm(), plugin.getName())) .orElseGet(() -> issueTracker.stream() .filter(item -> item.equals("github")) .findFirst() @@ -82,11 +84,11 @@ protected ProbeResult doApply(Plugin plugin, ProbeContext context) { * @param context the probe context data * @return a list which contains a map of issue tracker type */ - private List getIssueTrackerType(ProbeContext context) { + private List getIssueTrackerData(ProbeContext context, String filter) { return context.getUpdateCenter() .issueTrackers().stream() .flatMap(map -> map.entrySet().stream()) - .filter(map -> map.getKey().equals("type")) + .filter(map -> map.getKey().equals(filter)) .map(map -> map.getValue()) .collect(Collectors.toList()); } @@ -94,12 +96,10 @@ private List getIssueTrackerType(ProbeContext context) { /** * Get total number of open JIRA issues in a plugin */ - private ProbeResult getJiraIssues(ProbeContext context, String scm, String pluginName) { + private ProbeResult getJiraIssues(List issueTrackerData, String scm, String pluginName) { try { - Optional repository = context.getRepositoryName(scm); - String api = JIRA_HOST + JIRA_API_PATH + "?jql=component=" - + (repository.isPresent() ? context.getRepositoryName(scm).get().split("/")[1] : "") - + " AND status=open"; + URL url = new URL(issueTrackerData.get(0)); + String api = JIRA_HOST + url.getQuery() + " AND status=open"; RestTemplate restTemplate = new RestTemplate(); ResponseEntity response = restTemplate.getForEntity(api, String.class); @@ -112,6 +112,8 @@ private ProbeResult getJiraIssues(ProbeContext context, String scm, String plugi LOGGER.error("Cannot map JSON returned by JIRA API for plugin {}.", pluginName, e); } catch (JsonProcessingException e) { LOGGER.error("Cannot process JSON returned by JIRA API for plugin {}.", pluginName, e); + } catch (MalformedURLException e) { + LOGGER.error("Cannot process malformed URL for plugin {}.", pluginName, e); } return ProbeResult.failure(key(), String.format("Cannot fetch information from JIRA API for plugin %s.", pluginName)); } @@ -147,4 +149,22 @@ public String getDescription() { public String[] getProbeResultRequirement() { return new String[]{SCMLinkValidationProbe.KEY, UpdateCenterPluginPublicationProbe.KEY}; } + + private enum IssueTrackerKeysEnum { + REPORT("reportUrl"), + TYPE("type"), + VIEW("viewUrl"); + + private final String key; + + IssueTrackerKeysEnum(String key) { + this.key = key; + } + + public String getKey() { + return key; + } + + + } } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java index a6f8d3594..22e8b9050 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java @@ -2,7 +2,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.atMostOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -21,6 +20,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.IntNode; import org.junit.jupiter.api.Test; import org.kohsuke.github.GHRepository; import org.kohsuke.github.GitHub; @@ -124,7 +124,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesInBothJiraGH() throws IOException { .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "6 open issues found in JIRA. 10 open issues found in GitHub.")); - verify(probe, atMostOnce()).doApply(plugin, ctx); + verify(probe).doApply(plugin, ctx); } @Test @@ -135,7 +135,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesOnlyInJira() throws JsonProcessingExcep final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); - JsonNode jsonNode = mock(JsonNode.class); + JsonNode jsonNodeMock = mock(JsonNode.class); RestTemplate restTemplate = mock(RestTemplate.class); ResponseEntity responseEntity = mock(ResponseEntity.class); @@ -169,15 +169,15 @@ void shouldBeAbleToFindNumberOfOpenIssuesOnlyInJira() throws JsonProcessingExcep when(ctx.getRepositoryName(scmLink)).thenReturn(Optional.of(repository)); when(restTemplate.getForEntity(anyString(), anyString().getClass())).thenReturn(responseEntity); when(responseEntity.getBody()).thenReturn(jsonString); - when(jsonNode.get(anyString())).thenReturn(new ObjectMapper().readTree(jsonString)); + when(jsonNodeMock.get("total")).thenReturn(new IntNode(10)); final NumberOfOpenIssuesProbe probe = getSpy(); assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "67 open issues found in JIRA.")); - verify(probe, atMostOnce()).doApply(plugin, ctx); + .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "0 open issues found in JIRA.")); + verify(probe).doApply(plugin, ctx); } @Test @@ -226,7 +226,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesOnlyInGH() throws IOException { .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "6 open issues found in GitHub.")); - verify(probe, atMostOnce()).doApply(plugin, ctx); + verify(probe).doApply(plugin, ctx); } } From 1a549322885ef27700c6139c79111c3882c23dd4 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Wed, 2 Aug 2023 22:30:31 +0530 Subject: [PATCH 12/44] Added IssueTrackerDetectionProbe --- .../probes/IssueTrackerDetectionProbe.java | 69 +++++++++++++++++++ .../scoring/probes/ProbeContext.java | 9 +++ 2 files changed, 78 insertions(+) create mode 100644 core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java new file mode 100644 index 000000000..85594cb9d --- /dev/null +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java @@ -0,0 +1,69 @@ +/* + * MIT License + * + * Copyright (c) 2023 Jenkins Infra + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package io.jenkins.pluginhealth.scoring.probes; + +import java.util.Map; +import java.util.stream.Collectors; + +import io.jenkins.pluginhealth.scoring.model.Plugin; +import io.jenkins.pluginhealth.scoring.model.ProbeResult; + +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +@Component +@Order(value = IssueTrackerDetectionProbe.ORDER) +class IssueTrackerDetectionProbe extends Probe { + public static final String KEY = "issue-tracker-detection"; + public static final int ORDER = UpdateCenterPluginPublicationProbe.ORDER + 100 ; + + @Override + protected ProbeResult doApply(Plugin plugin, ProbeContext context) { + Map issueTrackerType = context.getUpdateCenter() + .issueTrackers().stream() + .collect(Collectors.toMap( + issueTracker -> issueTracker.get("type"), + issueTracker -> issueTracker.get("viewUrl") + )); + + context.setIssueTrack(issueTrackerType); + return ProbeResult.success(key(), "Issue tracker detected and returned successfully."); + } + + @Override + public String key() { + return KEY; + } + + @Override + public String getDescription() { + return "Detects the issues tracker type from Update Center."; + } + + @Override + public String[] getProbeResultRequirement() { + return new String[]{UpdateCenterPluginPublicationProbe.KEY}; + } +} diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java index 2d3e5c2dc..e757a6499 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java @@ -45,6 +45,7 @@ public class ProbeContext { private GitHub github; private ZonedDateTime lastCommitDate; private Map pluginDocumentationLinks; + private Map issueTrackerType; public ProbeContext(String pluginName, UpdateCenter updateCenter) throws IOException { this.updateCenter = updateCenter; @@ -88,6 +89,14 @@ public Optional getRepositoryName(String scm) { return match.find() ? Optional.of(match.group("repo")) : Optional.empty(); } + public void setIssueTrack(Map issueTrackerType) { + this.issueTrackerType = issueTrackerType; + } + + public Map getIssueTrackerType() { + return issueTrackerType; + } + /* default */ void cleanUp() throws IOException { try (Stream paths = Files.walk(this.scmRepository)) { paths.sorted(Comparator.reverseOrder()) From 4a144e549708704f7b07ef3cced3061efc69f99d Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sat, 5 Aug 2023 12:27:58 +0530 Subject: [PATCH 13/44] Update IssueTrackerDetectionProbe and added a test for the same --- .../scoring/model/updatecenter/Plugin.java | 8 +- .../probes/AbstractOpenIssuesProbe.java | 26 ++++++ .../scoring/probes/GitHubOpenIssuesProbe.java | 31 +++++++ .../probes/IssueTrackerDetectionProbe.java | 17 ++-- .../scoring/probes/JiraOpenIssuesProbe.java | 32 +++++++ .../scoring/probes/ProbeContext.java | 2 +- .../scoring/probes/CodeCoverageProbeTest.java | 20 +++-- .../probes/DeprecatedPluginProbeTest.java | 8 +- .../probes/InstallationStatProbeTest.java | 2 +- .../IssueTrackerDetectionProbeTest.java | 85 +++++++++++++++++++ .../scoring/probes/JenkinsCoreProbeTest.java | 3 +- .../KnownSecurityVulnerabilityProbeTest.java | 2 +- .../scoring/probes/SpotBugsProbeTest.java | 6 +- .../probes/UpForAdoptionProbeTest.java | 4 +- ...pdateCenterPluginPublicationProbeTest.java | 2 +- 15 files changed, 219 insertions(+), 29 deletions(-) create mode 100644 core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java create mode 100644 core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java create mode 100644 core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java create mode 100644 core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java index 6c51489e7..954890813 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java @@ -31,8 +31,14 @@ public record Plugin(String name, VersionNumber version, String scm, ZonedDateTime releaseTimestamp, List labels, - int popularity, String requiredCore, String defaultBranch) { + int popularity, String requiredCore, String defaultBranch, List issueTrackers) { public io.jenkins.pluginhealth.scoring.model.Plugin toPlugin() { return new io.jenkins.pluginhealth.scoring.model.Plugin(this.name(), this.version(), this.scm(), this.releaseTimestamp()); } + + public List getIssueTrackers() { + return this.issueTrackers; + } + + public record IssueTrackers(String type, String viewUrl, String reportUrl){} } diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java new file mode 100644 index 000000000..c79e55235 --- /dev/null +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java @@ -0,0 +1,26 @@ +package io.jenkins.pluginhealth.scoring.probes; + +import io.jenkins.pluginhealth.scoring.model.Plugin; +import io.jenkins.pluginhealth.scoring.model.ProbeResult; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractOpenIssuesProbe extends Probe { + public static final int ORDER = IssueTrackerDetectionProbe.ORDER + 100; + private static final String JIRA_HOST = "https://issues.jenkins.io/rest/api/latest/search?"; + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractOpenIssuesProbe.class); + + @Override + protected ProbeResult doApply(Plugin plugin, ProbeContext context) { + return null; + } + + @Override + public String[] getProbeResultRequirement() { + return new String[] { IssueTrackerDetectionProbe.KEY}; + } + + public abstract String getTrackerType(); + +} diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java new file mode 100644 index 000000000..de5988322 --- /dev/null +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java @@ -0,0 +1,31 @@ +package io.jenkins.pluginhealth.scoring.probes; + +import io.jenkins.pluginhealth.scoring.model.Plugin; +import io.jenkins.pluginhealth.scoring.model.ProbeResult; + +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +@Component +@Order(AbstractOpenIssuesProbe.ORDER) +class GitHubOpenIssuesProbe extends AbstractOpenIssuesProbe { + @Override + protected ProbeResult doApply(Plugin plugin, ProbeContext context) { + return null; + } + + @Override + public String getTrackerType() { + return "github"; + } + + @Override + public String key() { + return "github-open-issues"; + } + + @Override + public String getDescription() { + return "Returns the total number of open issues in GitHub."; + } +} diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java index 85594cb9d..eec5b112d 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java @@ -41,14 +41,7 @@ class IssueTrackerDetectionProbe extends Probe { @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { - Map issueTrackerType = context.getUpdateCenter() - .issueTrackers().stream() - .collect(Collectors.toMap( - issueTracker -> issueTracker.get("type"), - issueTracker -> issueTracker.get("viewUrl") - )); - - context.setIssueTrack(issueTrackerType); + context.setIssueTrackType(getIssueTrackerData(context.getUpdateCenter().plugins())); return ProbeResult.success(key(), "Issue tracker detected and returned successfully."); } @@ -66,4 +59,12 @@ public String getDescription() { public String[] getProbeResultRequirement() { return new String[]{UpdateCenterPluginPublicationProbe.KEY}; } + + private Map getIssueTrackerData(Map plugin) { + return plugin.values().stream() + .flatMap(entry -> entry.getIssueTrackers().stream()) + .collect(Collectors.toMap(io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers::type, + io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers::viewUrl)); + } + } diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java new file mode 100644 index 000000000..57cf94b7f --- /dev/null +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java @@ -0,0 +1,32 @@ +package io.jenkins.pluginhealth.scoring.probes; + +import io.jenkins.pluginhealth.scoring.model.Plugin; +import io.jenkins.pluginhealth.scoring.model.ProbeResult; + +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +@Component +@Order(AbstractOpenIssuesProbe.ORDER) +class JiraOpenIssuesProbe extends AbstractOpenIssuesProbe { + + @Override + protected ProbeResult doApply(Plugin plugin, ProbeContext context) { + return null; + } + + @Override + public String getTrackerType() { + return "jira"; + } + + @Override + public String key() { + return "jira-open-issues"; + } + + @Override + public String getDescription() { + return "Returns total number of open issues in JIRA."; + } +} diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java index e757a6499..8bd2ec6f5 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java @@ -89,7 +89,7 @@ public Optional getRepositoryName(String scm) { return match.find() ? Optional.of(match.group("repo")) : Optional.empty(); } - public void setIssueTrack(Map issueTrackerType) { + public void setIssueTrackType(Map issueTrackerType) { this.issueTrackerType = issueTrackerType; } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java index c5efd234b..98ca8c2c7 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java @@ -114,7 +114,7 @@ public void shouldBeInErrorWhenRepositoryIsNotInOrganization() { Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch + "42", defaultBranch, List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) ) ), Map.of(), @@ -159,7 +159,8 @@ public void shouldBeSuccessfulWhenRetrievedDetailsFromGitHubChecksIsAboveMinimum Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch + "42", defaultBranch, + List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) ) ), Map.of(), @@ -217,7 +218,8 @@ public void shouldBeSuccessfulWhenAboveThreshold() throws IOException { Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch + "42", defaultBranch, + List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) ) ), Map.of(), @@ -275,7 +277,8 @@ public void shouldFailWhenRetrievedDetailsFromGitHubChecksInBelowMinimumOnBothCr Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch + "42", defaultBranch, + List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) ) ), Map.of(), @@ -333,7 +336,8 @@ public void shouldFailWhenRetrievedDetailsFromGitHubChecksInBelowMinimumOnBranch Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch + "42", defaultBranch, + List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) ) ), Map.of(), @@ -391,7 +395,8 @@ public void shouldFailWhenRetrievedDetailsFromGitHubChecksInBelowMinimumOnLine() Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch + "42", defaultBranch, + List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) ) ), Map.of(), @@ -449,7 +454,8 @@ public void shouldBeInErrorIfThereIsNoCodeCoverage() throws IOException { Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch + "42", defaultBranch, + List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) ) ), Map.of(), diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java index c2990ef18..3ad9a8b41 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java @@ -62,7 +62,8 @@ void shouldBeAbleToDetectNonDeprecatedPlugin() { when(plugin.getName()).thenReturn("foo"); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main")), + Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main", + List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), Map.of("bar", new Deprecation("find-the-reason-here")), Collections.emptyList(), Collections.emptyList() @@ -81,7 +82,7 @@ void shouldBeAbleToDetectDeprecatedPlugin() { when(plugin.getName()).thenReturn("foo"); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main")), + Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), Map.of("bar", new Deprecation("find-the-reason-here"), "foo", new Deprecation("this-is-the-reason")), Collections.emptyList(), Collections.emptyList() @@ -102,7 +103,8 @@ void shouldBeAbleToDetectDeprecatedPluginFromLabels() { when(plugin.getName()).thenReturn(pluginName); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( - pluginName, new Plugin(pluginName, new VersionNumber("1.0"), "", ZonedDateTime.now(), List.of("deprecated"), 0, "2.361", "main") + pluginName, new Plugin(pluginName, new VersionNumber("1.0"), "", ZonedDateTime.now(), List.of("deprecated"), 0, "2.361", "main", + List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", ""))) ), Map.of(), Collections.emptyList(), diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java index 593773547..26d7fc6a9 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java @@ -92,7 +92,7 @@ void shouldBeAbleToFindInstallationCountInUpdateCenter() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( pluginName, - new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin(pluginName, null, null, null, List.of(), 100, "", "main") + new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin(pluginName, null, null, null, List.of(), 100, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", ""))) ), Map.of(), List.of(), diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java new file mode 100644 index 000000000..be71cab75 --- /dev/null +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java @@ -0,0 +1,85 @@ +/* + * MIT License + * + * Copyright (c) 2023 Jenkins Infra + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package io.jenkins.pluginhealth.scoring.probes; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import io.jenkins.pluginhealth.scoring.model.Plugin; +import io.jenkins.pluginhealth.scoring.model.ProbeResult; +import io.jenkins.pluginhealth.scoring.model.updatecenter.UpdateCenter; + +import org.junit.jupiter.api.Test; + +class IssueTrackerDetectionProbeTest extends AbstractProbeTest { + @Override + IssueTrackerDetectionProbe getSpy() { + return spy(IssueTrackerDetectionProbe.class); + } + + @Test + void shouldDetectIssueTrackerInPlugin() throws IOException { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx =spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of(), List.of())));; + final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerGithub = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("github", "https://github.com/foo-plugin/issues", "https://github.com/foo-plugin/issues/new/choose"); + final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerJira = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=18331", "https://www.jenkins.io/participate/report-issue/redirect/#18331"); + final String pluginName = "foo"; + + when(plugin.getDetails()).thenReturn( + Map.of( + UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") + ) + ); + + when(plugin.getName()).thenReturn(pluginName); + when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( + Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, null, null, null, List.of(), 0, "2.361.1", "main", + List.of(issueTrackerGithub, issueTrackerJira) + )), + Map.of(), + List.of(), + List.of() + )); + + final IssueTrackerDetectionProbe probe = getSpy(); + + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); + + assert(ctx.getIssueTrackerType()).equals(Map.of("github","https://github.com/foo-plugin/issues", "jira", "https://issues.jenkins.io/issues/?jql=component=18331")); + verify(probe).doApply(plugin, ctx); + } + +} diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java index e007048d7..261fcba01 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java @@ -96,7 +96,8 @@ void shouldBeAbleToExtractJenkinsVersionFromUpdateCenter() { Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( - pluginName, null, null, null, List.of(), 0, "2.361.1", "main" + pluginName, null, null, null, List.of(), 0, "2.361.1", "main", + List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) ) ), Map.of(), diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java index 47bfba82b..3eef947ee 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java @@ -79,7 +79,7 @@ void shouldBeOKWithNoSecurityWarning() { void shouldBeOKWithWarningOnDifferentPlugin() { final String pluginName = "foo-bar"; final VersionNumber pluginVersion = new VersionNumber("1.0"); - final var pluginInUC = new Plugin(pluginName, pluginVersion, "scm", ZonedDateTime.now().minusHours(1), List.of(), 0, "", "main"); + final var pluginInUC = new Plugin(pluginName, pluginVersion, "scm", ZonedDateTime.now().minusHours(1), List.of(), 0, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", ""))); final var plugin = mock(io.jenkins.pluginhealth.scoring.model.Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); final KnownSecurityVulnerabilityProbe probe = getSpy(); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java index b818d37cc..86f5d9b10 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java @@ -87,7 +87,7 @@ public void shouldFailWhenRepositoryIsNotInOrganization() { Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch + "42", defaultBranch, List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) ) ), Map.of(), @@ -130,7 +130,7 @@ public void shouldBeAbleToRetrieveDetailsFromGitHubChecks() throws IOException { Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch + "42", defaultBranch, List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) ) ), Map.of(), @@ -183,7 +183,7 @@ public void shouldFailIfThereIsNoSpotBugs() throws IOException { Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch + "42", defaultBranch, List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) ) ), Map.of(), diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java index 40b09713c..573e11971 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java @@ -61,7 +61,7 @@ void shouldBeAbleToDetectPluginForAdoption() { when(plugin.getName()).thenReturn("foo"); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder", "adopt-this-plugin"), 0, "", "main")), + Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder", "adopt-this-plugin"), 0, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), Collections.emptyMap(), Collections.emptyList(), Collections.emptyList() @@ -80,7 +80,7 @@ void shouldBeAbleToDetectPluginNotForAdoption() { when(plugin.getName()).thenReturn("foo"); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder"), 0, "", "main")), + Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder"), 0, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), Collections.emptyMap(), Collections.emptyList(), Collections.emptyList() diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java index 12bd78c10..972eef161 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java @@ -82,7 +82,7 @@ void shouldSucceedIfPluginIsInUpdateCenterMap() { when(plugin.getName()).thenReturn(pluginName); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( - pluginName, null, null, null, List.of(), 0, "2.361.1", "main" + pluginName, null, null, null, List.of(), 0, "2.361.1", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) )), Map.of(), List.of(), From d3fd18bb039d8801bd77389c4ed5b90cc4b46a4d Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sat, 5 Aug 2023 22:43:47 +0530 Subject: [PATCH 14/44] Added abstract probe class and jira and github issues count probe --- .../probes/AbstractOpenIssuesProbe.java | 113 ++++++++- .../scoring/probes/GitHubOpenIssuesProbe.java | 31 ++- .../scoring/probes/JiraOpenIssuesProbe.java | 35 ++- .../probes/NumberOfOpenIssuesProbe.java | 170 ------------- .../probes/GitHubOpenIssuesProbeTest.java | 136 ++++++++++ .../probes/JiraOpenIssuesProbeTest.java | 145 +++++++++++ .../probes/NumberOfOpenIssuesProbeTest.java | 235 ------------------ 7 files changed, 444 insertions(+), 421 deletions(-) delete mode 100644 core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java create mode 100644 core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java create mode 100644 core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java delete mode 100644 core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java index c79e55235..b60bb70fa 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java @@ -1,10 +1,49 @@ +/* + * MIT License + * + * Copyright (c) 2023 Jenkins Infra + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package io.jenkins.pluginhealth.scoring.probes; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.BiFunction; + import io.jenkins.pluginhealth.scoring.model.Plugin; import io.jenkins.pluginhealth.scoring.model.ProbeResult; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.kohsuke.github.GHRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; public abstract class AbstractOpenIssuesProbe extends Probe { public static final int ORDER = IssueTrackerDetectionProbe.ORDER + 100; @@ -13,14 +52,84 @@ public abstract class AbstractOpenIssuesProbe extends Probe { @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { - return null; + Map> trackerMethods = createTrackerMethods(); + BiFunction getOpenIssues = trackerMethods.get(getTrackerType()); + + if (getOpenIssues != null) { + return getOpenIssues.apply(plugin, context); + } + return ProbeResult.failure(key(), String.format("Could not find a valid issue tracker type for plugin {}", plugin.getName())); } @Override public String[] getProbeResultRequirement() { - return new String[] { IssueTrackerDetectionProbe.KEY}; + return new String[] { + SCMLinkValidationProbe.KEY, IssueTrackerDetectionProbe.KEY + }; } + /** + * @return a String the tracker "type" present in the "issueTrackers" in UpdateCenter. For ex: jira, github + */ public abstract String getTrackerType(); + private Optional getTrackerUrl(Map trackerType) { + return trackerType.entrySet().stream() + .filter(entry -> entry.getKey().equals(getTrackerType())) + .findFirst() + .map(entry -> entry.getValue()); + } + + /** + * Get total number of open JIRA issues in a plugin + */ + protected ProbeResult getJiraIssues(String viewJiraIssuesUrl, String pluginName) { + try { + if (viewJiraIssuesUrl.isEmpty()) { + return ProbeResult.failure(key(), String.format("JIRA issues is not configured for %s plugin.", pluginName)); + } + URL url = new URL(viewJiraIssuesUrl); + String api = JIRA_HOST + url.getQuery() + " AND status=open"; + System.out.println("api = " + api); + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity response = restTemplate.getForEntity(api, String.class); + ObjectMapper objectMapper = new ObjectMapper(); + String jsonResponse = response.getBody(); + JsonNode jsonNode = objectMapper.readTree(jsonResponse); + int openJIRAIssues = jsonNode.get("total").asInt(); + return ProbeResult.success(key(), String.format("%d open issues found in JIRA.", openJIRAIssues)); + } catch (JsonMappingException e) { + LOGGER.error("Cannot map JSON returned by JIRA API for plugin {}.", pluginName, e); + } catch (JsonProcessingException e) { + LOGGER.error("Cannot process JSON returned by JIRA API for plugin {}.", pluginName, e); + } catch (MalformedURLException e) { + LOGGER.error("Cannot process malformed URL for plugin {}.", pluginName, e); + } + return ProbeResult.failure(key(), String.format("Cannot fetch information from JIRA API for plugin %s.", pluginName)); + } + + /** + * Get total number of open GitHub issues in a plugin + */ + private ProbeResult getGitHubIssues(ProbeContext context, Plugin plugin) { + try { + final Optional repositoryName = context.getRepositoryName(plugin.getScm()); + if (repositoryName.isPresent()) { + final GHRepository ghRepository = context.getGitHub().getRepository(repositoryName.get()); + int openGitHubIssues = ghRepository.getOpenIssueCount(); + return ProbeResult.success(key(), String.format("%d open issues found in GitHub.", openGitHubIssues)); + } + } catch (IOException ex) { + return ProbeResult.error(key(), String.format("Cannot not read open issues on GitHub for plugin %s.", plugin.getName())); + } + return ProbeResult.failure(key(), String.format("Cannot find GitHub repository for plugin %s.", plugin.getName())); + } + + private Map> createTrackerMethods() { + Map> trackerMethods = new HashMap<>(); + trackerMethods.put("jira", (plugin, context) -> getJiraIssues(getTrackerUrl(context.getIssueTrackerType()).orElse(""), plugin.getName())); + trackerMethods.put("github", (plugin, context) -> getGitHubIssues(context, plugin)); + return trackerMethods; + } + } diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java index de5988322..c7df5e859 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) 2023 Jenkins Infra + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package io.jenkins.pluginhealth.scoring.probes; import io.jenkins.pluginhealth.scoring.model.Plugin; @@ -9,10 +33,7 @@ @Component @Order(AbstractOpenIssuesProbe.ORDER) class GitHubOpenIssuesProbe extends AbstractOpenIssuesProbe { - @Override - protected ProbeResult doApply(Plugin plugin, ProbeContext context) { - return null; - } + public static final String KEY = "github-open-issues"; @Override public String getTrackerType() { @@ -21,7 +42,7 @@ public String getTrackerType() { @Override public String key() { - return "github-open-issues"; + return KEY; } @Override diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java index 57cf94b7f..0593fe13a 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java @@ -1,7 +1,28 @@ -package io.jenkins.pluginhealth.scoring.probes; +/* + * MIT License + * + * Copyright (c) 2023 Jenkins Infra + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ -import io.jenkins.pluginhealth.scoring.model.Plugin; -import io.jenkins.pluginhealth.scoring.model.ProbeResult; +package io.jenkins.pluginhealth.scoring.probes; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -9,11 +30,7 @@ @Component @Order(AbstractOpenIssuesProbe.ORDER) class JiraOpenIssuesProbe extends AbstractOpenIssuesProbe { - - @Override - protected ProbeResult doApply(Plugin plugin, ProbeContext context) { - return null; - } + public static final String KEY = "jira-open-issues"; @Override public String getTrackerType() { @@ -22,7 +39,7 @@ public String getTrackerType() { @Override public String key() { - return "jira-open-issues"; + return KEY; } @Override diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java deleted file mode 100644 index 35dafe499..000000000 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbe.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2023 Jenkins Infra - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package io.jenkins.pluginhealth.scoring.probes; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -import io.jenkins.pluginhealth.scoring.model.Plugin; -import io.jenkins.pluginhealth.scoring.model.ProbeResult; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.kohsuke.github.GHRepository; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.annotation.Order; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; - -/** - * This probe counts the total number of open issues in GitHub and JIRA - */ -@Component -@Order(value = NumberOfOpenIssuesProbe.ORDER) -public class NumberOfOpenIssuesProbe extends Probe { - public static final String KEY = "open-issue"; - public static final int ORDER = UpdateCenterPluginPublicationProbe.ORDER + 100; - private static final String JIRA_HOST = "https://issues.jenkins.io/rest/api/latest/search?"; - private static final Logger LOGGER = LoggerFactory.getLogger(NumberOfOpenIssuesProbe.class); - - @Override - protected ProbeResult doApply(Plugin plugin, ProbeContext context) { - List issueTracker = getIssueTrackerData(context, IssueTrackerKeysEnum.TYPE.getKey()); - - if (issueTracker.size() > 1) { - return ProbeResult.success(key(), - getJiraIssues(issueTracker, plugin.getScm(), plugin.getName()).message().concat(" ") + - getGitHubIssues(context, plugin.getScm(), plugin.getName()).message()); - } - - return issueTracker.stream() - .filter(item -> item.equals("jira")) - .findFirst() - .map(entry -> getJiraIssues(getIssueTrackerData(context, IssueTrackerKeysEnum.VIEW.getKey()), plugin.getScm(), plugin.getName())) - .orElseGet(() -> issueTracker.stream() - .filter(item -> item.equals("github")) - .findFirst() - .map(entry -> getGitHubIssues(context, plugin.getScm(), plugin.getName())) - .orElse(ProbeResult.failure(key(), String.format("Cannot find issue tracker for %s in update center", plugin.getName())))); - } - - /** - * Get issueTracker data from UpdateCenter and filter the type - * - * @param context the probe context data - * @return a list which contains a map of issue tracker type - */ - private List getIssueTrackerData(ProbeContext context, String filter) { - return context.getUpdateCenter() - .issueTrackers().stream() - .flatMap(map -> map.entrySet().stream()) - .filter(map -> map.getKey().equals(filter)) - .map(map -> map.getValue()) - .collect(Collectors.toList()); - } - - /** - * Get total number of open JIRA issues in a plugin - */ - private ProbeResult getJiraIssues(List issueTrackerData, String scm, String pluginName) { - try { - URL url = new URL(issueTrackerData.get(0)); - String api = JIRA_HOST + url.getQuery() + " AND status=open"; - - RestTemplate restTemplate = new RestTemplate(); - ResponseEntity response = restTemplate.getForEntity(api, String.class); - ObjectMapper objectMapper = new ObjectMapper(); - String jsonResponse = response.getBody(); - JsonNode jsonNode = objectMapper.readTree(jsonResponse); - int openJIRAIssues = jsonNode.get("total").asInt(); - return ProbeResult.success(key(), String.format("%d open issues found in JIRA.", openJIRAIssues)); - } catch (JsonMappingException e) { - LOGGER.error("Cannot map JSON returned by JIRA API for plugin {}.", pluginName, e); - } catch (JsonProcessingException e) { - LOGGER.error("Cannot process JSON returned by JIRA API for plugin {}.", pluginName, e); - } catch (MalformedURLException e) { - LOGGER.error("Cannot process malformed URL for plugin {}.", pluginName, e); - } - return ProbeResult.failure(key(), String.format("Cannot fetch information from JIRA API for plugin %s.", pluginName)); - } - - /** - * Get total number of open GitHub issues in a plugin - */ - private ProbeResult getGitHubIssues(ProbeContext context, String scm, String pluginName) { - try { - final Optional repositoryName = context.getRepositoryName(scm); - if (repositoryName.isPresent()) { - final GHRepository ghRepository = context.getGitHub().getRepository(repositoryName.get()); - int openGitHubIssues = ghRepository.getOpenIssueCount(); - return ProbeResult.success(key(), String.format("%d open issues found in GitHub.", openGitHubIssues)); - } - } catch (IOException ex) { - return ProbeResult.error(key(), String.format("Cannot not read open issues on GitHub for plugin %s.", pluginName)); - } - return ProbeResult.failure(key(), String.format("Cannot find GitHub repository for plugin %s.", pluginName)); - } - - @Override - public String key() { - return KEY; - } - - @Override - public String getDescription() { - return "Returns the number of issues open in a plugin"; - } - - @Override - public String[] getProbeResultRequirement() { - return new String[]{SCMLinkValidationProbe.KEY, UpdateCenterPluginPublicationProbe.KEY}; - } - - private enum IssueTrackerKeysEnum { - REPORT("reportUrl"), - TYPE("type"), - VIEW("viewUrl"); - - private final String key; - - IssueTrackerKeysEnum(String key) { - this.key = key; - } - - public String getKey() { - return key; - } - - - } -} diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java new file mode 100644 index 000000000..0f42e2f46 --- /dev/null +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java @@ -0,0 +1,136 @@ +/* + * MIT License + * + * Copyright (c) 2023 Jenkins Infra + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package io.jenkins.pluginhealth.scoring.probes; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import io.jenkins.pluginhealth.scoring.model.Plugin; +import io.jenkins.pluginhealth.scoring.model.ProbeResult; +import io.jenkins.pluginhealth.scoring.model.updatecenter.UpdateCenter; + +import org.junit.jupiter.api.Test; +import org.kohsuke.github.GHRepository; +import org.kohsuke.github.GitHub; + +class GitHubOpenIssuesProbeTest extends AbstractProbeTest { + @Override + GitHubOpenIssuesProbe getSpy() { + return spy(GitHubOpenIssuesProbe.class); + } + + @Test + void shouldNotRunWithInvalidProbeResultRequirement() { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = mock(ProbeContext.class); + + when(plugin.getDetails()).thenReturn( + Map.of(), + Map.of( + IssueTrackerDetectionProbe.KEY, ProbeResult.success(IssueTrackerDetectionProbe.KEY, "") + ), + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, "") + ), + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.failure(SCMLinkValidationProbe.KEY, ""), + IssueTrackerDetectionProbe.KEY, ProbeResult.failure(IssueTrackerDetectionProbe.KEY, "") + ), + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, ""), + IssueTrackerDetectionProbe.KEY, ProbeResult.failure(IssueTrackerDetectionProbe.KEY, "") + ), + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.failure(SCMLinkValidationProbe.KEY, ""), + IssueTrackerDetectionProbe.KEY, ProbeResult.success(IssueTrackerDetectionProbe.KEY, "") + ) + ); + + final GitHubOpenIssuesProbe probe = getSpy(); + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.error(GitHubOpenIssuesProbe.KEY, "github-open-issues does not meet the criteria to be executed on null")); + verify(probe, never()).doApply(plugin, ctx); + } + + @Test + void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { + final String pluginName = "cloudevents"; + final String repository = "jenkinsci/" + pluginName + "-plugin"; + final String scmLink = "https://github.com/" + repository; + + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = mock(ProbeContext.class); + final GitHub gh = mock(GitHub.class); + final GHRepository ghRepository = mock(GHRepository.class); + final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerGithub = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("github", "https://github.com/" + repository + "/issues", "https://github.com/" + repository + "/issues/new/choose"); + + when(plugin.getName()).thenReturn(pluginName); + + when(plugin.getScm()).thenReturn(scmLink); + when(plugin.getDetails()).thenReturn( + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, ""), + IssueTrackerDetectionProbe.KEY, ProbeResult.success(IssueTrackerDetectionProbe.KEY, "") + ) + ); + + when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( + Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, null, null, null, List.of(), 0, "2.361.1", "main", + List.of(issueTrackerGithub) + )), + Map.of(), + List.of(), + List.of() + )); + + when(ctx.getGitHub()).thenReturn(gh); + when(ctx.getRepositoryName(plugin.getScm())).thenReturn(Optional.of(repository)); + when(gh.getRepository(repository)).thenReturn(ghRepository); + when(ghRepository.getOpenIssueCount()).thenReturn(6); + + final GitHubOpenIssuesProbe probe = getSpy(); + + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success(GitHubOpenIssuesProbe.KEY, "6 open issues found in GitHub.")); + + verify(probe).doApply(plugin, ctx); + + } + +} diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java new file mode 100644 index 000000000..41d2a996b --- /dev/null +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java @@ -0,0 +1,145 @@ +/* + * MIT License + * + * Copyright (c) 2023 Jenkins Infra + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package io.jenkins.pluginhealth.scoring.probes; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +import java.io.UnsupportedEncodingException; +import java.util.List; +import java.util.Map; + +import io.jenkins.pluginhealth.scoring.model.Plugin; +import io.jenkins.pluginhealth.scoring.model.ProbeResult; +import io.jenkins.pluginhealth.scoring.model.updatecenter.UpdateCenter; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.RestTemplate; + +class JiraOpenIssuesProbeTest extends AbstractProbeTest { + + @Override + JiraOpenIssuesProbe getSpy() { + return spy(JiraOpenIssuesProbe.class); + } + + @Test + void shouldNotRunWithInvalidProbeResultRequirement() { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = mock(ProbeContext.class); + + when(plugin.getDetails()).thenReturn( + Map.of(), + Map.of( + IssueTrackerDetectionProbe.KEY, ProbeResult.success(IssueTrackerDetectionProbe.KEY, "") + ), + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, "") + ), + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.failure(SCMLinkValidationProbe.KEY, ""), + IssueTrackerDetectionProbe.KEY, ProbeResult.failure(IssueTrackerDetectionProbe.KEY, "") + ), + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, ""), + IssueTrackerDetectionProbe.KEY, ProbeResult.failure(IssueTrackerDetectionProbe.KEY, "") + ), + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.failure(SCMLinkValidationProbe.KEY, ""), + IssueTrackerDetectionProbe.KEY, ProbeResult.success(IssueTrackerDetectionProbe.KEY, "") + ) + ); + + final JiraOpenIssuesProbe probe = getSpy(); + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.error(JiraOpenIssuesProbe.KEY, "jira-open-issues does not meet the criteria to be executed on null")); + verify(probe, never()).doApply(plugin, ctx); + } + + @Test + void shouldBeAbleToFindNumberOfOpenIssuesInJira() throws UnsupportedEncodingException { + final String pluginName = "mailer"; + final String repository = "jenkinsci/" + pluginName + "-plugin"; + final String scmLink = "https://github.com/" + repository; + RestTemplate restTemplate = mock(RestTemplate.class); + + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = mock(ProbeContext.class); + + final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerJira = + new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=18331", "https://www.jenkins.io/participate/report-issue/redirect/#18331"); + + final String jsonString = "{\"expand\":\"names,schema\",\"startAt\":0,\"maxResults\":50,\"total\":10,\"issues\":[]}"; + + when(plugin.getDetails()).thenReturn( + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, ""), + IssueTrackerDetectionProbe.KEY, ProbeResult.success(IssueTrackerDetectionProbe.KEY, "") + ) + ); + + when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( + Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, null, null, null, List.of(), 0, "2.361.1", "main", + List.of(issueTrackerJira) + )), + Map.of(), + List.of(), + List.of() + )); + + when(plugin.getName()).thenReturn(pluginName); + when(plugin.getScm()).thenReturn(scmLink); + when(ctx.getIssueTrackerType()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); + + MockRestServiceServer server = MockRestServiceServer.bindTo(restTemplate).build(); + server.expect(requestTo("https://issues.jenkins.io/rest/api/latest/search?jql=component%3D18331%20AND%20status%3Dopen")) + .andExpect(method(HttpMethod.GET)) + .andRespond(withSuccess(jsonString, MediaType.APPLICATION_JSON)); + + final JiraOpenIssuesProbe probe = getSpy(); + + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success(JiraOpenIssuesProbe.KEY, "0 open issues found in JIRA.")); + verify(probe).doApply(plugin, ctx); + } + +} diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java deleted file mode 100644 index 22e8b9050..000000000 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/NumberOfOpenIssuesProbeTest.java +++ /dev/null @@ -1,235 +0,0 @@ -package io.jenkins.pluginhealth.scoring.probes; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import io.jenkins.pluginhealth.scoring.model.Plugin; -import io.jenkins.pluginhealth.scoring.model.ProbeResult; -import io.jenkins.pluginhealth.scoring.model.updatecenter.UpdateCenter; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.IntNode; -import org.junit.jupiter.api.Test; -import org.kohsuke.github.GHRepository; -import org.kohsuke.github.GitHub; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; - -class NumberOfOpenIssuesProbeTest extends AbstractProbeTest { - - @Override - NumberOfOpenIssuesProbe getSpy() { - return spy(NumberOfOpenIssuesProbe.class); - } - - @Test - void shouldNotRunWithInvalidProbeResultRequirement() { - final Plugin plugin = mock(Plugin.class); - final ProbeContext ctx = mock(ProbeContext.class); - - when(plugin.getDetails()).thenReturn( - Map.of(), - Map.of( - UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") - ), - Map.of( - SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, "") - ), - Map.of( - SCMLinkValidationProbe.KEY, ProbeResult.failure(SCMLinkValidationProbe.KEY, ""), - UpdateCenterPluginPublicationProbe.KEY, ProbeResult.failure(UpdateCenterPluginPublicationProbe.KEY, "") - ), - Map.of( - SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, ""), - UpdateCenterPluginPublicationProbe.KEY, ProbeResult.failure(UpdateCenterPluginPublicationProbe.KEY, "") - ), - Map.of( - SCMLinkValidationProbe.KEY, ProbeResult.failure(SCMLinkValidationProbe.KEY, ""), - UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") - ) - ); - - final NumberOfOpenIssuesProbe probe = getSpy(); - assertThat(probe.apply(plugin, ctx)) - .usingRecursiveComparison() - .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.error(NumberOfOpenIssuesProbe.KEY, "open-issue does not meet the criteria to be executed on null")); - verify(probe, never()).doApply(plugin, ctx); - } - - @Test - void shouldBeAbleToFindNumberOfOpenIssuesInBothJiraGH() throws IOException { - final String pluginName = "maven-repo-cleaner"; - final String repository = "jenkinsci/" + pluginName + "-plugin"; - final String scmLink = "https://github.com/" + repository; - - final Plugin plugin = mock(Plugin.class); - final ProbeContext ctx = mock(ProbeContext.class); - final GitHub gh = mock(GitHub.class); - final GHRepository ghRepository = mock(GHRepository.class); - - when(plugin.getDetails()).thenReturn( - Map.of( - SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, ""), - UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") - ) - ); - - when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of(), - Map.of(), - List.of(), - List.of( - Map.of( - "reportUrl", - "https://www.jenkins.io/participate/report-issue/redirect/#15979", - "type", - "jira", - "viewUrl", - "https://issues.jenkins.io/issues/?jql=component=15979" - ), - Map.of( - "reportUrl", - "https://github.com/jenkinsci/maven-repo-cleaner-plugin/issues/new/choose", - "type", - "github", - "viewUrl", - "https://github.com/jenkinsci/maven-repo-cleaner-plugin/issues" - ) - ) - )); - when(plugin.getName()).thenReturn(pluginName); - when(plugin.getScm()).thenReturn(scmLink); - - when(ctx.getGitHub()).thenReturn(gh); - when(ctx.getRepositoryName(scmLink)).thenReturn(Optional.of(repository)); - when(gh.getRepository(repository)).thenReturn(ghRepository); - when(ghRepository.getOpenIssueCount()).thenReturn(10); - - final NumberOfOpenIssuesProbe probe = getSpy(); - - assertThat(probe.apply(plugin, ctx)) - .usingRecursiveComparison() - .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "6 open issues found in JIRA. 10 open issues found in GitHub.")); - verify(probe).doApply(plugin, ctx); - } - - @Test - void shouldBeAbleToFindNumberOfOpenIssuesOnlyInJira() throws JsonProcessingException { - final String pluginName = "mailer"; - final String repository = "jenkinsci/" + pluginName + "-plugin"; - final String scmLink = "https://github.com/" + repository; - - final Plugin plugin = mock(Plugin.class); - final ProbeContext ctx = mock(ProbeContext.class); - JsonNode jsonNodeMock = mock(JsonNode.class); - RestTemplate restTemplate = mock(RestTemplate.class); - ResponseEntity responseEntity = mock(ResponseEntity.class); - - final String jsonString = "{\"expand\":\"names,schema\",\"startAt\":0,\"maxResults\":50,\"total\":1,\"issues\":[]}"; - - when(plugin.getDetails()).thenReturn( - Map.of( - SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, ""), - UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") - ) - ); - - when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of(), - Map.of(), - List.of(), - List.of( - Map.of( - "reportUrl", - "https://www.jenkins.io/participate/report-issue/redirect/#18331", - "type", - "jira", - "viewUrl", - "https://issues.jenkins.io/issues/?jql=component=18331" - ) - ) - )); - - when(plugin.getName()).thenReturn(pluginName); - when(plugin.getScm()).thenReturn(scmLink); - when(ctx.getRepositoryName(scmLink)).thenReturn(Optional.of(repository)); - when(restTemplate.getForEntity(anyString(), anyString().getClass())).thenReturn(responseEntity); - when(responseEntity.getBody()).thenReturn(jsonString); - when(jsonNodeMock.get("total")).thenReturn(new IntNode(10)); - - final NumberOfOpenIssuesProbe probe = getSpy(); - - assertThat(probe.apply(plugin, ctx)) - .usingRecursiveComparison() - .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "0 open issues found in JIRA.")); - verify(probe).doApply(plugin, ctx); - } - - @Test - void shouldBeAbleToFindNumberOfOpenIssuesOnlyInGH() throws IOException { - final String pluginName = "cloudevents"; - final String repository = "jenkinsci/" + pluginName + "-plugin"; - final String scmLink = "https://github.com/" + repository; - - final Plugin plugin = mock(Plugin.class); - final ProbeContext ctx = mock(ProbeContext.class); - final GitHub gh = mock(GitHub.class); - final GHRepository ghRepository = mock(GHRepository.class); - - when(plugin.getName()).thenReturn(pluginName); - when(plugin.getDetails()).thenReturn( - Map.of( - SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, ""), - UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") - ) - ); - - when(plugin.getScm()).thenReturn(scmLink); - when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of(), - Map.of(), - List.of(), - List.of( - Map.of( - "reportUrl", - "https://github.com/" + repository + "/issues/new/choose", - "type", - "github", - "viewUrl", - "https://github.com/" + repository + "/issues" - ) - ) - )); - when(ctx.getGitHub()).thenReturn(gh); - when(ctx.getRepositoryName(plugin.getScm())).thenReturn(Optional.of(repository)); - when(gh.getRepository(repository)).thenReturn(ghRepository); - when(ghRepository.getOpenIssueCount()).thenReturn(6); - - final NumberOfOpenIssuesProbe probe = getSpy(); - - assertThat(probe.apply(plugin, ctx)) - .usingRecursiveComparison() - .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(NumberOfOpenIssuesProbe.KEY, "6 open issues found in GitHub.")); - verify(probe).doApply(plugin, ctx); - - } -} - - - From d9604480987df2a356d2dfb15cf6be45412951e5 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sat, 5 Aug 2023 22:58:27 +0530 Subject: [PATCH 15/44] Fixing checkstyle issues --- .../scoring/probes/AbstractOpenIssuesProbe.java | 6 ++---- .../pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java | 3 --- .../scoring/probes/IssueTrackerDetectionProbe.java | 2 +- .../scoring/probes/DeprecatedPluginProbeTest.java | 3 ++- .../scoring/probes/IssueTrackerDetectionProbeTest.java | 5 +++-- .../scoring/probes/JiraOpenIssuesProbeTest.java | 2 -- .../pluginhealth/scoring/probes/UpForAdoptionProbeTest.java | 6 ++++-- 7 files changed, 12 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java index b60bb70fa..51394d74f 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java @@ -63,9 +63,7 @@ protected ProbeResult doApply(Plugin plugin, ProbeContext context) { @Override public String[] getProbeResultRequirement() { - return new String[] { - SCMLinkValidationProbe.KEY, IssueTrackerDetectionProbe.KEY - }; + return new String[] {SCMLinkValidationProbe.KEY, IssueTrackerDetectionProbe.KEY}; } /** @@ -90,7 +88,7 @@ protected ProbeResult getJiraIssues(String viewJiraIssuesUrl, String pluginName) } URL url = new URL(viewJiraIssuesUrl); String api = JIRA_HOST + url.getQuery() + " AND status=open"; - System.out.println("api = " + api); + RestTemplate restTemplate = new RestTemplate(); ResponseEntity response = restTemplate.getForEntity(api, String.class); ObjectMapper objectMapper = new ObjectMapper(); diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java index c7df5e859..40151b613 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java @@ -24,9 +24,6 @@ package io.jenkins.pluginhealth.scoring.probes; -import io.jenkins.pluginhealth.scoring.model.Plugin; -import io.jenkins.pluginhealth.scoring.model.ProbeResult; - import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java index eec5b112d..26d74dffd 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java @@ -37,7 +37,7 @@ @Order(value = IssueTrackerDetectionProbe.ORDER) class IssueTrackerDetectionProbe extends Probe { public static final String KEY = "issue-tracker-detection"; - public static final int ORDER = UpdateCenterPluginPublicationProbe.ORDER + 100 ; + public static final int ORDER = UpdateCenterPluginPublicationProbe.ORDER + 100; @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java index 3ad9a8b41..ce81ff650 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java @@ -82,7 +82,8 @@ void shouldBeAbleToDetectDeprecatedPlugin() { when(plugin.getName()).thenReturn("foo"); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), + Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main", + List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), Map.of("bar", new Deprecation("find-the-reason-here"), "foo", new Deprecation("this-is-the-reason")), Collections.emptyList(), Collections.emptyList() diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java index be71cab75..c9dcebd72 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java @@ -33,6 +33,7 @@ import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.Objects; import io.jenkins.pluginhealth.scoring.model.Plugin; import io.jenkins.pluginhealth.scoring.model.ProbeResult; @@ -49,7 +50,7 @@ IssueTrackerDetectionProbe getSpy() { @Test void shouldDetectIssueTrackerInPlugin() throws IOException { final Plugin plugin = mock(Plugin.class); - final ProbeContext ctx =spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of(), List.of())));; + final ProbeContext ctx = spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of(), List.of())));; final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerGithub = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("github", "https://github.com/foo-plugin/issues", "https://github.com/foo-plugin/issues/new/choose"); final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerJira = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=18331", "https://www.jenkins.io/participate/report-issue/redirect/#18331"); final String pluginName = "foo"; @@ -78,7 +79,7 @@ void shouldDetectIssueTrackerInPlugin() throws IOException { .comparingOnlyFields("id", "status", "message") .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); - assert(ctx.getIssueTrackerType()).equals(Map.of("github","https://github.com/foo-plugin/issues", "jira", "https://issues.jenkins.io/issues/?jql=component=18331")); + assert Objects.equals(ctx.getIssueTrackerType(), Map.of("github", "https://github.com/foo-plugin/issues", "jira", "https://issues.jenkins.io/issues/?jql=component=18331")); verify(probe).doApply(plugin, ctx); } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java index 41d2a996b..dc60497dd 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java @@ -25,8 +25,6 @@ package io.jenkins.pluginhealth.scoring.probes; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java index 573e11971..113d0cb51 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java @@ -61,7 +61,8 @@ void shouldBeAbleToDetectPluginForAdoption() { when(plugin.getName()).thenReturn("foo"); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder", "adopt-this-plugin"), 0, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), + Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder", "adopt-this-plugin"), 0, "", "main", + List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), Collections.emptyMap(), Collections.emptyList(), Collections.emptyList() @@ -80,7 +81,8 @@ void shouldBeAbleToDetectPluginNotForAdoption() { when(plugin.getName()).thenReturn("foo"); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder"), 0, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), + Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder"), 0, "", "main", + List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), Collections.emptyMap(), Collections.emptyList(), Collections.emptyList() From eda1b13203ee42304d324ede399c88c955092f23 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sun, 6 Aug 2023 11:30:11 +0530 Subject: [PATCH 16/44] Fixed the test case for open jira issues count --- .../probes/AbstractOpenIssuesProbe.java | 3 +- .../probes/JiraOpenIssuesProbeTest.java | 33 ++++++++++++------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java index 51394d74f..b77228d81 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java @@ -49,6 +49,8 @@ public abstract class AbstractOpenIssuesProbe extends Probe { public static final int ORDER = IssueTrackerDetectionProbe.ORDER + 100; private static final String JIRA_HOST = "https://issues.jenkins.io/rest/api/latest/search?"; private static final Logger LOGGER = LoggerFactory.getLogger(AbstractOpenIssuesProbe.class); + RestTemplate restTemplate = new RestTemplate(); + @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { @@ -89,7 +91,6 @@ protected ProbeResult getJiraIssues(String viewJiraIssuesUrl, String pluginName) URL url = new URL(viewJiraIssuesUrl); String api = JIRA_HOST + url.getQuery() + " AND status=open"; - RestTemplate restTemplate = new RestTemplate(); ResponseEntity response = restTemplate.getForEntity(api, String.class); ObjectMapper objectMapper = new ObjectMapper(); String jsonResponse = response.getBody(); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java index dc60497dd..0af55c2c1 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java @@ -25,11 +25,9 @@ package io.jenkins.pluginhealth.scoring.probes; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; @@ -43,13 +41,18 @@ import io.jenkins.pluginhealth.scoring.model.updatecenter.UpdateCenter; import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.test.web.client.MockRestServiceServer; import org.springframework.web.client.RestTemplate; class JiraOpenIssuesProbeTest extends AbstractProbeTest { + @InjectMocks + JiraOpenIssuesProbe jiraOpenIssuesProbe = new JiraOpenIssuesProbe(); + @Override JiraOpenIssuesProbe getSpy() { return spy(JiraOpenIssuesProbe.class); @@ -95,10 +98,11 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() throws UnsupportedEncodingExce final String pluginName = "mailer"; final String repository = "jenkinsci/" + pluginName + "-plugin"; final String scmLink = "https://github.com/" + repository; - RestTemplate restTemplate = mock(RestTemplate.class); final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); + final RestTemplate mockedRestTemplate = mock(RestTemplate.class); + final ResponseEntity mockedResponseEntity = mock(ResponseEntity.class); final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerJira = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=18331", "https://www.jenkins.io/participate/report-issue/redirect/#18331"); @@ -126,18 +130,25 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() throws UnsupportedEncodingExce when(plugin.getScm()).thenReturn(scmLink); when(ctx.getIssueTrackerType()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); - MockRestServiceServer server = MockRestServiceServer.bindTo(restTemplate).build(); + MockRestServiceServer server = MockRestServiceServer.bindTo(mockedRestTemplate).build(); server.expect(requestTo("https://issues.jenkins.io/rest/api/latest/search?jql=component%3D18331%20AND%20status%3Dopen")) .andExpect(method(HttpMethod.GET)) .andRespond(withSuccess(jsonString, MediaType.APPLICATION_JSON)); - final JiraOpenIssuesProbe probe = getSpy(); + when(mockedResponseEntity.getBody()).thenReturn(jsonString); - assertThat(probe.apply(plugin, ctx)) + when(mockedRestTemplate.getForEntity( + anyString(), + any(Class.class) + )) + .thenReturn(mockedResponseEntity); + + jiraOpenIssuesProbe.restTemplate = mockedRestTemplate; + + assertThat(jiraOpenIssuesProbe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(JiraOpenIssuesProbe.KEY, "0 open issues found in JIRA.")); - verify(probe).doApply(plugin, ctx); + .isEqualTo(ProbeResult.success(JiraOpenIssuesProbe.KEY, "10 open issues found in JIRA.")); } } From 97aed2859ff749f41f0b064b251a53afa47fd5ff Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sun, 6 Aug 2023 11:56:48 +0530 Subject: [PATCH 17/44] Removing the issueTracker field from update center --- .../model/updatecenter/UpdateCenter.java | 4 +--- .../probes/AbstractOpenIssuesProbe.java | 1 - .../scoring/probes/CodeCoverageProbeTest.java | 7 ------ .../probes/DeprecatedPluginProbeTest.java | 4 ---- .../probes/GitHubOpenIssuesProbeTest.java | 1 - .../probes/InstallationStatProbeTest.java | 1 - .../IssueTrackerDetectionProbeTest.java | 3 +-- .../scoring/probes/JenkinsCoreProbeTest.java | 2 -- .../probes/JiraOpenIssuesProbeTest.java | 10 +++++---- .../KnownSecurityVulnerabilityProbeTest.java | 22 ++++++------------- .../scoring/probes/SpotBugsProbeTest.java | 3 --- .../probes/UpForAdoptionProbeTest.java | 3 --- ...pdateCenterPluginPublicationProbeTest.java | 2 -- .../scoring/probes/ProbeEngineTest.java | 1 - 14 files changed, 15 insertions(+), 49 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/UpdateCenter.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/UpdateCenter.java index 3bd7f673f..9d5b6f89e 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/UpdateCenter.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/UpdateCenter.java @@ -29,8 +29,6 @@ public record UpdateCenter(Map plugins, Map deprecations, - List warnings, - List> issueTrackers - + List warnings ) { } diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java index b77228d81..1a602f895 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java @@ -51,7 +51,6 @@ public abstract class AbstractOpenIssuesProbe extends Probe { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractOpenIssuesProbe.class); RestTemplate restTemplate = new RestTemplate(); - @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { Map> trackerMethods = createTrackerMethods(); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java index 98ca8c2c7..f929a8678 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java @@ -118,7 +118,6 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), - List.of(), List.of() )); when(ctx.getRepositoryName(plugin.getScm())).thenReturn(Optional.empty()); @@ -164,7 +163,6 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), - List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); @@ -223,7 +221,6 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), - List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); @@ -282,7 +279,6 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), - List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); @@ -341,7 +337,6 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), - List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); @@ -400,7 +395,6 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), - List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); @@ -459,7 +453,6 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), - List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java index ce81ff650..991a37a79 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java @@ -65,7 +65,6 @@ void shouldBeAbleToDetectNonDeprecatedPlugin() { Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), Map.of("bar", new Deprecation("find-the-reason-here")), - Collections.emptyList(), Collections.emptyList() )); @@ -85,7 +84,6 @@ void shouldBeAbleToDetectDeprecatedPlugin() { Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), Map.of("bar", new Deprecation("find-the-reason-here"), "foo", new Deprecation("this-is-the-reason")), - Collections.emptyList(), Collections.emptyList() )); @@ -108,7 +106,6 @@ pluginName, new Plugin(pluginName, new VersionNumber("1.0"), "", ZonedDateTime.n List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", ""))) ), Map.of(), - Collections.emptyList(), Collections.emptyList() )); @@ -131,7 +128,6 @@ void shouldSurviveIfPluginIsNotInUpdateCenter() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of(), Map.of(), - Collections.emptyList(), Collections.emptyList() )); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java index 0f42e2f46..3ed759297 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java @@ -113,7 +113,6 @@ void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { List.of(issueTrackerGithub) )), Map.of(), - List.of(), List.of() )); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java index 26d7fc6a9..07fa9d9bd 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java @@ -95,7 +95,6 @@ void shouldBeAbleToFindInstallationCountInUpdateCenter() { new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin(pluginName, null, null, null, List.of(), 100, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", ""))) ), Map.of(), - List.of(), List.of() )); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java index c9dcebd72..4d72d07de 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java @@ -50,7 +50,7 @@ IssueTrackerDetectionProbe getSpy() { @Test void shouldDetectIssueTrackerInPlugin() throws IOException { final Plugin plugin = mock(Plugin.class); - final ProbeContext ctx = spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of(), List.of())));; + final ProbeContext ctx = spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of()))); final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerGithub = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("github", "https://github.com/foo-plugin/issues", "https://github.com/foo-plugin/issues/new/choose"); final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerJira = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=18331", "https://www.jenkins.io/participate/report-issue/redirect/#18331"); final String pluginName = "foo"; @@ -68,7 +68,6 @@ void shouldDetectIssueTrackerInPlugin() throws IOException { List.of(issueTrackerGithub, issueTrackerJira) )), Map.of(), - List.of(), List.of() )); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java index 261fcba01..da31fa46a 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java @@ -67,7 +67,6 @@ void shouldFailIfPluginNotInUpdateCenter() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of(), Map.of(), - List.of(), List.of() )); @@ -101,7 +100,6 @@ void shouldBeAbleToExtractJenkinsVersionFromUpdateCenter() { ) ), Map.of(), - List.of(), List.of() )); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java index 0af55c2c1..54ab2651e 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java @@ -27,12 +27,15 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; -import java.io.UnsupportedEncodingException; import java.util.List; import java.util.Map; @@ -94,7 +97,7 @@ void shouldNotRunWithInvalidProbeResultRequirement() { } @Test - void shouldBeAbleToFindNumberOfOpenIssuesInJira() throws UnsupportedEncodingException { + void shouldBeAbleToFindNumberOfOpenIssuesInJira() { final String pluginName = "mailer"; final String repository = "jenkinsci/" + pluginName + "-plugin"; final String scmLink = "https://github.com/" + repository; @@ -122,7 +125,6 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() throws UnsupportedEncodingExce List.of(issueTrackerJira) )), Map.of(), - List.of(), List.of() )); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java index 3eef947ee..6794e0a53 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java @@ -65,7 +65,6 @@ void shouldBeOKWithNoSecurityWarning() { new UpdateCenter( Collections.emptyMap(), Collections.emptyMap(), - Collections.emptyList(), Collections.emptyList() ) ); @@ -90,8 +89,7 @@ void shouldBeOKWithWarningOnDifferentPlugin() { Collections.emptyMap(), List.of( new SecurityWarning("SECURITY-1", "wiz", List.of(new SecurityWarningVersion(null, ".*"))) - ), - List.of() + ) ) ); @@ -119,8 +117,7 @@ void shouldBeOKWithWarningOnOlderVersion() { new SecurityWarning("SECURITY-1", pluginName, List.of( new SecurityWarningVersion(new VersionNumber("1.0"), "0\\.*") )) - ), - List.of() + ) ) ); @@ -147,8 +144,7 @@ void shouldNotBeOKWithWarningOnCurrentVersion() { Collections.emptyMap(), List.of( new SecurityWarning(warningId, pluginName, List.of(new SecurityWarningVersion(pluginVersion, "1.0"))) - ), - List.of() + ) ) ); @@ -176,8 +172,7 @@ void shouldNotBeOKWithWarningWithoutLastVersion() { Collections.emptyMap(), List.of( new SecurityWarning(warningId, pluginName, List.of(new SecurityWarningVersion(null, ".*"))) - ), - List.of() + ) ) ); @@ -207,8 +202,7 @@ void shouldNotBeOKWithMultipleWarningsWithoutLastVersion() { List.of( new SecurityWarning(warningId1, pluginName, List.of(new SecurityWarningVersion(null, ".*"))), new SecurityWarning(warningId2, pluginName, List.of(new SecurityWarningVersion(null, ".*"))) - ), - List.of() + ) ) ); @@ -238,8 +232,7 @@ void shouldNotBeOKWithWarningWithoutLastVersionAndOneResolved() { List.of( new SecurityWarning(warningId1, pluginName, List.of(new SecurityWarningVersion(null, ".*"))), new SecurityWarning(warningId2, pluginName, List.of(new SecurityWarningVersion(new VersionNumber("1.1"), ".*"))) - ), - List.of() + ) ) ); @@ -266,8 +259,7 @@ void shouldBeOKWithWarningWithoutLastVersionButOutOfPattern() { Collections.emptyMap(), List.of( new SecurityWarning("SECURITY-1", pluginName, List.of(new SecurityWarningVersion(null, "[0-1]\\..*"))) - ), - List.of() + ) ) ); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java index 86f5d9b10..1eb4280d3 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java @@ -91,7 +91,6 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), - List.of(), List.of() )); when(ctx.getRepositoryName(plugin.getScm())).thenReturn(Optional.empty()); @@ -134,7 +133,6 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), - List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); @@ -187,7 +185,6 @@ pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0 ) ), Map.of(), - List.of(), List.of() )); when(ctx.getGitHub()).thenReturn(gh); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java index 113d0cb51..43c4c32d4 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java @@ -64,7 +64,6 @@ void shouldBeAbleToDetectPluginForAdoption() { Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder", "adopt-this-plugin"), 0, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), Collections.emptyMap(), - Collections.emptyList(), Collections.emptyList() )); @@ -84,7 +83,6 @@ void shouldBeAbleToDetectPluginNotForAdoption() { Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder"), 0, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), Collections.emptyMap(), - Collections.emptyList(), Collections.emptyList() )); @@ -103,7 +101,6 @@ void shouldFailWhenPluginNotPresentInUpdateCenter() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of(), Map.of(), - List.of(), List.of() )); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java index 972eef161..fe4886203 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java @@ -60,7 +60,6 @@ void shouldFailIfPluginIsNotInUpdateCenterMap() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of(), Map.of(), - Collections.emptyList(), Collections.emptyList() )); @@ -85,7 +84,6 @@ void shouldSucceedIfPluginIsInUpdateCenterMap() { pluginName, null, null, null, List.of(), 0, "2.361.1", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) )), Map.of(), - List.of(), List.of() )); diff --git a/war/src/test/java/io/jenkins/pluginhealth/scoring/probes/ProbeEngineTest.java b/war/src/test/java/io/jenkins/pluginhealth/scoring/probes/ProbeEngineTest.java index 36504ab92..6e06c2091 100644 --- a/war/src/test/java/io/jenkins/pluginhealth/scoring/probes/ProbeEngineTest.java +++ b/war/src/test/java/io/jenkins/pluginhealth/scoring/probes/ProbeEngineTest.java @@ -71,7 +71,6 @@ void setup() throws IOException { when(updateCenterService.fetchUpdateCenter()).thenReturn(new UpdateCenter( Map.of(), Map.of(), - List.of(), List.of() )); } From 528ab43b662e4600fc0b4f02d95e215424dd2b1a Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sun, 6 Aug 2023 12:43:30 +0530 Subject: [PATCH 18/44] Added a narrowed depedency in pom file and removed unwanted mock in jira issues test case --- core/pom.xml | 4 ++-- .../scoring/probes/JiraOpenIssuesProbeTest.java | 11 ----------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index ef38c2d37..bcb27e3d4 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -103,8 +103,8 @@ test - org.springframework.boot - spring-boot-starter-web + org.springframework + spring-web diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java index 54ab2651e..c4e535926 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java @@ -32,9 +32,6 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; -import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; -import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; import java.util.List; import java.util.Map; @@ -45,10 +42,7 @@ import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.test.web.client.MockRestServiceServer; import org.springframework.web.client.RestTemplate; class JiraOpenIssuesProbeTest extends AbstractProbeTest { @@ -132,11 +126,6 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() { when(plugin.getScm()).thenReturn(scmLink); when(ctx.getIssueTrackerType()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); - MockRestServiceServer server = MockRestServiceServer.bindTo(mockedRestTemplate).build(); - server.expect(requestTo("https://issues.jenkins.io/rest/api/latest/search?jql=component%3D18331%20AND%20status%3Dopen")) - .andExpect(method(HttpMethod.GET)) - .andRespond(withSuccess(jsonString, MediaType.APPLICATION_JSON)); - when(mockedResponseEntity.getBody()).thenReturn(jsonString); when(mockedRestTemplate.getForEntity( From 5f22f3839afd97a2daccdfcb2d2f64bfeabf8f99 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sun, 6 Aug 2023 13:09:31 +0530 Subject: [PATCH 19/44] Added more test case for IssueTrackerDetectionProbe --- .../probes/AbstractOpenIssuesProbe.java | 6 +- .../IssueTrackerDetectionProbeTest.java | 93 ++++++++++++++++++- 2 files changed, 92 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java index 1a602f895..7c033a9ef 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java @@ -59,7 +59,7 @@ protected ProbeResult doApply(Plugin plugin, ProbeContext context) { if (getOpenIssues != null) { return getOpenIssues.apply(plugin, context); } - return ProbeResult.failure(key(), String.format("Could not find a valid issue tracker type for plugin {}", plugin.getName())); + return ProbeResult.error(key(), String.format("Cannot not find a valid issue tracker type for plugin {}", plugin.getName())); } @Override @@ -88,7 +88,7 @@ protected ProbeResult getJiraIssues(String viewJiraIssuesUrl, String pluginName) return ProbeResult.failure(key(), String.format("JIRA issues is not configured for %s plugin.", pluginName)); } URL url = new URL(viewJiraIssuesUrl); - String api = JIRA_HOST + url.getQuery() + " AND status=open"; + String api = JIRA_HOST.concat(url.getQuery()).concat(" AND status=open"); ResponseEntity response = restTemplate.getForEntity(api, String.class); ObjectMapper objectMapper = new ObjectMapper(); @@ -103,7 +103,7 @@ protected ProbeResult getJiraIssues(String viewJiraIssuesUrl, String pluginName) } catch (MalformedURLException e) { LOGGER.error("Cannot process malformed URL for plugin {}.", pluginName, e); } - return ProbeResult.failure(key(), String.format("Cannot fetch information from JIRA API for plugin %s.", pluginName)); + return ProbeResult.error(key(), String.format("Cannot fetch information from JIRA API for plugin %s.", pluginName)); } /** diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java index 4d72d07de..8c9a20850 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java @@ -25,10 +25,7 @@ package io.jenkins.pluginhealth.scoring.probes; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; import java.io.IOException; import java.util.List; @@ -47,6 +44,26 @@ IssueTrackerDetectionProbe getSpy() { return spy(IssueTrackerDetectionProbe.class); } + @Test + void shouldNotRunWithInvalidProbeResultRequirement() { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = mock(ProbeContext.class); + + when(plugin.getDetails()).thenReturn( + Map.of(), + Map.of( + UpdateCenterPluginPublicationProbe.KEY, ProbeResult.failure(UpdateCenterPluginPublicationProbe.KEY, "") + ) + ); + + final IssueTrackerDetectionProbe probe = getSpy(); + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.error(IssueTrackerDetectionProbe.KEY, "issue-tracker-detection does not meet the criteria to be executed on null")); + verify(probe, never()).doApply(plugin, ctx); + } + @Test void shouldDetectIssueTrackerInPlugin() throws IOException { final Plugin plugin = mock(Plugin.class); @@ -82,4 +99,72 @@ void shouldDetectIssueTrackerInPlugin() throws IOException { verify(probe).doApply(plugin, ctx); } + @Test + void shouldDetectForOnlyGHInIssueTracker() throws IOException { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of()))); + final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerGithub = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("github", "https://github.com/foo-plugin/issues", "https://github.com/foo-plugin/issues/new/choose"); + final String pluginName = "foo"; + + when(plugin.getDetails()).thenReturn( + Map.of( + UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") + ) + ); + + when(plugin.getName()).thenReturn(pluginName); + when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( + Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, null, null, null, List.of(), 0, "2.361.1", "main", + List.of(issueTrackerGithub) + )), + Map.of(), + List.of() + )); + + final IssueTrackerDetectionProbe probe = getSpy(); + + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); + + assert Objects.equals(ctx.getIssueTrackerType(), Map.of("github", "https://github.com/foo-plugin/issues")); + verify(probe).doApply(plugin, ctx); + } + + @Test + void shouldDetectForOnlyJIRAInIssueTracker() throws IOException { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of()))); + final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerJira = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=18331", "https://www.jenkins.io/participate/report-issue/redirect/#18331"); + final String pluginName = "foo"; + + when(plugin.getDetails()).thenReturn( + Map.of( + UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") + ) + ); + + when(plugin.getName()).thenReturn(pluginName); + when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( + Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, null, null, null, List.of(), 0, "2.361.1", "main", + List.of(issueTrackerJira) + )), + Map.of(), + List.of() + )); + + final IssueTrackerDetectionProbe probe = getSpy(); + + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); + + assert Objects.equals(ctx.getIssueTrackerType(), Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); + verify(probe).doApply(plugin, ctx); + } + } From e13f3a83381292d101d7100bd08bc09b665ab8ce Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sun, 6 Aug 2023 14:56:16 +0530 Subject: [PATCH 20/44] Fixed checkstyle issues --- .../scoring/probes/IssueTrackerDetectionProbeTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java index 8c9a20850..a3dc18b2c 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java @@ -25,7 +25,11 @@ package io.jenkins.pluginhealth.scoring.probes; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.io.IOException; import java.util.List; From 9bcb49ed85fb57bc9813692387c30b0c165e285a Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sun, 6 Aug 2023 17:01:23 +0530 Subject: [PATCH 21/44] Adding more test case for jira open issues --- .../probes/AbstractOpenIssuesProbe.java | 8 ++- .../probes/JiraOpenIssuesProbeTest.java | 57 ++++++++++++++++++- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java index 7c033a9ef..cf9d304ff 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java @@ -82,10 +82,10 @@ private Optional getTrackerUrl(Map trackerType) { /** * Get total number of open JIRA issues in a plugin */ - protected ProbeResult getJiraIssues(String viewJiraIssuesUrl, String pluginName) { + private ProbeResult getJiraIssues(String viewJiraIssuesUrl, String pluginName) { try { if (viewJiraIssuesUrl.isEmpty()) { - return ProbeResult.failure(key(), String.format("JIRA issues is not configured for %s plugin.", pluginName)); + return ProbeResult.failure(key(), String.format("JIRA issues not found in Update Center for %s plugin.", pluginName)); } URL url = new URL(viewJiraIssuesUrl); String api = JIRA_HOST.concat(url.getQuery()).concat(" AND status=open"); @@ -94,6 +94,10 @@ protected ProbeResult getJiraIssues(String viewJiraIssuesUrl, String pluginName) ObjectMapper objectMapper = new ObjectMapper(); String jsonResponse = response.getBody(); JsonNode jsonNode = objectMapper.readTree(jsonResponse); + + if (jsonNode.get("errorMessages") != null) { + return ProbeResult.error(key(), String.format("Error returned from JIRA API for plugin %s. %s", pluginName, jsonNode.get("errorMessages"))); + } int openJIRAIssues = jsonNode.get("total").asInt(); return ProbeResult.success(key(), String.format("%d open issues found in JIRA.", openJIRAIssues)); } catch (JsonMappingException e) { diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java index c4e535926..56949d89e 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java @@ -48,7 +48,7 @@ class JiraOpenIssuesProbeTest extends AbstractProbeTest { @InjectMocks - JiraOpenIssuesProbe jiraOpenIssuesProbe = new JiraOpenIssuesProbe(); + JiraOpenIssuesProbe jiraOpenIssuesProbe = new JiraOpenIssuesProbe(); @Override JiraOpenIssuesProbe getSpy() { @@ -104,7 +104,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() { final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerJira = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=18331", "https://www.jenkins.io/participate/report-issue/redirect/#18331"); - final String jsonString = "{\"expand\":\"names,schema\",\"startAt\":0,\"maxResults\":50,\"total\":10,\"issues\":[]}"; + final String JSONString = "{\"expand\":\"names,schema\",\"startAt\":0,\"maxResults\":50,\"total\":10,\"issues\":[]}"; when(plugin.getDetails()).thenReturn( Map.of( @@ -126,7 +126,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() { when(plugin.getScm()).thenReturn(scmLink); when(ctx.getIssueTrackerType()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); - when(mockedResponseEntity.getBody()).thenReturn(jsonString); + when(mockedResponseEntity.getBody()).thenReturn(JSONString); when(mockedRestTemplate.getForEntity( anyString(), @@ -142,4 +142,55 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() { .isEqualTo(ProbeResult.success(JiraOpenIssuesProbe.KEY, "10 open issues found in JIRA.")); } + @Test + void shouldReturnErrorWhenJIRAReturnsErrors() { + final String pluginName = "foo"; + final String repository = "jenkinsci/" + pluginName + "-plugin"; + final String scmLink = "https://github.com/" + repository; + + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = mock(ProbeContext.class); + final RestTemplate mockedRestTemplate = mock(RestTemplate.class); + final ResponseEntity mockedResponseEntity = mock(ResponseEntity.class); + + final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerJira = + new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=0", "https://www.jenkins.io/participate/report-issue/redirect/#0"); + + final String errorJSONString = "{\"errorMessages\":[\"A value with ID '0' does not exist for the field 'component'.\"],\"errors\":{}}"; + + when(plugin.getDetails()).thenReturn( + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, ""), + IssueTrackerDetectionProbe.KEY, ProbeResult.success(IssueTrackerDetectionProbe.KEY, "") + ) + ); + + when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( + Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, null, null, null, List.of(), 0, "2.361.1", "main", + List.of(issueTrackerJira) + )), + Map.of(), + List.of() + )); + + when(plugin.getName()).thenReturn(pluginName); + when(plugin.getScm()).thenReturn(scmLink); + when(ctx.getIssueTrackerType()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=0")); + + when(mockedResponseEntity.getBody()).thenReturn(errorJSONString); + + when(mockedRestTemplate.getForEntity( + anyString(), + any(Class.class) + )).thenReturn(mockedResponseEntity); + + jiraOpenIssuesProbe.restTemplate = mockedRestTemplate; + + assertThat(jiraOpenIssuesProbe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.error(JiraOpenIssuesProbe.KEY, "Error returned from JIRA API for plugin foo. [\"A value with ID '0' does not exist for the field 'component'.\"]")); + } } + From 4989e811f6c028845992115dd858ddb965c372e9 Mon Sep 17 00:00:00 2001 From: Jagruti Tiwari Date: Tue, 8 Aug 2023 19:57:07 +0530 Subject: [PATCH 22/44] Apply suggestions from code review Co-authored-by: Adrien Lecharpentier --- .../scoring/probes/IssueTrackerDetectionProbeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java index a3dc18b2c..d6fb42b6d 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java @@ -42,7 +42,7 @@ import org.junit.jupiter.api.Test; -class IssueTrackerDetectionProbeTest extends AbstractProbeTest { +class IssueTrackerDetectionProbeTest extends AbstractProbeTest { @Override IssueTrackerDetectionProbe getSpy() { return spy(IssueTrackerDetectionProbe.class); From 7db7e7a23932ecfef7d4c0ad2e856e0eb887c431 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Wed, 9 Aug 2023 15:07:58 +0530 Subject: [PATCH 23/44] Fixed the abstract class and updated test cases --- .../probes/AbstractOpenIssuesProbe.java | 102 +----------------- .../scoring/probes/GitHubOpenIssuesProbe.java | 30 +++++- .../probes/IssueTrackerDetectionProbe.java | 10 +- .../scoring/probes/JiraOpenIssuesProbe.java | 55 +++++++++- .../scoring/probes/ProbeContext.java | 10 +- .../IssueTrackerDetectionProbeTest.java | 34 +++++- .../probes/JiraOpenIssuesProbeTest.java | 4 +- 7 files changed, 129 insertions(+), 116 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java index cf9d304ff..d4ba62c5a 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java @@ -24,114 +24,16 @@ package io.jenkins.pluginhealth.scoring.probes; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.function.BiFunction; - import io.jenkins.pluginhealth.scoring.model.Plugin; import io.jenkins.pluginhealth.scoring.model.ProbeResult; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.kohsuke.github.GHRepository; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; - public abstract class AbstractOpenIssuesProbe extends Probe { public static final int ORDER = IssueTrackerDetectionProbe.ORDER + 100; - private static final String JIRA_HOST = "https://issues.jenkins.io/rest/api/latest/search?"; - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractOpenIssuesProbe.class); - RestTemplate restTemplate = new RestTemplate(); - @Override - protected ProbeResult doApply(Plugin plugin, ProbeContext context) { - Map> trackerMethods = createTrackerMethods(); - BiFunction getOpenIssues = trackerMethods.get(getTrackerType()); - - if (getOpenIssues != null) { - return getOpenIssues.apply(plugin, context); - } - return ProbeResult.error(key(), String.format("Cannot not find a valid issue tracker type for plugin {}", plugin.getName())); - } + abstract ProbeResult getNumberOfOpenIssues(Plugin plugin, ProbeContext context); @Override public String[] getProbeResultRequirement() { - return new String[] {SCMLinkValidationProbe.KEY, IssueTrackerDetectionProbe.KEY}; + return new String[] { SCMLinkValidationProbe.KEY, IssueTrackerDetectionProbe.KEY }; } - - /** - * @return a String the tracker "type" present in the "issueTrackers" in UpdateCenter. For ex: jira, github - */ - public abstract String getTrackerType(); - - private Optional getTrackerUrl(Map trackerType) { - return trackerType.entrySet().stream() - .filter(entry -> entry.getKey().equals(getTrackerType())) - .findFirst() - .map(entry -> entry.getValue()); - } - - /** - * Get total number of open JIRA issues in a plugin - */ - private ProbeResult getJiraIssues(String viewJiraIssuesUrl, String pluginName) { - try { - if (viewJiraIssuesUrl.isEmpty()) { - return ProbeResult.failure(key(), String.format("JIRA issues not found in Update Center for %s plugin.", pluginName)); - } - URL url = new URL(viewJiraIssuesUrl); - String api = JIRA_HOST.concat(url.getQuery()).concat(" AND status=open"); - - ResponseEntity response = restTemplate.getForEntity(api, String.class); - ObjectMapper objectMapper = new ObjectMapper(); - String jsonResponse = response.getBody(); - JsonNode jsonNode = objectMapper.readTree(jsonResponse); - - if (jsonNode.get("errorMessages") != null) { - return ProbeResult.error(key(), String.format("Error returned from JIRA API for plugin %s. %s", pluginName, jsonNode.get("errorMessages"))); - } - int openJIRAIssues = jsonNode.get("total").asInt(); - return ProbeResult.success(key(), String.format("%d open issues found in JIRA.", openJIRAIssues)); - } catch (JsonMappingException e) { - LOGGER.error("Cannot map JSON returned by JIRA API for plugin {}.", pluginName, e); - } catch (JsonProcessingException e) { - LOGGER.error("Cannot process JSON returned by JIRA API for plugin {}.", pluginName, e); - } catch (MalformedURLException e) { - LOGGER.error("Cannot process malformed URL for plugin {}.", pluginName, e); - } - return ProbeResult.error(key(), String.format("Cannot fetch information from JIRA API for plugin %s.", pluginName)); - } - - /** - * Get total number of open GitHub issues in a plugin - */ - private ProbeResult getGitHubIssues(ProbeContext context, Plugin plugin) { - try { - final Optional repositoryName = context.getRepositoryName(plugin.getScm()); - if (repositoryName.isPresent()) { - final GHRepository ghRepository = context.getGitHub().getRepository(repositoryName.get()); - int openGitHubIssues = ghRepository.getOpenIssueCount(); - return ProbeResult.success(key(), String.format("%d open issues found in GitHub.", openGitHubIssues)); - } - } catch (IOException ex) { - return ProbeResult.error(key(), String.format("Cannot not read open issues on GitHub for plugin %s.", plugin.getName())); - } - return ProbeResult.failure(key(), String.format("Cannot find GitHub repository for plugin %s.", plugin.getName())); - } - - private Map> createTrackerMethods() { - Map> trackerMethods = new HashMap<>(); - trackerMethods.put("jira", (plugin, context) -> getJiraIssues(getTrackerUrl(context.getIssueTrackerType()).orElse(""), plugin.getName())); - trackerMethods.put("github", (plugin, context) -> getGitHubIssues(context, plugin)); - return trackerMethods; - } - } diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java index 40151b613..a95b8f7a8 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java @@ -24,6 +24,13 @@ package io.jenkins.pluginhealth.scoring.probes; +import java.io.IOException; +import java.util.Optional; + +import io.jenkins.pluginhealth.scoring.model.Plugin; +import io.jenkins.pluginhealth.scoring.model.ProbeResult; + +import org.kohsuke.github.GHRepository; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -33,8 +40,27 @@ class GitHubOpenIssuesProbe extends AbstractOpenIssuesProbe { public static final String KEY = "github-open-issues"; @Override - public String getTrackerType() { - return "github"; + protected ProbeResult doApply(Plugin plugin, ProbeContext context) { + return getNumberOfOpenIssues(plugin, context); + } + + /** + * Get total number of open GitHub issues in a plugin + */ + @Override + ProbeResult getNumberOfOpenIssues(Plugin plugin, ProbeContext context) { + try { + final Optional repositoryName = context.getRepositoryName(plugin.getScm()); + if (repositoryName.isPresent()) { + final GHRepository ghRepository = context.getGitHub().getRepository(repositoryName.get()); + int openGitHubIssues = ghRepository.getOpenIssueCount(); + return ProbeResult.success(key(), String.format("%d open issues found in GitHub.", openGitHubIssues)); + } + } catch (IOException ex) { + return ProbeResult.error(key(), String.format("Cannot not read open issues on GitHub for plugin %s.", plugin.getName())); + } + return ProbeResult.failure(key(), String.format("Cannot find GitHub repository for plugin %s.", plugin.getName())); + } @Override diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java index 26d74dffd..b2551e25b 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java @@ -32,6 +32,7 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; @Component @Order(value = IssueTrackerDetectionProbe.ORDER) @@ -41,7 +42,12 @@ class IssueTrackerDetectionProbe extends Probe { @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { - context.setIssueTrackType(getIssueTrackerData(context.getUpdateCenter().plugins())); + Map issueTrackerDetails = getIssueTrackerData(context.getUpdateCenter().plugins()); + + if (CollectionUtils.isEmpty(issueTrackerDetails)) { + return ProbeResult.failure(key(), String.format("%s plugin does not exists in Update Center.", plugin.getName())); + } + context.setIssueTrackerNameAndUrl(getIssueTrackerData(context.getUpdateCenter().plugins())); return ProbeResult.success(key(), "Issue tracker detected and returned successfully."); } @@ -57,7 +63,7 @@ public String getDescription() { @Override public String[] getProbeResultRequirement() { - return new String[]{UpdateCenterPluginPublicationProbe.KEY}; + return new String[]{ UpdateCenterPluginPublicationProbe.KEY }; } private Map getIssueTrackerData(Map plugin) { diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java index 0593fe13a..2d9a20179 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java @@ -24,17 +24,68 @@ package io.jenkins.pluginhealth.scoring.probes; +import java.net.MalformedURLException; +import java.net.URL; + +import io.jenkins.pluginhealth.scoring.model.Plugin; +import io.jenkins.pluginhealth.scoring.model.ProbeResult; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; @Component @Order(AbstractOpenIssuesProbe.ORDER) class JiraOpenIssuesProbe extends AbstractOpenIssuesProbe { public static final String KEY = "jira-open-issues"; + private static final String JIRA_HOST = "https://issues.jenkins.io/rest/api/latest/search?"; + private static final Logger LOGGER = LoggerFactory.getLogger(JiraOpenIssuesProbe.class); + RestTemplate restTemplate = new RestTemplate(); + + @Override + protected ProbeResult doApply(Plugin plugin, ProbeContext context) { + return getNumberOfOpenIssues(plugin, context); + } + /** + * Get total number of open JIRA issues in a plugin + */ @Override - public String getTrackerType() { - return "jira"; + ProbeResult getNumberOfOpenIssues(Plugin plugin, ProbeContext context) { + String viewJiraIssuesUrl = context.getIssueTrackerNameAndUrl().get("jira"); + + try { + if (viewJiraIssuesUrl == null || viewJiraIssuesUrl.isEmpty()) { + return ProbeResult.failure(key(), String.format("JIRA issues not found in Update Center for %s plugin.", plugin.getName())); + } + URL url = new URL(viewJiraIssuesUrl); + String api = JIRA_HOST.concat(url.getQuery()).concat(" AND status=open"); + + ResponseEntity response = restTemplate.getForEntity(api, String.class); + ObjectMapper objectMapper = new ObjectMapper(); + String jsonResponse = response.getBody(); + JsonNode jsonNode = objectMapper.readTree(jsonResponse); + + if (jsonNode.get("errorMessages") != null) { + return ProbeResult.error(key(), String.format("Error returned from JIRA API for plugin %s. %s", plugin.getName(), jsonNode.get("errorMessages"))); + } + int openJIRAIssues = jsonNode.get("total").asInt(); + return ProbeResult.success(key(), String.format("%d open issues found in JIRA.", openJIRAIssues)); + } catch (JsonMappingException e) { + LOGGER.error("Cannot map JSON returned by JIRA API for plugin {}.", plugin.getName(), e); + } catch (JsonProcessingException e) { + LOGGER.error("Cannot process JSON returned by JIRA API for plugin {}.", plugin.getName(), e); + } catch (MalformedURLException e) { + LOGGER.error("Cannot process malformed URL for plugin {}.", plugin.getName(), e); + } + return ProbeResult.error(key(), String.format("Cannot fetch information from JIRA API for plugin %s.", plugin.getName())); } @Override diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java index 8bd2ec6f5..2ba11c6c7 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java @@ -45,7 +45,7 @@ public class ProbeContext { private GitHub github; private ZonedDateTime lastCommitDate; private Map pluginDocumentationLinks; - private Map issueTrackerType; + private Map issueTrackerNameAndUrl; public ProbeContext(String pluginName, UpdateCenter updateCenter) throws IOException { this.updateCenter = updateCenter; @@ -89,12 +89,12 @@ public Optional getRepositoryName(String scm) { return match.find() ? Optional.of(match.group("repo")) : Optional.empty(); } - public void setIssueTrackType(Map issueTrackerType) { - this.issueTrackerType = issueTrackerType; + public void setIssueTrackerNameAndUrl(Map issueTrackerNameAndUrl) { + this.issueTrackerNameAndUrl = issueTrackerNameAndUrl; } - public Map getIssueTrackerType() { - return issueTrackerType; + public Map getIssueTrackerNameAndUrl() { + return issueTrackerNameAndUrl; } /* default */ void cleanUp() throws IOException { diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java index d6fb42b6d..7dc500e63 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java @@ -99,7 +99,7 @@ void shouldDetectIssueTrackerInPlugin() throws IOException { .comparingOnlyFields("id", "status", "message") .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); - assert Objects.equals(ctx.getIssueTrackerType(), Map.of("github", "https://github.com/foo-plugin/issues", "jira", "https://issues.jenkins.io/issues/?jql=component=18331")); + assert Objects.equals(ctx.getIssueTrackerNameAndUrl(), Map.of("github", "https://github.com/foo-plugin/issues", "jira", "https://issues.jenkins.io/issues/?jql=component=18331")); verify(probe).doApply(plugin, ctx); } @@ -133,7 +133,7 @@ void shouldDetectForOnlyGHInIssueTracker() throws IOException { .comparingOnlyFields("id", "status", "message") .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); - assert Objects.equals(ctx.getIssueTrackerType(), Map.of("github", "https://github.com/foo-plugin/issues")); + assert Objects.equals(ctx.getIssueTrackerNameAndUrl(), Map.of("github", "https://github.com/foo-plugin/issues")); verify(probe).doApply(plugin, ctx); } @@ -167,8 +167,36 @@ void shouldDetectForOnlyJIRAInIssueTracker() throws IOException { .comparingOnlyFields("id", "status", "message") .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); - assert Objects.equals(ctx.getIssueTrackerType(), Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); + assert Objects.equals(ctx.getIssueTrackerNameAndUrl(), Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); verify(probe).doApply(plugin, ctx); } + @Test + void shouldFailWhenPluginIsNotInUpdateCenter() throws IOException { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of()))); + final String pluginName = "foo"; + + when(plugin.getDetails()).thenReturn( + Map.of( + UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") + ) + ); + + when(plugin.getName()).thenReturn(pluginName); + when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( + Map.of(), + Map.of(), + List.of() + )); + + final IssueTrackerDetectionProbe probe = getSpy(); + + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.failure(IssueTrackerDetectionProbe.KEY, "foo plugin does not exists in Update Center.")); + + verify(probe).doApply(plugin, ctx); + } } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java index 56949d89e..9065326f4 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java @@ -124,7 +124,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() { when(plugin.getName()).thenReturn(pluginName); when(plugin.getScm()).thenReturn(scmLink); - when(ctx.getIssueTrackerType()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); + when(ctx.getIssueTrackerNameAndUrl()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); when(mockedResponseEntity.getBody()).thenReturn(JSONString); @@ -176,7 +176,7 @@ void shouldReturnErrorWhenJIRAReturnsErrors() { when(plugin.getName()).thenReturn(pluginName); when(plugin.getScm()).thenReturn(scmLink); - when(ctx.getIssueTrackerType()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=0")); + when(ctx.getIssueTrackerNameAndUrl()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=0")); when(mockedResponseEntity.getBody()).thenReturn(errorJSONString); From e45ce779999cb9307a435fcd83a418cfb0811935 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Wed, 9 Aug 2023 17:09:49 +0530 Subject: [PATCH 24/44] Updated the test cases --- .../scoring/probes/CodeCoverageProbeTest.java | 20 +++++++------------ .../probes/DeprecatedPluginProbeTest.java | 9 +++------ .../probes/InstallationStatProbeTest.java | 2 +- .../IssueTrackerDetectionProbeTest.java | 8 ++++---- .../scoring/probes/JenkinsCoreProbeTest.java | 3 +-- .../KnownSecurityVulnerabilityProbeTest.java | 2 +- .../scoring/probes/SpotBugsProbeTest.java | 6 +++--- .../probes/UpForAdoptionProbeTest.java | 5 ++--- ...pdateCenterPluginPublicationProbeTest.java | 2 +- 9 files changed, 23 insertions(+), 34 deletions(-) diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java index f929a8678..fac5f90b1 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java @@ -114,7 +114,7 @@ public void shouldBeInErrorWhenRepositoryIsNotInOrganization() { Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) + "42", defaultBranch, List.of() ) ), Map.of(), @@ -158,8 +158,7 @@ public void shouldBeSuccessfulWhenRetrievedDetailsFromGitHubChecksIsAboveMinimum Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, - List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) + "42", defaultBranch, List.of() ) ), Map.of(), @@ -216,8 +215,7 @@ public void shouldBeSuccessfulWhenAboveThreshold() throws IOException { Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, - List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) + "42", defaultBranch, List.of() ) ), Map.of(), @@ -274,8 +272,7 @@ public void shouldFailWhenRetrievedDetailsFromGitHubChecksInBelowMinimumOnBothCr Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, - List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) + "42", defaultBranch, List.of() ) ), Map.of(), @@ -332,8 +329,7 @@ public void shouldFailWhenRetrievedDetailsFromGitHubChecksInBelowMinimumOnBranch Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, - List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) + "42", defaultBranch, List.of() ) ), Map.of(), @@ -390,8 +386,7 @@ public void shouldFailWhenRetrievedDetailsFromGitHubChecksInBelowMinimumOnLine() Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, - List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) + "42", defaultBranch, List.of() ) ), Map.of(), @@ -448,8 +443,7 @@ public void shouldBeInErrorIfThereIsNoCodeCoverage() throws IOException { Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, - List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) + "42", defaultBranch, List.of() ) ), Map.of(), diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java index 991a37a79..31ae8eaf8 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java @@ -62,8 +62,7 @@ void shouldBeAbleToDetectNonDeprecatedPlugin() { when(plugin.getName()).thenReturn("foo"); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main", - List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), + Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main", List.of())), Map.of("bar", new Deprecation("find-the-reason-here")), Collections.emptyList() )); @@ -81,8 +80,7 @@ void shouldBeAbleToDetectDeprecatedPlugin() { when(plugin.getName()).thenReturn("foo"); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main", - List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), + Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main", List.of())), Map.of("bar", new Deprecation("find-the-reason-here"), "foo", new Deprecation("this-is-the-reason")), Collections.emptyList() )); @@ -102,8 +100,7 @@ void shouldBeAbleToDetectDeprecatedPluginFromLabels() { when(plugin.getName()).thenReturn(pluginName); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( - pluginName, new Plugin(pluginName, new VersionNumber("1.0"), "", ZonedDateTime.now(), List.of("deprecated"), 0, "2.361", "main", - List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", ""))) + pluginName, new Plugin(pluginName, new VersionNumber("1.0"), "", ZonedDateTime.now(), List.of("deprecated"), 0, "2.361", "main", List.of()) ), Map.of(), Collections.emptyList() diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java index 07fa9d9bd..c7cc4e986 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java @@ -92,7 +92,7 @@ void shouldBeAbleToFindInstallationCountInUpdateCenter() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( pluginName, - new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin(pluginName, null, null, null, List.of(), 100, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", ""))) + new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin(pluginName, null, null, null, List.of(), 100, "", "main", List.of()) ), Map.of(), List.of() diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java index 7dc500e63..c56527920 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java @@ -24,6 +24,7 @@ package io.jenkins.pluginhealth.scoring.probes; +import static java.util.Map.entry; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -34,7 +35,6 @@ import java.io.IOException; import java.util.List; import java.util.Map; -import java.util.Objects; import io.jenkins.pluginhealth.scoring.model.Plugin; import io.jenkins.pluginhealth.scoring.model.ProbeResult; @@ -99,7 +99,7 @@ void shouldDetectIssueTrackerInPlugin() throws IOException { .comparingOnlyFields("id", "status", "message") .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); - assert Objects.equals(ctx.getIssueTrackerNameAndUrl(), Map.of("github", "https://github.com/foo-plugin/issues", "jira", "https://issues.jenkins.io/issues/?jql=component=18331")); + assertThat(ctx.getIssueTrackerNameAndUrl()).contains(entry("github", "https://github.com/foo-plugin/issues"), entry("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); verify(probe).doApply(plugin, ctx); } @@ -133,7 +133,7 @@ void shouldDetectForOnlyGHInIssueTracker() throws IOException { .comparingOnlyFields("id", "status", "message") .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); - assert Objects.equals(ctx.getIssueTrackerNameAndUrl(), Map.of("github", "https://github.com/foo-plugin/issues")); + assertThat(ctx.getIssueTrackerNameAndUrl()).contains(entry("github", "https://github.com/foo-plugin/issues")); verify(probe).doApply(plugin, ctx); } @@ -167,7 +167,7 @@ void shouldDetectForOnlyJIRAInIssueTracker() throws IOException { .comparingOnlyFields("id", "status", "message") .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); - assert Objects.equals(ctx.getIssueTrackerNameAndUrl(), Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); + assertThat(ctx.getIssueTrackerNameAndUrl()).contains(entry("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); verify(probe).doApply(plugin, ctx); } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java index da31fa46a..73ea41729 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java @@ -95,8 +95,7 @@ void shouldBeAbleToExtractJenkinsVersionFromUpdateCenter() { Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( - pluginName, null, null, null, List.of(), 0, "2.361.1", "main", - List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) + pluginName, null, null, null, List.of(), 0, "2.361.1", "main", List.of() ) ), Map.of(), diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java index 6794e0a53..6e8bea3cb 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java @@ -78,7 +78,7 @@ void shouldBeOKWithNoSecurityWarning() { void shouldBeOKWithWarningOnDifferentPlugin() { final String pluginName = "foo-bar"; final VersionNumber pluginVersion = new VersionNumber("1.0"); - final var pluginInUC = new Plugin(pluginName, pluginVersion, "scm", ZonedDateTime.now().minusHours(1), List.of(), 0, "", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", ""))); + final var pluginInUC = new Plugin(pluginName, pluginVersion, "scm", ZonedDateTime.now().minusHours(1), List.of(), 0, "", "main", List.of()); final var plugin = mock(io.jenkins.pluginhealth.scoring.model.Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); final KnownSecurityVulnerabilityProbe probe = getSpy(); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java index 1eb4280d3..ad57a89ea 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java @@ -87,7 +87,7 @@ public void shouldFailWhenRepositoryIsNotInOrganization() { Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) + "42", defaultBranch, List.of() ) ), Map.of(), @@ -129,7 +129,7 @@ public void shouldBeAbleToRetrieveDetailsFromGitHubChecks() throws IOException { Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) + "42", defaultBranch, List.of() ) ), Map.of(), @@ -181,7 +181,7 @@ public void shouldFailIfThereIsNoSpotBugs() throws IOException { Map.of( pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) + "42", defaultBranch, List.of() ) ), Map.of(), diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java index 43c4c32d4..64d6ea1fb 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java @@ -61,8 +61,7 @@ void shouldBeAbleToDetectPluginForAdoption() { when(plugin.getName()).thenReturn("foo"); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder", "adopt-this-plugin"), 0, "", "main", - List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), + Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder", "adopt-this-plugin"), 0, "", "main", List.of())), Collections.emptyMap(), Collections.emptyList() )); @@ -81,7 +80,7 @@ void shouldBeAbleToDetectPluginNotForAdoption() { when(plugin.getName()).thenReturn("foo"); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder"), 0, "", "main", - List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")))), + List.of())), Collections.emptyMap(), Collections.emptyList() )); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java index fe4886203..4c46730a5 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java @@ -81,7 +81,7 @@ void shouldSucceedIfPluginIsInUpdateCenterMap() { when(plugin.getName()).thenReturn(pluginName); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( - pluginName, null, null, null, List.of(), 0, "2.361.1", "main", List.of(new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("", "", "")) + pluginName, null, null, null, List.of(), 0, "2.361.1", "main", List.of() )), Map.of(), List.of() From 510d340297408a590ace1a787cc8d15cccda86dc Mon Sep 17 00:00:00 2001 From: Jagruti Date: Wed, 9 Aug 2023 21:59:08 +0530 Subject: [PATCH 25/44] Modifying the abstract class to make it better --- .../probes/AbstractOpenIssuesProbe.java | 12 +++++++- .../scoring/probes/GitHubOpenIssuesProbe.java | 24 ++++++---------- .../scoring/probes/JiraOpenIssuesProbe.java | 28 ++++++++----------- .../probes/GitHubOpenIssuesProbeTest.java | 5 ++-- .../probes/JiraOpenIssuesProbeTest.java | 4 +-- 5 files changed, 36 insertions(+), 37 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java index d4ba62c5a..07d235d39 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/AbstractOpenIssuesProbe.java @@ -24,13 +24,23 @@ package io.jenkins.pluginhealth.scoring.probes; +import java.util.Optional; + import io.jenkins.pluginhealth.scoring.model.Plugin; import io.jenkins.pluginhealth.scoring.model.ProbeResult; public abstract class AbstractOpenIssuesProbe extends Probe { public static final int ORDER = IssueTrackerDetectionProbe.ORDER + 100; - abstract ProbeResult getNumberOfOpenIssues(Plugin plugin, ProbeContext context); + @Override + protected ProbeResult doApply(Plugin plugin, ProbeContext context) { + final Optional openIssuesCount = getCountOfOpenIssues(context); + return openIssuesCount.isPresent() + ? ProbeResult.success(key(), String.format("%d open issues found in the %s plugin.", openIssuesCount.get(), plugin.getName())) + : ProbeResult.failure(key(), String.format("Could not find open issues in the %s plugin.", plugin.getName())); + } + + abstract Optional getCountOfOpenIssues(ProbeContext context); @Override public String[] getProbeResultRequirement() { diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java index a95b8f7a8..ee66633be 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java @@ -27,10 +27,9 @@ import java.io.IOException; import java.util.Optional; -import io.jenkins.pluginhealth.scoring.model.Plugin; -import io.jenkins.pluginhealth.scoring.model.ProbeResult; - import org.kohsuke.github.GHRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -38,29 +37,24 @@ @Order(AbstractOpenIssuesProbe.ORDER) class GitHubOpenIssuesProbe extends AbstractOpenIssuesProbe { public static final String KEY = "github-open-issues"; - - @Override - protected ProbeResult doApply(Plugin plugin, ProbeContext context) { - return getNumberOfOpenIssues(plugin, context); - } + private static final Logger LOGGER = LoggerFactory.getLogger(GitHubOpenIssuesProbe.class); /** * Get total number of open GitHub issues in a plugin */ @Override - ProbeResult getNumberOfOpenIssues(Plugin plugin, ProbeContext context) { + Optional getCountOfOpenIssues(ProbeContext context) { + String issueTrackerUrl = context.getIssueTrackerNameAndUrl().get("github"); try { - final Optional repositoryName = context.getRepositoryName(plugin.getScm()); + final Optional repositoryName = context.getRepositoryName(issueTrackerUrl.substring(0, issueTrackerUrl.lastIndexOf("/"))); if (repositoryName.isPresent()) { final GHRepository ghRepository = context.getGitHub().getRepository(repositoryName.get()); - int openGitHubIssues = ghRepository.getOpenIssueCount(); - return ProbeResult.success(key(), String.format("%d open issues found in GitHub.", openGitHubIssues)); + return Optional.of(ghRepository.getOpenIssueCount()); } } catch (IOException ex) { - return ProbeResult.error(key(), String.format("Cannot not read open issues on GitHub for plugin %s.", plugin.getName())); + LOGGER.error("Cannot not read open issues on GitHub for the plugin"); } - return ProbeResult.failure(key(), String.format("Cannot find GitHub repository for plugin %s.", plugin.getName())); - + return Optional.empty(); } @Override diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java index 2d9a20179..b3e7bba58 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java @@ -26,9 +26,7 @@ import java.net.MalformedURLException; import java.net.URL; - -import io.jenkins.pluginhealth.scoring.model.Plugin; -import io.jenkins.pluginhealth.scoring.model.ProbeResult; +import java.util.Optional; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; @@ -49,21 +47,17 @@ class JiraOpenIssuesProbe extends AbstractOpenIssuesProbe { private static final Logger LOGGER = LoggerFactory.getLogger(JiraOpenIssuesProbe.class); RestTemplate restTemplate = new RestTemplate(); - @Override - protected ProbeResult doApply(Plugin plugin, ProbeContext context) { - return getNumberOfOpenIssues(plugin, context); - } - /** * Get total number of open JIRA issues in a plugin */ @Override - ProbeResult getNumberOfOpenIssues(Plugin plugin, ProbeContext context) { + Optional getCountOfOpenIssues(ProbeContext context) { String viewJiraIssuesUrl = context.getIssueTrackerNameAndUrl().get("jira"); try { if (viewJiraIssuesUrl == null || viewJiraIssuesUrl.isEmpty()) { - return ProbeResult.failure(key(), String.format("JIRA issues not found in Update Center for %s plugin.", plugin.getName())); + LOGGER.error("JIRA issues not found in Update Center for the plugin"); + return Optional.empty(); } URL url = new URL(viewJiraIssuesUrl); String api = JIRA_HOST.concat(url.getQuery()).concat(" AND status=open"); @@ -74,18 +68,18 @@ ProbeResult getNumberOfOpenIssues(Plugin plugin, ProbeContext context) { JsonNode jsonNode = objectMapper.readTree(jsonResponse); if (jsonNode.get("errorMessages") != null) { - return ProbeResult.error(key(), String.format("Error returned from JIRA API for plugin %s. %s", plugin.getName(), jsonNode.get("errorMessages"))); + LOGGER.error("Error returned from JIRA API for plugin {}", jsonNode.get("errorMessages")); + return Optional.empty(); } - int openJIRAIssues = jsonNode.get("total").asInt(); - return ProbeResult.success(key(), String.format("%d open issues found in JIRA.", openJIRAIssues)); + return Optional.of(jsonNode.get("total").asInt()); } catch (JsonMappingException e) { - LOGGER.error("Cannot map JSON returned by JIRA API for plugin {}.", plugin.getName(), e); + LOGGER.error("Cannot map JSON returned by JIRA API for plugin ", e); } catch (JsonProcessingException e) { - LOGGER.error("Cannot process JSON returned by JIRA API for plugin {}.", plugin.getName(), e); + LOGGER.error("Cannot process JSON returned by JIRA API for plugin {}.", e); } catch (MalformedURLException e) { - LOGGER.error("Cannot process malformed URL for plugin {}.", plugin.getName(), e); + LOGGER.error("Cannot process malformed URL for plugin {}.", e); } - return ProbeResult.error(key(), String.format("Cannot fetch information from JIRA API for plugin %s.", plugin.getName())); + return Optional.empty(); } @Override diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java index 3ed759297..5b041aeee 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java @@ -98,7 +98,6 @@ void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerGithub = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("github", "https://github.com/" + repository + "/issues", "https://github.com/" + repository + "/issues/new/choose"); when(plugin.getName()).thenReturn(pluginName); - when(plugin.getScm()).thenReturn(scmLink); when(plugin.getDetails()).thenReturn( Map.of( @@ -116,6 +115,8 @@ void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { List.of() )); + when(ctx.getIssueTrackerNameAndUrl()).thenReturn(Map.of("github", "https://github.com/" + repository + "/issues")); + when(ctx.getGitHub()).thenReturn(gh); when(ctx.getRepositoryName(plugin.getScm())).thenReturn(Optional.of(repository)); when(gh.getRepository(repository)).thenReturn(ghRepository); @@ -126,7 +127,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(GitHubOpenIssuesProbe.KEY, "6 open issues found in GitHub.")); + .isEqualTo(ProbeResult.success(GitHubOpenIssuesProbe.KEY, "6 open issues found in the cloudevents plugin.")); verify(probe).doApply(plugin, ctx); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java index 9065326f4..e4733a6ea 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java @@ -139,7 +139,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() { assertThat(jiraOpenIssuesProbe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(JiraOpenIssuesProbe.KEY, "10 open issues found in JIRA.")); + .isEqualTo(ProbeResult.success(JiraOpenIssuesProbe.KEY, "10 open issues found in the mailer plugin.")); } @Test @@ -190,7 +190,7 @@ void shouldReturnErrorWhenJIRAReturnsErrors() { assertThat(jiraOpenIssuesProbe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.error(JiraOpenIssuesProbe.KEY, "Error returned from JIRA API for plugin foo. [\"A value with ID '0' does not exist for the field 'component'.\"]")); + .isEqualTo(ProbeResult.failure(JiraOpenIssuesProbe.KEY, "Could not find open issues in the foo plugin.")); } } From 3cf74069984195bc5713056a16920f2948fabb90 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sat, 12 Aug 2023 22:21:43 +0530 Subject: [PATCH 26/44] Refactored code in GitHub open issues probe --- .../scoring/model/updatecenter/Plugin.java | 7 +++ .../scoring/probes/GitHubOpenIssuesProbe.java | 18 ++++++-- .../probes/GitHubOpenIssuesProbeTest.java | 46 +++++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java index 954890813..5c81c068f 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java @@ -40,5 +40,12 @@ public List getIssueTrackers() { return this.issueTrackers; } + /** + * Gets issue tracker details about a plugin. + * + * @param type The type of platform used to track issues. For ex: GitHub, JIRA + * @param reportUrl An url to report issues about the plugin + * @param viewUrl An url to view all the issues in the plugin + */ public record IssueTrackers(String type, String viewUrl, String reportUrl){} } diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java index ee66633be..3ab71faf0 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java @@ -40,19 +40,29 @@ class GitHubOpenIssuesProbe extends AbstractOpenIssuesProbe { private static final Logger LOGGER = LoggerFactory.getLogger(GitHubOpenIssuesProbe.class); /** - * Get total number of open GitHub issues in a plugin + * Get total number of open GitHub issues in a plugin. + * @param context @see {@link ProbeContext} + * + * @return Optional an Integer value will give total count of open issues. */ @Override Optional getCountOfOpenIssues(ProbeContext context) { - String issueTrackerUrl = context.getIssueTrackerNameAndUrl().get("github"); + // Stores the GitHub URL to view all existing issues in the plugin. Ex: https://github.com/jenkinsci/cloudevents-plugin/issues + String issueTrackerViewUrl = context.getIssueTrackerNameAndUrl().get("github"); + + if (issueTrackerViewUrl == null) { + LOGGER.info("The plugin does not use GitHub issues to tracker issues."); + return Optional.empty(); + } + try { - final Optional repositoryName = context.getRepositoryName(issueTrackerUrl.substring(0, issueTrackerUrl.lastIndexOf("/"))); + final Optional repositoryName = context.getRepositoryName(issueTrackerViewUrl.substring(0, issueTrackerViewUrl.lastIndexOf("/"))); if (repositoryName.isPresent()) { final GHRepository ghRepository = context.getGitHub().getRepository(repositoryName.get()); return Optional.of(ghRepository.getOpenIssueCount()); } } catch (IOException ex) { - LOGGER.error("Cannot not read open issues on GitHub for the plugin"); + LOGGER.error("Cannot read open issues on GitHub for the plugin. {}", ex); } return Optional.empty(); } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java index 5b041aeee..6cd5f1276 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java @@ -133,4 +133,50 @@ void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { } + + @Test + void shouldFailWhereThereIsNoGitHubTracker() throws IOException { + final String pluginName = "foo"; + final String repository = "jenkinsci/" + pluginName + "-plugin"; + final String scmLink = "https://github.com/" + repository; + + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = mock(ProbeContext.class); + final GitHub gh = mock(GitHub.class); + final GHRepository ghRepository = mock(GHRepository.class); + + when(plugin.getName()).thenReturn(pluginName); + when(plugin.getScm()).thenReturn(scmLink); + when(plugin.getDetails()).thenReturn( + Map.of( + SCMLinkValidationProbe.KEY, ProbeResult.success(SCMLinkValidationProbe.KEY, ""), + IssueTrackerDetectionProbe.KEY, ProbeResult.success(IssueTrackerDetectionProbe.KEY, "") + ) + ); + + when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( + Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, null, null, null, List.of(), 0, "2.361.1", "main", + List.of() + )), + Map.of(), + List.of() + )); + + when(ctx.getIssueTrackerNameAndUrl()).thenReturn(Map.of()); + + when(ctx.getGitHub()).thenReturn(gh); + when(ctx.getRepositoryName(plugin.getScm())).thenReturn(Optional.of(repository)); + when(gh.getRepository(repository)).thenReturn(ghRepository); + + final GitHubOpenIssuesProbe probe = getSpy(); + + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.failure(GitHubOpenIssuesProbe.KEY, "Could not find open issues in the foo plugin.")); + + verify(probe).doApply(plugin, ctx); + } + } From b9cda9c0f04ed26cc33ca0cf975814a8ebbadeec Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sun, 13 Aug 2023 12:31:48 +0530 Subject: [PATCH 27/44] Restructured IssueTrackerDetectionProbe and improved its readability --- .../probes/IssueTrackerDetectionProbe.java | 47 +++++++++++++------ .../IssueTrackerDetectionProbeTest.java | 34 +++++++++++++- 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java index b2551e25b..02127ee21 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java @@ -24,33 +24,40 @@ package io.jenkins.pluginhealth.scoring.probes; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; import io.jenkins.pluginhealth.scoring.model.Plugin; import io.jenkins.pluginhealth.scoring.model.ProbeResult; +import io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers; +import io.jenkins.pluginhealth.scoring.model.updatecenter.UpdateCenter; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; @Component @Order(value = IssueTrackerDetectionProbe.ORDER) class IssueTrackerDetectionProbe extends Probe { public static final String KEY = "issue-tracker-detection"; - public static final int ORDER = UpdateCenterPluginPublicationProbe.ORDER + 100; + public static final int ORDER = UpdateCenterPluginPublicationProbe.ORDER; @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { - Map issueTrackerDetails = getIssueTrackerData(context.getUpdateCenter().plugins()); + Map issueTrackerDetails = getIssueTrackersForAPlugin(plugin.getName(), context.getUpdateCenter()); - if (CollectionUtils.isEmpty(issueTrackerDetails)) { - return ProbeResult.failure(key(), String.format("%s plugin does not exists in Update Center.", plugin.getName())); + if (issueTrackerDetails.isEmpty()) { + return ProbeResult.failure(key(), String.format("No issue tracker data available for %s plugin in Update Center.", plugin.getName())); } - context.setIssueTrackerNameAndUrl(getIssueTrackerData(context.getUpdateCenter().plugins())); + context.setIssueTrackerNameAndUrl(issueTrackerDetails); return ProbeResult.success(key(), "Issue tracker detected and returned successfully."); } + @Override + public String[] getProbeResultRequirement() { + return new String[]{UpdateCenterPluginPublicationProbe.KEY}; + } + @Override public String key() { return KEY; @@ -61,16 +68,28 @@ public String getDescription() { return "Detects the issues tracker type from Update Center."; } - @Override - public String[] getProbeResultRequirement() { - return new String[]{ UpdateCenterPluginPublicationProbe.KEY }; + /** + * Gets issue trackers for a specific plugin from Update Center. + * + * @param pluginName name of the plugin to fetch issue tracker data for. + * @param updateCenter @see {@link UpdateCenter}. + * @return A Map of filtered data from issue trackers. + */ + private Map getIssueTrackersForAPlugin(String pluginName, UpdateCenter updateCenter) { + return updateCenter.plugins().get(pluginName) != null + ? filterIssueTrackersForTypeAndViewUrl(updateCenter.plugins().get(pluginName).getIssueTrackers()) + : Map.of(); } - private Map getIssueTrackerData(Map plugin) { - return plugin.values().stream() - .flatMap(entry -> entry.getIssueTrackers().stream()) - .collect(Collectors.toMap(io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers::type, - io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers::viewUrl)); + /** + * Filters IssueTrackers for "type" and "viewUrl". + * + * @param issueTrackers Accepts a list of @see {@link IssueTrackers}. + * @return A Map of {@code IssueTrackers::type} and {@code IssueTrackers::viewUrl}. + */ + private Map filterIssueTrackersForTypeAndViewUrl(List issueTrackers) { + return issueTrackers.stream() + .collect(Collectors.toMap(IssueTrackers::type, IssueTrackers::viewUrl)); } } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java index c56527920..14f21562f 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java @@ -171,6 +171,38 @@ void shouldDetectForOnlyJIRAInIssueTracker() throws IOException { verify(probe).doApply(plugin, ctx); } + @Test + void shouldFailWhenPluginIssueTrackerIsNotInUpdateCenter() throws IOException { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of()))); + final String pluginName = "foo"; + + when(plugin.getDetails()).thenReturn( + Map.of( + UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") + ) + ); + + when(plugin.getName()).thenReturn(pluginName); + when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( + Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, null, null, null, List.of(), 0, "2.361.1", "main", + List.of() + )), + Map.of(), + List.of() + )); + + final IssueTrackerDetectionProbe probe = getSpy(); + + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.failure(IssueTrackerDetectionProbe.KEY, "No issue tracker data available for foo plugin in Update Center.")); + + verify(probe).doApply(plugin, ctx); + } + @Test void shouldFailWhenPluginIsNotInUpdateCenter() throws IOException { final Plugin plugin = mock(Plugin.class); @@ -195,7 +227,7 @@ void shouldFailWhenPluginIsNotInUpdateCenter() throws IOException { assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.failure(IssueTrackerDetectionProbe.KEY, "foo plugin does not exists in Update Center.")); + .isEqualTo(ProbeResult.failure(IssueTrackerDetectionProbe.KEY, "No issue tracker data available for foo plugin in Update Center.")); verify(probe).doApply(plugin, ctx); } From 37884d51c46d6cbd1d48ab68b1989f2231754d3c Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sun, 13 Aug 2023 13:03:05 +0530 Subject: [PATCH 28/44] Added a new test case for IssueTrackerDertectionProbe --- .../IssueTrackerDetectionProbeTest.java | 81 +++++++++++++++---- 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java index 14f21562f..676be5bf4 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java @@ -33,21 +33,19 @@ import static org.mockito.Mockito.when; import java.io.IOException; +import java.util.HashMap; import java.util.List; import java.util.Map; import io.jenkins.pluginhealth.scoring.model.Plugin; import io.jenkins.pluginhealth.scoring.model.ProbeResult; +import io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers; import io.jenkins.pluginhealth.scoring.model.updatecenter.UpdateCenter; + import org.junit.jupiter.api.Test; class IssueTrackerDetectionProbeTest extends AbstractProbeTest { - @Override - IssueTrackerDetectionProbe getSpy() { - return spy(IssueTrackerDetectionProbe.class); - } - @Test void shouldNotRunWithInvalidProbeResultRequirement() { final Plugin plugin = mock(Plugin.class); @@ -68,12 +66,17 @@ void shouldNotRunWithInvalidProbeResultRequirement() { verify(probe, never()).doApply(plugin, ctx); } + @Override + IssueTrackerDetectionProbe getSpy() { + return spy(IssueTrackerDetectionProbe.class); + } + @Test - void shouldDetectIssueTrackerInPlugin() throws IOException { + void shouldDetectIssueTrackersInPlugin() throws IOException { final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of()))); - final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerGithub = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("github", "https://github.com/foo-plugin/issues", "https://github.com/foo-plugin/issues/new/choose"); - final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerJira = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=18331", "https://www.jenkins.io/participate/report-issue/redirect/#18331"); + final IssueTrackers issueTrackerGithub = new IssueTrackers("github", "https://github.com/foo-plugin/issues", "https://github.com/foo-plugin/issues/new/choose"); + final IssueTrackers issueTrackerJira = new IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=18331", "https://www.jenkins.io/participate/report-issue/redirect/#18331"); final String pluginName = "foo"; when(plugin.getDetails()).thenReturn( @@ -104,10 +107,55 @@ void shouldDetectIssueTrackerInPlugin() throws IOException { } @Test - void shouldDetectForOnlyGHInIssueTracker() throws IOException { + void shouldAlwaysFilterDataForTheCorrectPluginFromIssueTrackers() throws IOException { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of()))); + final IssueTrackers issueTrackerJira = new IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=18331", "https://www.jenkins.io/participate/report-issue/redirect/#18331"); + final String correctPluginToFilterFor = "foo"; + final String inCorrectPlugin = "bar"; + + when(plugin.getDetails()).thenReturn( + Map.of( + UpdateCenterPluginPublicationProbe.KEY, ProbeResult.success(UpdateCenterPluginPublicationProbe.KEY, "") + ) + ); + + when(plugin.getName()).thenReturn(correctPluginToFilterFor); + when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( + Map.of(correctPluginToFilterFor, + new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + correctPluginToFilterFor, null, null, null, List.of(), 0, "2.361.1", "main", + List.of(issueTrackerJira) + ), + inCorrectPlugin, + new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + inCorrectPlugin, null, null, null, List.of(), 0, "2.361.1", "main", + List.of()) + ), + Map.of(), + List.of() + )); + + Map correctIssueSetToMatch = new HashMap<>(); + correctIssueSetToMatch.put("jira", "https://issues.jenkins.io/issues/?jql=component=18331"); + + final IssueTrackerDetectionProbe probe = getSpy(); + + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); + + assertThat(plugin.getName()).isEqualTo(correctPluginToFilterFor); + assertThat(ctx.getIssueTrackerNameAndUrl()).containsExactlyEntriesOf(correctIssueSetToMatch); + verify(probe).doApply(plugin, ctx); + } + + @Test + void shouldDetectForOnlyGHInIssueTrackers() throws IOException { final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of()))); - final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerGithub = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("github", "https://github.com/foo-plugin/issues", "https://github.com/foo-plugin/issues/new/choose"); + final IssueTrackers issueTrackerGithub = new IssueTrackers("github", "https://github.com/foo-plugin/issues", "https://github.com/foo-plugin/issues/new/choose"); final String pluginName = "foo"; when(plugin.getDetails()).thenReturn( @@ -120,7 +168,7 @@ void shouldDetectForOnlyGHInIssueTracker() throws IOException { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( pluginName, null, null, null, List.of(), 0, "2.361.1", "main", - List.of(issueTrackerGithub) + List.of(issueTrackerGithub) )), Map.of(), List.of() @@ -137,11 +185,12 @@ void shouldDetectForOnlyGHInIssueTracker() throws IOException { verify(probe).doApply(plugin, ctx); } + @Test - void shouldDetectForOnlyJIRAInIssueTracker() throws IOException { + void shouldDetectForOnlyJIRAInIssueTrackers() throws IOException { final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of()))); - final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerJira = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=18331", "https://www.jenkins.io/participate/report-issue/redirect/#18331"); + final IssueTrackers issueTrackerJira = new IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=18331", "https://www.jenkins.io/participate/report-issue/redirect/#18331"); final String pluginName = "foo"; when(plugin.getDetails()).thenReturn( @@ -172,9 +221,9 @@ void shouldDetectForOnlyJIRAInIssueTracker() throws IOException { } @Test - void shouldFailWhenPluginIssueTrackerIsNotInUpdateCenter() throws IOException { + void shouldFailWhenPluginIssueTrackersIsNotInUpdateCenter() throws IOException { final Plugin plugin = mock(Plugin.class); - final ProbeContext ctx = spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of()))); + final ProbeContext ctx = mock(ProbeContext.class); final String pluginName = "foo"; when(plugin.getDetails()).thenReturn( @@ -206,7 +255,7 @@ void shouldFailWhenPluginIssueTrackerIsNotInUpdateCenter() throws IOException { @Test void shouldFailWhenPluginIsNotInUpdateCenter() throws IOException { final Plugin plugin = mock(Plugin.class); - final ProbeContext ctx = spy(new ProbeContext(plugin.getName(), new UpdateCenter(Map.of(), Map.of(), List.of()))); + final ProbeContext ctx = mock(ProbeContext.class); final String pluginName = "foo"; when(plugin.getDetails()).thenReturn( From 898c86cea5dcfdd673bf127d8f7527be0401b177 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sun, 13 Aug 2023 22:22:44 +0530 Subject: [PATCH 29/44] Refactored code, test cases, fixed border cases --- core/pom.xml | 6 +- .../scoring/model/updatecenter/Plugin.java | 18 ++++- .../scoring/probes/JiraOpenIssuesProbe.java | 66 ++++++++++++++----- .../scoring/probes/CodeCoverageProbeTest.java | 39 ++++++----- .../probes/DeprecatedPluginProbeTest.java | 12 ++-- .../probes/GitHubOpenIssuesProbeTest.java | 22 +++---- .../probes/InstallationStatProbeTest.java | 12 ++-- .../IssueTrackerDetectionProbeTest.java | 5 +- .../scoring/probes/JenkinsCoreProbeTest.java | 14 ++-- .../probes/JiraOpenIssuesProbeTest.java | 66 +++++++++---------- .../KnownSecurityVulnerabilityProbeTest.java | 12 ++-- .../scoring/probes/SpotBugsProbeTest.java | 22 +++---- .../probes/UpForAdoptionProbeTest.java | 13 ++-- ...pdateCenterPluginPublicationProbeTest.java | 14 ++-- 14 files changed, 183 insertions(+), 138 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index bcb27e3d4..32631b4f9 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -102,9 +102,11 @@ postgresql test + - org.springframework - spring-web + org.apache.httpcomponents + httpclient + 4.5.14 diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java index 5c81c068f..c3885cb78 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java @@ -32,6 +32,17 @@ public record Plugin(String name, VersionNumber version, String scm, ZonedDateTime releaseTimestamp, List labels, int popularity, String requiredCore, String defaultBranch, List issueTrackers) { + + /* This constructor is used in test cases + when List is not required as a parameter. + */ + public static Plugin of(String name, VersionNumber version, String scm, + ZonedDateTime releaseTimestamp, List labels, + int popularity, String requiredCore, String defaultBranch) { + return new Plugin(name, version, scm, releaseTimestamp, + labels, popularity, requiredCore, defaultBranch, List.of()); + } + public io.jenkins.pluginhealth.scoring.model.Plugin toPlugin() { return new io.jenkins.pluginhealth.scoring.model.Plugin(this.name(), this.version(), this.scm(), this.releaseTimestamp()); } @@ -43,9 +54,10 @@ public List getIssueTrackers() { /** * Gets issue tracker details about a plugin. * - * @param type The type of platform used to track issues. For ex: GitHub, JIRA + * @param type The type of platform used to track issues. For ex: GitHub, JIRA * @param reportUrl An url to report issues about the plugin - * @param viewUrl An url to view all the issues in the plugin + * @param viewUrl An url to view all the issues in the plugin */ - public record IssueTrackers(String type, String viewUrl, String reportUrl){} + public record IssueTrackers(String type, String viewUrl, String reportUrl) { + } } diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java index b3e7bba58..508399953 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java @@ -24,8 +24,19 @@ package io.jenkins.pluginhealth.scoring.probes; +import static java.time.temporal.ChronoUnit.SECONDS; + +import java.io.IOException; import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.time.Duration; import java.util.Optional; import com.fasterxml.jackson.core.JsonProcessingException; @@ -35,9 +46,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; @Component @Order(AbstractOpenIssuesProbe.ORDER) @@ -45,39 +54,64 @@ class JiraOpenIssuesProbe extends AbstractOpenIssuesProbe { public static final String KEY = "jira-open-issues"; private static final String JIRA_HOST = "https://issues.jenkins.io/rest/api/latest/search?"; private static final Logger LOGGER = LoggerFactory.getLogger(JiraOpenIssuesProbe.class); - RestTemplate restTemplate = new RestTemplate(); + final ObjectMapper objectMapper = new ObjectMapper(); + HttpClient httpClient; + HttpRequest httpRequest; /** - * Get total number of open JIRA issues in a plugin + * Get total number of open JIRA issues in a plugin. + * + * @param context @see {@link ProbeContext} + * @return Optional of type Integer. */ @Override Optional getCountOfOpenIssues(ProbeContext context) { String viewJiraIssuesUrl = context.getIssueTrackerNameAndUrl().get("jira"); + if (viewJiraIssuesUrl == null || viewJiraIssuesUrl.isEmpty()) { + LOGGER.warn("JIRA issues not found in Update Center for the plugin."); + return Optional.empty(); + } + try { - if (viewJiraIssuesUrl == null || viewJiraIssuesUrl.isEmpty()) { - LOGGER.error("JIRA issues not found in Update Center for the plugin"); - return Optional.empty(); - } + // The `url` will contain the JIRA url to view issues. For ex: https://issues.jenkins.io/rest/api/latest/search?jql=component=15979 URL url = new URL(viewJiraIssuesUrl); - String api = JIRA_HOST.concat(url.getQuery()).concat(" AND status=open"); - ResponseEntity response = restTemplate.getForEntity(api, String.class); - ObjectMapper objectMapper = new ObjectMapper(); - String jsonResponse = response.getBody(); + /* Here, the query of the url "?jql=component=1833" is concatenated with " AND status=open". + This gives the final API required to fetch JIRA issues. + For ex: https://issues.jenkins.io/rest/api/latest/search?jql=component=15979%20and%20status=open + */ + String api = JIRA_HOST.concat(url.getQuery()) + .concat(URLEncoder.encode(" AND ", StandardCharsets.UTF_8.toString()).replace("+", "%20") + .concat("status=open")); + + httpRequest = HttpRequest.newBuilder() + .uri(new URI(api)) + .timeout(Duration.of(5, SECONDS)) + .GET() + .build(); + + HttpResponse response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); + String jsonResponse = response.body(); JsonNode jsonNode = objectMapper.readTree(jsonResponse); if (jsonNode.get("errorMessages") != null) { - LOGGER.error("Error returned from JIRA API for plugin {}", jsonNode.get("errorMessages")); + LOGGER.error("Error returned from JIRA API for the plugin. {}", jsonNode.get("errorMessages")); return Optional.empty(); } return Optional.of(jsonNode.get("total").asInt()); } catch (JsonMappingException e) { - LOGGER.error("Cannot map JSON returned by JIRA API for plugin ", e); + LOGGER.error("Cannot map JSON returned by JIRA API for the plugin. {}", e); } catch (JsonProcessingException e) { - LOGGER.error("Cannot process JSON returned by JIRA API for plugin {}.", e); + LOGGER.error("Cannot process JSON returned by JIRA API for the plugin. {}", e); } catch (MalformedURLException e) { - LOGGER.error("Cannot process malformed URL for plugin {}.", e); + LOGGER.error("Cannot process malformed URL for the plugin. {}", e); + } catch (URISyntaxException e) { + LOGGER.error("Incorrect URI syntax in the plugin. {}", e); + } catch (IOException e) { + LOGGER.error("Cannot read HttpResponse for the plugin. {}", e); + } catch (InterruptedException e) { + LOGGER.error("Interruption occurred when waiting for JIRA API for the plugin. {}", e); } return Optional.empty(); } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java index fac5f90b1..867f585f3 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java @@ -49,16 +49,16 @@ import org.kohsuke.github.PagedIterable; class CodeCoverageProbeTest extends AbstractProbeTest { - @Override - CodeCoverageProbe getSpy() { - return spy(CodeCoverageProbe.class); - } - @Test public void shouldNotRequireRelease() { assertThat(getSpy().requiresRelease()).isFalse(); } + @Override + CodeCoverageProbe getSpy() { + return spy(CodeCoverageProbe.class); + } + @Test public void shouldBeRelatedToCode() { assertThat(getSpy().isSourceCodeRelated()).isTrue(); @@ -112,9 +112,9 @@ public void shouldBeInErrorWhenRepositoryIsNotInOrganization() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( - pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, List.of() + "42", defaultBranch ) ), Map.of(), @@ -156,9 +156,9 @@ public void shouldBeSuccessfulWhenRetrievedDetailsFromGitHubChecksIsAboveMinimum when(plugin.getScm()).thenReturn(scmLink); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( - pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, List.of() + "42", defaultBranch ) ), Map.of(), @@ -213,9 +213,9 @@ public void shouldBeSuccessfulWhenAboveThreshold() throws IOException { when(plugin.getScm()).thenReturn(scmLink); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( - pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, List.of() + "42", defaultBranch ) ), Map.of(), @@ -270,9 +270,9 @@ public void shouldFailWhenRetrievedDetailsFromGitHubChecksInBelowMinimumOnBothCr when(plugin.getScm()).thenReturn(scmLink); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( - pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, List.of() + "42", defaultBranch ) ), Map.of(), @@ -327,10 +327,9 @@ public void shouldFailWhenRetrievedDetailsFromGitHubChecksInBelowMinimumOnBranch when(plugin.getScm()).thenReturn(scmLink); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( - pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, List.of() - ) + "42", defaultBranch) ), Map.of(), List.of() @@ -384,9 +383,9 @@ public void shouldFailWhenRetrievedDetailsFromGitHubChecksInBelowMinimumOnLine() when(plugin.getScm()).thenReturn(scmLink); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( - pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, List.of() + "42", defaultBranch ) ), Map.of(), @@ -441,9 +440,9 @@ public void shouldBeInErrorIfThereIsNoCodeCoverage() throws IOException { when(plugin.getScm()).thenReturn(scmLink); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( - pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, List.of() + "42", defaultBranch ) ), Map.of(), diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java index 31ae8eaf8..c0e72e04c 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java @@ -44,16 +44,16 @@ import org.junit.jupiter.api.Test; class DeprecatedPluginProbeTest extends AbstractProbeTest { - @Override - DeprecatedPluginProbe getSpy() { - return spy(DeprecatedPluginProbe.class); - } - @Test void shouldNotRequireRelease() { assertThat(getSpy().requiresRelease()).isFalse(); } + @Override + DeprecatedPluginProbe getSpy() { + return spy(DeprecatedPluginProbe.class); + } + @Test void shouldBeAbleToDetectNonDeprecatedPlugin() { final var plugin = mock(io.jenkins.pluginhealth.scoring.model.Plugin.class); @@ -62,7 +62,7 @@ void shouldBeAbleToDetectNonDeprecatedPlugin() { when(plugin.getName()).thenReturn("foo"); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main", List.of())), + Map.of("foo", Plugin.of("foo", new VersionNumber("1.0"), "scm", ZonedDateTime.now().minusDays(1), Collections.emptyList(), 0, "", "main")), Map.of("bar", new Deprecation("find-the-reason-here")), Collections.emptyList() )); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java index 6cd5f1276..f46a7fe8a 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java @@ -38,6 +38,7 @@ import io.jenkins.pluginhealth.scoring.model.Plugin; import io.jenkins.pluginhealth.scoring.model.ProbeResult; +import io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers; import io.jenkins.pluginhealth.scoring.model.updatecenter.UpdateCenter; import org.junit.jupiter.api.Test; @@ -45,11 +46,6 @@ import org.kohsuke.github.GitHub; class GitHubOpenIssuesProbeTest extends AbstractProbeTest { - @Override - GitHubOpenIssuesProbe getSpy() { - return spy(GitHubOpenIssuesProbe.class); - } - @Test void shouldNotRunWithInvalidProbeResultRequirement() { final Plugin plugin = mock(Plugin.class); @@ -85,9 +81,14 @@ void shouldNotRunWithInvalidProbeResultRequirement() { verify(probe, never()).doApply(plugin, ctx); } + @Override + GitHubOpenIssuesProbe getSpy() { + return spy(GitHubOpenIssuesProbe.class); + } + @Test void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { - final String pluginName = "cloudevents"; + final String pluginName = "mockedForTests "; final String repository = "jenkinsci/" + pluginName + "-plugin"; final String scmLink = "https://github.com/" + repository; @@ -95,7 +96,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { final ProbeContext ctx = mock(ProbeContext.class); final GitHub gh = mock(GitHub.class); final GHRepository ghRepository = mock(GHRepository.class); - final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerGithub = new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("github", "https://github.com/" + repository + "/issues", "https://github.com/" + repository + "/issues/new/choose"); + final IssueTrackers issueTrackerGithub = new IssueTrackers("github", scmLink + "/issues", scmLink + "/issues/new/choose"); when(plugin.getName()).thenReturn(pluginName); when(plugin.getScm()).thenReturn(scmLink); @@ -127,7 +128,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(GitHubOpenIssuesProbe.KEY, "6 open issues found in the cloudevents plugin.")); + .isEqualTo(ProbeResult.success(GitHubOpenIssuesProbe.KEY, "6 open issues found in the mockedForTests plugin.")); verify(probe).doApply(plugin, ctx); @@ -155,9 +156,8 @@ void shouldFailWhereThereIsNoGitHubTracker() throws IOException { ); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( - pluginName, null, null, null, List.of(), 0, "2.361.1", "main", - List.of() + Map.of(pluginName, io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of( + pluginName, null, null, null, List.of(), 0, "2.361.1", "main" )), Map.of(), List.of() diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java index c7cc4e986..a40764bef 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java @@ -43,16 +43,16 @@ import org.junit.jupiter.api.Test; class InstallationStatProbeTest extends AbstractProbeTest { - @Override - InstallationStatProbe getSpy() { - return spy(InstallationStatProbe.class); - } - @Test void doesNotRequireRelease() { assertThat(getSpy().requiresRelease()).isFalse(); } + @Override + InstallationStatProbe getSpy() { + return spy(InstallationStatProbe.class); + } + @Test void doesNotRequireCodeModification() { assertThat(getSpy().isSourceCodeRelated()).isFalse(); @@ -92,7 +92,7 @@ void shouldBeAbleToFindInstallationCountInUpdateCenter() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( pluginName, - new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin(pluginName, null, null, null, List.of(), 100, "", "main", List.of()) + io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of(pluginName, null, null, null, List.of(), 100, "", "main") ), Map.of(), List.of() diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java index 676be5bf4..7cfb83eb0 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java @@ -42,7 +42,6 @@ import io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers; import io.jenkins.pluginhealth.scoring.model.updatecenter.UpdateCenter; - import org.junit.jupiter.api.Test; class IssueTrackerDetectionProbeTest extends AbstractProbeTest { @@ -221,7 +220,7 @@ void shouldDetectForOnlyJIRAInIssueTrackers() throws IOException { } @Test - void shouldFailWhenPluginIssueTrackersIsNotInUpdateCenter() throws IOException { + void shouldFailWhenPluginIssueTrackersIsNotInUpdateCenter() { final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); final String pluginName = "foo"; @@ -253,7 +252,7 @@ void shouldFailWhenPluginIssueTrackersIsNotInUpdateCenter() throws IOException { } @Test - void shouldFailWhenPluginIsNotInUpdateCenter() throws IOException { + void shouldFailWhenPluginIsNotInUpdateCenter() { final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); final String pluginName = "foo"; diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java index 73ea41729..1609a8ae3 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java @@ -42,16 +42,16 @@ import org.junit.jupiter.api.Test; class JenkinsCoreProbeTest extends AbstractProbeTest { - @Override - JenkinsCoreProbe getSpy() { - return spy(JenkinsCoreProbe.class); - } - @Test void shouldRequireRelease() { assertThat(getSpy().requiresRelease()).isTrue(); } + @Override + JenkinsCoreProbe getSpy() { + return spy(JenkinsCoreProbe.class); + } + @Test void shouldNotRequireSourceCodeChange() { assertThat(getSpy().isSourceCodeRelated()).isFalse(); @@ -94,8 +94,8 @@ void shouldBeAbleToExtractJenkinsVersionFromUpdateCenter() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( pluginName, - new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( - pluginName, null, null, null, List.of(), 0, "2.361.1", "main", List.of() + io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of( + pluginName, null, null, null, List.of(), 0, "2.361.1", "main" ) ), Map.of(), diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java index e4733a6ea..2c46a7673 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java @@ -26,34 +26,31 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.io.IOException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.util.List; import java.util.Map; import io.jenkins.pluginhealth.scoring.model.Plugin; import io.jenkins.pluginhealth.scoring.model.ProbeResult; +import io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers; import io.jenkins.pluginhealth.scoring.model.updatecenter.UpdateCenter; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; class JiraOpenIssuesProbeTest extends AbstractProbeTest { @InjectMocks - JiraOpenIssuesProbe jiraOpenIssuesProbe = new JiraOpenIssuesProbe(); - - @Override - JiraOpenIssuesProbe getSpy() { - return spy(JiraOpenIssuesProbe.class); - } + JiraOpenIssuesProbe jiraOpenIssuesProbe = new JiraOpenIssuesProbe(); @Test void shouldNotRunWithInvalidProbeResultRequirement() { @@ -90,19 +87,24 @@ void shouldNotRunWithInvalidProbeResultRequirement() { verify(probe, never()).doApply(plugin, ctx); } + @Override + JiraOpenIssuesProbe getSpy() { + return spy(JiraOpenIssuesProbe.class); + } + @Test - void shouldBeAbleToFindNumberOfOpenIssuesInJira() { + void shouldBeAbleToFindNumberOfOpenIssuesInJira() throws IOException, InterruptedException { final String pluginName = "mailer"; final String repository = "jenkinsci/" + pluginName + "-plugin"; final String scmLink = "https://github.com/" + repository; final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); - final RestTemplate mockedRestTemplate = mock(RestTemplate.class); - final ResponseEntity mockedResponseEntity = mock(ResponseEntity.class); + final HttpClient mockedHttpClient = mock(HttpClient.class); + final HttpResponse mockedHttpResponse = mock(HttpResponse.class); - final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerJira = - new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=18331", "https://www.jenkins.io/participate/report-issue/redirect/#18331"); + final IssueTrackers issueTrackerJira = + new IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=18331", "https://www.jenkins.io/participate/report-issue/redirect/#18331"); final String JSONString = "{\"expand\":\"names,schema\",\"startAt\":0,\"maxResults\":50,\"total\":10,\"issues\":[]}"; @@ -126,15 +128,14 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() { when(plugin.getScm()).thenReturn(scmLink); when(ctx.getIssueTrackerNameAndUrl()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); - when(mockedResponseEntity.getBody()).thenReturn(JSONString); + when(mockedHttpResponse.body()).thenReturn(JSONString); - when(mockedRestTemplate.getForEntity( - anyString(), - any(Class.class) - )) - .thenReturn(mockedResponseEntity); + when(mockedHttpClient.send( + any(HttpRequest.class), + any(HttpResponse.BodyHandler.class) + )).thenReturn(mockedHttpResponse); - jiraOpenIssuesProbe.restTemplate = mockedRestTemplate; + jiraOpenIssuesProbe.httpClient = mockedHttpClient; assertThat(jiraOpenIssuesProbe.apply(plugin, ctx)) .usingRecursiveComparison() @@ -143,18 +144,18 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() { } @Test - void shouldReturnErrorWhenJIRAReturnsErrors() { + void shouldReturnErrorWhenJIRAReturnsErrors() throws IOException, InterruptedException { final String pluginName = "foo"; final String repository = "jenkinsci/" + pluginName + "-plugin"; final String scmLink = "https://github.com/" + repository; final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); - final RestTemplate mockedRestTemplate = mock(RestTemplate.class); - final ResponseEntity mockedResponseEntity = mock(ResponseEntity.class); + final HttpClient mockedHttpClient = mock(HttpClient.class); + final HttpResponse mockedHttpResponse = mock(HttpResponse.class); - final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers issueTrackerJira = - new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=0", "https://www.jenkins.io/participate/report-issue/redirect/#0"); + final IssueTrackers issueTrackerJira = + new IssueTrackers("jira", "https://issues.jenkins.io/issues/?jql=component=0", "https://www.jenkins.io/participate/report-issue/redirect/#0"); final String errorJSONString = "{\"errorMessages\":[\"A value with ID '0' does not exist for the field 'component'.\"],\"errors\":{}}"; @@ -178,14 +179,14 @@ void shouldReturnErrorWhenJIRAReturnsErrors() { when(plugin.getScm()).thenReturn(scmLink); when(ctx.getIssueTrackerNameAndUrl()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=0")); - when(mockedResponseEntity.getBody()).thenReturn(errorJSONString); + when(mockedHttpResponse.body()).thenReturn(errorJSONString); - when(mockedRestTemplate.getForEntity( - anyString(), - any(Class.class) - )).thenReturn(mockedResponseEntity); + when(mockedHttpClient.send( + any(HttpRequest.class), + any(HttpResponse.BodyHandler.class) + )).thenReturn(mockedHttpResponse); - jiraOpenIssuesProbe.restTemplate = mockedRestTemplate; + jiraOpenIssuesProbe.httpClient = mockedHttpClient; assertThat(jiraOpenIssuesProbe.apply(plugin, ctx)) .usingRecursiveComparison() @@ -193,4 +194,3 @@ void shouldReturnErrorWhenJIRAReturnsErrors() { .isEqualTo(ProbeResult.failure(JiraOpenIssuesProbe.KEY, "Could not find open issues in the foo plugin.")); } } - diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java index 6e8bea3cb..1a2aaca89 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java @@ -45,16 +45,16 @@ import org.junit.jupiter.api.Test; class KnownSecurityVulnerabilityProbeTest extends AbstractProbeTest { - @Override - KnownSecurityVulnerabilityProbe getSpy() { - return spy(KnownSecurityVulnerabilityProbe.class); - } - @Test void shouldNotRequireNewRelease() { assertThat(getSpy().requiresRelease()).isFalse(); } + @Override + KnownSecurityVulnerabilityProbe getSpy() { + return spy(KnownSecurityVulnerabilityProbe.class); + } + @Test void shouldBeOKWithNoSecurityWarning() { final var plugin = mock(io.jenkins.pluginhealth.scoring.model.Plugin.class); @@ -78,7 +78,7 @@ void shouldBeOKWithNoSecurityWarning() { void shouldBeOKWithWarningOnDifferentPlugin() { final String pluginName = "foo-bar"; final VersionNumber pluginVersion = new VersionNumber("1.0"); - final var pluginInUC = new Plugin(pluginName, pluginVersion, "scm", ZonedDateTime.now().minusHours(1), List.of(), 0, "", "main", List.of()); + final var pluginInUC = Plugin.of(pluginName, pluginVersion, "scm", ZonedDateTime.now().minusHours(1), List.of(), 0, "", "main"); final var plugin = mock(io.jenkins.pluginhealth.scoring.model.Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); final KnownSecurityVulnerabilityProbe probe = getSpy(); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java index ad57a89ea..15dbddbe7 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java @@ -50,16 +50,16 @@ @ExtendWith(MockitoExtension.class) class SpotBugsProbeTest extends AbstractProbeTest { - @Override - protected SpotBugsProbe getSpy() { - return spy(SpotBugsProbe.class); - } - @Test public void shouldNotRequireRelease() { assertThat(getSpy().requiresRelease()).isFalse(); } + @Override + protected SpotBugsProbe getSpy() { + return spy(SpotBugsProbe.class); + } + @Test public void shouldBeRelatedToCode() { assertThat(getSpy().isSourceCodeRelated()).isTrue(); @@ -85,9 +85,9 @@ public void shouldFailWhenRepositoryIsNotInOrganization() { when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( - pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, List.of() + "42", defaultBranch ) ), Map.of(), @@ -127,9 +127,9 @@ public void shouldBeAbleToRetrieveDetailsFromGitHubChecks() throws IOException { when(plugin.getScm()).thenReturn(scmLink); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( - pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, List.of() + "42", defaultBranch ) ), Map.of(), @@ -179,9 +179,9 @@ public void shouldFailIfThereIsNoSpotBugs() throws IOException { when(plugin.getScm()).thenReturn(scmLink); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( Map.of( - pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( + pluginName, io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of( pluginName, new VersionNumber("1.0"), scmLink, ZonedDateTime.now(), List.of(), 0, - "42", defaultBranch, List.of() + "42", defaultBranch ) ), Map.of(), diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java index 64d6ea1fb..5155b2533 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java @@ -43,16 +43,16 @@ import org.junit.jupiter.api.Test; class UpForAdoptionProbeTest extends AbstractProbeTest { - @Override - UpForAdoptionProbe getSpy() { - return spy(UpForAdoptionProbe.class); - } - @Test void shouldNotRequireNewRelease() { assertThat(getSpy().requiresRelease()).isFalse(); } + @Override + UpForAdoptionProbe getSpy() { + return spy(UpForAdoptionProbe.class); + } + @Test void shouldBeAbleToDetectPluginForAdoption() { final var plugin = mock(io.jenkins.pluginhealth.scoring.model.Plugin.class); @@ -79,8 +79,7 @@ void shouldBeAbleToDetectPluginNotForAdoption() { when(plugin.getName()).thenReturn("foo"); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of("foo", new Plugin("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder"), 0, "", "main", - List.of())), + Map.of("foo", Plugin.of("foo", new VersionNumber("1.0"), "not-a-scm", ZonedDateTime.now().minusDays(1), List.of("builder"), 0, "", "main")), Collections.emptyMap(), Collections.emptyList() )); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java index 4c46730a5..0555323f5 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java @@ -40,16 +40,16 @@ import org.junit.jupiter.api.Test; class UpdateCenterPluginPublicationProbeTest extends AbstractProbeTest { - @Override - UpdateCenterPluginPublicationProbe getSpy() { - return spy(UpdateCenterPluginPublicationProbe.class); - } - @Test void shouldNotRequireRelease() { assertThat(getSpy().requiresRelease()).isFalse(); } + @Override + UpdateCenterPluginPublicationProbe getSpy() { + return spy(UpdateCenterPluginPublicationProbe.class); + } + @Test void shouldFailIfPluginIsNotInUpdateCenterMap() { final Plugin plugin = mock(Plugin.class); @@ -80,8 +80,8 @@ void shouldSucceedIfPluginIsInUpdateCenterMap() { when(plugin.getName()).thenReturn(pluginName); when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter( - Map.of(pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin( - pluginName, null, null, null, List.of(), 0, "2.361.1", "main", List.of() + Map.of(pluginName, io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of( + pluginName, null, null, null, List.of(), 0, "2.361.1", "main" )), Map.of(), List.of() From fdd1a4ee7ec4f79e504adaef8a1020ec4dcfb5f9 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sun, 13 Aug 2023 22:43:58 +0530 Subject: [PATCH 30/44] Updating IssueTrackerDetectionProbe ORDER --- .../pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java index 02127ee21..564dc3224 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java @@ -40,7 +40,7 @@ @Order(value = IssueTrackerDetectionProbe.ORDER) class IssueTrackerDetectionProbe extends Probe { public static final String KEY = "issue-tracker-detection"; - public static final int ORDER = UpdateCenterPluginPublicationProbe.ORDER; + public static final int ORDER = UpdateCenterPluginPublicationProbe.ORDER + 100; @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { From 1940e676454da6b0e6d9f53a3c23fcf70bbaf06e Mon Sep 17 00:00:00 2001 From: Jagruti Date: Mon, 14 Aug 2023 20:52:14 +0530 Subject: [PATCH 31/44] Fixed method names --- .../scoring/probes/GitHubOpenIssuesProbe.java | 2 +- .../scoring/probes/JiraOpenIssuesProbe.java | 10 ++++----- .../scoring/probes/ProbeContext.java | 21 ++++++++++++------- .../probes/GitHubOpenIssuesProbeTest.java | 8 +++---- .../IssueTrackerDetectionProbeTest.java | 8 +++---- .../probes/JiraOpenIssuesProbeTest.java | 4 ++-- 6 files changed, 29 insertions(+), 24 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java index 3ab71faf0..9e40afd2a 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java @@ -48,7 +48,7 @@ class GitHubOpenIssuesProbe extends AbstractOpenIssuesProbe { @Override Optional getCountOfOpenIssues(ProbeContext context) { // Stores the GitHub URL to view all existing issues in the plugin. Ex: https://github.com/jenkinsci/cloudevents-plugin/issues - String issueTrackerViewUrl = context.getIssueTrackerNameAndUrl().get("github"); + String issueTrackerViewUrl = context.getIssueTrackerUrlsByNames().get("github"); if (issueTrackerViewUrl == null) { LOGGER.info("The plugin does not use GitHub issues to tracker issues."); diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java index 508399953..03cbe406a 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java @@ -66,10 +66,10 @@ class JiraOpenIssuesProbe extends AbstractOpenIssuesProbe { */ @Override Optional getCountOfOpenIssues(ProbeContext context) { - String viewJiraIssuesUrl = context.getIssueTrackerNameAndUrl().get("jira"); + String viewJiraIssuesUrl = context.getIssueTrackerUrlsByNames().get("jira"); - if (viewJiraIssuesUrl == null || viewJiraIssuesUrl.isEmpty()) { - LOGGER.warn("JIRA issues not found in Update Center for the plugin."); + if (viewJiraIssuesUrl == null || viewJiraIssuesUrl.isEmpty()) { + LOGGER.info("JIRA issues not found in Update Center for the plugin."); return Optional.empty(); } @@ -82,8 +82,8 @@ Optional getCountOfOpenIssues(ProbeContext context) { For ex: https://issues.jenkins.io/rest/api/latest/search?jql=component=15979%20and%20status=open */ String api = JIRA_HOST.concat(url.getQuery()) - .concat(URLEncoder.encode(" AND ", StandardCharsets.UTF_8.toString()).replace("+", "%20") - .concat("status=open")); + .concat("%20AND%20") + .concat("status=open"); httpRequest = HttpRequest.newBuilder() .uri(new URI(api)) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java index 2ba11c6c7..1def645b7 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java @@ -45,7 +45,7 @@ public class ProbeContext { private GitHub github; private ZonedDateTime lastCommitDate; private Map pluginDocumentationLinks; - private Map issueTrackerNameAndUrl; + private Map issueTrackerUrlsByNames; public ProbeContext(String pluginName, UpdateCenter updateCenter) throws IOException { this.updateCenter = updateCenter; @@ -76,25 +76,30 @@ public void setGitHub(GitHub github) { this.github = github; } - public void setPluginDocumentationLinks(Map pluginDocumentationLinks) { - this.pluginDocumentationLinks = pluginDocumentationLinks; - } - public Map getPluginDocumentationLinks() { return pluginDocumentationLinks; } + public void setPluginDocumentationLinks(Map pluginDocumentationLinks) { + this.pluginDocumentationLinks = pluginDocumentationLinks; + } + public Optional getRepositoryName(String scm) { final Matcher match = SCMLinkValidationProbe.GH_PATTERN.matcher(scm); return match.find() ? Optional.of(match.group("repo")) : Optional.empty(); } public void setIssueTrackerNameAndUrl(Map issueTrackerNameAndUrl) { - this.issueTrackerNameAndUrl = issueTrackerNameAndUrl; + this.issueTrackerUrlsByNames = issueTrackerNameAndUrl; } - public Map getIssueTrackerNameAndUrl() { - return issueTrackerNameAndUrl; + /** + * Gets the issue tracker names and its urls. + * + * @return a Map that consists of @see {@link io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers} "type" as key and "viewUrl" as its value. + */ + public Map getIssueTrackerUrlsByNames() { + return issueTrackerUrlsByNames; } /* default */ void cleanUp() throws IOException { diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java index f46a7fe8a..9ed1e4346 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java @@ -88,7 +88,7 @@ GitHubOpenIssuesProbe getSpy() { @Test void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { - final String pluginName = "mockedForTests "; + final String pluginName = "foo"; final String repository = "jenkinsci/" + pluginName + "-plugin"; final String scmLink = "https://github.com/" + repository; @@ -116,7 +116,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { List.of() )); - when(ctx.getIssueTrackerNameAndUrl()).thenReturn(Map.of("github", "https://github.com/" + repository + "/issues")); + when(ctx.getIssueTrackerUrlsByNames()).thenReturn(Map.of("github", "https://github.com/" + repository + "/issues")); when(ctx.getGitHub()).thenReturn(gh); when(ctx.getRepositoryName(plugin.getScm())).thenReturn(Optional.of(repository)); @@ -128,7 +128,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(GitHubOpenIssuesProbe.KEY, "6 open issues found in the mockedForTests plugin.")); + .isEqualTo(ProbeResult.success(GitHubOpenIssuesProbe.KEY, "6 open issues found in the foo plugin.")); verify(probe).doApply(plugin, ctx); @@ -163,7 +163,7 @@ void shouldFailWhereThereIsNoGitHubTracker() throws IOException { List.of() )); - when(ctx.getIssueTrackerNameAndUrl()).thenReturn(Map.of()); + when(ctx.getIssueTrackerUrlsByNames()).thenReturn(Map.of()); when(ctx.getGitHub()).thenReturn(gh); when(ctx.getRepositoryName(plugin.getScm())).thenReturn(Optional.of(repository)); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java index 7cfb83eb0..e6e90c924 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java @@ -101,7 +101,7 @@ void shouldDetectIssueTrackersInPlugin() throws IOException { .comparingOnlyFields("id", "status", "message") .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); - assertThat(ctx.getIssueTrackerNameAndUrl()).contains(entry("github", "https://github.com/foo-plugin/issues"), entry("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); + assertThat(ctx.getIssueTrackerUrlsByNames()).contains(entry("github", "https://github.com/foo-plugin/issues"), entry("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); verify(probe).doApply(plugin, ctx); } @@ -146,7 +146,7 @@ void shouldAlwaysFilterDataForTheCorrectPluginFromIssueTrackers() throws IOExcep .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); assertThat(plugin.getName()).isEqualTo(correctPluginToFilterFor); - assertThat(ctx.getIssueTrackerNameAndUrl()).containsExactlyEntriesOf(correctIssueSetToMatch); + assertThat(ctx.getIssueTrackerUrlsByNames()).containsExactlyEntriesOf(correctIssueSetToMatch); verify(probe).doApply(plugin, ctx); } @@ -180,7 +180,7 @@ void shouldDetectForOnlyGHInIssueTrackers() throws IOException { .comparingOnlyFields("id", "status", "message") .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); - assertThat(ctx.getIssueTrackerNameAndUrl()).contains(entry("github", "https://github.com/foo-plugin/issues")); + assertThat(ctx.getIssueTrackerUrlsByNames()).contains(entry("github", "https://github.com/foo-plugin/issues")); verify(probe).doApply(plugin, ctx); } @@ -215,7 +215,7 @@ void shouldDetectForOnlyJIRAInIssueTrackers() throws IOException { .comparingOnlyFields("id", "status", "message") .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); - assertThat(ctx.getIssueTrackerNameAndUrl()).contains(entry("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); + assertThat(ctx.getIssueTrackerUrlsByNames()).contains(entry("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); verify(probe).doApply(plugin, ctx); } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java index 2c46a7673..5f5b256ae 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java @@ -126,7 +126,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() throws IOException, Interrupte when(plugin.getName()).thenReturn(pluginName); when(plugin.getScm()).thenReturn(scmLink); - when(ctx.getIssueTrackerNameAndUrl()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); + when(ctx.getIssueTrackerUrlsByNames()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); when(mockedHttpResponse.body()).thenReturn(JSONString); @@ -177,7 +177,7 @@ void shouldReturnErrorWhenJIRAReturnsErrors() throws IOException, InterruptedExc when(plugin.getName()).thenReturn(pluginName); when(plugin.getScm()).thenReturn(scmLink); - when(ctx.getIssueTrackerNameAndUrl()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=0")); + when(ctx.getIssueTrackerUrlsByNames()).thenReturn(Map.of("jira", "https://issues.jenkins.io/issues/?jql=component=0")); when(mockedHttpResponse.body()).thenReturn(errorJSONString); From 12ef4aaaa99ebc3beea3b11bf74530d7253e8898 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Mon, 14 Aug 2023 21:08:51 +0530 Subject: [PATCH 32/44] Removed unused imports --- .../pluginhealth/scoring/probes/JiraOpenIssuesProbe.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java index 03cbe406a..1a610812b 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java @@ -31,11 +31,9 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.net.URLEncoder; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; -import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Optional; From 6a7214aa0bd91298632cb241527f868424a191cc Mon Sep 17 00:00:00 2001 From: Jagruti Date: Tue, 15 Aug 2023 18:25:20 +0530 Subject: [PATCH 33/44] Fixed JavaDocs --- .../scoring/probes/GitHubOpenIssuesProbe.java | 4 ++-- .../scoring/probes/IssueTrackerDetectionProbe.java | 4 ++-- .../scoring/probes/JiraOpenIssuesProbe.java | 13 +++++++------ .../pluginhealth/scoring/probes/ProbeContext.java | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java index 9e40afd2a..bdfe53aed 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java @@ -41,13 +41,13 @@ class GitHubOpenIssuesProbe extends AbstractOpenIssuesProbe { /** * Get total number of open GitHub issues in a plugin. - * @param context @see {@link ProbeContext} * + * @param context {@link ProbeContext} * @return Optional an Integer value will give total count of open issues. */ @Override Optional getCountOfOpenIssues(ProbeContext context) { - // Stores the GitHub URL to view all existing issues in the plugin. Ex: https://github.com/jenkinsci/cloudevents-plugin/issues + /* Stores the GitHub URL to view all existing issues in the plugin. Ex: https://github.com/jenkinsci/cloudevents-plugin/issues */ String issueTrackerViewUrl = context.getIssueTrackerUrlsByNames().get("github"); if (issueTrackerViewUrl == null) { diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java index 564dc3224..e37ec3915 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java @@ -72,7 +72,7 @@ public String getDescription() { * Gets issue trackers for a specific plugin from Update Center. * * @param pluginName name of the plugin to fetch issue tracker data for. - * @param updateCenter @see {@link UpdateCenter}. + * @param updateCenter The {@link UpdateCenter}. * @return A Map of filtered data from issue trackers. */ private Map getIssueTrackersForAPlugin(String pluginName, UpdateCenter updateCenter) { @@ -84,7 +84,7 @@ private Map getIssueTrackersForAPlugin(String pluginName, Update /** * Filters IssueTrackers for "type" and "viewUrl". * - * @param issueTrackers Accepts a list of @see {@link IssueTrackers}. + * @param issueTrackers Accepts a list of {@link IssueTrackers}. * @return A Map of {@code IssueTrackers::type} and {@code IssueTrackers::viewUrl}. */ private Map filterIssueTrackersForTypeAndViewUrl(List issueTrackers) { diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java index 1a610812b..660029d98 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java @@ -59,20 +59,21 @@ class JiraOpenIssuesProbe extends AbstractOpenIssuesProbe { /** * Get total number of open JIRA issues in a plugin. * - * @param context @see {@link ProbeContext} + * @param context {@link ProbeContext} * @return Optional of type Integer. */ @Override Optional getCountOfOpenIssues(ProbeContext context) { String viewJiraIssuesUrl = context.getIssueTrackerUrlsByNames().get("jira"); - if (viewJiraIssuesUrl == null || viewJiraIssuesUrl.isEmpty()) { + if (viewJiraIssuesUrl == null || viewJiraIssuesUrl.isEmpty()) { LOGGER.info("JIRA issues not found in Update Center for the plugin."); return Optional.empty(); } - try { - // The `url` will contain the JIRA url to view issues. For ex: https://issues.jenkins.io/rest/api/latest/search?jql=component=15979 + /* The `url` will contain the JIRA url to view issues. + For ex: https://issues.jenkins.io/rest/api/latest/search?jql=component=15979 + */ URL url = new URL(viewJiraIssuesUrl); /* Here, the query of the url "?jql=component=1833" is concatenated with " AND status=open". @@ -80,8 +81,8 @@ Optional getCountOfOpenIssues(ProbeContext context) { For ex: https://issues.jenkins.io/rest/api/latest/search?jql=component=15979%20and%20status=open */ String api = JIRA_HOST.concat(url.getQuery()) - .concat("%20AND%20") - .concat("status=open"); + .concat("%20AND%20") + .concat("status=open"); httpRequest = HttpRequest.newBuilder() .uri(new URI(api)) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java index 1def645b7..8bd781e91 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java @@ -96,7 +96,7 @@ public void setIssueTrackerNameAndUrl(Map issueTrackerNameAndUrl /** * Gets the issue tracker names and its urls. * - * @return a Map that consists of @see {@link io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers} "type" as key and "viewUrl" as its value. + * @return a Map that consists of {@link io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.IssueTrackers} "type" as key and "viewUrl" as its value. */ public Map getIssueTrackerUrlsByNames() { return issueTrackerUrlsByNames; From 8e0f12a492c9e0d3e4a2f745a09f75ac4356d4de Mon Sep 17 00:00:00 2001 From: Jagruti Tiwari Date: Sat, 19 Aug 2023 19:52:49 +0530 Subject: [PATCH 34/44] Update core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java Co-authored-by: Antoine Neveux --- .../pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java index bdfe53aed..f48908470 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java @@ -51,7 +51,7 @@ Optional getCountOfOpenIssues(ProbeContext context) { String issueTrackerViewUrl = context.getIssueTrackerUrlsByNames().get("github"); if (issueTrackerViewUrl == null) { - LOGGER.info("The plugin does not use GitHub issues to tracker issues."); + LOGGER.info("The plugin does not use GitHub issues to track issues."); return Optional.empty(); } From 12db24bce5498baa4ee28a2ea1bfbfd25593f10e Mon Sep 17 00:00:00 2001 From: Jagruti Date: Sat, 19 Aug 2023 21:46:30 +0530 Subject: [PATCH 35/44] Removed unwanted dependencies and fixed log statements --- core/pom.xml | 6 ------ .../pluginhealth/scoring/probes/JiraOpenIssuesProbe.java | 4 ++-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 32631b4f9..024955b15 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -102,11 +102,5 @@ postgresql test - - - org.apache.httpcomponents - httpclient - 4.5.14 - diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java index 660029d98..f92d1f77c 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java @@ -67,7 +67,7 @@ Optional getCountOfOpenIssues(ProbeContext context) { String viewJiraIssuesUrl = context.getIssueTrackerUrlsByNames().get("jira"); if (viewJiraIssuesUrl == null || viewJiraIssuesUrl.isEmpty()) { - LOGGER.info("JIRA issues not found in Update Center for the plugin."); + LOGGER.info("The plugin does not use JIRA to track issues."); return Optional.empty(); } try { @@ -95,7 +95,7 @@ Optional getCountOfOpenIssues(ProbeContext context) { JsonNode jsonNode = objectMapper.readTree(jsonResponse); if (jsonNode.get("errorMessages") != null) { - LOGGER.error("Error returned from JIRA API for the plugin. {}", jsonNode.get("errorMessages")); + LOGGER.error("Cannot request JIRA API for the plugin. {}", jsonNode.get("errorMessages")); return Optional.empty(); } return Optional.of(jsonNode.get("total").asInt()); From 793114bb8d42d45ad432a53b6dac468faa7adbb2 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Tue, 22 Aug 2023 15:55:41 +0530 Subject: [PATCH 36/44] Adding a comment --- .../pluginhealth/scoring/probes/JiraOpenIssuesProbe.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java index f92d1f77c..56e0f217a 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java @@ -86,7 +86,7 @@ Optional getCountOfOpenIssues(ProbeContext context) { httpRequest = HttpRequest.newBuilder() .uri(new URI(api)) - .timeout(Duration.of(5, SECONDS)) + .timeout(Duration.of(5, SECONDS)) // based on manual testing, timeout after 5 seconds works. .GET() .build(); From e13b17e6a8abbc7a6fca5d36b972817f4ea4b62e Mon Sep 17 00:00:00 2001 From: Jagruti Tiwari Date: Wed, 23 Aug 2023 22:28:30 +0530 Subject: [PATCH 37/44] Update core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java Co-authored-by: Antoine Neveux --- .../pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java index 9ed1e4346..f67161489 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java @@ -116,7 +116,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { List.of() )); - when(ctx.getIssueTrackerUrlsByNames()).thenReturn(Map.of("github", "https://github.com/" + repository + "/issues")); + when(ctx.getIssueTrackerUrlsByNames()).thenReturn(Map.of("github", scmLink + "/issues")); when(ctx.getGitHub()).thenReturn(gh); when(ctx.getRepositoryName(plugin.getScm())).thenReturn(Optional.of(repository)); From f4ef76e2263a9feae4aa6d6a95af552276ef2c0e Mon Sep 17 00:00:00 2001 From: Jagruti Date: Wed, 23 Aug 2023 22:38:33 +0530 Subject: [PATCH 38/44] Made minor changes based on code review --- .../pluginhealth/scoring/model/updatecenter/Plugin.java | 4 +--- .../scoring/probes/GitHubOpenIssuesProbe.java | 4 ++++ .../scoring/probes/IssueTrackerDetectionProbe.java | 4 ++-- .../pluginhealth/scoring/probes/JiraOpenIssuesProbe.java | 6 ++++++ .../scoring/probes/IssueTrackerDetectionProbeTest.java | 8 ++++---- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java index c3885cb78..01d2e3ea1 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java @@ -33,9 +33,7 @@ public record Plugin(String name, VersionNumber version, String scm, ZonedDateTime releaseTimestamp, List labels, int popularity, String requiredCore, String defaultBranch, List issueTrackers) { - /* This constructor is used in test cases - when List is not required as a parameter. - */ + /* This builder function is used in test cases when List is not required as a mandatory parameter. */ public static Plugin of(String name, VersionNumber version, String scm, ZonedDateTime releaseTimestamp, List labels, int popularity, String requiredCore, String defaultBranch) { diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java index f48908470..edb38aa36 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java @@ -47,6 +47,10 @@ class GitHubOpenIssuesProbe extends AbstractOpenIssuesProbe { */ @Override Optional getCountOfOpenIssues(ProbeContext context) { + if (context.getIssueTrackerUrlsByNames().get("github") == null) { + LOGGER.info("IssueTracker has no GitHub open issues for the plugin."); + return Optional.empty(); + } /* Stores the GitHub URL to view all existing issues in the plugin. Ex: https://github.com/jenkinsci/cloudevents-plugin/issues */ String issueTrackerViewUrl = context.getIssueTrackerUrlsByNames().get("github"); diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java index e37ec3915..a3fd1e724 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java @@ -50,7 +50,7 @@ protected ProbeResult doApply(Plugin plugin, ProbeContext context) { return ProbeResult.failure(key(), String.format("No issue tracker data available for %s plugin in Update Center.", plugin.getName())); } context.setIssueTrackerNameAndUrl(issueTrackerDetails); - return ProbeResult.success(key(), "Issue tracker detected and returned successfully."); + return ProbeResult.success(key(), String.format("Found %d issue trackers configured for the %s plugin.", issueTrackerDetails.size(), plugin.getName())); } @Override @@ -76,7 +76,7 @@ public String getDescription() { * @return A Map of filtered data from issue trackers. */ private Map getIssueTrackersForAPlugin(String pluginName, UpdateCenter updateCenter) { - return updateCenter.plugins().get(pluginName) != null + return (updateCenter.plugins().get(pluginName) != null) && (updateCenter.plugins().get(pluginName).getIssueTrackers() != null) ? filterIssueTrackersForTypeAndViewUrl(updateCenter.plugins().get(pluginName).getIssueTrackers()) : Map.of(); } diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java index 56e0f217a..d8379cb58 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java @@ -64,6 +64,12 @@ class JiraOpenIssuesProbe extends AbstractOpenIssuesProbe { */ @Override Optional getCountOfOpenIssues(ProbeContext context) { + if (context.getIssueTrackerUrlsByNames().get("jira") == null) { + LOGGER.info("IssueTracker has no JIRA open issues for the plugin."); + return Optional.empty(); + } + + /* Stores the JIRA URL to view all existing issues in the plugin. Ex: https://github.com/jenkinsci/cloudevents-plugin/issues */ String viewJiraIssuesUrl = context.getIssueTrackerUrlsByNames().get("jira"); if (viewJiraIssuesUrl == null || viewJiraIssuesUrl.isEmpty()) { diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java index e6e90c924..20a0fef42 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java @@ -99,7 +99,7 @@ void shouldDetectIssueTrackersInPlugin() throws IOException { assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); + .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Found 2 issue trackers configured for the foo plugin.")); assertThat(ctx.getIssueTrackerUrlsByNames()).contains(entry("github", "https://github.com/foo-plugin/issues"), entry("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); verify(probe).doApply(plugin, ctx); @@ -143,7 +143,7 @@ void shouldAlwaysFilterDataForTheCorrectPluginFromIssueTrackers() throws IOExcep assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); + .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Found 1 issue trackers configured for the foo plugin.")); assertThat(plugin.getName()).isEqualTo(correctPluginToFilterFor); assertThat(ctx.getIssueTrackerUrlsByNames()).containsExactlyEntriesOf(correctIssueSetToMatch); @@ -178,7 +178,7 @@ void shouldDetectForOnlyGHInIssueTrackers() throws IOException { assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); + .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Found 1 issue trackers configured for the foo plugin.")); assertThat(ctx.getIssueTrackerUrlsByNames()).contains(entry("github", "https://github.com/foo-plugin/issues")); verify(probe).doApply(plugin, ctx); @@ -213,7 +213,7 @@ void shouldDetectForOnlyJIRAInIssueTrackers() throws IOException { assertThat(probe.apply(plugin, ctx)) .usingRecursiveComparison() .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Issue tracker detected and returned successfully.")); + .isEqualTo(ProbeResult.success(IssueTrackerDetectionProbe.KEY, "Found 1 issue trackers configured for the foo plugin.")); assertThat(ctx.getIssueTrackerUrlsByNames()).contains(entry("jira", "https://issues.jenkins.io/issues/?jql=component=18331")); verify(probe).doApply(plugin, ctx); From d9fad0ca0970f5b5b2d53bb59d564be4d204bbca Mon Sep 17 00:00:00 2001 From: Jagruti Date: Thu, 24 Aug 2023 20:10:06 +0530 Subject: [PATCH 39/44] Adding null checks --- .../pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java | 2 +- .../pluginhealth/scoring/probes/JiraOpenIssuesProbe.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java index edb38aa36..6073d0159 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbe.java @@ -47,7 +47,7 @@ class GitHubOpenIssuesProbe extends AbstractOpenIssuesProbe { */ @Override Optional getCountOfOpenIssues(ProbeContext context) { - if (context.getIssueTrackerUrlsByNames().get("github") == null) { + if (context.getIssueTrackerUrlsByNames() == null) { LOGGER.info("IssueTracker has no GitHub open issues for the plugin."); return Optional.empty(); } diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java index d8379cb58..aa9853ea6 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java @@ -64,7 +64,7 @@ class JiraOpenIssuesProbe extends AbstractOpenIssuesProbe { */ @Override Optional getCountOfOpenIssues(ProbeContext context) { - if (context.getIssueTrackerUrlsByNames().get("jira") == null) { + if (context.getIssueTrackerUrlsByNames() == null) { LOGGER.info("IssueTracker has no JIRA open issues for the plugin."); return Optional.empty(); } From 663282c185b004cb83f7b00575c54ece0fa6ef38 Mon Sep 17 00:00:00 2001 From: Jagruti Tiwari Date: Wed, 6 Sep 2023 20:37:42 +0530 Subject: [PATCH 40/44] Apply suggestions from code review Co-authored-by: Adrien Lecharpentier --- .../pluginhealth/scoring/model/updatecenter/Plugin.java | 5 ----- .../scoring/probes/IssueTrackerDetectionProbe.java | 2 +- .../pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java | 4 ---- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java index 01d2e3ea1..d1f38da2c 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java @@ -44,11 +44,6 @@ public static Plugin of(String name, VersionNumber version, String scm, public io.jenkins.pluginhealth.scoring.model.Plugin toPlugin() { return new io.jenkins.pluginhealth.scoring.model.Plugin(this.name(), this.version(), this.scm(), this.releaseTimestamp()); } - - public List getIssueTrackers() { - return this.issueTrackers; - } - /** * Gets issue tracker details about a plugin. * diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java index a3fd1e724..c9a2b18f3 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java @@ -77,7 +77,7 @@ public String getDescription() { */ private Map getIssueTrackersForAPlugin(String pluginName, UpdateCenter updateCenter) { return (updateCenter.plugins().get(pluginName) != null) && (updateCenter.plugins().get(pluginName).getIssueTrackers() != null) - ? filterIssueTrackersForTypeAndViewUrl(updateCenter.plugins().get(pluginName).getIssueTrackers()) + ? filterIssueTrackersForTypeAndViewUrl(updateCenter.plugins().get(pluginName).issueTrackers()) : Map.of(); } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java index 5f5b256ae..43e514842 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java @@ -45,13 +45,9 @@ import io.jenkins.pluginhealth.scoring.model.updatecenter.UpdateCenter; import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; class JiraOpenIssuesProbeTest extends AbstractProbeTest { - @InjectMocks - JiraOpenIssuesProbe jiraOpenIssuesProbe = new JiraOpenIssuesProbe(); - @Test void shouldNotRunWithInvalidProbeResultRequirement() { final Plugin plugin = mock(Plugin.class); From c099e409cd4b1283096dd36aec074c805c307292 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Wed, 6 Sep 2023 21:01:13 +0530 Subject: [PATCH 41/44] Fixed foramatting, updated library uses based on code review --- .../scoring/probes/IssueTrackerDetectionProbe.java | 2 +- .../scoring/probes/JiraOpenIssuesProbe.java | 5 ++--- .../scoring/probes/CodeCoverageProbeTest.java | 10 +++++----- .../scoring/probes/DeprecatedPluginProbeTest.java | 10 +++++----- .../scoring/probes/GitHubOpenIssuesProbeTest.java | 10 +++++----- .../scoring/probes/InstallationStatProbeTest.java | 10 +++++----- .../probes/IssueTrackerDetectionProbeTest.java | 10 +++++----- .../scoring/probes/JenkinsCoreProbeTest.java | 10 +++++----- .../scoring/probes/JiraOpenIssuesProbeTest.java | 11 ++++++----- .../probes/KnownSecurityVulnerabilityProbeTest.java | 10 +++++----- .../scoring/probes/SpotBugsProbeTest.java | 10 +++++----- .../scoring/probes/UpForAdoptionProbeTest.java | 10 +++++----- .../UpdateCenterPluginPublicationProbeTest.java | 10 +++++----- 13 files changed, 59 insertions(+), 59 deletions(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java index c9a2b18f3..b16593354 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbe.java @@ -76,7 +76,7 @@ public String getDescription() { * @return A Map of filtered data from issue trackers. */ private Map getIssueTrackersForAPlugin(String pluginName, UpdateCenter updateCenter) { - return (updateCenter.plugins().get(pluginName) != null) && (updateCenter.plugins().get(pluginName).getIssueTrackers() != null) + return (updateCenter.plugins().get(pluginName) != null) && (updateCenter.plugins().get(pluginName).issueTrackers() != null) ? filterIssueTrackersForTypeAndViewUrl(updateCenter.plugins().get(pluginName).issueTrackers()) : Map.of(); } diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java index aa9853ea6..6bf30c1f9 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java @@ -30,7 +30,6 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; @@ -80,13 +79,13 @@ Optional getCountOfOpenIssues(ProbeContext context) { /* The `url` will contain the JIRA url to view issues. For ex: https://issues.jenkins.io/rest/api/latest/search?jql=component=15979 */ - URL url = new URL(viewJiraIssuesUrl); + URI uri = new URI(viewJiraIssuesUrl); /* Here, the query of the url "?jql=component=1833" is concatenated with " AND status=open". This gives the final API required to fetch JIRA issues. For ex: https://issues.jenkins.io/rest/api/latest/search?jql=component=15979%20and%20status=open */ - String api = JIRA_HOST.concat(url.getQuery()) + String api = JIRA_HOST.concat(uri.getQuery()) .concat("%20AND%20") .concat("status=open"); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java index 867f585f3..681aa6039 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbeTest.java @@ -49,16 +49,16 @@ import org.kohsuke.github.PagedIterable; class CodeCoverageProbeTest extends AbstractProbeTest { - @Test - public void shouldNotRequireRelease() { - assertThat(getSpy().requiresRelease()).isFalse(); - } - @Override CodeCoverageProbe getSpy() { return spy(CodeCoverageProbe.class); } + @Test + public void shouldNotRequireRelease() { + assertThat(getSpy().requiresRelease()).isFalse(); + } + @Test public void shouldBeRelatedToCode() { assertThat(getSpy().isSourceCodeRelated()).isTrue(); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java index c0e72e04c..ac2f61f36 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/DeprecatedPluginProbeTest.java @@ -44,16 +44,16 @@ import org.junit.jupiter.api.Test; class DeprecatedPluginProbeTest extends AbstractProbeTest { - @Test - void shouldNotRequireRelease() { - assertThat(getSpy().requiresRelease()).isFalse(); - } - @Override DeprecatedPluginProbe getSpy() { return spy(DeprecatedPluginProbe.class); } + @Test + void shouldNotRequireRelease() { + assertThat(getSpy().requiresRelease()).isFalse(); + } + @Test void shouldBeAbleToDetectNonDeprecatedPlugin() { final var plugin = mock(io.jenkins.pluginhealth.scoring.model.Plugin.class); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java index f67161489..454162278 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/GitHubOpenIssuesProbeTest.java @@ -46,6 +46,11 @@ import org.kohsuke.github.GitHub; class GitHubOpenIssuesProbeTest extends AbstractProbeTest { + @Override + GitHubOpenIssuesProbe getSpy() { + return spy(GitHubOpenIssuesProbe.class); + } + @Test void shouldNotRunWithInvalidProbeResultRequirement() { final Plugin plugin = mock(Plugin.class); @@ -81,11 +86,6 @@ void shouldNotRunWithInvalidProbeResultRequirement() { verify(probe, never()).doApply(plugin, ctx); } - @Override - GitHubOpenIssuesProbe getSpy() { - return spy(GitHubOpenIssuesProbe.class); - } - @Test void shouldBeAbleToFindNumberOfOpenIssuesInGH() throws IOException { final String pluginName = "foo"; diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java index a40764bef..af2c14d77 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/InstallationStatProbeTest.java @@ -43,16 +43,16 @@ import org.junit.jupiter.api.Test; class InstallationStatProbeTest extends AbstractProbeTest { - @Test - void doesNotRequireRelease() { - assertThat(getSpy().requiresRelease()).isFalse(); - } - @Override InstallationStatProbe getSpy() { return spy(InstallationStatProbe.class); } + @Test + void doesNotRequireRelease() { + assertThat(getSpy().requiresRelease()).isFalse(); + } + @Test void doesNotRequireCodeModification() { assertThat(getSpy().isSourceCodeRelated()).isFalse(); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java index 20a0fef42..24f5370f7 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/IssueTrackerDetectionProbeTest.java @@ -45,6 +45,11 @@ import org.junit.jupiter.api.Test; class IssueTrackerDetectionProbeTest extends AbstractProbeTest { + @Override + IssueTrackerDetectionProbe getSpy() { + return spy(IssueTrackerDetectionProbe.class); + } + @Test void shouldNotRunWithInvalidProbeResultRequirement() { final Plugin plugin = mock(Plugin.class); @@ -65,11 +70,6 @@ void shouldNotRunWithInvalidProbeResultRequirement() { verify(probe, never()).doApply(plugin, ctx); } - @Override - IssueTrackerDetectionProbe getSpy() { - return spy(IssueTrackerDetectionProbe.class); - } - @Test void shouldDetectIssueTrackersInPlugin() throws IOException { final Plugin plugin = mock(Plugin.class); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java index 1609a8ae3..de2e22a34 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JenkinsCoreProbeTest.java @@ -42,16 +42,16 @@ import org.junit.jupiter.api.Test; class JenkinsCoreProbeTest extends AbstractProbeTest { - @Test - void shouldRequireRelease() { - assertThat(getSpy().requiresRelease()).isTrue(); - } - @Override JenkinsCoreProbe getSpy() { return spy(JenkinsCoreProbe.class); } + @Test + void shouldRequireRelease() { + assertThat(getSpy().requiresRelease()).isTrue(); + } + @Test void shouldNotRequireSourceCodeChange() { assertThat(getSpy().isSourceCodeRelated()).isFalse(); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java index 43e514842..011efc393 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbeTest.java @@ -47,6 +47,10 @@ import org.junit.jupiter.api.Test; class JiraOpenIssuesProbeTest extends AbstractProbeTest { + @Override + JiraOpenIssuesProbe getSpy() { + return spy(JiraOpenIssuesProbe.class); + } @Test void shouldNotRunWithInvalidProbeResultRequirement() { @@ -83,11 +87,6 @@ void shouldNotRunWithInvalidProbeResultRequirement() { verify(probe, never()).doApply(plugin, ctx); } - @Override - JiraOpenIssuesProbe getSpy() { - return spy(JiraOpenIssuesProbe.class); - } - @Test void shouldBeAbleToFindNumberOfOpenIssuesInJira() throws IOException, InterruptedException { final String pluginName = "mailer"; @@ -131,6 +130,7 @@ void shouldBeAbleToFindNumberOfOpenIssuesInJira() throws IOException, Interrupte any(HttpResponse.BodyHandler.class) )).thenReturn(mockedHttpResponse); + final JiraOpenIssuesProbe jiraOpenIssuesProbe = spy(JiraOpenIssuesProbe.class); jiraOpenIssuesProbe.httpClient = mockedHttpClient; assertThat(jiraOpenIssuesProbe.apply(plugin, ctx)) @@ -182,6 +182,7 @@ void shouldReturnErrorWhenJIRAReturnsErrors() throws IOException, InterruptedExc any(HttpResponse.BodyHandler.class) )).thenReturn(mockedHttpResponse); + final JiraOpenIssuesProbe jiraOpenIssuesProbe = spy(JiraOpenIssuesProbe.class); jiraOpenIssuesProbe.httpClient = mockedHttpClient; assertThat(jiraOpenIssuesProbe.apply(plugin, ctx)) diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java index 1a2aaca89..f4eec51db 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbeTest.java @@ -45,16 +45,16 @@ import org.junit.jupiter.api.Test; class KnownSecurityVulnerabilityProbeTest extends AbstractProbeTest { - @Test - void shouldNotRequireNewRelease() { - assertThat(getSpy().requiresRelease()).isFalse(); - } - @Override KnownSecurityVulnerabilityProbe getSpy() { return spy(KnownSecurityVulnerabilityProbe.class); } + @Test + void shouldNotRequireNewRelease() { + assertThat(getSpy().requiresRelease()).isFalse(); + } + @Test void shouldBeOKWithNoSecurityWarning() { final var plugin = mock(io.jenkins.pluginhealth.scoring.model.Plugin.class); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java index 15dbddbe7..56bb75b79 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SpotBugsProbeTest.java @@ -50,16 +50,16 @@ @ExtendWith(MockitoExtension.class) class SpotBugsProbeTest extends AbstractProbeTest { - @Test - public void shouldNotRequireRelease() { - assertThat(getSpy().requiresRelease()).isFalse(); - } - @Override protected SpotBugsProbe getSpy() { return spy(SpotBugsProbe.class); } + @Test + public void shouldNotRequireRelease() { + assertThat(getSpy().requiresRelease()).isFalse(); + } + @Test public void shouldBeRelatedToCode() { assertThat(getSpy().isSourceCodeRelated()).isTrue(); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java index 5155b2533..50659cd96 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpForAdoptionProbeTest.java @@ -43,16 +43,16 @@ import org.junit.jupiter.api.Test; class UpForAdoptionProbeTest extends AbstractProbeTest { - @Test - void shouldNotRequireNewRelease() { - assertThat(getSpy().requiresRelease()).isFalse(); - } - @Override UpForAdoptionProbe getSpy() { return spy(UpForAdoptionProbe.class); } + @Test + void shouldNotRequireNewRelease() { + assertThat(getSpy().requiresRelease()).isFalse(); + } + @Test void shouldBeAbleToDetectPluginForAdoption() { final var plugin = mock(io.jenkins.pluginhealth.scoring.model.Plugin.class); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java index 0555323f5..2c9d4fdfb 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/UpdateCenterPluginPublicationProbeTest.java @@ -40,16 +40,16 @@ import org.junit.jupiter.api.Test; class UpdateCenterPluginPublicationProbeTest extends AbstractProbeTest { - @Test - void shouldNotRequireRelease() { - assertThat(getSpy().requiresRelease()).isFalse(); - } - @Override UpdateCenterPluginPublicationProbe getSpy() { return spy(UpdateCenterPluginPublicationProbe.class); } + @Test + void shouldNotRequireRelease() { + assertThat(getSpy().requiresRelease()).isFalse(); + } + @Test void shouldFailIfPluginIsNotInUpdateCenterMap() { final Plugin plugin = mock(Plugin.class); From ec28408b66d1e0f0ef999eda7ac26249fd55681d Mon Sep 17 00:00:00 2001 From: Jagruti Date: Wed, 6 Sep 2023 21:27:12 +0530 Subject: [PATCH 42/44] Updated syntax for null check --- .../pluginhealth/scoring/probes/JiraOpenIssuesProbe.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java index 6bf30c1f9..31f2832b6 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/JiraOpenIssuesProbe.java @@ -69,7 +69,7 @@ Optional getCountOfOpenIssues(ProbeContext context) { } /* Stores the JIRA URL to view all existing issues in the plugin. Ex: https://github.com/jenkinsci/cloudevents-plugin/issues */ - String viewJiraIssuesUrl = context.getIssueTrackerUrlsByNames().get("jira"); + String viewJiraIssuesUrl = context.getIssueTrackerUrlsByNames().getOrDefault("jira", ""); if (viewJiraIssuesUrl == null || viewJiraIssuesUrl.isEmpty()) { LOGGER.info("The plugin does not use JIRA to track issues."); From 9244d60b6eb51dcd67d2922ee2cec66f22abf6c1 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Thu, 7 Sep 2023 16:51:33 +0530 Subject: [PATCH 43/44] Fixing merge issues --- .../io/jenkins/pluginhealth/scoring/probes/ProbeContext.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java index 4a2805f6f..bec7ea5f8 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeContext.java @@ -101,6 +101,7 @@ public void setIssueTrackerNameAndUrl(Map issueTrackerNameAndUrl */ public Map getIssueTrackerUrlsByNames() { return issueTrackerUrlsByNames; + } public Optional getScmFolderPath() { return scmFolderPath; From b722a875e474f652dc6d4cf9e140a777af5bdc80 Mon Sep 17 00:00:00 2001 From: Jagruti Date: Thu, 7 Sep 2023 21:44:36 +0530 Subject: [PATCH 44/44] Fixing checkstyle issues --- .../jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java index d1f38da2c..c3879c48f 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/model/updatecenter/Plugin.java @@ -44,6 +44,7 @@ public static Plugin of(String name, VersionNumber version, String scm, public io.jenkins.pluginhealth.scoring.model.Plugin toPlugin() { return new io.jenkins.pluginhealth.scoring.model.Plugin(this.name(), this.version(), this.scm(), this.releaseTimestamp()); } + /** * Gets issue tracker details about a plugin. *