Skip to content

Commit

Permalink
Extracts plugin maintenance scoring into more precise scorings (#466)
Browse files Browse the repository at this point in the history
  • Loading branch information
alecharp authored Feb 20, 2024
1 parent a036c70 commit e32f0eb
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 115 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* 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.scores;

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.ScoringComponentResult;
import io.jenkins.pluginhealth.scoring.probes.ContributingGuidelinesProbe;
import io.jenkins.pluginhealth.scoring.probes.DocumentationMigrationProbe;

import org.springframework.stereotype.Component;

@Component
public class DocumentationScoring extends Scoring {
public static final String KEY = "documentation";

@Override
public String key() {
return KEY;
}

@Override
public float weight() {
return .5f;
}

@Override
public String description() {
return "Validates that the plugin has a specific contributing guide and a documentation.";
}

@Override
public List<ScoringComponent> getComponents() {
return List.of(new ScoringComponent() {
@Override
public String getDescription() {
return "The plugin has a specific contributing guide.";
}

@Override
public ScoringComponentResult getScore(Plugin plugin, Map<String, ProbeResult> probeResults) {
ProbeResult probeResult = probeResults.get(ContributingGuidelinesProbe.KEY);
if (probeResult != null && "Contributing guidelines found.".equals(probeResult.message())) {
return new ScoringComponentResult(100, getWeight(), List.of("Plugin has a contributing guide."));
}
return new ScoringComponentResult(0, getWeight(), List.of("The plugin relies on the global contributing guide."));
}

@Override
public int getWeight() {
return 2;
}
},
new ScoringComponent() {
@Override
public String getDescription() {
return "Plugin documentation should be migrated from the wiki.";
}

@Override
public ScoringComponentResult getScore(Plugin $, Map<String, ProbeResult> probeResults) {
final ProbeResult probeResult = probeResults.get(DocumentationMigrationProbe.KEY);
if (probeResult == null || ProbeResult.Status.ERROR.equals(probeResult.status())) {
return new ScoringComponentResult(0, getWeight(), List.of("Cannot confirm or not the documentation migration."));
}
return switch (probeResult.message()) {
case "Documentation is located in the plugin repository." ->
new ScoringComponentResult(100, getWeight(), List.of("Documentation is in plugin repository."));
case "Documentation is not located in the plugin repository." ->
new ScoringComponentResult(
0,
getWeight(),
List.of("Documentation should be migrated in plugin repository."),
List.of("https://www.jenkins.io/doc/developer/tutorial-improve/migrate-documentation-to-github/")
);
default ->
new ScoringComponentResult(0, getWeight(), List.of("Cannot confirm or not the documentation migration.", probeResult.message()));
};
}

@Override
public int getWeight() {
return 8;
}
});
}

@Override
public int version() {
return 1;
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -33,7 +33,6 @@
import io.jenkins.pluginhealth.scoring.probes.ContinuousDeliveryProbe;
import io.jenkins.pluginhealth.scoring.probes.DependabotProbe;
import io.jenkins.pluginhealth.scoring.probes.DependabotPullRequestProbe;
import io.jenkins.pluginhealth.scoring.probes.DocumentationMigrationProbe;
import io.jenkins.pluginhealth.scoring.probes.JenkinsfileProbe;
import io.jenkins.pluginhealth.scoring.probes.RenovateProbe;

Expand Down Expand Up @@ -79,38 +78,6 @@ public int getWeight() {
return 65;
}
},
new ScoringComponent() { // Documentation migration done
@Override
public String getDescription() {
return "Plugin documentation should be migrated from the wiki.";
}

@Override
public ScoringComponentResult getScore(Plugin $, Map<String, ProbeResult> probeResults) {
final ProbeResult probeResult = probeResults.get(DocumentationMigrationProbe.KEY);
if (probeResult == null || ProbeResult.Status.ERROR.equals(probeResult.status())) {
return new ScoringComponentResult(0, getWeight(), List.of("Cannot confirm or not the documentation migration."));
}
return switch (probeResult.message()) {
case "Documentation is located in the plugin repository." ->
new ScoringComponentResult(100, getWeight(), List.of("Documentation is in plugin repository."));
case "Documentation is not located in the plugin repository." ->
new ScoringComponentResult(
0,
getWeight(),
List.of("Documentation should be migrated in plugin repository."),
List.of("https://www.jenkins.io/doc/developer/tutorial-improve/migrate-documentation-to-github/")
);
default ->
new ScoringComponentResult(0, getWeight(), List.of("Cannot confirm or not the documentation migration.", probeResult.message()));
};
}

@Override
public int getWeight() {
return 15;
}
},
new ScoringComponent() { // Dependabot and not dependency pull requests
@Override
public String getDescription() {
Expand Down Expand Up @@ -221,6 +188,6 @@ public String description() {

@Override
public int version() {
return 2;
return 3;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* 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.scores;

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.util.Map;
import java.util.Set;

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.ContributingGuidelinesProbe;
import io.jenkins.pluginhealth.scoring.probes.DocumentationMigrationProbe;

import org.junit.jupiter.api.Test;

class DocumentationScoringTest extends AbstractScoringTest<DocumentationScoring> {
@Override
DocumentationScoring getSpy() {
return spy(DocumentationScoring.class);
}

@Test
void shouldScoreOneHundredWithMigratedDocumentationAndContributingGuide() {
final Plugin plugin = mock(Plugin.class);
final DocumentationScoring scoring = getSpy();

when(plugin.getDetails()).thenReturn(Map.of(
DocumentationMigrationProbe.KEY, ProbeResult.success(DocumentationMigrationProbe.KEY, "Documentation is located in the plugin repository.", 1),
ContributingGuidelinesProbe.KEY, ProbeResult.success(ContributingGuidelinesProbe.KEY, "Contributing guidelines found.", 1)
));

ScoreResult result = scoring.apply(plugin);
assertThat(result)
.isNotNull()
.usingRecursiveComparison().comparingOnlyFields("key", "value")
.isEqualTo(new ScoreResult(DocumentationScoring.KEY, 100, .5f, Set.of(), 1));
}

@Test
void shouldScoreEightyWithMigratedDocumentationOnly() {
final Plugin plugin = mock(Plugin.class);
final DocumentationScoring scoring = getSpy();

when(plugin.getDetails()).thenReturn(Map.of(
DocumentationMigrationProbe.KEY, ProbeResult.success(DocumentationMigrationProbe.KEY, "Documentation is located in the plugin repository.", 1),
ContributingGuidelinesProbe.KEY, ProbeResult.success(ContributingGuidelinesProbe.KEY, "No contributing guidelines found.", 1)
));

ScoreResult result = scoring.apply(plugin);
assertThat(result)
.isNotNull()
.usingRecursiveComparison().comparingOnlyFields("key", "value")
.isEqualTo(new ScoreResult(DocumentationScoring.KEY, 80, .5f, Set.of(), 1));
}

@Test
void shouldScoreZeroWithMigratedDocumentationOnly() {
final Plugin plugin = mock(Plugin.class);
final DocumentationScoring scoring = getSpy();

when(plugin.getDetails()).thenReturn(Map.of(
DocumentationMigrationProbe.KEY, ProbeResult.success(DocumentationMigrationProbe.KEY, "Documentation is not located in the plugin repository.", 1),
ContributingGuidelinesProbe.KEY, ProbeResult.success(ContributingGuidelinesProbe.KEY, "No contributing guidelines found.", 1)
));

ScoreResult result = scoring.apply(plugin);
assertThat(result)
.isNotNull()
.usingRecursiveComparison().comparingOnlyFields("key", "value")
.isEqualTo(new ScoreResult(DocumentationScoring.KEY, 0, .5f, Set.of(), 1));
}
}
Loading

0 comments on commit e32f0eb

Please sign in to comment.