-
-
Notifications
You must be signed in to change notification settings - Fork 8.6k
/
RunListener.java
282 lines (260 loc) · 9.67 KB
/
RunListener.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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Tom Huybrechts
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.model.listeners;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import hudson.ExtensionList;
import hudson.ExtensionListView;
import hudson.ExtensionPoint;
import hudson.FilePath;
import hudson.Functions;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.model.Environment;
import hudson.model.Job;
import hudson.model.JobProperty;
import hudson.model.Run;
import hudson.model.Run.RunnerAbortedException;
import hudson.model.TaskListener;
import hudson.scm.SCM;
import hudson.tasks.BuildWrapper;
import hudson.util.CopyOnWriteList;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import jenkins.model.lazy.AbstractLazyLoadRunMap;
import jenkins.util.Listeners;
import org.jvnet.tiger_types.Types;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.Beta;
/**
* Receives notifications about builds.
*
* <p>
* Listener is always Hudson-wide, so once registered it gets notifications for every build
* that happens in this Hudson.
*
* <p>
* This is an abstract class so that methods added in the future won't break existing listeners.
*
* @author Kohsuke Kawaguchi
* @since 1.145
*/
public abstract class RunListener<R extends Run> implements ExtensionPoint {
public final Class<R> targetType;
protected RunListener(Class<R> targetType) {
this.targetType = targetType;
}
protected RunListener() {
Type type = Types.getBaseClass(getClass(), RunListener.class);
if (type instanceof ParameterizedType)
targetType = Types.erasure(Types.getTypeArgument(type, 0));
else
throw new IllegalStateException(getClass() + " uses the raw type for extending RunListener");
}
/**
* Called after a build is completed.
*
* @param r
* The completed build.
* @param listener
* The listener for this build. This can be used to produce log messages, for example,
* which becomes a part of the "console output" of this build. But when this method runs,
* the build is considered completed, so its status cannot be changed anymore.
* @throws RuntimeException
* Any exception/error thrown from this method will be swallowed to prevent broken listeners
* from breaking all the builds.
*/
public void onCompleted(R r, @NonNull TaskListener listener) {}
/**
* Called after a build is moved to the {@code Run.State.COMPLETED} state.
*
* <p>
* At this point, all the records related to a build is written down to the disk. As such,
* {@link TaskListener} is no longer available. This happens later than {@link #onCompleted(Run, TaskListener)}.
*
* @throws RuntimeException
* Any exception/error thrown from this method will be swallowed to prevent broken listeners
* from breaking all the builds.
*/
public void onFinalized(R r) {}
/**
* Called when a Run is entering execution.
* @param r
* The started build.
* @since 2.9
*/
public void onInitialize(R r) {}
/**
* Called when a build is started (i.e. it was in the queue, and will now start running
* on an executor)
*
* @param r
* The started build.
* @param listener
* The listener for this build. This can be used to produce log messages, for example,
* which becomes a part of the "console output" of this build.
* @throws RuntimeException
* Any exception/error thrown from this method will be swallowed to prevent broken listeners
* from breaking all the builds.
*/
public void onStarted(R r, TaskListener listener) {}
/**
* Runs before the {@link SCM#checkout(AbstractBuild, Launcher, FilePath, BuildListener, File)} runs, and performs a set up.
* Can contribute additional properties/env vars to the environment.
*
* <p>
* A typical strategy is for implementations to check {@link JobProperty}s and other configuration
* of the project to determine the environment to inject, which allows you to achieve the equivalent of
* {@link BuildWrapper}, but without UI.
*
* @param build
* The build in progress for which an {@link Environment} object is created.
* Never null.
* @param launcher
* This launcher can be used to launch processes for this build.
* If the build runs remotely, launcher will also run a job on that remote machine.
* Never null.
* @param listener
* Can be used to send any message.
* @return
* non-null if the build can continue, null if there was an error
* and the build needs to be aborted.
* @throws IOException
* terminates the build abnormally. Hudson will handle the exception
* and reports a nice error message.
* @throws RunnerAbortedException
* If a fatal error is detected and the callee handled it gracefully, throw this exception
* to suppress a stack trace by the receiver.
* @since 1.410
*/
public Environment setUpEnvironment(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException, RunnerAbortedException {
return new Environment() {};
}
/**
* Called right before a build is going to be deleted.
*
* @param r The build.
* @throws RuntimeException
* Any exception/error thrown from this method will be swallowed to prevent broken listeners
* from breaking all the builds.
*/
public void onDeleted(R r) {}
/**
* Allows listeners to veto build loading.
* @param job the job from which a build might be loaded
* @param buildNumber the proposed build number
* @return false to veto build loading
* @see AbstractLazyLoadRunMap#recognizeNumber
*/
@Restricted(Beta.class)
public boolean allowLoad(@NonNull Job<?, ?> job, int buildNumber) {
return true;
}
/**
* Registers this object as an active listener so that it can start getting
* callbacks invoked.
*
* @deprecated as of 1.281
* Put {@link Extension} on your class to get it auto-registered.
*/
@Deprecated
public void register() {
all().add(this);
}
/**
* Reverse operation of {@link #register()}.
*/
public void unregister() {
all().remove(this);
}
/**
* List of registered listeners.
* @deprecated as of 1.281
* Use {@link #all()} for read access, and use {@link Extension} for registration.
*/
@Deprecated
public static final CopyOnWriteList<RunListener> LISTENERS = ExtensionListView.createCopyOnWriteList(RunListener.class);
/**
* Fires the {@link #onCompleted(Run, TaskListener)} event.
*/
public static void fireCompleted(Run r, @NonNull TaskListener listener) {
Listeners.notify(RunListener.class, true, l -> {
if (l.targetType.isInstance(r)) {
l.onCompleted(r, listener);
}
});
}
/**
* Fires the {@link #onInitialize(Run)} event.
*/
public static void fireInitialize(Run r) {
Listeners.notify(RunListener.class, true, l -> {
if (l.targetType.isInstance(r)) {
l.onInitialize(r);
}
});
}
/**
* Fires the {@link #onStarted(Run, TaskListener)} event.
*/
public static void fireStarted(Run r, TaskListener listener) {
Listeners.notify(RunListener.class, true, l -> {
if (l.targetType.isInstance(r)) {
l.onStarted(r, listener);
}
});
}
/**
* Fires the {@link #onFinalized(Run)} event.
*/
public static void fireFinalized(Run r) {
if (!Functions.isExtensionsAvailable()) {
return;
}
Listeners.notify(RunListener.class, true, l -> {
if (l.targetType.isInstance(r)) {
l.onFinalized(r);
}
});
}
/**
* Fires the {@link #onDeleted} event.
*/
public static void fireDeleted(Run r) {
Listeners.notify(RunListener.class, true, l -> {
if (l.targetType.isInstance(r)) {
l.onDeleted(r);
}
});
}
/**
* Returns all the registered {@link RunListener}s.
*/
public static ExtensionList<RunListener> all() {
return ExtensionList.lookup(RunListener.class);
}
}