Skip to content
Permalink
Browse files
JENKINS-30115 Allow downstream jobs to attach GitHub status messages …
…to pulled repo

- Added support for GitHub contexts and messages to be added from downstream jobs
  • Loading branch information
kevinsuwala committed Aug 24, 2015
1 parent c875ec2 commit 9470f35cc66ab4beefa83e885c26b0923da4a88a
@@ -59,6 +59,7 @@ public void build(GhprbPullRequest pr, GHUser triggerSender, String commentBody)


public void onStarted(AbstractBuild<?, ?> build, TaskListener listener) {
GhprbCustomStatusRepoPasser.addRepo(build.getFullDisplayName(), repo.getGitHubRepo());
PrintStream logger = listener.getLogger();
GhprbCause c = Ghprb.getCause(build);
if (c == null) {
@@ -0,0 +1,74 @@
package org.jenkinsci.plugins.ghprb;

import hudson.Extension;
import hudson.Launcher;
import hudson.model.*;
import hudson.tasks.BuildWrapper;
import hudson.util.FormValidation;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

import javax.servlet.ServletException;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Logger;

/**
* @author Kevin Suwala
*/

public class GhprbCustomStatus extends BuildWrapper {
private static final Logger logger = Logger.getLogger(Ghprb.class.getName());
private String context = "";
private String message = "";
public String getContext() {
return context;
}

public String getMessage() {
return message;
}

@DataBoundConstructor
public GhprbCustomStatus(String context, String message) {
this.message = message;
this.context = context;
}

@Extension
public static final class DescriptorImpl extends Descriptor<BuildWrapper> {
public DescriptorImpl() {
load();
}

@Override
public String getDisplayName() {
return "Set GitHub commit status with custom context and message (Must configure upstream job using GHPRB)";
}

public FormValidation doCheckValue(@QueryParameter String value) throws IOException, ServletException {
if(value.isEmpty()) {
return FormValidation.error("You must have a context!");
}
return FormValidation.ok();
}
}

// sets the context and message as env vars so that they are available in the Listener class
@Override
public void makeBuildVariables(AbstractBuild build, Map<String,String> variables){
variables.put("context", context);
variables.put("message", message);
}

@Override
public BuildWrapper.Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException {
makeBuildVariables(build, build.getBuildVariables());
return new Environment(){};
}

@Override
public void preCheckout(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException {
makeBuildVariables(build, build.getBuildVariables());
}
}
@@ -0,0 +1,103 @@
package org.jenkinsci.plugins.ghprb;

import hudson.EnvVars;
import hudson.Extension;
import hudson.Launcher;
import hudson.model.*;
import hudson.model.listeners.RunListener;
import org.kohsuke.github.GHCommitState;
import org.kohsuke.github.GHRepository;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* @author Kevin Suwala
* This class is responsible for sending the custom status and message on
* downstream jobs that have the option configured.
*/

@Extension
public class GhprbCustomStatusListener extends RunListener<AbstractBuild<?, ?>> {
private static final Logger logger = Logger.getLogger(Ghprb.class.getName());
private String context = "";
private String message = "";
private String sha = "";
private String url = "";
private String upstreamJob = "";
private String jobName = "";

// Gets all the custom env vars needed to send information to GitHub
private void updateEnvironmentVars(AbstractBuild<?, ?> build, TaskListener listener){
EnvVars envVars = new EnvVars();
try {
envVars = build.getEnvironment(listener);
} catch (Exception e) {
logger.log(Level.WARNING, "Unable to get update environment variables!");
listener.getLogger().println("Unable to get environment variables, is the upstream job configured with the GHPRB plugin?");
return;
}

context = envVars.get("context");
message = envVars.get("message");
sha = envVars.get("ghprbActualCommit");
url = envVars.get("BUILD_URL");
if (url == "") url = envVars.get("JOB_URL");
jobName = envVars.get("JOB_NAME");
upstreamJob = envVars.get("ghprbTriggerJob");
}

// Sends the commit status and message to GitHub
private void createCommitStatus(String sha, GHCommitState state, String url, String message, String context, AbstractBuild<?, ?> build) {
// return if it's the upstream job, otherwise if context isn't set make it job name
if (context == null) return;
if (context.isEmpty()) context = jobName;

logger.log(Level.FINE, "Job: " + build.getFullDisplayName() + " Attempting to send GitHub commit status");
GHRepository r = GhprbCustomStatusRepoPasser.getRepoMap().get(upstreamJob);

try {
r.createCommitStatus(sha, state, url, message, context);
logger.log(Level.FINE, "Status sent successfully");
} catch(Exception e) {
logger.log(Level.WARNING, "GitHub status could not be created!");
}
}

// Sets the status as pending when the job starts and then calls the createCommitStatus method to send it to GitHub
@Override
public Environment setUpEnvironment(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException, Run.RunnerAbortedException {
updateEnvironmentVars(build, listener);

GHCommitState state = GHCommitState.PENDING;
createCommitStatus(sha, state, url, "Build has started, please wait for results... ", context, build);

return new hudson.model.Environment(){};
}

@Override
public void onStarted(AbstractBuild<?, ?> build, TaskListener listener) {
updateEnvironmentVars(build, listener);
}

// Sets the status to the build result when the job is done, and then calls the createCommitStatus method to send it to GitHub
@Override
public void onCompleted(AbstractBuild<?, ?> build, TaskListener listener) {
updateEnvironmentVars(build, listener);

GHCommitState state = GHCommitState.SUCCESS;

if (build.getResult().isWorseThan(Result.SUCCESS)) {
state = GHCommitState.FAILURE;
}

String newMessage = "";
if (message.isEmpty()) {
newMessage = "Build finished.";
} else {
newMessage = "Build finished with message: " + message;
}
createCommitStatus(sha, state, url, newMessage, context, build);
}
}
@@ -0,0 +1,24 @@
package org.jenkinsci.plugins.ghprb;

import org.kohsuke.github.GHRepository;

import java.util.HashMap;
import java.util.Map;

/**
* @author Kevin Suwala
* This class is responsible for storing the GHRepository for each job and making
* it accesible for other classes
*/

public class GhprbCustomStatusRepoPasser {
private static Map<String, GHRepository> repoMap = new HashMap<String, GHRepository>();

public static void addRepo(String name, GHRepository repo) {
repoMap.put(name, repo);
}

public static Map<String, GHRepository> getRepoMap() {
return repoMap;
}
}
@@ -260,6 +260,7 @@ public void run() {
values.add(new StringParameterValue("ghprbPullLink", String.valueOf(cause.getUrl())));
values.add(new StringParameterValue("ghprbPullLongDescription", String.valueOf(cause.getDescription())));
values.add(new StringParameterValue("ghprbCommentBody", String.valueOf(cause.getCommentBody())));
values.add(new StringParameterValue("ghprbTriggerJob", this.job.getFullDisplayName() + " #" + this.job.getNextBuildNumber()));

// add the previous pr BuildData as an action so that the correct change log is generated by the GitSCM plugin
// note that this will be removed from the Actions list after the job is completed so that the old (and incorrect)
@@ -0,0 +1,9 @@
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:entry title="${%Context}" field="context">
<f:textbox default="${descriptor.context}"
checkUrl="'descriptorByName/GhprbCustomStatus/checkValue?value='+escape(this.value)" />
</f:entry>
<f:entry title="${%Message}" field="message">
<f:textbox default="${descriptor.message}"/>
</f:entry>
</j:jelly>
@@ -0,0 +1,3 @@
<div>
Set a custom context that will appear on the Github PR that the upstream job pulled
</div>
@@ -0,0 +1,3 @@
<div>
Set a custom message that will appear on the Github PR that the upstream job pulled
</div>
@@ -0,0 +1,8 @@
<div>
Allows you to set a custom context and message on a pull request pulled using GHPRB.
<BR/> This will add the context and message to the pull request found in the upstream job NOT on any pull requests taken on this job
<BR/> To add a custom context and message on any pull requests on THIS job see the GHPRB section in the Build Triggers section
<BR/>
<BR/>IMPORTANT:
<BR/>This will only work if you configure a upstream job that uses the Github Pull Request Builder Plugin
</div>

0 comments on commit 9470f35

Please sign in to comment.