Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,41 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.views.ListViewColumnDescriptor;

/**
* Abstract base class for additional metric column descriptors.
* Provides common functionality for metric columns including display name handling
* and default visibility configuration.
*/
abstract class AdditionalMetricColumnDescriptor extends ListViewColumnDescriptor {

private final String displayName;

/**
* Creates a new additional metric column descriptor with the specified display name.
*
* @param displayName the human-readable name for this column type
*/
AdditionalMetricColumnDescriptor(String displayName) {
this.displayName = displayName;
}

/**
* Indicates whether this column should be shown by default in list views.
* Additional metric columns are not shown by default and must be explicitly added by users.
*
* @return false, indicating this column is not shown by default
*/
@Override
public boolean shownByDefault() {
return false;
}

/**
* Returns the display name for this column type.
* This name appears in the Jenkins UI when users are configuring list view columns.
*
* @return the human-readable display name for this column type
*/
@NonNull
@Override
public String getDisplayName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,27 @@
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;

/**
* A Jenkins list view column that displays the average duration of completed builds for a job.
*/
public class AvgDurationColumn extends ListViewColumn {

/**
* Creates a new average duration column.
* This constructor is used by Jenkins for data binding.
*/
@DataBoundConstructor
public AvgDurationColumn() {
super();
}

/**
* Calculates and returns the average duration of completed builds for the specified job.
* Only considers builds that have completed (not currently building).
*
* @param job the Jenkins job to calculate the average duration for
* @return the average duration of completed builds, or null if no completed builds exist
*/
@Metric
public Duration getAverageDuration(Job<? extends Job, ? extends Run> job) {
return averageDuration(job.getBuilds(), COMPLETED, RUN_DURATION).orElse(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@ private CheckoutDuration() {

static long checkoutDurationOf(Run run) {
Jenkins instance = Jenkins.getInstanceOrNull();
if (instance != null && instance.getPlugin("workflow-job") != null && run instanceof WorkflowRun currentBuild) {
FlowExecution execution = currentBuild.getExecution();
if (execution != null) {
return countCheckoutDuration(execution);
}
if (instance == null || instance.getPlugin("workflow-job") == null) {
return 0;
}

if (!(run instanceof WorkflowRun currentBuild)) {
return 0;
}

FlowExecution execution = currentBuild.getExecution();
if (execution == null) {
return 0;
}

return 0;
return countCheckoutDuration(execution);
}

private static long countCheckoutDuration(FlowExecution execution) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,27 @@

import hudson.Util;

/**
* Represents a time duration in milliseconds.
* Provides methods to access the duration as a long value or as a human-readable string.
*/
public record Duration(long milliseconds) {

/**
* Returns the duration in milliseconds.
*
* @return the duration value in milliseconds
*/
public long getAsLong() {
return milliseconds;
}

/**
* Returns the duration as a human-readable time span string.
* Uses Jenkins' utility method to format the duration (e.g., "2 hr 30 min").
*
* @return the duration formatted as a human-readable string
*/
public String getAsString() {
return Util.getTimeSpanString(milliseconds);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,29 @@
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;

/**
* A Jenkins list view column that displays the failure rate of completed builds for a job.
* The failure rate is calculated as the percentage of completed builds that did not succeed.
*/
public class FailureRateColumn extends ListViewColumn {

/**
* Creates a new failure rate column.
* This constructor is used by Jenkins for data binding.
*/
@DataBoundConstructor
public FailureRateColumn() {
super();
}

/**
* Calculates and returns the failure rate of completed builds for the specified job.
* The failure rate includes all non-successful builds (failed, unstable, aborted, etc.).
* Only considers builds that have completed (not currently building).
*
* @param job the Jenkins job to calculate the failure rate for
* @return the failure rate as a Rate object, or null if no completed builds exist
*/
@Metric
public Rate getFailureRate(Job<? extends Job, ? extends Run> job) {
return rateOf(job.getBuilds(), COMPLETED, NOT_SUCCESS).orElse(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,29 @@
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;

/**
* A Jenkins list view column that displays the longest running completed build for a job.
* Shows both the build information and its duration.
*/
public class MaxDurationColumn extends ListViewColumn {

/**
* Creates a new maximum duration column.
* This constructor is used by Jenkins for data binding.
*/
@DataBoundConstructor
public MaxDurationColumn() {
super();
}

/**
* Finds and returns the completed build with the longest duration for the specified job.
* Only considers builds that have completed (not currently building) and have a positive duration.
*
* @param job the Jenkins job to find the longest running build for
* @return a RunWithDuration containing the longest running build and its duration,
* or null if no completed builds with positive duration exist
*/
@Metric
public RunWithDuration getLongestRun(Job<? extends Job, ? extends Run> job) {
return findRun(job.getBuilds(), COMPLETED, RUN_DURATION, MAX).orElse(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Annotation used to mark methods that calculate and return metric values.
* This annotation is used by the additional metrics plugin to identify methods
* that provide metric data for Jenkins list view columns.
* <p>
* Methods annotated with @Metric should:
* - Be public
* - Return a metric value (Duration, Rate, RunWithDuration, etc.)
* - Accept a Job parameter to calculate metrics for
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Metric {}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,29 @@
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;

/**
* A Jenkins list view column that displays the shortest running completed build for a job.
* Shows both the build information and its duration.
*/
public class MinDurationColumn extends ListViewColumn {

/**
* Creates a new minimum duration column.
* This constructor is used by Jenkins for data binding.
*/
@DataBoundConstructor
public MinDurationColumn() {
super();
}

/**
* Finds and returns the completed build with the shortest duration for the specified job.
* Only considers builds that have completed (not currently building) and have a positive duration.
*
* @param job the Jenkins job to find the shortest running build for
* @return a RunWithDuration containing the shortest running build and its duration,
* or null if no completed builds with positive duration exist
*/
@Metric
public RunWithDuration getShortestRun(Job<? extends Job, ? extends Run> job) {
return findRun(job.getBuilds(), COMPLETED, RUN_DURATION, MIN).orElse(null);
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/org/jenkinsci/plugins/additionalmetrics/Rate.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,27 @@
import java.text.DecimalFormat;
import java.text.NumberFormat;

/**
* Represents a rate as a double value between 0.0 and 1.0.
* Provides methods to access the rate as a double or as a formatted percentage string.
*/
public record Rate(double rate) {

/**
* Returns the rate as a double value.
*
* @return the rate value as a double between 0.0 and 1.0
*/
public double getAsDouble() {
return rate;
}

/**
* Returns the rate as a formatted percentage string.
* The percentage is formatted to two decimal places with a "%" suffix.
*
* @return the rate formatted as a percentage string (e.g., "75.25%")
*/
public String getAsString() {
NumberFormat formatter = new DecimalFormat("0.00");
return (formatter.format(rate * 100) + "%");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,11 @@

import hudson.model.Run;

/**
* A record that pairs a Jenkins build run with its associated duration.
* This is used to store and pass around run information along with calculated duration metrics.
*
* @param run the Jenkins build run
* @param duration the calculated duration for the run
*/
public record RunWithDuration(Run run, Duration duration) {}
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ private static Optional<Duration> durationFunction(
}

private static Stream<? extends Run> preFilter(List<? extends Run> runs, Predicate<Run> preFilter) {
return runs.stream().filter(preFilter);
Stream<? extends Run> stream = runs.size() > 100 ? runs.parallelStream() : runs.stream();
return stream.filter(preFilter);
}
}