/
CampfireNotifier.java
169 lines (154 loc) · 7.15 KB
/
CampfireNotifier.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package hudson.plugins.campfire;
import hudson.tasks.Notifier;
import hudson.tasks.BuildStepMonitor;
import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.model.Result;
import hudson.model.User;
import hudson.scm.ChangeLogSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.lang.reflect.Method;
import java.io.*;
import java.util.regex.Pattern;
import java.io.IOException;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;
public class CampfireNotifier extends Notifier {
private transient Campfire campfire;
private Room room;
private String hudsonUrl;
private boolean smartNotify;
// getter for project configuration..
// Configured room name should be null unless different from descriptor/global room name
public String getConfiguredRoomName() {
if ( DESCRIPTOR.getRoom().equals(room.getName()) ) {
return null;
} else {
return room.getName();
}
}
@Extension
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
private static final Logger LOGGER = Logger.getLogger(CampfireNotifier.class.getName());
public CampfireNotifier() throws IOException {
super();
initialize();
}
public CampfireNotifier(String subdomain, String token, String room, String hudsonUrl, boolean ssl, boolean smartNotify) throws IOException {
super();
initialize(subdomain, token, room, hudsonUrl, ssl, smartNotify);
}
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.BUILD;
}
private void publish(AbstractBuild<?, ?> build) throws IOException {
checkCampfireConnection();
Result result = build.getResult();
String changeString = "No changes";
if (!build.hasChangeSetComputed()) {
changeString = "Changes not determined";
} else if (build.getChangeSet().iterator().hasNext()) {
ChangeLogSet changeSet = build.getChangeSet();
ChangeLogSet.Entry entry = build.getChangeSet().iterator().next();
// note: iterator should return recent changes first, but GitChangeSetList currently reverses the log entries
if (changeSet.getClass().getSimpleName().equals("GitChangeSetList")) {
String log_warn_prefix = "Workaround to obtain latest commit info from git plugin failed: ";
try {
// find the sha for the first commit in the changelog file, and then grab the corresponding entry from the changeset, yikes!
String changeLogPath = build.getRootDir().toString() + File.separator + "changelog.xml";
String line;
String sha = "";
BufferedReader reader = new BufferedReader(new FileReader(changeLogPath));
while((line = reader.readLine()) != null) {
if (line.matches("^commit [a-zA-Z0-9]+$")) {
sha = line.replace("commit ", "");
break;
}
}
reader.close();
if (sha != "") {
Method getIdMethod = entry.getClass().getDeclaredMethod("getId");
for(ChangeLogSet.Entry nextEntry : build.getChangeSet()) {
if ( ( (String)getIdMethod.invoke(entry) ).compareTo(sha) != 0 ) entry = nextEntry;
}
}
} catch ( IOException e ){
LOGGER.log(Level.WARNING, log_warn_prefix + e.getMessage());
} catch ( NoSuchMethodException e ) {
LOGGER.log(Level.WARNING, log_warn_prefix + e.getMessage());
} catch ( IllegalAccessException e ) {
LOGGER.log(Level.WARNING, log_warn_prefix + e.getMessage());
} catch ( SecurityException e ) {
LOGGER.log(Level.WARNING, log_warn_prefix + e.getMessage());
} catch ( Exception e ) {
throw new RuntimeException(e.getMessage(), e);
}
}
String commitMsg = entry.getMsg().trim();
if (commitMsg != "") {
if (commitMsg.length() > 47) {
commitMsg = commitMsg.substring(0, 46) + "...";
}
changeString = commitMsg + " - " + entry.getAuthor().toString();
}
}
String resultString = result.toString();
if (!smartNotify && result == Result.SUCCESS) resultString = resultString.toLowerCase();
String message = build.getProject().getName() + " " + build.getDisplayName() + " \"" + changeString + "\": " + resultString;
if (hudsonUrl != null && hudsonUrl.length() > 1 && (smartNotify || result != Result.SUCCESS)) {
message = message + " (" + hudsonUrl + build.getUrl() + ")";
}
room.speak(message);
}
private void checkCampfireConnection() throws IOException {
if (campfire == null) {
initialize();
}
}
private void initialize() throws IOException {
initialize(DESCRIPTOR.getSubdomain(), DESCRIPTOR.getToken(), DESCRIPTOR.getRoom(), DESCRIPTOR.getHudsonUrl(), DESCRIPTOR.getSsl(), DESCRIPTOR.getSmartNotify());
}
private void initialize(String subdomain, String token, String roomName, String hudsonUrl, boolean ssl, boolean smartNotify) throws IOException {
campfire = new Campfire(subdomain, token, ssl);
try {
this.room = campfire.findRoomByName(roomName);
if ( this.room == null ) {
throw new IOException("Room '" + roomName + "' not found");
}
} catch (IOException e) {
throw new IOException("Cannot join room: " + e.getMessage());
} catch (ParserConfigurationException e) {
throw new IOException("Cannot join room: " + e.getMessage());
} catch (XPathExpressionException e) {
throw new IOException("Cannot join room: " + e.getMessage());
} catch (SAXException e) {
throw new IOException("Cannot join room: " + e.getMessage());
}
this.hudsonUrl = hudsonUrl;
this.smartNotify = smartNotify;
}
@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher,
BuildListener listener) throws InterruptedException, IOException {
// If SmartNotify is enabled, only notify if:
// (1) there was no previous build, or
// (2) the current build did not succeed, or
// (3) the previous build failed and the current build succeeded.
if (smartNotify) {
AbstractBuild previousBuild = build.getPreviousBuild();
if (previousBuild == null ||
build.getResult() != Result.SUCCESS ||
previousBuild.getResult() != Result.SUCCESS)
{
publish(build);
}
} else {
publish(build);
}
return true;
}
}