Skip to content

Commit

Permalink
Using release drafter is not mandatory but a good documentation pract…
Browse files Browse the repository at this point in the history
…ice (#468)
  • Loading branch information
alecharp authored Feb 21, 2024
1 parent f02426e commit 80d992e
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,11 @@
import org.springframework.stereotype.Component;

@Component
@Order(DrafterReleaseProbe.ORDER)
public class DrafterReleaseProbe extends Probe {

@Order(ReleaseDrafterProbe.ORDER)
public class ReleaseDrafterProbe extends Probe {
public static final String KEY = "release-drafter";

public static final int ORDER = LastCommitDateProbe.ORDER + 100;
private static final Logger LOGGER = LoggerFactory.getLogger(DrafterReleaseProbe.class);
private static final Logger LOGGER = LoggerFactory.getLogger(ReleaseDrafterProbe.class);

@Override
protected ProbeResult doApply(Plugin plugin, ProbeContext context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
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.ContinuousDeliveryProbe;
import io.jenkins.pluginhealth.scoring.probes.ContributingGuidelinesProbe;
import io.jenkins.pluginhealth.scoring.probes.DocumentationMigrationProbe;
import io.jenkins.pluginhealth.scoring.probes.ReleaseDrafterProbe;

import org.springframework.stereotype.Component;

Expand All @@ -57,26 +59,35 @@ public String description() {

@Override
public List<ScoringComponent> getComponents() {
return List.of(new ScoringComponent() {
@Override
public String getDescription() {
return "The plugin has a specific contributing guide.";
}
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."));
@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."),
List.of(new Resolution(
"See why and how to add a contributing guide",
"https://www.jenkins.io/doc/developer/tutorial-improve/add-a-contributing-guide/"
))
);
}
return new ScoringComponentResult(0, getWeight(), List.of("The plugin relies on the global contributing guide."));
}

@Override
public int getWeight() {
return 2;
}
},
@Override
public int getWeight() {
return 2;
}
},
new ScoringComponent() {
@Override
public String getDescription() {
Expand Down Expand Up @@ -110,11 +121,52 @@ public ScoringComponentResult getScore(Plugin $, Map<String, ProbeResult> probeR
public int getWeight() {
return 8;
}
});
},
new ScoringComponent() {
@Override
public String getDescription() {
return "Recommend to setup Release Drafter on the plugin repository.";
}

@Override
public ScoringComponentResult getScore(Plugin plugin, Map<String, ProbeResult> probeResults) {
ProbeResult cdProbe = probeResults.get(ContinuousDeliveryProbe.KEY);
if (cdProbe != null && "JEP-229 workflow definition found.".equals(cdProbe.message())) {
return new ScoringComponentResult(
100,
getWeight(),
List.of("Plugin using Release Drafter because it has CD configured.")
);
}
ProbeResult result = probeResults.get(ReleaseDrafterProbe.KEY);
if (result != null && "Release Drafter is configured.".equals(result.message())) {
return new ScoringComponentResult(
100,
getWeight(),
List.of("Plugin is using Release Drafter.")
);
}
return new ScoringComponentResult(
0,
0,
List.of("Plugin is not using Release Drafter to manage its changelog."),
List.of(new Resolution(
"Plugin could benefit from using Release Drafter.",
"https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc"
))
);
}

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

@Override
public int version() {
return 1;
return 2;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@

import org.junit.jupiter.api.Test;

class DrafterReleaseProbeTest extends AbstractProbeTest<DrafterReleaseProbe> {
class ReleaseDrafterProbeTest extends AbstractProbeTest<ReleaseDrafterProbe> {
@Override
DrafterReleaseProbe getSpy() {
return spy(DrafterReleaseProbe.class);
ReleaseDrafterProbe getSpy() {
return spy(ReleaseDrafterProbe.class);
}

@Test
Expand All @@ -59,35 +59,35 @@ void shouldRequireValidSCM() {
when(plugin.getName()).thenReturn("foo");
when(ctx.getScmRepository()).thenReturn(Optional.empty());

final DrafterReleaseProbe probe = getSpy();
final ReleaseDrafterProbe probe = getSpy();

assertThat(probe.apply(plugin, ctx))
.usingRecursiveComparison()
.comparingOnlyFields("id", "message", "status")
.isEqualTo(ProbeResult.error(DrafterReleaseProbe.KEY, "There is no local repository for plugin " + plugin.getName() + ".", probe.getVersion()));
.isEqualTo(ProbeResult.error(ReleaseDrafterProbe.KEY, "There is no local repository for plugin " + plugin.getName() + ".", probe.getVersion()));
}

@Test
void shouldDetectMissingGithubConfigurationFolder() throws Exception {
final Plugin plugin = mock(Plugin.class);
final ProbeContext ctx = mock(ProbeContext.class);
final DrafterReleaseProbe probe = getSpy();
final ReleaseDrafterProbe probe = getSpy();

final Path repo = Files.createTempDirectory("foo");
when(ctx.getScmRepository()).thenReturn(Optional.of(repo));

assertThat(probe.apply(plugin, ctx))
.usingRecursiveComparison()
.comparingOnlyFields("id", "message", "status")
.isEqualTo(ProbeResult.success(DrafterReleaseProbe.KEY, "No GitHub configuration folder found.", probe.getVersion()));
.isEqualTo(ProbeResult.success(ReleaseDrafterProbe.KEY, "No GitHub configuration folder found.", probe.getVersion()));
verify(probe).doApply(any(Plugin.class), any(ProbeContext.class));
}

@Test
void shouldDetectMissingReleaseDrafterFile() throws Exception {
final Plugin plugin = mock(Plugin.class);
final ProbeContext ctx = mock(ProbeContext.class);
final DrafterReleaseProbe probe = getSpy();
final ReleaseDrafterProbe probe = getSpy();

final Path repo = Files.createTempDirectory("foo");
Files.createDirectories(repo.resolve(".github"));
Expand All @@ -96,15 +96,15 @@ void shouldDetectMissingReleaseDrafterFile() throws Exception {
assertThat(probe.apply(plugin, ctx))
.usingRecursiveComparison()
.comparingOnlyFields("id", "message", "status")
.isEqualTo(ProbeResult.success(DrafterReleaseProbe.KEY, "Release Drafter is not configured.", probe.getVersion()));
.isEqualTo(ProbeResult.success(ReleaseDrafterProbe.KEY, "Release Drafter is not configured.", probe.getVersion()));
verify(probe).doApply(any(Plugin.class), any(ProbeContext.class));
}

@Test
void shouldDetectReleaseDrafterFile() throws Exception {
final Plugin plugin = mock(Plugin.class);
final ProbeContext ctx = mock(ProbeContext.class);
final DrafterReleaseProbe probe = getSpy();
final ReleaseDrafterProbe probe = getSpy();

final Path repo = Files.createTempDirectory("foo");
final Path github = Files.createDirectories(repo.resolve(".github"));
Expand All @@ -115,15 +115,15 @@ void shouldDetectReleaseDrafterFile() throws Exception {
assertThat(probe.apply(plugin, ctx))
.usingRecursiveComparison()
.comparingOnlyFields("id", "message", "status")
.isEqualTo(ProbeResult.success(DrafterReleaseProbe.KEY, "Release Drafter is configured.", probe.getVersion()));
.isEqualTo(ProbeResult.success(ReleaseDrafterProbe.KEY, "Release Drafter is configured.", probe.getVersion()));
verify(probe).doApply(any(Plugin.class), any(ProbeContext.class));
}

@Test
void shouldDetectReleaseDrafterFileWithFullFileExtension() throws Exception {
final Plugin plugin = mock(Plugin.class);
final ProbeContext ctx = mock(ProbeContext.class);
final DrafterReleaseProbe probe = getSpy();
final ReleaseDrafterProbe probe = getSpy();

final Path repo = Files.createTempDirectory("foo");
final Path github = Files.createDirectories(repo.resolve(".github"));
Expand All @@ -134,7 +134,7 @@ void shouldDetectReleaseDrafterFileWithFullFileExtension() throws Exception {
assertThat(probe.apply(plugin, ctx))
.usingRecursiveComparison()
.comparingOnlyFields("id", "message", "status")
.isEqualTo(ProbeResult.success(DrafterReleaseProbe.KEY, "Release Drafter is configured.", probe.getVersion()));
.isEqualTo(ProbeResult.success(ReleaseDrafterProbe.KEY, "Release Drafter is configured.", probe.getVersion()));
verify(probe).doApply(any(Plugin.class), any(ProbeContext.class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,12 @@
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.ContinuousDeliveryProbe;
import io.jenkins.pluginhealth.scoring.probes.ContributingGuidelinesProbe;
import io.jenkins.pluginhealth.scoring.probes.DocumentationMigrationProbe;
import io.jenkins.pluginhealth.scoring.probes.ReleaseDrafterProbe;

import org.assertj.core.api.Condition;
import org.junit.jupiter.api.Test;

class DocumentationScoringTest extends AbstractScoringTest<DocumentationScoring> {
Expand All @@ -53,7 +56,8 @@ void shouldScoreOneHundredWithMigratedDocumentationAndContributingGuide() {

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)
ContributingGuidelinesProbe.KEY, ProbeResult.success(ContributingGuidelinesProbe.KEY, "Contributing guidelines found.", 1),
ReleaseDrafterProbe.KEY, ProbeResult.success(ReleaseDrafterProbe.KEY, "Release Drafter is configured.", 1)
));

ScoreResult result = scoring.apply(plugin);
Expand All @@ -63,6 +67,61 @@ void shouldScoreOneHundredWithMigratedDocumentationAndContributingGuide() {
.isEqualTo(new ScoreResult(DocumentationScoring.KEY, 100, .5f, Set.of(), 1));
}

@Test
void shouldScoreOneHundredEvenWithoutReleaseDrafter() {
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),
ReleaseDrafterProbe.KEY, ProbeResult.success(ReleaseDrafterProbe.KEY, "Release Drafter not is configured.", 1)
));

ScoreResult result = scoring.apply(plugin);
assertThat(result)
.isNotNull()
.usingRecursiveComparison().comparingOnlyFields("key", "value")
.isEqualTo(new ScoreResult(DocumentationScoring.KEY, 100, .5f, Set.of(), 1));
assertThat(result.componentsResults())
.hasSize(3)
.haveAtLeastOne(new Condition<>(
res -> {
return res.weight() == 0 && res.score() == 0 && res.resolutions().size() == 1 &&
res.reasons().contains("Plugin is not using Release Drafter to manage its changelog.");
},
"Release drafter is not configured"
));
}

@Test
void shouldConsiderCDAsConfiguringReleaseDrafter() {
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),
ReleaseDrafterProbe.KEY, ProbeResult.success(ReleaseDrafterProbe.KEY, "Release Drafter not is configured.", 1),
ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1)
));

ScoreResult result = scoring.apply(plugin);
assertThat(result)
.isNotNull()
.usingRecursiveComparison().comparingOnlyFields("key", "value")
.isEqualTo(new ScoreResult(DocumentationScoring.KEY, 100, .5f, Set.of(), 1));
assertThat(result.componentsResults())
.hasSize(3)
.haveAtLeastOne(new Condition<>(
res -> {
return res.weight() == 0 && res.score() == 100 && res.reasons().size() == 1 &&
res.reasons().contains("Plugin using Release Drafter because it has CD configured.");
},
"CD is configured."
));
}

@Test
void shouldScoreEightyWithMigratedDocumentationOnly() {
final Plugin plugin = mock(Plugin.class);
Expand Down

0 comments on commit 80d992e

Please sign in to comment.