Skip to content
This repository has been archived by the owner on Dec 18, 2019. It is now read-only.

Commit

Permalink
Allow rebuilds to invoke the Slack Plugin for successful rebuilds
Browse files Browse the repository at this point in the history
  • Loading branch information
ivantsepp committed May 22, 2017
1 parent d947f25 commit 2a4b232
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target
8 changes: 7 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<groupId>com.etsy.jenkins</groupId>
<artifactId>MasterProject</artifactId>
<version>1.1.5</version>
<version>1.2.5</version>
<packaging>hpi</packaging>

<name>Jenkins Master Project Plugin</name>
Expand Down Expand Up @@ -58,6 +58,12 @@
<version>1.4.7</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>slack</artifactId>
<version>2.2</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>mailer</artifactId>
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/etsy/jenkins/MasterBuild.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class MasterBuild extends Build<MasterProject, MasterBuild> {
private Set<String> hiddenSubProjects;

private int maxRetries;
private boolean notifyOnRebuild;

private transient List<Future<AbstractBuild>> futuresToAbort =
Lists.<Future<AbstractBuild>>newArrayList();
Expand All @@ -46,6 +47,7 @@ public MasterBuild(MasterProject project) throws IOException {
this.subProjects = project.getSubProjectNames();
this.hiddenSubProjects = Sets.<String>newHashSet();
this.maxRetries = 0;
this.notifyOnRebuild = false;
}

public MasterBuild(MasterProject project, File file) throws IOException {
Expand Down Expand Up @@ -76,6 +78,14 @@ public int getMaxRetries() {
this.maxRetries = maxRetries;
}

public boolean getNotifyOnRebuild() {
return this.notifyOnRebuild;
}

/*package*/ void setNotifyOnRebuild(boolean notifyOnRebuild) {
this.notifyOnRebuild = notifyOnRebuild;
}

private Set<AbstractProject> getProjectsByNames(Set<String> subProjects) {
Set<AbstractProject> projects = Sets.<AbstractProject>newHashSet();

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/etsy/jenkins/MasterModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ protected void configure() {
.toInstance(executor);

requestStaticInjection(MasterBuild.class);
requestStaticInjection(RebuildWatcher.class);
requestStaticInjection(MasterProject.class);
requestStaticInjection(MasterResult.class);
requestStaticInjection(SubResult.class);
requestStaticInjection(SubProjectsAction.class);
requestStaticInjection(SubProjectsJobProperty.class);
requestStaticInjection(BuildMasterCommand.class);
requestStaticInjection(MasterProjectOptionHandler.class);
requestStaticInjection(RebuildNotifierProperty.class);
}
}

66 changes: 66 additions & 0 deletions src/main/java/com/etsy/jenkins/RebuildNotifierProperty.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.etsy.jenkins;

import hudson.Extension;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.model.Descriptor;
import hudson.model.Job;
import hudson.model.Hudson;
import hudson.model.JobProperty;
import hudson.model.JobPropertyDescriptor;
import com.google.inject.Inject;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;
import com.etsy.jenkins.MasterBuild;
import net.sf.json.JSONObject;

public class RebuildNotifierProperty extends JobProperty<MasterProject> {

@Inject static Hudson hudson;
private boolean notifyOnRebuild;

@DataBoundConstructor
public RebuildNotifierProperty(boolean notifyOnRebuild) {
this.notifyOnRebuild = notifyOnRebuild;
}

@Override
public boolean prebuild(AbstractBuild build, BuildListener listener) {
((MasterBuild) build).setNotifyOnRebuild(this.notifyOnRebuild);
return true;
}

public boolean getNotifyOnRebuild() {
return this.notifyOnRebuild;
}

@Override
public JobPropertyDescriptor getDescriptor() {
return DESCRIPTOR;
}

@Extension
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static class DescriptorImpl extends JobPropertyDescriptor {

@Override
public String getDisplayName() {
return "Allow rebuilds to notify Slack when rebuilds are successful";
}

@Override
public boolean isApplicable(Class<? extends Job> jobType) {
return jobType.equals(MasterProject.class) && hudson.getPlugin("slack") != null && hudson.getPlugin("slack").getWrapper().isActive();
}

@Override
public JobProperty<?> newInstance(
StaplerRequest req,
JSONObject formData)
throws Descriptor.FormException {

boolean notifyOnRebuild = formData.getBoolean("notifyOnRebuild");
return new RebuildNotifierProperty(notifyOnRebuild);
}
}
}
34 changes: 34 additions & 0 deletions src/main/java/com/etsy/jenkins/RebuildWatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Cause;
import hudson.model.Hudson;
import hudson.model.Result;

import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
Expand All @@ -14,6 +16,15 @@
import hudson.model.queue.QueueTaskFuture;
import java.util.concurrent.ExecutionException;
import jenkins.model.PeepholePermalink;
import org.apache.commons.io.output.NullOutputStream;

import hudson.model.StreamBuildListener;
import java.util.Map;
import hudson.model.Descriptor;
import hudson.tasks.Publisher;
import jenkins.plugins.slack.SlackNotifier;
import jenkins.plugins.slack.ActiveNotifier;
import jenkins.plugins.slack.SlackService;

/**
* A Runnable that watches a rebuilt sub-job from start to finish.
Expand All @@ -38,6 +49,7 @@ RebuildWatcher create(
private final AbstractProject project;
private final Cause cause;
private final QueueTaskFuture<?> buildFuture;
@Inject static Hudson hudson;

@Inject
public RebuildWatcher(
Expand Down Expand Up @@ -73,6 +85,9 @@ public void run() {
throw new RuntimeException(ex);
}

// Invoke SlackNotifier when rebuilds result in a successful build
this.rebuildNotify();

// Update the "last stable build" and "last successful build" permalinks.
new UpdateableProxyPermalink(
(PeepholePermalink) Permalink.LAST_STABLE_BUILD)
Expand All @@ -82,6 +97,25 @@ public void run() {
.update(masterBuild.getProject(), masterBuild);
}

private void rebuildNotify() {
if (masterBuild.getNotifyOnRebuild() && hudson.getPlugin("slack") != null && hudson.getPlugin("slack").getWrapper().isActive()) {
if (masterBuild.getResult() == Result.SUCCESS) {

SlackNotifier notifier = null;
Map<Descriptor<Publisher>, Publisher> map = masterBuild.getProject().getPublishersList().toMap();
for (Publisher publisher : map.values()) {
if (publisher instanceof SlackNotifier) {
notifier = (SlackNotifier) publisher;
}
}

ActiveNotifier.MessageBuilder messageBuilder = new ActiveNotifier.MessageBuilder(notifier, masterBuild);
String message = messageBuilder.append(" Rebuild was successful").appendOpenLink().toString();
notifier.newSlackService(masterBuild, new StreamBuildListener(new NullOutputStream())).publish(message, "good");
}
}
}

private void rest() {
try {
Thread.sleep(pingTime);
Expand Down
22 changes: 20 additions & 2 deletions src/main/java/com/etsy/jenkins/SubResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import com.etsy.jenkins.finder.BuildFinder;

import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Result;
import hudson.model.Hudson;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
Expand All @@ -20,17 +22,23 @@
@Inject static BuildFinder buildFinder;

/*package*/ final String projectName;
/*package*/ final AbstractProject project;
/*package*/ final TreeSet<Integer> buildNumbers;

public SubResult(String projectName) {
this.projectName = projectName;
this.project = (AbstractProject) Hudson.getInstance().getItemMap().get(projectName);
this.buildNumbers = Sets.<Integer>newTreeSet();
}

public String getProjectName() {
return this.projectName;
}

public AbstractProject getProject() {
return this.project;
}

public void addBuildNumber(int buildNumber) {
this.buildNumbers.add(buildNumber);
}
Expand All @@ -54,7 +62,10 @@ public Result getResult() {
while (it.hasNext()) {
int buildNumber = it.next();
AbstractBuild build = buildFinder
.findBuild(getProjectName(), buildNumber);
.findBuild(getProjectName(), buildNumber);
if (build == null) {
build = findBuild(buildNumber);
}
if (build != null) {
result = build.getResult();
if (result != Result.NOT_BUILT) {
Expand All @@ -65,5 +76,12 @@ public Result getResult() {

return result;
}
}

private AbstractBuild findBuild(int buildNumber) {
if (getProject() != null) {
return buildFinder.findBuild(getProject(), buildNumber);
} else {
return buildFinder.findBuild(getProjectName(), buildNumber);
}
}
}
6 changes: 5 additions & 1 deletion src/main/java/com/etsy/jenkins/finder/BuildFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ public AbstractBuild findBuild(String projectName, int buildNumber) {

public AbstractBuild findBuild(AbstractProject project, int buildNumber) {
if (project == null) return null;
return (AbstractBuild) project.getBuildByNumber(buildNumber);
try {
return (AbstractBuild) project.getBuildByNumber(buildNumber);
} catch (java.lang.NullPointerException e) {
return null;
}
}

public AbstractBuild findBuild(String projectName, Cause cause) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define"
xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form"
xmlns:i="jelly:fmt" xmlns:p="/lib/hudson/project">

<f:optionalBlock field="notifyOnRebuild" title="${%Notify Slack on successful rebuilds}" inline="true" />

</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div>
<p>Allow rebuilds to invoke the Slack plugin when the master build is successful</p>
<small>This will only work if the <a href="https://wiki.jenkins-ci.org/display/JENKINS/Slack+Plugin" target="_blank">slack plugin</a> is installed and is a publisher of this project (A post-build action)</small>
</div>

0 comments on commit 2a4b232

Please sign in to comment.