-
Notifications
You must be signed in to change notification settings - Fork 277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merge job started messages based on aggregation interval #313
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,8 @@ | |
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.util.List; | ||
|
||
/** | ||
* Start position that notifies Gerrit of events. | ||
* @author Robert Sandell <[email protected]> | ||
|
@@ -70,18 +72,24 @@ public GerritNotifier(IGerritHudsonTriggerConfig config, GerritCmdRunner cmdRunn | |
|
||
/** | ||
* Generates the build-started command based on configured templates and build-values and sends it to Gerrit. | ||
* @param build the build. | ||
* @param builds the builds. | ||
* @param taskListener the taskListener. | ||
* @param event the event. | ||
* @param stats the stats. | ||
*/ | ||
public void buildStarted(Run build, TaskListener taskListener, | ||
GerritTriggeredEvent event, BuildsStartedStats stats) { | ||
public void buildStarted(List<Run> builds, TaskListener taskListener, | ||
GerritTriggeredEvent event, BuildsStartedStats stats) { | ||
try { | ||
/* Without a change, it doesn't make sense to notify gerrit */ | ||
if (event instanceof ChangeBasedEvent) { | ||
String command = | ||
parameterExpander.getBuildStartedCommand(build, taskListener, (ChangeBasedEvent)event, stats); | ||
String command; | ||
if (builds.size() == 1) { | ||
command = parameterExpander.getBuildStartedCommand(builds.get(0), taskListener, | ||
(ChangeBasedEvent)event, stats); | ||
} else { | ||
command = parameterExpander.getBuildsStartedCommand(builds, taskListener, | ||
(ChangeBasedEvent)event, stats); | ||
} | ||
if (command != null) { | ||
if (!command.isEmpty()) { | ||
logger.info("Notifying BuildStarted to gerrit: {}", command); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,10 +41,12 @@ | |
import hudson.model.Run; | ||
import hudson.model.TaskListener; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.Comparator; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import jenkins.model.Jenkins; | ||
|
@@ -105,7 +107,7 @@ public String getBuildStartedCommand(Run r, TaskListener taskListener, | |
|
||
GerritTrigger trigger = GerritTrigger.getTrigger(r.getParent()); | ||
String gerritCmd = config.getGerritCmdBuildStarted(); | ||
Map<String, String> parameters = createStandardParameters(r, event, | ||
Map<String, String> parameters = createStandardParameters(event, | ||
getBuildStartedCodeReviewValue(r), | ||
getBuildStartedVerifiedValue(r), | ||
Notify.ALL.name()); | ||
|
@@ -127,11 +129,76 @@ public String getBuildStartedCommand(Run r, TaskListener taskListener, | |
} | ||
} | ||
|
||
parameters.put("BUILDURL", jenkins.getRootUrl() + r.getUrl()); | ||
parameters.put("STARTED_STATS", startedStats.toString()); | ||
|
||
return expandParameters(gerritCmd, r, taskListener, parameters); | ||
} | ||
|
||
/** | ||
* Gets the expanded string to send to Gerrit for a build-started event. | ||
* @param runs the builds. | ||
* @param taskListener the taskListener. | ||
* @param event the event. | ||
* @param stats the statistics. | ||
* @return the "expanded" command string. | ||
*/ | ||
public String getBuildsStartedCommand(List<Run> runs, TaskListener taskListener, | ||
ChangeBasedEvent event, BuildsStartedStats stats) { | ||
|
||
String gerritCmd = config.getGerritCmdBuildStarted(); | ||
|
||
Integer minCodeReview = Integer.MAX_VALUE; | ||
Integer minVerified = Integer.MAX_VALUE; | ||
|
||
StringBuilder aggregatedBuilds = new StringBuilder(); | ||
|
||
int offset = runs.size() - 1; | ||
|
||
for (Run r : runs) { | ||
GerritTrigger trigger = GerritTrigger.getTrigger(r.getParent()); | ||
|
||
minCodeReview = Math.min(minCodeReview, getBuildStartedCodeReviewValue(r)); | ||
minVerified = Math.min(minVerified, getBuildStartedVerifiedValue(r)); | ||
|
||
aggregatedBuilds.append("\n\n"); | ||
|
||
String buildStartMessage = trigger.getBuildStartMessage(); | ||
if (buildStartMessage != null && !buildStartMessage.isEmpty()) { | ||
aggregatedBuilds.append("\n\n").append(buildStartMessage); | ||
} | ||
|
||
String buildUrl = jenkins.getRootUrl() + r.getUrl(); | ||
aggregatedBuilds.append(buildUrl); | ||
|
||
if (stats.getTotalBuildsToStart() > 1) { | ||
aggregatedBuilds.append(" "); | ||
aggregatedBuilds.append(stats.stringWithOffset(offset)); | ||
aggregatedBuilds.append(" "); | ||
offset--; | ||
} | ||
|
||
if (config.isEnablePluginMessages()) { | ||
for (GerritMessageProvider messageProvider : emptyIfNull(GerritMessageProvider.all())) { | ||
String extensionMessage = messageProvider.getBuildStartedMessage(r); | ||
if (extensionMessage != null) { | ||
aggregatedBuilds.append("\n\n").append(extensionMessage); | ||
} | ||
} | ||
} | ||
} | ||
|
||
Map<String, String> parameters = createStandardParameters(event, | ||
minCodeReview, | ||
minVerified, | ||
Notify.ALL.name()); | ||
|
||
parameters.put("BUILDURL", ""); | ||
parameters.put("STARTED_STATS", aggregatedBuilds.toString()); | ||
|
||
return expandParameters(gerritCmd, runs.get(0), taskListener, parameters); | ||
} | ||
|
||
/** | ||
* Helper for ensuring no NPEs when iterating iterables. | ||
* | ||
|
@@ -213,14 +280,13 @@ private Integer getBuildStartedCodeReviewValue(Run r) { | |
* <li><strong>CODE_REVIEW</strong>: The code review vote.</li> | ||
* <li><strong>NOTIFICATION_LEVEL</strong>: The notification level.</li> | ||
* </ul> | ||
* @param r the build. | ||
* @param gerritEvent the event. | ||
* @param codeReview the code review vote. | ||
* @param verified the verified vote. | ||
* @param notifyLevel the notify level. | ||
* @return the parameters and their values. | ||
*/ | ||
private Map<String, String> createStandardParameters(Run r, GerritTriggeredEvent gerritEvent, | ||
private Map<String, String> createStandardParameters(GerritTriggeredEvent gerritEvent, | ||
Integer codeReview, Integer verified, String notifyLevel) { | ||
//<GERRIT_NAME> <BRANCH> <CHANGE> <PATCHSET> <PATCHSET_REVISION> <REFSPEC> <BUILDURL> VERIFIED CODE_REVIEW | ||
Map<String, String> map = new HashMap<String, String>(DEFAULT_PARAMETERS_COUNT); | ||
|
@@ -239,9 +305,7 @@ private Map<String, String> createStandardParameters(Run r, GerritTriggeredEvent | |
map.put("REFSPEC", StringUtil.makeRefSpec(event)); | ||
} | ||
} | ||
if (r != null) { | ||
map.put("BUILDURL", jenkins.getRootUrl() + r.getUrl()); | ||
} | ||
|
||
map.put("VERIFIED", String.valueOf(verified)); | ||
map.put("CODE_REVIEW", String.valueOf(codeReview)); | ||
map.put("NOTIFICATION_LEVEL", notifyLevel); | ||
|
@@ -404,6 +468,24 @@ public Integer getMinimumVerifiedValue(MemoryImprint memoryImprint, boolean only | |
return verified; | ||
} | ||
|
||
/** | ||
* Convert entries of memoryImprint object to list of builds | ||
* | ||
* @param memoryImprint the memory | ||
* @return the list of run objects from memory | ||
*/ | ||
private List<Run> fromMemoryImprintToBuilds(MemoryImprint memoryImprint) { | ||
final List<Run> runs = new ArrayList<Run>(memoryImprint.getEntries().length); | ||
for (Entry entry : memoryImprint.getEntries()) { | ||
if (entry == null || entry.getBuild() == null) { | ||
continue; | ||
} | ||
runs.add(entry.getBuild()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
} | ||
|
||
return runs; | ||
} | ||
|
||
/** | ||
* Returns the minimum code review value for the build results in the memory. | ||
* If no builds have contributed to code review value, this method returns null | ||
|
@@ -449,21 +531,30 @@ public Integer getMinimumCodeReviewValue(MemoryImprint memoryImprint, boolean on | |
* @return the highest configured notification level. | ||
*/ | ||
public Notify getHighestNotificationLevel(MemoryImprint memoryImprint, boolean onlyBuilt) { | ||
return getHighestNotificationLevel(fromMemoryImprintToBuilds(memoryImprint), onlyBuilt); | ||
} | ||
|
||
/** | ||
* Returns the highest configured notification level. | ||
* | ||
* @param builds the list of builds | ||
* @param onlyBuilt only count builds that completed (no NOT_BUILT builds) | ||
* @return the highest configured notification level. | ||
*/ | ||
public Notify getHighestNotificationLevel(List<Run> builds, boolean onlyBuilt) { | ||
Notify highestLevel = Notify.NONE; | ||
for (Entry entry : memoryImprint.getEntries()) { | ||
if (entry == null) { | ||
continue; | ||
} | ||
Run build = entry.getBuild(); | ||
|
||
for (Run build : builds) { | ||
if (build == null) { | ||
continue; | ||
} | ||
|
||
Result result = build.getResult(); | ||
if (onlyBuilt && result == Result.NOT_BUILT) { | ||
continue; | ||
} | ||
|
||
GerritTrigger trigger = GerritTrigger.getTrigger(entry.getProject()); | ||
GerritTrigger trigger = GerritTrigger.getTrigger(build.getParent()); | ||
if (trigger == null || shouldSkip(trigger.getSkipVote(), result)) { | ||
continue; | ||
} | ||
|
@@ -473,6 +564,7 @@ public Notify getHighestNotificationLevel(MemoryImprint memoryImprint, boolean o | |
highestLevel = level; | ||
} | ||
} | ||
|
||
return highestLevel; | ||
} | ||
|
||
|
@@ -530,7 +622,7 @@ public String getBuildCompletedCommand(MemoryImprint memoryImprint, TaskListener | |
notifyLevel = getHighestNotificationLevel(memoryImprint, onlyCountBuilt); | ||
} | ||
|
||
Map<String, String> parameters = createStandardParameters(null, memoryImprint.getEvent(), | ||
Map<String, String> parameters = createStandardParameters(memoryImprint.getEvent(), | ||
codeReview, verified, notifyLevel.name()); | ||
// escapes ' as '"'"' in order to avoid breaking command line param | ||
// Details: http://stackoverflow.com/a/26165123/99834 | ||
|
@@ -668,15 +760,21 @@ public String getBuildCompletedMessage(MemoryImprint memoryImprint, TaskListener | |
/** | ||
* Returns cover message to be send after build has been started. | ||
* | ||
* @param build build | ||
* @param builds build | ||
* @param listener listener | ||
* @param event event | ||
* @param stats stats | ||
* @return the message for the build started command. | ||
*/ | ||
public String getBuildStartedMessage(Run build, TaskListener listener, ChangeBasedEvent event, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still nervous of removing signatures like this, even though it should be safe in this context as only careless plugina uthors would rely on this code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want, I can restore this one and mark like |
||
BuildsStartedStats stats) { | ||
String startedCommand = getBuildStartedCommand(build, listener, event, stats); | ||
public String getBuildsStartedMessage(List<Run> builds, TaskListener listener, ChangeBasedEvent event, | ||
BuildsStartedStats stats) { | ||
String startedCommand; | ||
if (builds.size() == 1) { | ||
startedCommand = getBuildStartedCommand(builds.get(0), listener, event, stats); | ||
} else { | ||
startedCommand = getBuildsStartedCommand(builds, listener, event, stats); | ||
} | ||
|
||
return findMessage(startedCommand); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it would have been better if we could change the command templates and separate the message part with the actual command part. And then in case of a compound message like this the message part would be just two messages correctly expanded with
BUILDURL
and all and added to the one command.This seems a bit hacky to me as it omits certain variables in case an admin has changed the message format.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did it, because it was already like that implemented for
Completed
message (it just ignoredBUILDURL
) completely :). I don't want to touch template part in my PR, but I can add more details inhelp
section.