diff --git a/analytics/checkstyle-configuration.xml b/analytics/checkstyle-configuration.xml index 5954cb34b..90edb53a0 100644 --- a/analytics/checkstyle-configuration.xml +++ b/analytics/checkstyle-configuration.xml @@ -120,7 +120,7 @@ + value="ANNOTATION, ANNOTATION_FIELD_DEF, CTOR_CALL, CTOR_DEF, DOT, ENUM_CONSTANT_DEF, EXPR, LITERAL_CATCH, LITERAL_DO, LITERAL_FOR, LITERAL_IF, LITERAL_NEW, LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_WHILE, METHOD_DEF, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL, LAMBDA, RECORD_DEF"/> diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/CodeOwnershipProbe.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/CodeOwnershipProbe.java new file mode 100644 index 000000000..7ce290141 --- /dev/null +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/probes/CodeOwnershipProbe.java @@ -0,0 +1,91 @@ +/* + * MIT License + * + * Copyright (c) 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 + * 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.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Stream; + +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(CodeOwnershipProbe.ORDER) +public class CodeOwnershipProbe extends Probe { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDependencyBotConfigurationProbe.class); + public static final String KEY = "code-ownership"; + public static final int ORDER = AbstractDependencyBotConfigurationProbe.ORDER + 100; + + @Override + protected ProbeResult doApply(Plugin plugin, ProbeContext context) { + if (context.getScmRepository().isEmpty()) { + return this.error("There is no local repository for plugin " + plugin.getName() + "."); + } + final Path scmRepository = context.getScmRepository().get(); + + try (Stream paths = Files.find( + scmRepository, + 2, + (path, $) -> Files.isRegularFile(path) + && "CODEOWNERS".equals(path.getFileName().toString()))) { + return paths.findFirst() + .map(file -> { + try { + return Files.readAllLines(file).stream() + .anyMatch(line -> line.contains( + "@jenkinsci/%s-plugin-developers".formatted(plugin.getName()))) + ? this.success("CODEOWNERS file is valid.") + : this.success("CODEOWNERS file is not set correctly."); + } catch (IOException ex) { + return this.error("Could not read CODEOWNERS file."); + } + }) + .orElseGet(() -> this.success("No CODEOWNERS file found in plugin repository.")); + } catch (IOException ex) { + LOGGER.error("Could not browse the plugin folder during probe {}", key(), ex); + return this.error("Could not browse the plugin folder."); + } + } + + @Override + public String key() { + return KEY; + } + + @Override + public String getDescription() { + return "Detects if the code ownership file is set correctly or not."; + } + + @Override + public long getVersion() { + return 1; + } +} diff --git a/core/src/main/java/io/jenkins/pluginhealth/scoring/scores/PluginMaintenanceScoring.java b/core/src/main/java/io/jenkins/pluginhealth/scoring/scores/PluginMaintenanceScoring.java index b5b5d76fb..bf1088f46 100644 --- a/core/src/main/java/io/jenkins/pluginhealth/scoring/scores/PluginMaintenanceScoring.java +++ b/core/src/main/java/io/jenkins/pluginhealth/scoring/scores/PluginMaintenanceScoring.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2023-2024 Jenkins Infra + * Copyright (c) 2022-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.scores; import java.util.List; @@ -31,6 +30,7 @@ import io.jenkins.pluginhealth.scoring.model.ProbeResult; import io.jenkins.pluginhealth.scoring.model.Resolution; import io.jenkins.pluginhealth.scoring.model.ScoringComponentResult; +import io.jenkins.pluginhealth.scoring.probes.CodeOwnershipProbe; import io.jenkins.pluginhealth.scoring.probes.ContinuousDeliveryProbe; import io.jenkins.pluginhealth.scoring.probes.DependabotProbe; import io.jenkins.pluginhealth.scoring.probes.DependabotPullRequestProbe; @@ -47,133 +47,182 @@ public class PluginMaintenanceScoring extends Scoring { @Override public List getComponents() { return List.of( - new ScoringComponent() { // JenkinsFile presence - @Override - public String getDescription() { - return "Plugin must have a Jenkinsfile."; - } - - @Override - public ScoringComponentResult getScore(Plugin $, Map probeResults) { - final ProbeResult probeResult = probeResults.get(JenkinsfileProbe.KEY); - if (probeResult == null || ProbeResult.Status.ERROR.equals(probeResult.status())) { - return new ScoringComponentResult(0, getWeight(), List.of("Cannot confirm or not the presence of Jenkinsfile.")); + new ScoringComponent() { // JenkinsFile presence + @Override + public String getDescription() { + return "Plugin must have a Jenkinsfile."; } - return switch (probeResult.message()) { - case "Jenkinsfile found" -> - new ScoringComponentResult(100, getWeight(), List.of("Jenkinsfile detected in plugin repository.")); - case "No Jenkinsfile found" -> - new ScoringComponentResult( - 0, - getWeight(), - List.of("Jenkinsfile not detected in plugin repository."), - List.of( - new Resolution("See how to add a Jenkinsfile", "https://www.jenkins.io/doc/developer/tutorial-improve/add-a-jenkinsfile/") - ) - ); - default -> - new ScoringComponentResult(0, getWeight(), List.of("Cannot confirm or not the presence of Jenkinsfile.", probeResult.message())); - }; - } - - @Override - public int getWeight() { - return 65; - } - }, - new ScoringComponent() { // Dependabot and not dependency pull requests - @Override - public String getDescription() { - return "Plugin should be using a using a dependency version management bot."; - } - - @Override - public ScoringComponentResult getScore(Plugin pl, Map probeResults) { - final ProbeResult dependabot = probeResults.get(DependabotProbe.KEY); - final ProbeResult renovate = probeResults.get(RenovateProbe.KEY); - final ProbeResult dependencyPullRequest = probeResults.get(DependabotPullRequestProbe.KEY); - - if (dependabot != null && "Dependabot is configured.".equals(dependabot.message()) && renovate != null && "Renovate is configured.".equals(renovate.message())) { - return new ScoringComponentResult(50, getWeight(), List.of("It seems that both dependabot and renovate are configured.", dependabot.message(), renovate.message())); + + @Override + public ScoringComponentResult getScore(Plugin $, Map probeResults) { + final ProbeResult probeResult = probeResults.get(JenkinsfileProbe.KEY); + if (probeResult == null || ProbeResult.Status.ERROR.equals(probeResult.status())) { + return new ScoringComponentResult( + 0, getWeight(), List.of("Cannot confirm or not the presence of Jenkinsfile.")); + } + return switch (probeResult.message()) { + case "Jenkinsfile found" -> new ScoringComponentResult( + 100, getWeight(), List.of("Jenkinsfile detected in plugin repository.")); + case "No Jenkinsfile found" -> new ScoringComponentResult( + 0, + getWeight(), + List.of("Jenkinsfile not detected in plugin repository."), + List.of( + new Resolution( + "See how to add a Jenkinsfile", + "https://www.jenkins.io/doc/developer/tutorial-improve/add-a-jenkinsfile/"))); + default -> new ScoringComponentResult( + 0, + getWeight(), + List.of( + "Cannot confirm or not the presence of Jenkinsfile.", + probeResult.message())); + }; } - if (dependabot != null && ProbeResult.Status.SUCCESS.equals(dependabot.status()) && "Dependabot is configured.".equals(dependabot.message())) { - return manageOpenDependencyPullRequestValue(pl, dependabot, dependencyPullRequest); + @Override + public int getWeight() { + return 50; } - if (renovate != null && ProbeResult.Status.SUCCESS.equals(renovate.status()) && "Renovate is configured.".equals(renovate.message())) { - return manageOpenDependencyPullRequestValue(pl, renovate, dependencyPullRequest); + }, + new ScoringComponent() { // Dependabot and not dependency pull requests + @Override + public String getDescription() { + return "Plugin should be using a using a dependency version management bot."; } - return new ScoringComponentResult( - 0, - getWeight(), - List.of("No dependency version manager bot are used on the plugin repository."), - List.of( - new Resolution("See how to automate the dependencies updates", "https://www.jenkins.io/doc/developer/tutorial-improve/automate-dependency-update-checks/") - ) - ); - } - - private ScoringComponentResult manageOpenDependencyPullRequestValue(Plugin plugin, ProbeResult dependencyBotResult, ProbeResult dependencyPullRequestResult) { - if (dependencyPullRequestResult != null) { - return "0".equals(dependencyPullRequestResult.message()) ? - new ScoringComponentResult( - 100, + @Override + public ScoringComponentResult getScore(Plugin pl, Map probeResults) { + final ProbeResult dependabot = probeResults.get(DependabotProbe.KEY); + final ProbeResult renovate = probeResults.get(RenovateProbe.KEY); + final ProbeResult dependencyPullRequest = probeResults.get(DependabotPullRequestProbe.KEY); + + if (dependabot != null + && "Dependabot is configured.".equals(dependabot.message()) + && renovate != null + && "Renovate is configured.".equals(renovate.message())) { + return new ScoringComponentResult( + 50, + getWeight(), + List.of( + "It seems that both dependabot and renovate are configured.", + dependabot.message(), + renovate.message())); + } + + if (dependabot != null + && ProbeResult.Status.SUCCESS.equals(dependabot.status()) + && "Dependabot is configured.".equals(dependabot.message())) { + return manageOpenDependencyPullRequestValue(pl, dependabot, dependencyPullRequest); + } + if (renovate != null + && ProbeResult.Status.SUCCESS.equals(renovate.status()) + && "Renovate is configured.".equals(renovate.message())) { + return manageOpenDependencyPullRequestValue(pl, renovate, dependencyPullRequest); + } + + return new ScoringComponentResult( + 0, getWeight(), - List.of(dependencyBotResult.message(), "%s open dependency pull request".formatted(dependencyPullRequestResult.message())) - ) : - new ScoringComponentResult( - 50, + List.of("No dependency version manager bot are used on the plugin repository."), + List.of( + new Resolution( + "See how to automate the dependencies updates", + "https://www.jenkins.io/doc/developer/tutorial-improve/automate-dependency-update-checks/"))); + } + + private ScoringComponentResult manageOpenDependencyPullRequestValue( + Plugin plugin, ProbeResult dependencyBotResult, ProbeResult dependencyPullRequestResult) { + if (dependencyPullRequestResult != null) { + return "0".equals(dependencyPullRequestResult.message()) + ? new ScoringComponentResult( + 100, + getWeight(), + List.of( + dependencyBotResult.message(), + "%s open dependency pull request" + .formatted(dependencyPullRequestResult.message()))) + : new ScoringComponentResult( + 50, + getWeight(), + List.of( + dependencyBotResult.message(), + "%s open dependency pull request" + .formatted(dependencyPullRequestResult.message())), + List.of(new Resolution( + "See the open pull requests of the plugin", + "%s/pulls?q=is%%3Aopen+is%%3Apr+label%%3Adependencies" + .formatted(plugin.getScm())))); + } + return new ScoringComponentResult( + 0, getWeight(), - List.of(dependencyBotResult.message(), "%s open dependency pull request".formatted(dependencyPullRequestResult.message())), List.of( - new Resolution("See the open pull requests of the plugin", "%s/pulls?q=is%%3Aopen+is%%3Apr+label%%3Adependencies".formatted(plugin.getScm())) - ) - ); + dependencyBotResult.message(), + "Cannot determine if there is any dependency pull request opened on the repository.")); } - return new ScoringComponentResult( - 0, - getWeight(), - List.of( - dependencyBotResult.message(), - "Cannot determine if there is any dependency pull request opened on the repository." - ) - ); - } - - @Override - public int getWeight() { - return 15; - } - }, - new ScoringComponent() { // ContinuousDelivery JEP - @Override - public String getDescription() { - return "The plugin could benefit from setting up the continuous delivery workflow."; - } - - @Override - public ScoringComponentResult getScore(Plugin $, Map probeResults) { - final ProbeResult probeResult = probeResults.get(ContinuousDeliveryProbe.KEY); - if (probeResult == null || ProbeResult.Status.ERROR.equals(probeResult.status())) { - return new ScoringComponentResult(0, getWeight(), List.of("Cannot confirm or not the JEP-229 configuration.")); + + @Override + public int getWeight() { + return 20; + } + }, + new ScoringComponent() { // ContinuousDelivery JEP + @Override + public String getDescription() { + return "The plugin could benefit from setting up the continuous delivery workflow."; + } + + @Override + public ScoringComponentResult getScore(Plugin $, Map probeResults) { + final ProbeResult probeResult = probeResults.get(ContinuousDeliveryProbe.KEY); + if (probeResult == null || ProbeResult.Status.ERROR.equals(probeResult.status())) { + return new ScoringComponentResult( + 0, getWeight(), List.of("Cannot confirm or not the JEP-229 configuration.")); + } + return switch (probeResult.message()) { + case "JEP-229 workflow definition found." -> new ScoringComponentResult( + 100, getWeight(), List.of("JEP-229 is configured on the plugin.")); + case "Could not find JEP-229 workflow definition." -> new ScoringComponentResult( + 0, getWeight(), List.of("JEP-229 is not configured on the plugin.")); + default -> new ScoringComponentResult( + 0, + getWeight(), + List.of("Cannot confirm or not the JEP-229 configuration.", probeResult.message())); + }; + } + + @Override + public int getWeight() { + return 10; + } + }, + new ScoringComponent() { + @Override + public String getDescription() { + return "Plugin should have a valid CODEOWNERS file."; + } + + @Override + public ScoringComponentResult getScore(Plugin plugin, Map probeResults) { + final ProbeResult result = probeResults.get(CodeOwnershipProbe.KEY); + if (result == null || ProbeResult.Status.ERROR.equals(result.status())) { + return new ScoringComponentResult(0, getWeight(), List.of()); + } + + return switch (result.message()) { + case "CODEOWNERS file is valid." -> new ScoringComponentResult(100, getWeight(), List.of()); + case "CODEOWNERS file is not set correctly." -> new ScoringComponentResult( + 50, getWeight(), List.of()); + default -> new ScoringComponentResult(0, getWeight(), List.of()); + }; + } + + @Override + public int getWeight() { + return 20; } - return switch (probeResult.message()) { - case "JEP-229 workflow definition found." -> - new ScoringComponentResult(100, getWeight(), List.of("JEP-229 is configured on the plugin.")); - case "Could not find JEP-229 workflow definition." -> - new ScoringComponentResult(0, getWeight(), List.of("JEP-229 is not configured on the plugin.")); - default -> - new ScoringComponentResult(0, getWeight(), List.of("Cannot confirm or not the JEP-229 configuration.", probeResult.message())); - }; - } - - @Override - public int getWeight() { - return 5; - } - } - ); + }); } @Override @@ -195,6 +244,6 @@ public String description() { @Override public int version() { - return 3; + return 4; } } diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeOwnershipProbeTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeOwnershipProbeTest.java new file mode 100644 index 000000000..0ff7e4385 --- /dev/null +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/probes/CodeOwnershipProbeTest.java @@ -0,0 +1,169 @@ +/* + * MIT License + * + * Copyright (c) 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 + * 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.when; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; + +import io.jenkins.pluginhealth.scoring.model.Plugin; +import io.jenkins.pluginhealth.scoring.model.ProbeResult; + +import org.junit.jupiter.api.Test; + +public class CodeOwnershipProbeTest extends AbstractProbeTest { + @Override + CodeOwnershipProbe getSpy() { + return spy(CodeOwnershipProbe.class); + } + + @Test + void shouldDetectMissingCodeOwnershipFile() throws IOException { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = mock(ProbeContext.class); + + final Path repo = Files.createTempDirectory(getClass().getName()); + when(ctx.getScmRepository()).thenReturn(Optional.of(repo)); + + final CodeOwnershipProbe probe = getSpy(); + final ProbeResult result = probe.apply(plugin, ctx); + + assertThat(result) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success(probe.key(), "No CODEOWNERS file found in plugin repository.", 0)); + } + + @Test + void shouldDetectCodeOwnershipFileWithInvalidContent() throws IOException { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = mock(ProbeContext.class); + + when(plugin.getName()).thenReturn("new-super"); + + { + final Path repo = Files.createTempDirectory(getClass().getName()); + final Path codeowners = Files.createFile(repo.resolve("CODEOWNERS")); + Files.writeString( + codeowners, """ + * @jenkinsci/sample-plugin-developers + """); + when(ctx.getScmRepository()).thenReturn(Optional.of(repo)); + } + { + final Path repo = Files.createTempDirectory(getClass().getName()); + final Path github = Files.createDirectory(repo.resolve(".github")); + final Path codeowners = Files.createFile(github.resolve("CODEOWNERS")); + Files.writeString( + codeowners, """ + * @jenkinsci/sample-plugin-developers + """); + when(ctx.getScmRepository()).thenReturn(Optional.of(repo)); + } + { + final Path repo = Files.createTempDirectory(getClass().getName()); + final Path docs = Files.createDirectory(repo.resolve("docs")); + final Path codeowners = Files.createFile(docs.resolve("CODEOWNERS")); + Files.writeString( + codeowners, """ + * @jenkinsci/sample-plugin-developers + """); + when(ctx.getScmRepository()).thenReturn(Optional.of(repo)); + } + + final CodeOwnershipProbe probe = getSpy(); + + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success(probe.key(), "CODEOWNERS file is not set correctly.", 0)); + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success(probe.key(), "CODEOWNERS file is not set correctly.", 0)); + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success(probe.key(), "CODEOWNERS file is not set correctly.", 0)); + } + + @Test + void shouldDetectCodeOwnershipFileWithValidTeam() throws IOException { + final Plugin plugin = mock(Plugin.class); + final ProbeContext ctx = mock(ProbeContext.class); + + when(plugin.getName()).thenReturn("sample"); + + { + final Path repo = Files.createTempDirectory(getClass().getName()); + final Path codeowners = Files.createFile(repo.resolve("CODEOWNERS")); + Files.writeString( + codeowners, """ + * @jenkinsci/sample-plugin-developers + """); + when(ctx.getScmRepository()).thenReturn(Optional.of(repo)); + } + { + final Path repo = Files.createTempDirectory(getClass().getName()); + final Path github = Files.createDirectory(repo.resolve(".github")); + final Path codeowners = Files.createFile(github.resolve("CODEOWNERS")); + Files.writeString( + codeowners, """ + * @jenkinsci/sample-plugin-developers + """); + when(ctx.getScmRepository()).thenReturn(Optional.of(repo)); + } + { + final Path repo = Files.createTempDirectory(getClass().getName()); + final Path docs = Files.createDirectory(repo.resolve("docs")); + final Path codeowners = Files.createFile(docs.resolve("CODEOWNERS")); + Files.writeString( + codeowners, """ + * @jenkinsci/sample-plugin-developers + """); + when(ctx.getScmRepository()).thenReturn(Optional.of(repo)); + } + + final CodeOwnershipProbe probe = getSpy(); + + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success(probe.key(), "CODEOWNERS file is valid.", 0)); + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success(probe.key(), "CODEOWNERS file is valid.", 0)); + assertThat(probe.apply(plugin, ctx)) + .usingRecursiveComparison() + .comparingOnlyFields("id", "status", "message") + .isEqualTo(ProbeResult.success(probe.key(), "CODEOWNERS file is valid.", 0)); + } +} diff --git a/core/src/test/java/io/jenkins/pluginhealth/scoring/scores/PluginMaintenanceScoringTest.java b/core/src/test/java/io/jenkins/pluginhealth/scoring/scores/PluginMaintenanceScoringTest.java index 6f13c3103..da3f23f74 100644 --- a/core/src/test/java/io/jenkins/pluginhealth/scoring/scores/PluginMaintenanceScoringTest.java +++ b/core/src/test/java/io/jenkins/pluginhealth/scoring/scores/PluginMaintenanceScoringTest.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2023-2024 Jenkins Infra + * Copyright (c) 2022-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.scores; import static org.assertj.core.api.Assertions.assertThat; @@ -37,6 +36,7 @@ import io.jenkins.pluginhealth.scoring.model.Plugin; import io.jenkins.pluginhealth.scoring.model.ProbeResult; import io.jenkins.pluginhealth.scoring.model.ScoreResult; +import io.jenkins.pluginhealth.scoring.probes.CodeOwnershipProbe; import io.jenkins.pluginhealth.scoring.probes.ContinuousDeliveryProbe; import io.jenkins.pluginhealth.scoring.probes.DependabotProbe; import io.jenkins.pluginhealth.scoring.probes.DependabotPullRequestProbe; @@ -58,189 +58,445 @@ PluginMaintenanceScoring getSpy() { static Stream probeResultsAndValue() { return Stream.of( - arguments(// Nothing - Map.of(), - 0 - ), - arguments(// All bad - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "Could not find JEP-229 workflow definition.", 1) - ), - 0 - ), - arguments(// All bad with open dependabot pull request - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "Could not find JEP-229 workflow definition.", 1) - ), - 0 - ), - arguments(// All good - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1) - ), - 100 - ), - arguments(// All good - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1) - ), - 100 - ), - arguments(// Only Jenkinsfile - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "Could not find JEP-229 workflow definition.", 1) - ), - 76 - ), - arguments(// Jenkinsfile and dependabot but with open pull request - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "Could not find JEP-229 workflow definition.", 1) - ), - 85 - ), - arguments(// Jenkinsfile and dependabot with no open pull request - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "Could not find JEP-229 workflow definition.", 1) - ), - 94 - ), - arguments(// Jenkinsfile and renovate but with open pull request - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot not is configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "Could not find JEP-229 workflow definition.", 1) - ), - 85 - ), - arguments(// Jenkinsfile and renovate with no open pull request - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot not is configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "Could not find JEP-229 workflow definition.", 1) - ), - 94 - ), - arguments(// Jenkinsfile and CD - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1) - ), - 82 - ), - arguments(// Jenkinsfile and CD and dependabot but with open pull request - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1) - ), - 91 - ), - arguments(// Dependabot only with no open pull requests - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "Could not find JEP-229 workflow definition.", 1) - ), - 18 - ), - arguments(// Dependabot only with open pull requests - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "Could not find JEP-229 workflow definition.", 1) - ), - 9 - ), - arguments(// Dependabot with no open pull request and CD - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1) - ), - 24 - ), - arguments(// Renovate only with no open pull requests - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "Could not find JEP-229 workflow definition.", 1) - ), - 18 - ), - arguments(// Renovate only with open pull requests - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "Could not find JEP-229 workflow definition.", 1) - ), - 9 - ), - arguments(// Renovate with no open pull request and CD - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1) - ), - 24 - ), - arguments(// CD only - Map.of( - JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), - DependabotProbe.KEY, ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), - RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), - DependabotPullRequestProbe.KEY, ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), - ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1) - ), - 6 - ) - ); + arguments( // Nothing + Map.of(), 0), + arguments( // All bad + Map.of( + JenkinsfileProbe.KEY, + ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, + "Could not find JEP-229 workflow definition.", + 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 0), + arguments( // All bad with open dependabot pull request + Map.of( + JenkinsfileProbe.KEY, + ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, + "Could not find JEP-229 workflow definition.", + 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 0), + arguments( // All good + Map.of( + JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1), + CodeOwnershipProbe.KEY, + ProbeResult.success(CodeOwnershipProbe.KEY, "CODEOWNERS file is valid.", 1)), + 100), + arguments( // All good + Map.of( + JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), + RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1), + CodeOwnershipProbe.KEY, + ProbeResult.success(CodeOwnershipProbe.KEY, "CODEOWNERS file is valid.", 1)), + 100), + arguments( // Only Jenkinsfile + Map.of( + JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, + "Could not find JEP-229 workflow definition.", + 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 50), + arguments( // Jenkinsfile and dependabot but with open pull request + Map.of( + JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, + "Could not find JEP-229 workflow definition.", + 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 60), + arguments( // Jenkinsfile and dependabot with no open pull request + Map.of( + JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, + "Could not find JEP-229 workflow definition.", + 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 70), + arguments( // Jenkinsfile and renovate but with open pull request + Map.of( + JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot not is configured.", 1), + RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, + "Could not find JEP-229 workflow definition.", + 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 60), + arguments( // Jenkinsfile and renovate with no open pull request + Map.of( + JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot not is configured.", 1), + RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, + "Could not find JEP-229 workflow definition.", + 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 70), + arguments( // Jenkinsfile and CD + Map.of( + JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 60), + arguments( // Jenkinsfile and CD and dependabot but with open pull request + Map.of( + JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 70), + arguments( // Jenkinsfile and CD and dependabot but with no open pull request + Map.of( + JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 80), + arguments( // Dependabot only with no open pull requests + Map.of( + JenkinsfileProbe.KEY, + ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, + "Could not find JEP-229 workflow definition.", + 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 20), + arguments( // Dependabot only with open pull requests + Map.of( + JenkinsfileProbe.KEY, + ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, + "Could not find JEP-229 workflow definition.", + 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 10), + arguments( // Dependabot with no open pull request and CD + Map.of( + JenkinsfileProbe.KEY, + ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 30), + arguments( // Renovate only with no open pull requests + Map.of( + JenkinsfileProbe.KEY, + ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), + RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, + "Could not find JEP-229 workflow definition.", + 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 20), + arguments( // Renovate only with open pull requests + Map.of( + JenkinsfileProbe.KEY, + ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), + RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, + "Could not find JEP-229 workflow definition.", + 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 10), + arguments( // Renovate with no open pull request and CD + Map.of( + JenkinsfileProbe.KEY, + ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), + RenovateProbe.KEY, ProbeResult.success(RenovateProbe.KEY, "Renovate is configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 30), + arguments( // CD only + Map.of( + JenkinsfileProbe.KEY, + ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1), + CodeOwnershipProbe.KEY, + ProbeResult.success( + CodeOwnershipProbe.KEY, + "No CODEOWNERS file found in plugin repository.", + 1)), + 10), + arguments( // Codeownership only + Map.of( + JenkinsfileProbe.KEY, + ProbeResult.success(JenkinsfileProbe.KEY, "No Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, + "Could not find JEP-229 workflow definition.", + 1), + CodeOwnershipProbe.KEY, + ProbeResult.success(CodeOwnershipProbe.KEY, "CODEOWNERS file is valid.", 1)), + 20), + arguments( // Codeownership + Jenkinsfile + Map.of( + JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, + "Could not find JEP-229 workflow definition.", + 1), + CodeOwnershipProbe.KEY, + ProbeResult.success(CodeOwnershipProbe.KEY, "CODEOWNERS file is valid.", 1)), + 70), + arguments( // Codeownership + Jenkinsfile + CD + Map.of( + JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is not configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1), + CodeOwnershipProbe.KEY, + ProbeResult.success(CodeOwnershipProbe.KEY, "CODEOWNERS file is valid.", 1)), + 80), + arguments( // Codeownership + Jenkinsfile + CD + Dependabot + Map.of( + JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "1", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1), + CodeOwnershipProbe.KEY, + ProbeResult.success(CodeOwnershipProbe.KEY, "CODEOWNERS file is valid.", 1)), + 90), + arguments( // Codeownership + Jenkinsfile + CD + Map.of( + JenkinsfileProbe.KEY, ProbeResult.success(JenkinsfileProbe.KEY, "Jenkinsfile found", 1), + DependabotProbe.KEY, + ProbeResult.success(DependabotProbe.KEY, "Dependabot is configured.", 1), + RenovateProbe.KEY, + ProbeResult.success(RenovateProbe.KEY, "Renovate is not configured.", 1), + DependabotPullRequestProbe.KEY, + ProbeResult.success(DependabotPullRequestProbe.KEY, "0", 1), + ContinuousDeliveryProbe.KEY, + ProbeResult.success( + ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1), + CodeOwnershipProbe.KEY, + ProbeResult.success(CodeOwnershipProbe.KEY, "CODEOWNERS file is valid.", 1)), + 100)); } @ParameterizedTest @@ -253,11 +509,11 @@ public void shouldScorePluginBasedOnProbeResultMatrix(Map d final ScoreResult result = scoring.apply(plugin); - assertThat(result.componentsResults().size()).isEqualTo(3); + assertThat(result.componentsResults().size()).isEqualTo(4); assertThat(result) - .isNotNull() - .usingRecursiveComparison() - .comparingOnlyFields("key", "value", "weight") - .isEqualTo(new ScoreResult(KEY, value, COEFFICIENT, Set.of(), scoring.version())); + .isNotNull() + .usingRecursiveComparison() + .comparingOnlyFields("key", "value", "weight") + .isEqualTo(new ScoreResult(KEY, value, COEFFICIENT, Set.of(), scoring.version())); } }