-
Notifications
You must be signed in to change notification settings - Fork 141
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
JENKINS-56448 Introduce a report of the time spent in each phase of t…
…he Maven build (compile, test...)
- Loading branch information
1 parent
638895d
commit 67198a2
Showing
20 changed files
with
2,385 additions
and
522 deletions.
There are no files selected for viewing
88 changes: 88 additions & 0 deletions
88
...ava/org/jenkinsci/plugins/pipeline/maven/model/MavenExecutionAggregatedPhasesDetails.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package org.jenkinsci.plugins.pipeline.maven.model; | ||
|
||
import edu.umd.cs.findbugs.annotations.NonNull; | ||
|
||
import java.time.Duration; | ||
import java.time.ZonedDateTime; | ||
import java.time.temporal.ChronoUnit; | ||
import java.time.temporal.TemporalUnit; | ||
import java.util.Arrays; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
import java.util.SortedSet; | ||
import java.util.TreeSet; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
import javax.annotation.Nonnull; | ||
|
||
/** | ||
* @author <a href="mailto:[email protected]">Cyrille Le Clerc</a> | ||
*/ | ||
public class MavenExecutionAggregatedPhasesDetails implements Comparable<MavenExecutionAggregatedPhasesDetails> { | ||
@NonNull | ||
private Set<String> phases; | ||
@NonNull | ||
private SortedSet<MavenMojoExecutionDetails> mojoExecutionDetails = new TreeSet<>(); | ||
|
||
public MavenExecutionAggregatedPhasesDetails(@NonNull String... phases) { | ||
this.phases = new HashSet<>(Arrays.asList(phases)); | ||
} | ||
|
||
/** | ||
* @param mojoExecutionDetails | ||
* @return {@code true} if given {@link MavenMojoExecutionDetails} was added to this aggregate. | ||
*/ | ||
public boolean offer(@NonNull MavenMojoExecutionDetails mojoExecutionDetails) { | ||
if (phases.contains(mojoExecutionDetails.getLifecyclePhase())) { | ||
this.mojoExecutionDetails.add(mojoExecutionDetails); | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
@Nonnull | ||
public ZonedDateTime getStart() { | ||
return mojoExecutionDetails.first().getStart(); | ||
} | ||
|
||
@Nonnull | ||
public ZonedDateTime getStop() { | ||
return mojoExecutionDetails.last().getStop(); | ||
} | ||
|
||
@Nonnull | ||
public String getDuration() { | ||
int durationInSecs = 0; | ||
for (MavenMojoExecutionDetails mojoExecutionDetails:getMojoExecutionDetails()) { | ||
durationInSecs += mojoExecutionDetails.getDurationMillis(); | ||
} | ||
return TimeUnit.SECONDS.convert(durationInSecs, TimeUnit.MILLISECONDS) + "s"; | ||
} | ||
|
||
public Set<String> getPhases() { | ||
return phases; | ||
} | ||
|
||
public SortedSet<MavenMojoExecutionDetails> getMojoExecutionDetails() { | ||
return mojoExecutionDetails; | ||
} | ||
|
||
@Override | ||
public int compareTo(MavenExecutionAggregatedPhasesDetails other) { | ||
int comparison = this.getStart().compareTo(other.getStart()); | ||
|
||
if (comparison == 0) { | ||
comparison = this.getStop().compareTo(other.getStop()); | ||
} | ||
return comparison; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "MavenExecutionAggregatedPhasesDetails{" + | ||
"phases=" + phases + | ||
", mojoExecutionDetails=" + mojoExecutionDetails + | ||
'}'; | ||
} | ||
} |
126 changes: 126 additions & 0 deletions
126
...lugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/model/MavenExecutionDetails.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
package org.jenkinsci.plugins.pipeline.maven.model; | ||
|
||
import java.io.Serializable; | ||
import java.time.ZonedDateTime; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.SortedSet; | ||
import java.util.TreeSet; | ||
import java.util.stream.Collectors; | ||
|
||
import javax.annotation.Nonnull; | ||
|
||
/** | ||
* @author <a href="mailto:[email protected]">Cyrille Le Clerc</a> | ||
*/ | ||
public class MavenExecutionDetails implements Comparable<MavenExecutionDetails>, Serializable { | ||
|
||
private static final long serialVersionUID = 1L; | ||
|
||
private SortedSet<MavenProjectExecutionDetails> mavenProjectExecutionDetails = new TreeSet<>(); | ||
|
||
@Nonnull | ||
private final ZonedDateTime start; | ||
@Nonnull | ||
private ZonedDateTime stop; | ||
|
||
public MavenExecutionDetails(@Nonnull ZonedDateTime start) { | ||
this.start = start; | ||
this.stop = stop; | ||
} | ||
|
||
public SortedSet<MavenProjectExecutionDetails> getMavenProjectExecutionDetails() { | ||
return mavenProjectExecutionDetails; | ||
} | ||
|
||
@Nonnull | ||
public ZonedDateTime getStart() { | ||
return start; | ||
} | ||
|
||
@Nonnull | ||
public ZonedDateTime getStop() { | ||
return stop; | ||
} | ||
|
||
public void setStop(@Nonnull ZonedDateTime stop) { | ||
this.stop = stop; | ||
} | ||
|
||
@Override | ||
public int compareTo(MavenExecutionDetails o) { | ||
return this.start.compareTo(o.start); | ||
} | ||
|
||
/** | ||
* it's a poor comparison but there is no risk of having 2 builds starting at the same time | ||
* | ||
* @param o | ||
* @return | ||
*/ | ||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
if (o == null || getClass() != o.getClass()) return false; | ||
|
||
MavenExecutionDetails that = (MavenExecutionDetails) o; | ||
|
||
return start.equals(that.start); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return start.hashCode(); | ||
} | ||
|
||
public String getExecutionDurationDetails() { | ||
List<MavenExecutionAggregatedPhasesDetails> aggregates = new ArrayList(Arrays.asList( | ||
new MavenExecutionAggregatedPhasesDetails("validate", "initialize"), | ||
new MavenExecutionAggregatedPhasesDetails("generate-sources", "process-sources", "generate-resources", "process-resources", "compile", "process-classes"), | ||
new MavenExecutionAggregatedPhasesDetails("generate-test-sources", "process-test-sources", "generate-test-resources", "process-test-resources", "test-compile", "process-test-classes", "test"), | ||
new MavenExecutionAggregatedPhasesDetails("prepare-package", "package"), | ||
new MavenExecutionAggregatedPhasesDetails("pre-integration-test", "integration-test", "post-integration-test"), | ||
new MavenExecutionAggregatedPhasesDetails("install"), | ||
new MavenExecutionAggregatedPhasesDetails("deploy"), | ||
new MavenExecutionAggregatedPhasesDetails("pre-clean", "clean", "post-clean"), | ||
new MavenExecutionAggregatedPhasesDetails("pre-site", "site", "post-site", "site-deploy") | ||
|
||
)); | ||
|
||
for (MavenProjectExecutionDetails projectExecutionDetails : | ||
getMavenProjectExecutionDetails()) { | ||
for (MavenMojoExecutionDetails mojoExecutionDetails : projectExecutionDetails.getMojoExecutionDetails()) { | ||
boolean added = false; | ||
for (MavenExecutionAggregatedPhasesDetails aggregate : aggregates) { | ||
if (aggregate.offer(mojoExecutionDetails)) { | ||
added = true; | ||
break; | ||
} | ||
} | ||
if (!added) { | ||
MavenExecutionAggregatedPhasesDetails aggregate = new MavenExecutionAggregatedPhasesDetails(mojoExecutionDetails.getLifecyclePhase()); | ||
aggregates.add(aggregate); | ||
boolean offer = aggregate.offer(mojoExecutionDetails); | ||
if (offer == false) { | ||
throw new IllegalStateException("Failure to add " + mojoExecutionDetails + " to " + aggregate); | ||
} | ||
} | ||
} | ||
} | ||
StringBuilder sb = new StringBuilder(); | ||
|
||
for (MavenExecutionAggregatedPhasesDetails aggregate : aggregates) { | ||
if (aggregate.getMojoExecutionDetails().isEmpty()) { | ||
|
||
} else { | ||
sb.append(" * " + aggregate.getPhases().stream().collect(Collectors.joining(", ")) + " --- " + aggregate.getDuration() + "\n"); | ||
for (MavenMojoExecutionDetails mojoExecutionDetails : aggregate.getMojoExecutionDetails().stream().filter(m -> m.getDurationMillis() > 1000).collect(Collectors.toList())) { | ||
sb.append(" * " + mojoExecutionDetails.getPlugin().getArtifactId() + ":" + mojoExecutionDetails.getGoal() + " (" + mojoExecutionDetails.getExecutionId() + ")" + " @ " + mojoExecutionDetails.getProject().getArtifactId() + " --- " + mojoExecutionDetails.getDuration() + "\n"); | ||
} | ||
} | ||
} | ||
|
||
return sb.toString(); | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
...gin/src/main/java/org/jenkinsci/plugins/pipeline/maven/model/MavenExecutionEventType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package org.jenkinsci.plugins.pipeline.maven.model; | ||
|
||
/** | ||
* See {@code org.apache.maven.execution.ExecutionEvent.Type} | ||
*/ | ||
public enum MavenExecutionEventType { | ||
ProjectDiscoveryStarted, | ||
SessionStarted, | ||
SessionEnded, | ||
ProjectSkipped, | ||
ProjectStarted, | ||
ProjectSucceeded, | ||
ProjectFailed, | ||
MojoSkipped, | ||
MojoStarted, | ||
MojoSucceeded, | ||
MojoFailed, | ||
ForkStarted, | ||
ForkSucceeded, | ||
ForkFailed, | ||
ForkedProjectStarted, | ||
ForkedProjectSucceeded, | ||
ForkedProjectFailed | ||
} |
6 changes: 6 additions & 0 deletions
6
...plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/model/MavenExecutionStatus.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package org.jenkinsci.plugins.pipeline.maven.model; | ||
|
||
/** | ||
* See {@code org.apache.maven.execution.BuildSuccess} and {@code org.apache.maven.execution.BuildFailure} | ||
*/ | ||
public enum MavenExecutionStatus {Success, Failure} |
148 changes: 148 additions & 0 deletions
148
...n/src/main/java/org/jenkinsci/plugins/pipeline/maven/model/MavenMojoExecutionDetails.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
package org.jenkinsci.plugins.pipeline.maven.model; | ||
|
||
import org.jenkinsci.plugins.pipeline.maven.MavenArtifact; | ||
|
||
import java.io.Serializable; | ||
import java.time.Duration; | ||
import java.time.ZonedDateTime; | ||
import java.time.temporal.ChronoUnit; | ||
|
||
import javax.annotation.Nonnull; | ||
|
||
/** | ||
* @author <a href="mailto:[email protected]">Cyrille Le Clerc</a> | ||
*/ | ||
public class MavenMojoExecutionDetails implements Comparable<MavenMojoExecutionDetails>, Serializable { | ||
|
||
private static final long serialVersionUID = 1L; | ||
|
||
@Nonnull | ||
private final MavenArtifact project; | ||
@Nonnull | ||
private final MavenArtifact plugin; | ||
@Nonnull | ||
private final String executionId; | ||
@Nonnull | ||
private final String goal; | ||
@Nonnull | ||
private final String lifecyclePhase; | ||
@Nonnull | ||
private final ZonedDateTime start; | ||
@Nonnull | ||
private ZonedDateTime stop; | ||
@Nonnull | ||
private MavenExecutionEventType type; | ||
|
||
public MavenMojoExecutionDetails(@Nonnull MavenArtifact project, @Nonnull MavenArtifact plugin, @Nonnull String executionId, @Nonnull String lifecyclePhase, @Nonnull String goal, @Nonnull ZonedDateTime start, @Nonnull MavenExecutionEventType type) { | ||
this.project = project; | ||
this.plugin = plugin; | ||
this.executionId = executionId; | ||
this.lifecyclePhase = lifecyclePhase; | ||
this.goal = goal; | ||
this.start = start; | ||
this.stop = start; | ||
this.type = type; | ||
} | ||
|
||
/** | ||
* See {@code org.apache.maven.execution.ExecutionEvent.Type#MojoStarted} | ||
*/ | ||
@Nonnull | ||
public ZonedDateTime getStart() { | ||
return start; | ||
} | ||
|
||
/** | ||
* See {@code org.apache.maven.execution.ExecutionEvent.Type#MojoSucceeded} and {@code org.apache.maven.execution.ExecutionEvent.Type#MojoFailed} | ||
*/ | ||
@Nonnull | ||
public ZonedDateTime getStop() { | ||
return stop; | ||
} | ||
|
||
public void stop(@Nonnull ZonedDateTime stop, MavenExecutionEventType type) { | ||
this.stop = stop; | ||
this.type = type; | ||
} | ||
|
||
@Nonnull | ||
public MavenArtifact getProject() { | ||
return project; | ||
} | ||
|
||
@Nonnull | ||
public MavenArtifact getPlugin() { | ||
return plugin; | ||
} | ||
|
||
@Nonnull | ||
public String getExecutionId() { | ||
return executionId; | ||
} | ||
|
||
@Nonnull | ||
public String getLifecyclePhase() { | ||
return lifecyclePhase; | ||
} | ||
|
||
@Nonnull | ||
public String getGoal() { | ||
return goal; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "MavenMojoExecutionDetails{" + | ||
"project=" + project.getId() + | ||
", plugin=" + plugin.getId() + | ||
", executionId='" + executionId + '\'' + | ||
", lifecyclePhase='" + lifecyclePhase + '\'' + | ||
", goal='" + goal + '\'' + | ||
", start=" + start + | ||
", stop=" + stop + | ||
", type=" + type + | ||
'}'; | ||
} | ||
|
||
@Override | ||
public int compareTo(MavenMojoExecutionDetails other) { | ||
int comparison = this.getStart().compareTo(other.getStart()); | ||
|
||
if (comparison == 0) { | ||
comparison = this.getStop().compareTo(other.getStop()); | ||
} | ||
return comparison; | ||
} | ||
|
||
@Nonnull | ||
public String getDuration() { | ||
return Duration.between(start, stop).getSeconds() + "s"; | ||
} | ||
|
||
@Nonnull | ||
public long getDurationMillis() { | ||
return start.until(stop, ChronoUnit.MILLIS); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
if (o == null || getClass() != o.getClass()) return false; | ||
|
||
MavenMojoExecutionDetails that = (MavenMojoExecutionDetails) o; | ||
|
||
if (!project.equals(that.project)) return false; | ||
if (!plugin.equals(that.plugin)) return false; | ||
if (!executionId.equals(that.executionId)) return false; | ||
return goal.equals(that.goal); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
int result = project.hashCode(); | ||
result = 31 * result + plugin.hashCode(); | ||
result = 31 * result + executionId.hashCode(); | ||
result = 31 * result + goal.hashCode(); | ||
return result; | ||
} | ||
} |
Oops, something went wrong.