Useful events and config.
JSON build info is now emitted in the published events and the plugin is configurable. Config option include whether or not events should be emitted (global option and per project option) and the TCP port to listen on.
This commit is contained in:
parent
28a4fa86e1
commit
fd1480b87d
6
pom.xml
6
pom.xml
|
@ -70,13 +70,17 @@
|
|||
<version>2.1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.zeromq</groupId>
|
||||
<artifactId>jzmq</artifactId>
|
||||
<version>2.1.0-SNAPSHOT</version>
|
||||
<classifier>native-${os.arch}-${native.os}</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright Authors of the Jenkins Notification Plugin
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jenkinsci.plugins.ZMQEventPublisher;
|
||||
|
||||
import hudson.Extension;
|
||||
import hudson.model.Job;
|
||||
import hudson.model.JobProperty;
|
||||
import hudson.model.JobPropertyDescriptor;
|
||||
import hudson.model.AbstractProject;
|
||||
import hudson.util.FormValidation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.sf.json.JSON;
|
||||
import net.sf.json.JSONArray;
|
||||
import net.sf.json.JSONObject;
|
||||
|
||||
import org.kohsuke.stapler.DataBoundConstructor;
|
||||
import org.kohsuke.stapler.QueryParameter;
|
||||
import org.kohsuke.stapler.StaplerRequest;
|
||||
|
||||
public class HudsonNotificationProperty extends
|
||||
JobProperty<AbstractProject<?, ?>> {
|
||||
|
||||
final public boolean enabled;
|
||||
|
||||
@DataBoundConstructor
|
||||
public HudsonNotificationProperty(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HudsonNotificationPropertyDescriptor getDescriptor() {
|
||||
return (HudsonNotificationPropertyDescriptor) super.getDescriptor();
|
||||
}
|
||||
|
||||
@Extension
|
||||
public static final class HudsonNotificationPropertyDescriptor extends JobPropertyDescriptor {
|
||||
|
||||
private boolean globallyEnabled;
|
||||
private int port;
|
||||
|
||||
public HudsonNotificationPropertyDescriptor() {
|
||||
globallyEnabled = false;
|
||||
port = 8888;
|
||||
load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(@SuppressWarnings("rawtypes") Class<? extends Job> jobType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return "Jenkins ZMQ Event Publisher";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean configure(StaplerRequest staplerRequest, JSONObject json) throws FormException {
|
||||
globallyEnabled = json.getBoolean("globallyEnabled");
|
||||
port = json.getInt("port");
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isGloballyEnabled() {
|
||||
return globallyEnabled;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright Authors of the Jenkins Notification Plugin
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jenkinsci.plugins.ZMQEventPublisher;
|
||||
|
||||
import hudson.EnvVars;
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.model.Hudson;
|
||||
import hudson.model.Job;
|
||||
import hudson.model.ParameterValue;
|
||||
import hudson.model.ParametersAction;
|
||||
import hudson.model.Run;
|
||||
import hudson.model.TaskListener;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import org.jenkinsci.plugins.ZMQEventPublisher.model.BuildState;;
|
||||
import org.jenkinsci.plugins.ZMQEventPublisher.model.JobState;;
|
||||
|
||||
public enum Phase {
|
||||
STARTED, COMPLETED, FINISHED;
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public String handlePhase(Run run, String status, TaskListener listener) {
|
||||
HudsonNotificationProperty property = (HudsonNotificationProperty) run.getParent().getProperty(HudsonNotificationProperty.class);
|
||||
if (property != null) {
|
||||
HudsonNotificationProperty.HudsonNotificationPropertyDescriptor globalProperty = property.getDescriptor();
|
||||
if (globalProperty.isGloballyEnabled() || property.isEnabled()) {
|
||||
return buildMessage(run.getParent(), run, status);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Gson gson = new GsonBuilder().setFieldNamingPolicy(
|
||||
FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
||||
|
||||
private String buildMessage(Job job, Run run, String status) {
|
||||
JobState jobState = new JobState();
|
||||
jobState.setName(job.getName());
|
||||
jobState.setUrl(job.getUrl());
|
||||
BuildState buildState = new BuildState();
|
||||
buildState.setNumber(run.number);
|
||||
buildState.setUrl(run.getUrl());
|
||||
buildState.setPhase(this);
|
||||
buildState.setStatus(status);
|
||||
|
||||
String rootUrl = Hudson.getInstance().getRootUrl();
|
||||
if (rootUrl != null) {
|
||||
buildState.setFullUrl(rootUrl + run.getUrl());
|
||||
}
|
||||
|
||||
jobState.setBuild(buildState);
|
||||
|
||||
ParametersAction paramsAction = run.getAction(ParametersAction.class);
|
||||
if (paramsAction != null && run instanceof AbstractBuild) {
|
||||
AbstractBuild build = (AbstractBuild) run;
|
||||
EnvVars env = new EnvVars();
|
||||
for (ParameterValue value : paramsAction.getParameters())
|
||||
if (!value.isSensitive())
|
||||
value.buildEnvVars(build, env);
|
||||
buildState.setParameters(env);
|
||||
}
|
||||
|
||||
return gson.toJson(jobState);
|
||||
}
|
||||
}
|
|
@ -1,71 +1,121 @@
|
|||
/*
|
||||
* Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
* Copyright Authors of the Jenkins Notification Plugin
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.jenkinsci.plugins.ZMQEventPublisher;
|
||||
|
||||
import hudson.Extension;
|
||||
import hudson.EnvVars;
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.model.Result;
|
||||
import hudson.model.Run;
|
||||
import hudson.model.TaskListener;
|
||||
import hudson.model.listeners.RunListener;
|
||||
|
||||
import org.zeromq.ZMQ;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.InterruptedException;
|
||||
|
||||
/*
|
||||
* Listener to publish Jenkins build events through ZMQ
|
||||
*
|
||||
* @author Clark Boylan
|
||||
*/
|
||||
@Extension
|
||||
public class RunListenerImpl extends RunListener<AbstractBuild> {
|
||||
private final int port;
|
||||
public class RunListenerImpl extends RunListener<Run> {
|
||||
private int port;
|
||||
private String bind_addr;
|
||||
private ZMQ.Context context;
|
||||
private ZMQ.Socket publisher;
|
||||
private final String bind_addr;
|
||||
|
||||
public RunListenerImpl() {
|
||||
super(AbstractBuild.class);
|
||||
this.port = 8888;
|
||||
this.context = ZMQ.context(1);
|
||||
this.publisher = context.socket(ZMQ.PUB);
|
||||
|
||||
bind_addr = String.format("tcp://*:%d", this.port);
|
||||
this.publisher.bind(bind_addr);
|
||||
super(Run.class);
|
||||
context = ZMQ.context(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted(AbstractBuild build, TaskListener listener) {
|
||||
String update = String.format("onCompleted");
|
||||
try {
|
||||
EnvVars env = build.getEnvironment(listener);
|
||||
update = update + " " + env.toString();
|
||||
} catch (IOException e) {
|
||||
} catch (InterruptedException e) {
|
||||
private int getPort(Run build) {
|
||||
HudsonNotificationProperty property = (HudsonNotificationProperty) build.getParent().getProperty(HudsonNotificationProperty.class);
|
||||
if (property != null) {
|
||||
HudsonNotificationProperty.HudsonNotificationPropertyDescriptor globalProperty = property.getDescriptor();
|
||||
return globalProperty.getPort();
|
||||
}
|
||||
return 8888;
|
||||
}
|
||||
|
||||
private void bindSocket(Run build) {
|
||||
int tmpPort = getPort(build);
|
||||
if (publisher == null) {
|
||||
port = tmpPort;
|
||||
publisher = context.socket(ZMQ.PUB);
|
||||
bind_addr = String.format("tcp://*:%d", port);
|
||||
publisher.bind(bind_addr);
|
||||
}
|
||||
else if (tmpPort != port) {
|
||||
publisher.unbind(bind_addr);
|
||||
publisher.close();
|
||||
publisher = context.socket(ZMQ.PUB);
|
||||
port = tmpPort;
|
||||
bind_addr = String.format("tcp://*:%d", port);
|
||||
publisher.bind(bind_addr);
|
||||
}
|
||||
this.publisher.send(update.getBytes(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleted(AbstractBuild build) {
|
||||
public void onCompleted(Run build, TaskListener listener) {
|
||||
String event = "onCompleted";
|
||||
String json = Phase.COMPLETED.handlePhase(build, getStatus(build), listener);
|
||||
if (json != null) {
|
||||
bindSocket(build);
|
||||
event = event + " " + json;
|
||||
publisher.send(event.getBytes(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@Override
|
||||
public void onDeleted(Run build) {
|
||||
String update = String.format("onDeleted");
|
||||
this.publisher.send(update.getBytes(), 0);
|
||||
bindSocket(build);
|
||||
publisher.send(update.getBytes(), 0);
|
||||
}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void onFinalized(AbstractBuild build) {
|
||||
String update = String.format("onFinalized");
|
||||
this.publisher.send(update.getBytes(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStarted(AbstractBuild build, TaskListener listener) {
|
||||
String update = String.format("onStarted");
|
||||
try {
|
||||
EnvVars env = build.getEnvironment(listener);
|
||||
update = update + " " + env.toString();
|
||||
} catch (IOException e) {
|
||||
} catch (InterruptedException e) {
|
||||
public void onFinalized(Run build) {
|
||||
String event = "onFinalized";
|
||||
String json = Phase.FINISHED.handlePhase(build, getStatus(build), TaskListener.NULL);
|
||||
if (json != null) {
|
||||
bindSocket(build);
|
||||
event = event + " " + json;
|
||||
publisher.send(event.getBytes(), 0);
|
||||
}
|
||||
this.publisher.send(update.getBytes(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStarted(Run build, TaskListener listener) {
|
||||
String event = "onStarted";
|
||||
String json = Phase.STARTED.handlePhase(build, getStatus(build), listener);
|
||||
if (json != null) {
|
||||
bindSocket(build);
|
||||
event = event + " " + json;
|
||||
publisher.send(event.getBytes(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private String getStatus(Run r) {
|
||||
Result result = r.getResult();
|
||||
String status = null;
|
||||
if (result != null) {
|
||||
status = result.toString();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright Authors of the Jenkins Notification Plugin
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jenkinsci.plugins.ZMQEventPublisher.model;
|
||||
|
||||
import org.jenkinsci.plugins.ZMQEventPublisher.Phase;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class BuildState {
|
||||
|
||||
private String fullUrl;
|
||||
|
||||
private int number;
|
||||
|
||||
private Phase phase;
|
||||
|
||||
private String status;
|
||||
|
||||
private String url;
|
||||
|
||||
private Map<String, String> parameters;
|
||||
|
||||
public int getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setNumber(int number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Phase getPhase() {
|
||||
return phase;
|
||||
}
|
||||
|
||||
public void setPhase(Phase phase) {
|
||||
this.phase = phase;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getFullUrl() {
|
||||
return fullUrl;
|
||||
}
|
||||
|
||||
public void setFullUrl(String fullUrl) {
|
||||
this.fullUrl = fullUrl;
|
||||
}
|
||||
|
||||
public Map<String, String> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public void setParameters(Map<String, String> params) {
|
||||
this.parameters = params;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright Authors of the Jenkins Notification Plugin
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jenkinsci.plugins.ZMQEventPublisher.model;
|
||||
|
||||
public class JobState {
|
||||
|
||||
private String name;
|
||||
|
||||
private String url;
|
||||
|
||||
private BuildState build;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public BuildState getBuild() {
|
||||
return build;
|
||||
}
|
||||
|
||||
public void setBuild(BuildState build) {
|
||||
this.build = build;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<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">
|
||||
|
||||
<f:section title="ZMQ Event Publisher">
|
||||
<f:entry title="ZMQ Events" field="enabled">
|
||||
<f:checkbox title="Check if ZMQ events should be published for this project." name="zmqpublisher.enabled" checked="${HudsonNotificationProperty.isEnabled()}" />
|
||||
</f:entry>
|
||||
</f:section>
|
||||
</j:jelly>
|
|
@ -0,0 +1,12 @@
|
|||
<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">
|
||||
<f:section title="ZMQ Event Publisher">
|
||||
<f:entry title="Enable on all Jobs"
|
||||
description="Check if we should publish events for all jobs.">
|
||||
<f:checkbox name="zmqpublisher.globallyEnabled" checked="${descriptor.isGloballyEnabled()}" />
|
||||
</f:entry>
|
||||
<f:entry title="TCP port to publish on"
|
||||
description="Bind to this TCP port and publish events on it">
|
||||
<f:textbox name="zmqpublisher.port" value="${descriptor.getPort()}" />
|
||||
</f:entry>
|
||||
</f:section>
|
||||
</j:jelly>
|
|
@ -1,2 +0,0 @@
|
|||
<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">
|
||||
</j:jelly>
|
|
@ -0,0 +1,6 @@
|
|||
<div>
|
||||
<p>
|
||||
Plugin that will publish Jenkins Job run events on the specified port
|
||||
via ZMQ PUB SUB.
|
||||
</p>
|
||||
</div>
|
Loading…
Reference in New Issue