diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbe.java index a2bbc15b2..a30abda39 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/CodeCoverageProbe.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2023 Jenkins Infra + * Copyright (c) 2023-2024 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 @@ -21,13 +21,11 @@ * 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.regex.Matcher; import java.util.regex.Pattern; @@ -50,7 +48,7 @@ public class CodeCoverageProbe extends Probe { private static final Logger LOGGER = LoggerFactory.getLogger(CodeCoverageProbe.class); private static final String COVERAGE_TITLE_REGEXP = - "^Line(?: Coverage)?: (?\\d{1,2}(?:\\.\\d{1,2})?)%(?: \\(.+\\))?. Branch(?: Coverage)?: (?\\d{1,2}(?:\\.\\d{1,2})?)%(?: \\(.+\\))?\\.?$"; + "^Line(?: Coverage)?: (?\\d{1,2}(?:\\.\\d{1,2})?)%(?: \\(.+\\))?. Branch(?: Coverage)?: (?\\d{1,2}(?:\\.\\d{1,2})?)%(?: \\(.+\\))?\\.?$"; private static final Pattern COVERAGE_TITLE_PATTERN = Pattern.compile(COVERAGE_TITLE_REGEXP); public static final String KEY = "code-coverage"; @@ -59,7 +57,7 @@ public class CodeCoverageProbe extends Probe { @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { final io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin ucPlugin = - context.getUpdateCenter().plugins().get(plugin.getName()); + context.getUpdateCenter().plugins().get(plugin.getName()); if (ucPlugin == null) { return error("Plugin cannot be found in Update-Center."); } @@ -67,32 +65,34 @@ protected ProbeResult doApply(Plugin plugin, ProbeContext context) { if (defaultBranch == null || defaultBranch.isBlank()) { return this.error("No default branch configured for the plugin."); } + if (context.getRepositoryName().isEmpty()) { + return this.error("Cannot determine plugin repository."); + } try { - final Optional repositoryName = context.getRepositoryName(); - if (repositoryName.isPresent()) { - final GHRepository ghRepository = context.getGitHub().getRepository(repositoryName.get()); - final List ghCheckRuns = - ghRepository.getCheckRuns(defaultBranch, Map.of("check_name", "Code Coverage")).toList(); - if (ghCheckRuns.isEmpty()) { - return this.success("Could not determine code coverage for the plugin."); - } + final String repositoryName = context.getRepositoryName().get(); + final GHRepository ghRepository = context.getGitHub().getRepository(repositoryName); + final List ghCheckRuns = ghRepository + .getCheckRuns(defaultBranch, Map.of("check_name", "Code Coverage")) + .toList(); + if (ghCheckRuns.isEmpty()) { + return this.success("Could not determine code coverage for the plugin."); + } - double overall_line_coverage = 100; - double overall_branch_coverage = 100; - for (GHCheckRun checkRun : ghCheckRuns) { - final Matcher matcher = COVERAGE_TITLE_PATTERN.matcher(checkRun.getOutput().getTitle()); - if (matcher.matches()) { - final double line_coverage = Double.parseDouble(matcher.group("line")); - final double branch_coverage = Double.parseDouble(matcher.group("branch")); - overall_line_coverage = Math.min(overall_line_coverage, line_coverage); - overall_branch_coverage = Math.min(overall_branch_coverage, branch_coverage); - } + double overall_line_coverage = 100; + double overall_branch_coverage = 100; + for (GHCheckRun checkRun : ghCheckRuns) { + final Matcher matcher = + COVERAGE_TITLE_PATTERN.matcher(checkRun.getOutput().getTitle()); + if (matcher.matches()) { + final double line_coverage = Double.parseDouble(matcher.group("line")); + final double branch_coverage = Double.parseDouble(matcher.group("branch")); + overall_line_coverage = Math.min(overall_line_coverage, line_coverage); + overall_branch_coverage = Math.min(overall_branch_coverage, branch_coverage); } - - return this.success("Line coverage: " + overall_line_coverage + "%. Branch coverage: " + overall_branch_coverage + "%."); - } else { - return this.error("Cannot determine plugin repository."); } + + return this.success("Line coverage: " + overall_line_coverage + "%. Branch coverage: " + + overall_branch_coverage + "%."); } catch (IOException e) { LOGGER.warn("Could not get Coverage check for {}", plugin.getName(), e); return this.error("Could not get coverage check"); diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/DependabotPullRequestProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/DependabotPullRequestProbe.java index dadd18734..6835a28d2 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/DependabotPullRequestProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/DependabotPullRequestProbe.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2023 Jenkins Infra + * Copyright (c) 2023-2024 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 @@ -21,7 +21,6 @@ * 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; @@ -50,14 +49,18 @@ public class DependabotPullRequestProbe extends Probe { @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { + if (context.getRepositoryName().isEmpty()) { + return this.error("There is no repository for " + plugin.getName() + "."); + } try { final GitHub gh = context.getGitHub(); - final GHRepository repository = gh.getRepository(context.getRepositoryName().orElseThrow()); + final GHRepository repository = + gh.getRepository(context.getRepositoryName().get()); final List pullRequests = repository.getPullRequests(GHIssueState.OPEN); final long count = pullRequests.stream() - .filter(pr -> pr.getLabels().stream().anyMatch(label -> "dependencies".equals(label.getName()))) - .count(); + .filter(pr -> pr.getLabels().stream().anyMatch(label -> "dependencies".equals(label.getName()))) + .count(); return this.success("%d".formatted(count)); } catch (NoSuchElementException | IOException e) { diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbe.java index fbcf560f5..9b99ecab0 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/KnownSecurityVulnerabilityProbe.java @@ -54,7 +54,7 @@ protected ProbeResult doApply(Plugin plugin, ProbeContext context) { final Matcher matcher = pattern.matcher(plugin.getVersion().toString()); return matcher.find(); })) - .map(warning -> warning.id() + "|" + warning.url()) + .map(warning -> String.join("|", warning.id(), warning.url())) .collect(Collectors.joining(", ")); return !issues.isBlank() ? this.success(issues) : this.success("No known security vulnerabilities."); diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/PluginDescriptionMigrationProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/PluginDescriptionMigrationProbe.java index e2a5e4058..799a9a94d 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/PluginDescriptionMigrationProbe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/PluginDescriptionMigrationProbe.java @@ -43,12 +43,11 @@ public class PluginDescriptionMigrationProbe extends Probe { @Override protected ProbeResult doApply(Plugin plugin, ProbeContext context) { - final Optional scmRepositoryOpt = context.getScmRepository(); - if (scmRepositoryOpt.isEmpty()) { - return error("Cannot access plugin repository."); + if (context.getScmRepository().isEmpty()) { + return this.error("There is no local repository for plugin " + plugin.getName() + "."); } - final Path repository = scmRepositoryOpt.get(); + final Path repository = context.getScmRepository().get(); final Path pluginFolder = context.getScmFolderPath().map(repository::resolve).orElse(repository); diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/Probe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/Probe.java index 4e144ab3b..74929256a 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/Probe.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/Probe.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2023 Jenkins Infra + * Copyright (c) 2023-2024 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 @@ -21,7 +21,6 @@ * 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.nio.file.Path; @@ -56,9 +55,7 @@ public final ProbeResult apply(Plugin plugin, ProbeContext context) { return doApply(plugin, context); } final ProbeResult lastResult = plugin.getDetails().get(key()); - return lastResult != null ? - lastResult : - this.error(key() + " was not executed on " + plugin.getName()); + return lastResult != null ? lastResult : this.error(key() + " was not executed on " + plugin.getName()); } private boolean shouldBeExecuted(Plugin plugin, ProbeContext context) { @@ -75,26 +72,28 @@ private boolean shouldBeExecuted(Plugin plugin, ProbeContext context) { if (!this.requiresRelease() && !this.isSourceCodeRelated()) { return true; } - if (this.requiresRelease() && - (previousResult.timestamp() != null && previousResult.timestamp().isBefore(plugin.getReleaseTimestamp()))) { + if (this.requiresRelease() + && (previousResult.timestamp() != null + && previousResult.timestamp().isBefore(plugin.getReleaseTimestamp()))) { return true; } final Optional optionalScmRepository = context.getScmRepository(); if (this.isSourceCodeRelated() && optionalScmRepository.isEmpty()) { - LOGGER.info( - "{} requires the SCM for {} but the SCM was not cloned locally", - this.key(), plugin.getName() - ); + LOGGER.info("{} requires the SCM for {} but the SCM was not cloned locally", this.key(), plugin.getName()); return false; } final Optional optionalLastCommit = context.getLastCommitDate(); - if (this.isSourceCodeRelated() && - optionalLastCommit - .map(date -> previousResult.timestamp() != null && previousResult.timestamp().isBefore(date)) - .orElseGet(() -> { - LOGGER.info("{} is based on code modification but last commit for {} is unknown. It will be executed.", key(), plugin.getName()); - return true; - })) { + if (this.isSourceCodeRelated() + && optionalLastCommit + .map(date -> previousResult.timestamp() != null + && previousResult.timestamp().isBefore(date)) + .orElseGet(() -> { + LOGGER.info( + "{} is based on code modification but last commit for {} is unknown. It will be executed.", + key(), + plugin.getName()); + return true; + })) { return true; } diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/scores/SecurityWarningScoring.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/scores/SecurityWarningScoring.java index 31aa576d0..496120766 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/scores/SecurityWarningScoring.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/scores/SecurityWarningScoring.java @@ -60,7 +60,7 @@ public ScoringComponentResult getScore(Plugin $, Map probeR 100, getWeight(), List.of("Plugin does not seem to have on-going security advisory.")); } final List resolutions = Arrays.stream( - probeResult.message().split(",")) + probeResult.message().split(", ")) .map(m -> { final String[] parts = m.trim().split("\\|"); return new Resolution(parts[0], parts[1]); diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/PluginDescriptionMigrationProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/PluginDescriptionMigrationProbeTest.java index c54e7d46f..4bdd31881 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/PluginDescriptionMigrationProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/PluginDescriptionMigrationProbeTest.java @@ -21,7 +21,6 @@ * 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; @@ -54,13 +53,16 @@ void shouldRequiresPluginRepository() { final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); + when(plugin.getName()).thenReturn("plugin-a"); + final PluginDescriptionMigrationProbe probe = getSpy(); final ProbeResult result = probe.apply(plugin, ctx); assertThat(result) - .usingRecursiveComparison() - .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.error(PluginDescriptionMigrationProbe.KEY, "Cannot access plugin repository.", 0)); + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.error( + PluginDescriptionMigrationProbe.KEY, "There is no local repository for plugin plugin-a.", 0)); } @Test @@ -75,9 +77,10 @@ void shouldFailWhenPluginRepositoryIsEmpty() throws Exception { final ProbeResult result = probe.apply(plugin, ctx); assertThat(result) - .usingRecursiveComparison() - .comparingOnlyFields("id", "message", "status") - .isEqualTo(ProbeResult.error(PluginDescriptionMigrationProbe.KEY, "Cannot browse plugin source code folder.", 0)); + .usingRecursiveComparison() + .comparingOnlyFields("id", "message", "status") + .isEqualTo(ProbeResult.error( + PluginDescriptionMigrationProbe.KEY, "Cannot browse plugin source code folder.", 0)); } @Test @@ -93,9 +96,12 @@ void shouldDetectMissingJellyFile() throws Exception { final ProbeResult result = probe.apply(plugin, ctx); assertThat(result) - .usingRecursiveComparison() - .comparingOnlyFields("id", "message", "status") - .isEqualTo(ProbeResult.success(PluginDescriptionMigrationProbe.KEY, "There is no `index.jelly` file in `src/main/resources`.", 0)); + .usingRecursiveComparison() + .comparingOnlyFields("id", "message", "status") + .isEqualTo(ProbeResult.success( + PluginDescriptionMigrationProbe.KEY, + "There is no `index.jelly` file in `src/main/resources`.", + 0)); } @Test @@ -104,7 +110,8 @@ void shouldDetectExampleJellyFile() throws Exception { final ProbeContext ctx = mock(ProbeContext.class); final Path repository = Files.createTempDirectory(getClass().getSimpleName()); - final Path resources = Files.createDirectories(repository.resolve("src").resolve("main").resolve("resources")); + final Path resources = Files.createDirectories( + repository.resolve("src").resolve("main").resolve("resources")); final Path jelly = Files.createFile(resources.resolve("index.jelly")); Files.writeString(jelly, """
@@ -117,9 +124,12 @@ void shouldDetectExampleJellyFile() throws Exception { final ProbeResult result = probe.apply(plugin, ctx); assertThat(result) - .usingRecursiveComparison() - .comparingOnlyFields("id", "message", "status") - .isEqualTo(ProbeResult.success(PluginDescriptionMigrationProbe.KEY, "Plugin is using description from the plugin archetype.", 0)); + .usingRecursiveComparison() + .comparingOnlyFields("id", "message", "status") + .isEqualTo(ProbeResult.success( + PluginDescriptionMigrationProbe.KEY, + "Plugin is using description from the plugin archetype.", + 0)); } @Test @@ -129,7 +139,8 @@ void shouldDetectExampleJellyFileWithModule() throws Exception { final Path repository = Files.createTempDirectory(getClass().getSimpleName()); final Path module = Files.createDirectory(repository.resolve("plugin")); - final Path resources = Files.createDirectories(module.resolve("src").resolve("main").resolve("resources")); + final Path resources = + Files.createDirectories(module.resolve("src").resolve("main").resolve("resources")); final Path jelly = Files.createFile(resources.resolve("index.jelly")); Files.writeString(jelly, """
@@ -143,9 +154,12 @@ void shouldDetectExampleJellyFileWithModule() throws Exception { final ProbeResult result = probe.apply(plugin, ctx); assertThat(result) - .usingRecursiveComparison() - .comparingOnlyFields("id", "message", "status") - .isEqualTo(ProbeResult.success(PluginDescriptionMigrationProbe.KEY, "Plugin is using description from the plugin archetype.", 0)); + .usingRecursiveComparison() + .comparingOnlyFields("id", "message", "status") + .isEqualTo(ProbeResult.success( + PluginDescriptionMigrationProbe.KEY, + "Plugin is using description from the plugin archetype.", + 0)); } @Test @@ -154,9 +168,12 @@ void shouldDetectCorrectJellyFile() throws Exception { final ProbeContext ctx = mock(ProbeContext.class); final Path repository = Files.createTempDirectory(getClass().getSimpleName()); - final Path resources = Files.createDirectories(repository.resolve("src").resolve("main").resolve("resources")); + final Path resources = Files.createDirectories( + repository.resolve("src").resolve("main").resolve("resources")); final Path jelly = Files.createFile(resources.resolve("index.jelly")); - Files.writeString(jelly, """ + Files.writeString( + jelly, + """
This is a plugin doing something.
@@ -167,9 +184,10 @@ void shouldDetectCorrectJellyFile() throws Exception { final ProbeResult result = probe.apply(plugin, ctx); assertThat(result) - .usingRecursiveComparison() - .comparingOnlyFields("id", "message", "status") - .isEqualTo(ProbeResult.success(PluginDescriptionMigrationProbe.KEY, "Plugin seems to have a correct description.", 0)); + .usingRecursiveComparison() + .comparingOnlyFields("id", "message", "status") + .isEqualTo(ProbeResult.success( + PluginDescriptionMigrationProbe.KEY, "Plugin seems to have a correct description.", 0)); } @Test @@ -179,9 +197,12 @@ void shouldDetectCorrectJellyFileWithModule() throws Exception { final Path repository = Files.createTempDirectory(getClass().getSimpleName()); final Path module = Files.createDirectory(repository.resolve("plugin")); - final Path resources = Files.createDirectories(module.resolve("src").resolve("main").resolve("resources")); + final Path resources = + Files.createDirectories(module.resolve("src").resolve("main").resolve("resources")); final Path jelly = Files.createFile(resources.resolve("index.jelly")); - Files.writeString(jelly, """ + Files.writeString( + jelly, + """
This is a plugin doing something.
@@ -193,8 +214,9 @@ void shouldDetectCorrectJellyFileWithModule() throws Exception { final ProbeResult result = probe.apply(plugin, ctx); assertThat(result) - .usingRecursiveComparison() - .comparingOnlyFields("id", "message", "status") - .isEqualTo(ProbeResult.success(PluginDescriptionMigrationProbe.KEY, "Plugin seems to have a correct description.", 0)); + .usingRecursiveComparison() + .comparingOnlyFields("id", "message", "status") + .isEqualTo(ProbeResult.success( + PluginDescriptionMigrationProbe.KEY, "Plugin seems to have a correct description.", 0)); } } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SCMLinkValidationProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SCMLinkValidationProbeTest.java index 234d6312a..7139255b9 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SCMLinkValidationProbeTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/SCMLinkValidationProbeTest.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2023 Jenkins Infra + * Copyright (c) 2023-2024 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 @@ -21,7 +21,6 @@ * 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; @@ -58,22 +57,23 @@ void shouldNotAcceptNullNorEmptyScm() { final Plugin plugin = mock(Plugin.class); final ProbeContext ctx = mock(ProbeContext.class); - when(plugin.getScm()).thenReturn( - null, "" - ); + when(plugin.getName()).thenReturn("plugin-a"); + when(plugin.getScm()).thenReturn(null, ""); final SCMLinkValidationProbe probe = getSpy(); assertThat(probe.apply(plugin, ctx)) - .isNotNull() - .usingRecursiveComparison() - .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.error(SCMLinkValidationProbe.KEY, "The plugin SCM link is empty.", probe.getVersion())); + .isNotNull() + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.error( + SCMLinkValidationProbe.KEY, "The plugin SCM link is empty.", probe.getVersion())); assertThat(probe.apply(plugin, ctx)) - .isNotNull() - .usingRecursiveComparison() - .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.error(SCMLinkValidationProbe.KEY, "The plugin SCM link is empty.", probe.getVersion())); + .isNotNull() + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.error( + SCMLinkValidationProbe.KEY, "The plugin SCM link is empty.", probe.getVersion())); } @Test @@ -85,10 +85,13 @@ void shouldRecognizeIncorrectSCMUrl() { when(plugin.getScm()).thenReturn("this-is-not-correct"); assertThat(probe.apply(plugin, ctx)) - .isNotNull() - .usingRecursiveComparison() - .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.error(SCMLinkValidationProbe.KEY, "SCM link doesn't match GitHub plugin repositories.", probe.getVersion())); + .isNotNull() + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.error( + SCMLinkValidationProbe.KEY, + "SCM link doesn't match GitHub plugin repositories.", + probe.getVersion())); } @Test @@ -100,19 +103,20 @@ void shouldRecognizeCorrectGitHubUrl() throws IOException { when(plugin.getName()).thenReturn("test-repo"); when(plugin.getScm()).thenReturn("https://github.com/" + repositoryName); - when(ctx.getScmRepository()).thenReturn(Optional.of( - Path.of("src/test/resources/jenkinsci/test-repo/test-nested-dir-1/test-nested-dir-2") - )); + when(ctx.getScmRepository()) + .thenReturn(Optional.of( + Path.of("src/test/resources/jenkinsci/test-repo/test-nested-dir-1/test-nested-dir-2"))); when(ctx.getGitHub()).thenReturn(gh); when(gh.getRepository(repositoryName)).thenReturn(new GHRepository()); final SCMLinkValidationProbe probe = getSpy(); assertThat(probe.apply(plugin, ctx)) - .isNotNull() - .usingRecursiveComparison() - .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success(SCMLinkValidationProbe.KEY, "The plugin SCM link is valid.", probe.getVersion())); + .isNotNull() + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success( + SCMLinkValidationProbe.KEY, "The plugin SCM link is valid.", probe.getVersion())); } @Test @@ -132,10 +136,10 @@ void shouldRecognizeInvalidGitHubUrl() throws Exception { final SCMLinkValidationProbe probe = getSpy(); assertThat(probe.apply(plugin, ctx)) - .isNotNull() - .usingRecursiveComparison() - .comparingOnlyFields("id", "status", "message") - .isEqualTo(ProbeResult.success("scm", "The plugin SCM link is invalid.", probe.getVersion())); + .isNotNull() + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success("scm", "The plugin SCM link is invalid.", probe.getVersion())); } @Test @@ -149,9 +153,8 @@ void shouldBeAbleToFindPluginInModule() throws IOException { when(plugin.getScm()).thenReturn("https://github.com/jenkinsci/this-is-fine"); when(plugin.getName()).thenReturn("test-repo"); - when(ctx.getScmRepository()).thenReturn(Optional.of( - Path.of("src/test/resources/jenkinsci/test-repo/test-nested-dir-1") - )); + when(ctx.getScmRepository()) + .thenReturn(Optional.of(Path.of("src/test/resources/jenkinsci/test-repo/test-nested-dir-1"))); when(ctx.getGitHub()).thenReturn(gh); when(gh.getRepository("jenkinsci/this-is-fine")).thenReturn(ghRepo); @@ -159,9 +162,9 @@ void shouldBeAbleToFindPluginInModule() throws IOException { final ProbeResult result = probe.apply(plugin, ctx); assertThat(result) - .usingRecursiveComparison() - .comparingOnlyFields("id", "message", "status") - .isEqualTo(ProbeResult.success(probe.key(), "The plugin SCM link is valid.", probe.getVersion())); + .usingRecursiveComparison() + .comparingOnlyFields("id", "message", "status") + .isEqualTo(ProbeResult.success(probe.key(), "The plugin SCM link is valid.", probe.getVersion())); verify(ctx).setScmFolderPath(Path.of("test-nested-dir-2")); } diff --git a/war/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeEngine.java b/war/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeEngine.java index f24e1efa0..29515e3d5 100644 --- a/war/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeEngine.java +++ b/war/src/main/java/io/jenkins/pluginhealth/scoring/probes/ProbeEngine.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2023 Jenkins Infra + * Copyright (c) 2023-2024 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 @@ -21,7 +21,6 @@ * 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; @@ -57,7 +56,12 @@ public final class ProbeEngine { private final GitHub gitHub; private final PluginDocumentationService pluginDocumentationService; - public ProbeEngine(ProbeService probeService, PluginService pluginService, UpdateCenterService updateCenterService, GitHub gitHub, PluginDocumentationService pluginDocumentationService) { + public ProbeEngine( + ProbeService probeService, + PluginService pluginService, + UpdateCenterService updateCenterService, + GitHub gitHub, + PluginDocumentationService pluginDocumentationService) { this.probeService = probeService; this.pluginService = pluginService; this.updateCenterService = updateCenterService; @@ -72,8 +76,10 @@ public void run() throws IOException { LOGGER.info("Start running probes on all plugins"); final UpdateCenter updateCenter = updateCenterService.fetchUpdateCenter(); final Map pluginDocumentationUrl = pluginDocumentationService.fetchPluginDocumentationUrl(); - pluginService.streamAll().parallel() - .forEach(plugin -> this.runOn(plugin, updateCenter, pluginDocumentationUrl)); + pluginService + .streamAll() + .parallel() + .forEach(plugin -> this.runOn(plugin, updateCenter, pluginDocumentationUrl)); LOGGER.info("Probe engine has finished"); } @@ -92,10 +98,6 @@ public void runOn(Plugin plugin) throws IOException { } private void runOn(Plugin plugin, UpdateCenter updateCenter, Map pluginDocumentationUrl) { - if (plugin.getScm() == null || plugin.getScm().isBlank()) { - LOGGER.info("Will not run probes on {} because its SCM is not set correctly.", plugin.getName()); - return; - } final ProbeContext probeContext; try { probeContext = probeService.getProbeContext(plugin, updateCenter);