Skip to content

Commit

Permalink
Provides link to help / guide how to improve scores (#452)
Browse files Browse the repository at this point in the history
  • Loading branch information
alecharp authored Feb 13, 2024
1 parent d9717b5 commit 76202c4
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 61 deletions.
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 @@ -84,9 +84,11 @@ public long getValue() {

private void computeValue() {
var sum = details.stream()
.filter(Objects::nonNull)
.flatMapToDouble(res -> DoubleStream.of(res.value() * res.weight()))
.sum();
var coefficient = details.stream()
.filter(Objects::nonNull)
.flatMapToDouble(res -> DoubleStream.of(res.weight()))
.sum();
this.value = Math.round((sum / coefficient));
Expand Down
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 @@ -31,9 +31,13 @@
/**
* Describes the evaluation from a {@link ScoringComponent} on a specific plugin.
*
* @param score the score representing the points granted to the plugin, out of 100 (one hundred).
* @param weight the weight of the score
* @param reasons the list of string explaining the score granted to the plugin
* @param score the score representing the points granted to the plugin, out of 100 (one hundred).
* @param weight the weight of the score
* @param reasons the list of string explaining the score granted to the plugin
* @param resolutions the list of link providing help to increase the score
*/
public record ScoringComponentResult(int score, float weight, List<String> reasons) {
public record ScoringComponentResult(int score, float weight, List<String> reasons, List<String> resolutions) {
public ScoringComponentResult(int score, float weight, List<String> reasons) {
this(score, weight, reasons, List.of());
}
}
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 @@ -83,7 +83,12 @@ public ScoringComponentResult getScore(Plugin $, Map<String, ProbeResult> probeR
case "This plugin is not up for adoption." ->
new ScoringComponentResult(100, getWeight(), List.of("The plugin is not marked as up for adoption."));
case "This plugin is up for adoption." ->
new ScoringComponentResult(-1000, getWeight(), List.of("The plugin is marked as up for adoption."));
new ScoringComponentResult(
-1000,
getWeight(),
List.of("The plugin is marked as up for adoption."),
List.of("https://www.jenkins.io/doc/developer/plugin-governance/adopt-a-plugin/#plugins-marked-for-adoption")
);
default -> new ScoringComponentResult(-100, getWeight(), List.of());
};
}
Expand Down Expand Up @@ -142,6 +147,6 @@ public String description() {

@Override
public int version() {
return 2;
return 3;
}
}
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 @@ -57,7 +57,12 @@ public ScoringComponentResult getScore(Plugin $, Map<String, ProbeResult> probeR

return switch (probeResult.message()) {
case "This plugin is marked as deprecated." ->
new ScoringComponentResult(0, getWeight(), List.of("Plugin is marked as deprecated."));
new ScoringComponentResult(
0,
getWeight(),
List.of("Plugin is marked as deprecated."),
List.of("https://www.jenkins.io/doc/developer/plugin-governance/deprecating-or-removing-plugin/")
);
case "This plugin is NOT deprecated." ->
new ScoringComponentResult(100, getWeight(), List.of("Plugin is not marked as deprecated."));
default ->
Expand Down Expand Up @@ -90,6 +95,6 @@ public String description() {

@Override
public int version() {
return 1;
return 2;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,12 @@ public ScoringComponentResult getScore(Plugin $, Map<String, ProbeResult> probeR
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."));
new ScoringComponentResult(
0,
getWeight(),
List.of("Jenkinsfile not detected in plugin repository."),
List.of("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()));
};
Expand All @@ -90,7 +95,12 @@ public ScoringComponentResult getScore(Plugin $, Map<String, ProbeResult> probeR
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."));
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()));
};
Expand All @@ -108,7 +118,7 @@ public String getDescription() {
}

@Override
public ScoringComponentResult getScore(Plugin $, Map<String, ProbeResult> probeResults) {
public ScoringComponentResult getScore(Plugin pl, Map<String, ProbeResult> probeResults) {
final ProbeResult dependabot = probeResults.get(DependabotProbe.KEY);
final ProbeResult renovate = probeResults.get(RenovateProbe.KEY);
final ProbeResult dependencyPullRequest = probeResults.get(DependabotPullRequestProbe.KEY);
Expand All @@ -118,31 +128,41 @@ public ScoringComponentResult getScore(Plugin $, Map<String, ProbeResult> probeR
}

if (dependabot != null && ProbeResult.Status.SUCCESS.equals(dependabot.status()) && "Dependabot is configured.".equals(dependabot.message())) {
return manageOpenDependencyPullRequestValue(dependabot, dependencyPullRequest);
return manageOpenDependencyPullRequestValue(pl, dependabot, dependencyPullRequest);
}
if (renovate != null && ProbeResult.Status.SUCCESS.equals(renovate.status()) && "Renovate is configured.".equals(renovate.message())) {
return manageOpenDependencyPullRequestValue(renovate, dependencyPullRequest);
return manageOpenDependencyPullRequestValue(pl, renovate, dependencyPullRequest);
}

return new ScoringComponentResult(0, getWeight(), List.of("No dependency version manager bot are used on the plugin repository."));
return new ScoringComponentResult(
0,
getWeight(),
List.of("No dependency version manager bot are used on the plugin repository."),
List.of("https://www.jenkins.io/doc/developer/tutorial-improve/automate-dependency-update-checks/")
);
}

private ScoringComponentResult manageOpenDependencyPullRequestValue(ProbeResult dependencyBotResult, ProbeResult dependencyPullRequestResult) {
if (dependencyPullRequestResult != null && "0".equals(dependencyPullRequestResult.message())) {
return new ScoringComponentResult(
100,
getWeight(),
List.of(dependencyBotResult.message(), "%s open dependency pull request".formatted(dependencyPullRequestResult.message()))
);
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("%s/pulls?q=is%%3Aopen+is%%3Apr+label%%3Adependencies".formatted(plugin.getScm()))
);
}
return new ScoringComponentResult(
0,
getWeight(),
List.of(
dependencyBotResult.message(),
dependencyPullRequestResult == null ?
"Cannot determine if there is any dependency pull request opened on the repository." :
"%s open dependency pull requests".formatted(dependencyPullRequestResult.message())
"Cannot determine if there is any dependency pull request opened on the repository."
)
);
}
Expand Down Expand Up @@ -201,6 +221,6 @@ public String description() {

@Override
public int version() {
return 1;
return 2;
}
}
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 @@ -32,7 +32,7 @@

public interface ScoringComponent {
/**
* Provides a human readable description of the behavior of the Changelog.
* Provides a human-readable description of the behavior of the Changelog.
*
* @return the description of the implementation.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ static Stream<Arguments> probeResultsAndValue() {
ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "Could not find JEP-229 workflow definition.", 1),
DocumentationMigrationProbe.KEY, ProbeResult.success(DocumentationMigrationProbe.KEY, "Documentation is not located in the plugin repository.", 1)
),
65
73
),
arguments(// Jenkinsfile and dependabot with no open pull request
Map.of(
Expand Down Expand Up @@ -160,7 +160,7 @@ static Stream<Arguments> probeResultsAndValue() {
ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "JEP-229 workflow definition found.", 1),
DocumentationMigrationProbe.KEY, ProbeResult.success(DocumentationMigrationProbe.KEY, "Documentation is not located in the plugin repository.", 1)
),
70
78
),
arguments(// Jenkinsfile and CD and dependabot with no open pull request
Map.of(
Expand Down Expand Up @@ -228,7 +228,7 @@ static Stream<Arguments> probeResultsAndValue() {
ContinuousDeliveryProbe.KEY, ProbeResult.success(ContinuousDeliveryProbe.KEY, "Could not find JEP-229 workflow definition.", 1),
DocumentationMigrationProbe.KEY, ProbeResult.success(DocumentationMigrationProbe.KEY, "Documentation is located in the plugin repository.", 1)
),
15
23
),
arguments(// Documentation migration and Dependabot with no open pull requests
Map.of(
Expand Down
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 @@ -29,6 +29,7 @@
import java.util.stream.Collectors;

import io.jenkins.pluginhealth.scoring.model.ScoreResult;
import io.jenkins.pluginhealth.scoring.model.ScoringComponentResult;
import io.jenkins.pluginhealth.scoring.service.ScoreService;

import org.springframework.http.MediaType;
Expand All @@ -45,7 +46,7 @@ public ScoreAPI(ScoreService scoreService) {
this.scoreService = scoreService;
}

@GetMapping(value = { "", "/" }, produces = MediaType.APPLICATION_JSON_VALUE)
@GetMapping(value = {"", "/"}, produces = MediaType.APPLICATION_JSON_VALUE)
public ScoreReport getReport() {
final ScoreService.ScoreStatistics stats = scoreService.getScoresStatistics();
record Tuple(String name, PluginScoreSummary summary) {
Expand All @@ -61,37 +62,39 @@ record Tuple(String name, PluginScoreSummary summary) {
score.getValue(),
score.getDetails().stream()
.collect(Collectors.toMap(
ScoreResult::key,
scoreResult -> new PluginScoreDetail(
scoreResult.value(),
scoreResult.weight(),
scoreResult.componentsResults().stream()
.map(changelogResult ->
new PluginScoreDetailComponent(
changelogResult.score(),
changelogResult.weight(),
changelogResult.reasons()
)
)
.collect(Collectors.toList())
ScoreResult::key,
PluginScoreDetail::new
)
))
)
)
);
})
.collect(Collectors.toMap(Tuple::name, Tuple::summary));
return new ScoreReport(plugins, stats);
}

private record ScoreReport(Map<String, PluginScoreSummary> plugins, ScoreService.ScoreStatistics statistics) {
public record ScoreReport(Map<String, PluginScoreSummary> plugins, ScoreService.ScoreStatistics statistics) {
}

private record PluginScoreSummary(long value, Map<String, PluginScoreDetail> details) {
}

private record PluginScoreDetail(float value, float weight, List<PluginScoreDetailComponent> components) {
private PluginScoreDetail(ScoreResult result) {
this(
result.value(),
result.weight(),
result.componentsResults().stream()
.map(PluginScoreDetailComponent::new)
.collect(Collectors.toList())
);
}
}

private record PluginScoreDetailComponent(int value, float weight, List<String> reasons) {

private record PluginScoreDetailComponent(int value, float weight, List<String> reasons, List<String> resolutions) {
private PluginScoreDetailComponent(ScoringComponentResult result) {
this(result.score(), result.weight(), result.reasons(), result.resolutions());
}
}
}
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 @@ -78,7 +78,7 @@ public Score runOn(Plugin plugin) {
if (latestScore.isPresent() && (latestProbeResult.isEmpty() || latestProbeResult.get().isBefore(latestScore.get().getComputedAt()))) {
final Score score = latestScore.get();
boolean scoringIsSame = scoringService.getScoringList().stream()
.anyMatch(scoring ->
.allMatch(scoring ->
score.getDetails().stream()
.filter(sr -> sr.key().equals(scoring.key()))
.findFirst()
Expand Down
Loading

0 comments on commit 76202c4

Please sign in to comment.