File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\matrix\MatrixBuild.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi,
5 * Red Hat, Inc., Tom Huybrechts
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25 package hudson.matrix;
26
27 import hudson.AbortException;
28 import hudson.Functions;
29 import hudson.Util;
30 import hudson.console.ModelHyperlinkNote;
31 import hudson.matrix.MatrixConfiguration.ParentBuildAction;
32 import hudson.model.AbstractBuild;
33 import hudson.model.AbstractProject;
34 import hudson.model.BuildListener;
35 import hudson.model.Executor;
36 import hudson.model.Fingerprint;
37 import hudson.model.Queue;
38 import hudson.model.Queue.Item;
39 import hudson.model.Result;
40 import hudson.util.HttpResponses;
41 import jenkins.model.Jenkins;
42 import org.kohsuke.stapler.Stapler;
43 import org.kohsuke.stapler.StaplerRequest;
44 import org.kohsuke.stapler.StaplerResponse;
45 import org.kohsuke.stapler.export.Exported;
46 import org.kohsuke.stapler.interceptor.RequirePOST;
47
48 import java.io.File;
49 import java.io.IOException;
50 import java.io.PrintStream;
51 import java.util.ArrayList;
52 import java.util.Calendar;
53 import java.util.Collection;
54 import java.util.List;
55 import java.util.Set;
56
57 import javax.servlet.ServletException;
58
59 /**
60 * Build of {@link MatrixProject}.
61 *
62 * @author Kohsuke Kawaguchi
63 */
64 public class MatrixBuild extends AbstractBuild<MatrixProject,MatrixBuild> {
65 private AxisList axes;
66
67 /**
68 * If non-null, the {@link MatrixBuild} originates from the given build number.
69 */
70 private Integer baseBuild;
71
72 public MatrixBuild(MatrixProject job) throws IOException {
73 super(job);
74 }
75
76 public MatrixBuild(MatrixProject job, Calendar timestamp) {
77 super(job, timestamp);
78 }
79
80 public MatrixBuild(MatrixProject project, File buildDir) throws IOException {
81 super(project, buildDir);
82 }
83
84 public Object readResolve() {
85 // MatrixBuild.axes added in 1.285; default to parent axes for old data
86 if (axes==null)
87 axes = getParent().getAxes();
88 return this;
89 }
90
91 /**
92 * Deletes the build and all matrix configurations in this build when the button is pressed.
93 */
94 @RequirePOST
95 public void doDoDeleteAll( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
96 checkPermission(DELETE);
97
98 // We should not simply delete the build if it has been explicitly
99 // marked to be preserved, or if the build should not be deleted
100 // due to dependencies!
101 String why = getWhyKeepLog();
102 if (why!=null) {
103 sendError(hudson.model.Messages.Run_UnableToDelete(toString(),why),req,rsp);
104 return;
105 }
106
107 List<MatrixRun> runs = getExactRuns();
108 for(MatrixRun run : runs){
109 why = run.getWhyKeepLog();
110 if (why!=null) {
111 sendError(hudson.model.Messages.Run_UnableToDelete(toString(),why),req,rsp);
112 return;
113 }
114 run.delete();
115 }
116 delete();
117 rsp.sendRedirect2(req.getContextPath()+'/' + getParent().getUrl());
118 }
119
120
121 /**
122 * Used by view to render a ball for {@link MatrixRun}.
123 */
124 public final class RunPtr {
125 public final Combination combination;
126 private RunPtr(Combination c) { this.combination=c; }
127
128 public MatrixRun getRun() {
129 return MatrixBuild.this.getRun(combination);
130 }
131
132 /**
133 * Return the URL to the run that this pointer references.
134 *
135 * In the typical case, this creates {@linkplain #getShortUrl() a very short relative url}.
136 * If the referenced run is a nearest previous build, this method returns a longer URL to that exact build.
137 * {@link MatrixRun} which belongs to a given build {@link MatrixBuild}.
138 * If there is no run which belongs to the build, return url of run, which belongs to the nearest previous build.
139 */
140 public String getNearestRunUrl() {
141 MatrixRun r = getRun();
142 if (r==null) return null;
143 if (getNumber()==r.getNumber())
144 return getShortUrl()+'/';
145 else
146 return Stapler.getCurrentRequest().getContextPath()+'/'+r.getUrl();
147 }
148
149 public String getShortUrl() {
150 return Util.rawEncode(combination.toString());
151 }
152
153 public String getTooltip() {
154 MatrixRun r = getRun();
155 if(r!=null) return r.getIconColor().getDescription();
156 Queue.Item item = Jenkins.getInstance().getQueue().getItem(getParent().getItem(combination));
157 if(item!=null)
158 return item.getWhy();
159 return null; // fall back
160 }
161 }
162
163 public Layouter<RunPtr> getLayouter() {
164 // axes can be null if build page is access right when build starts
165 return axes == null ? null : new Layouter<RunPtr>(axes) {
166 protected RunPtr getT(Combination c) {
167 return new RunPtr(c);
168 }
169 };
170 }
171
172 /**
173 * Sets the base build from which this build is derived.
174 * @since 1.416
175 */
176 public void setBaseBuild(MatrixBuild baseBuild) {
177 this.baseBuild = (baseBuild==null || baseBuild==getPreviousBuild()) ? null : baseBuild.getNumber();
178 }
179
180 /**
181 * Returns the base {@link MatrixBuild} that this build originates from.
182 * <p>
183 * If this build is a partial build, unexecuted {@link MatrixRun}s are delegated to this build number.
184 */
185 public MatrixBuild getBaseBuild() {
186 return baseBuild==null ? getPreviousBuild() : getParent().getBuildByNumber(baseBuild);
187 }
188
189 /**
190 * Gets the {@link MatrixRun} in this build that corresponds
191 * to the given combination.
192 */
193 public MatrixRun getRun(Combination c) {
194 MatrixConfiguration config = getParent().getItem(c);
195 if(config==null) return null;
196 return getRunForConfiguration(config);
197 }
198
199 /**
200 * Like {@link #getRun(Combination)}, but do not approximate the result by earlier execution
201 * of the given combination (which is done for partial rebuild of the matrix.)
202 */
203 public MatrixRun getExactRun(Combination c) {
204 MatrixConfiguration config = getParent().getItem(c);
205 if(config==null) return null;
206 return config.getBuildByNumber(getNumber());
207 }
208
209 /**
210 * Returns all {@link MatrixRun}s for this {@link MatrixBuild}.
211 */
212 @Exported
213 public List<MatrixRun> getRuns() {
214 List<MatrixRun> r = new ArrayList<MatrixRun>();
215 for(MatrixConfiguration c : getParent().getItems()) {
216 MatrixRun b = getRunForConfiguration(c);
217 if (b != null) r.add(b);
218 }
219 return r;
220 }
221
222 private MatrixRun getRunForConfiguration(MatrixConfiguration c) {
223 for (MatrixBuild b=this; b!=null; b=b.getBaseBuild()) {
224 MatrixRun r = c.getBuildByNumber(b.getNumber());
225 if (r!=null) return r;
226 }
227 return null;
228 }
229
230 /**
231 * Returns all {@link MatrixRun}s for exactly this {@link MatrixBuild}.
232 * <p>
233 * Unlike {@link #getRuns()}, this method excludes those runs
234 * that didn't run and got inherited.
235 * @since 1.413
236 */
237 public List<MatrixRun> getExactRuns() {
238 List<MatrixRun> r = new ArrayList<MatrixRun>();
239 for(MatrixConfiguration c : getParent().getItems()) {
240 MatrixRun b = c.getBuildByNumber(getNumber());
241 if (b != null) r.add(b);
242 }
243 return r;
244 }
245
246 @Override
247 public String getWhyKeepLog() {
248 MatrixBuild b = getNextBuild();
249 if (isLinkedBy(b))
250 return b.getDisplayName()+" depends on this";
251 return super.getWhyKeepLog();
252 }
253
254 /**
255 * @return True if another {@link MatrixBuild} build (passed as a parameter) depends on this build.
256 * @since 1.481
257 */
258 public boolean isLinkedBy(MatrixBuild b) {
259 if(null == b)
260 return false;
261 for(MatrixConfiguration c : b.getParent().getActiveConfigurations()) {
262 MatrixRun r = c.getNearestOldBuild(b.getNumber());
263 if (r != null && r.getNumber()==getNumber())
264 return true;
265 }
266 return false;
267 }
268
269 /**
270 * True if this build didn't do a full build and it is depending on the result of the previous build.
271 */
272 public boolean isPartial() {
273 for(MatrixConfiguration c : getParent().getActiveConfigurations()) {
274 MatrixRun b = c.getNearestOldBuild(getNumber());
275 if (b != null && b.getNumber()!=getNumber())
276 return true;
277 }
278 return false;
279 }
280
281 @Override
282 public Object getDynamic(String token, StaplerRequest req, StaplerResponse rsp) {
283 try {
284 MatrixRun item = getRun(Combination.fromString(token));
285 if(item!=null) {
286 if (item.getNumber()==this.getNumber())
287 return item;
288 else {
289 // redirect the user to the correct URL
290 String url = Functions.joinPath(item.getUrl(), req.getRestOfPath());
291 String qs = req.getQueryString();
292 if (qs!=null) url+='?'+qs;
293 throw HttpResponses.redirectViaContextPath(url);
294 }
295 }
296 } catch (IllegalArgumentException _) {
297 // failed to parse the token as Combination. Must be something else
298 }
299 return super.getDynamic(token,req,rsp);
300 }
301
302 @Override
303 public void run() {
304 execute(new MatrixBuildExecution());
305 }
306
307 @Override
308 public Fingerprint.RangeSet getDownstreamRelationship(AbstractProject that) {
309 Fingerprint.RangeSet rs = super.getDownstreamRelationship(that);
310 for(MatrixRun run : getRuns())
311 rs.add(run.getDownstreamRelationship(that));
312 return rs;
313 }
314
315 /**
316 * Object that lives from the start of {@link MatrixBuild} execution to its end.
317 *
318 * Used to keep track of things that are needed only during the build.
319 */
320 public class MatrixBuildExecution extends AbstractBuildExecution {
321 private final List<MatrixAggregator> aggregators = new ArrayList<MatrixAggregator>();
322 private Set<MatrixConfiguration> activeConfigurations;
323
324 /**
325 * Snapshot of {@link MatrixProject#getActiveConfigurations()} to ensure
326 * that the build will use a consistent view of it.
327 */
328 public Set<MatrixConfiguration> getActiveConfigurations() {
329 return activeConfigurations;
330 }
331
332 /**
333 * Aggregators attached to this build execution, that are notified
334 * of every start/end of {@link MatrixRun}.
335 */
336 public List<MatrixAggregator> getAggregators() {
337 return aggregators;
338 }
339
340 protected Result doRun(BuildListener listener) throws Exception {
341 MatrixProject p = getProject();
342 PrintStream logger = listener.getLogger();
343
344 // give axes a chance to rebuild themselves
345 activeConfigurations = p.rebuildConfigurations(this);
346
347 // list up aggregators
348 listUpAggregators(p.getPublishers().values());
349 listUpAggregators(p.getProperties().values());
350 listUpAggregators(p.getBuildWrappers().values());
351
352 axes = p.getAxes();
353
354 try {
355 return p.getExecutionStrategy().run(this);
356 } catch( InterruptedException e ) {
357 logger.println("Aborted");
358 Executor x = Executor.currentExecutor();
359 x.recordCauseOfInterruption(MatrixBuild.this, listener);
360 return x.abortResult();
361 } catch (AbortException e) {
362 logger.println(e.getMessage());
363 return Result.FAILURE;
364 } finally {
365 // if the build was aborted in the middle. Cancel all the configuration builds.
366 Queue q = Jenkins.getInstance().getQueue();
367 synchronized(q) {// avoid micro-locking in q.cancel.
368 final int n = getNumber();
369 for (MatrixConfiguration c : activeConfigurations) {
370 for (Item i : q.getItems(c)) {
371 if (i.getAction(ParentBuildAction.class).parent==getBuild()) {
372 q.cancel(i);
373 logger.println(Messages.MatrixBuild_Cancelled(ModelHyperlinkNote.encodeTo(c)));
374 }
375 }
376 MatrixRun b = c.getBuildByNumber(n);
377 if(b!=null && b.isBuilding()) {// executor can spend some time in post production state, so only cancel in-progress builds.
378 Executor exe = b.getExecutor();
379 if(exe!=null) {
380 logger.println(Messages.MatrixBuild_Interrupting(ModelHyperlinkNote.encodeTo(b)));
381 exe.interrupt();
382 }
383 }
384 }
385 }
386 }
387 }
388
389 private void listUpAggregators(Collection<?> values) {
390 for (Object v : values) {
391 if (v instanceof MatrixAggregatable) {
392 MatrixAggregatable ma = (MatrixAggregatable) v;
393 MatrixAggregator a = ma.createAggregator(MatrixBuild.this, launcher, listener);
394 if(a!=null)
395 aggregators.add(a);
396 }
397 }
398 }
399
400 public void post2(BuildListener listener) throws Exception {
401 for (MatrixAggregator a : aggregators)
402 a.endBuild();
403 }
404 }
405 }
406