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

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Jorg Heymans, Peter Hayes, Red Hat, Inc., Stephen Connolly, id:cactusman
5 * Olivier Lamy
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.maven;
26
27 import static hudson.model.ItemGroupMixIn.loadChildren;
28 import hudson.CopyOnWrite;
29 import hudson.EnvVars;
30 import hudson.Extension;
31 import hudson.FilePath;
32 import hudson.Functions;
33 import hudson.Indenter;
34 import hudson.Plugin;
35 import hudson.Util;
36 import hudson.maven.local_repo.DefaultLocalRepositoryLocator;
37 import hudson.maven.local_repo.LocalRepositoryLocator;
38 import hudson.maven.local_repo.PerJobLocalRepositoryLocator;
39 import hudson.model.AbstractProject;
40 import hudson.model.Action;
41 import hudson.model.BuildableItemWithBuildWrappers;
42 import hudson.model.DependencyGraph;
43 import hudson.model.Descriptor;
44 import hudson.model.Descriptor.FormException;
45 import hudson.model.Executor;
46 import hudson.model.Item;
47 import hudson.model.ItemGroup;
48 import hudson.model.Job;
49 import hudson.model.Queue;
50 import hudson.model.Queue.Task;
51 import hudson.model.ResourceActivity;
52 import hudson.model.Result;
53 import hudson.model.SCMedItem;
54 import hudson.model.Saveable;
55 import hudson.model.TaskListener;
56 import hudson.model.TopLevelItem;
57 import hudson.search.CollectionSearchIndex;
58 import hudson.search.SearchIndexBuilder;
59 import hudson.tasks.BuildStep;
60 import hudson.tasks.BuildWrapper;
61 import hudson.tasks.BuildWrappers;
62 import hudson.tasks.Builder;
63 import hudson.tasks.Fingerprinter;
64 import hudson.tasks.Maven;
65 import hudson.tasks.Maven.MavenInstallation;
66 import hudson.tasks.Publisher;
67 import hudson.tasks.JavadocArchiver;
68 import hudson.tasks.junit.JUnitResultArchiver;
69 import hudson.util.CopyOnWriteMap;
70 import hudson.util.DescribableList;
71 import hudson.util.FormValidation;
72 import hudson.util.Function1;
73
74 import java.io.File;
75 import java.io.IOException;
76 import java.util.ArrayList;
77 import java.util.Arrays;
78 import java.util.Collection;
79 import java.util.Collections;
80 import java.util.HashSet;
81 import java.util.LinkedHashMap;
82 import java.util.List;
83 import java.util.Map;
84 import java.util.Properties;
85 import java.util.Set;
86 import java.util.Stack;
87 import java.util.logging.Logger;
88
89 import javax.servlet.ServletException;
90
91 import jenkins.model.Jenkins;
92 import jenkins.mvn.DefaultGlobalSettingsProvider;
93 import jenkins.mvn.DefaultSettingsProvider;
94 import jenkins.mvn.FilePathSettingsProvider;
95 import jenkins.mvn.GlobalSettingsProvider;
96 import jenkins.mvn.GlobalSettingsProviderDescriptor;
97 import jenkins.mvn.SettingsProvider;
98 import jenkins.mvn.SettingsProviderDescriptor;
99 import net.sf.json.JSONObject;
100
101 import org.apache.commons.beanutils.PropertyUtils;
102 import org.apache.commons.lang.StringUtils;
103 import org.apache.commons.lang.math.NumberUtils;
104 import org.apache.maven.model.building.ModelBuildingRequest;
105 import org.apache.tools.ant.taskdefs.email.Mailer;
106 import org.kohsuke.stapler.HttpResponse;
107 import org.kohsuke.stapler.HttpResponses;
108 import org.kohsuke.stapler.QueryParameter;
109 import org.kohsuke.stapler.StaplerRequest;
110 import org.kohsuke.stapler.StaplerResponse;
111 import org.kohsuke.stapler.export.Exported;
112
113 /**
114 * Group of {@link MavenModule}s.
115 *
116 * <p>
117 * This corresponds to the group of Maven POMs that constitute a single
118 * tree of projects. This group serves as the grouping of those related
119 * modules.
120 *
121 * @author Kohsuke Kawaguchi
122 */
123 public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenModuleSetBuild> implements TopLevelItem, ItemGroup<MavenModule>, SCMedItem, Saveable, BuildableItemWithBuildWrappers {
124
125 /**
126 * All {@link MavenModule}s, keyed by their {@link MavenModule#getModuleName()} module name}s.
127 */
128 transient /*final*/ Map<ModuleName,MavenModule> modules = new CopyOnWriteMap.Tree<ModuleName,MavenModule>();
129
130 /**
131 * Topologically sorted list of modules. This only includes live modules,
132 * since archived ones usually don't have consistent history.
133 */
134 @CopyOnWrite
135 transient List<MavenModule> sortedActiveModules;
136
137 /**
138 * Name of the top-level module. Null until the root module is determined.
139 */
140 private ModuleName rootModule;
141
142 private String rootPOM;
143
144 private String goals;
145
146 /**
147 * @deprecated as of 1.481
148 * Subsumed by {@link #settings}, maps to {@link FilePathSettingsProvider}
149 */
150 private transient String alternateSettings;
151
152 /**
153 * Default goals specified in POM. Can be null.
154 */
155 private String defaultGoals;
156
157 /**
158 * Identifies {@link MavenInstallation} to be used.
159 * Null to indicate 'default' maven.
160 */
161 private String mavenName;
162
163 /**
164 * Equivalent of CLI <tt>MAVEN_OPTS</tt>. Can be null.
165 */
166 private String mavenOpts;
167
168 /**
169 * If true, the build will be aggregator style, meaning
170 * all the modules are executed in a single Maven invocation, as in CLI.
171 * False otherwise, meaning each module is built separately and possibly in parallel.
172 *
173 * @since 1.133
174 */
175 private boolean aggregatorStyleBuild = true;
176
177 /**
178 * If true, and if aggregatorStyleBuild is false and we are using Maven 2.1 or later, the build will
179 * check the changeset before building, and if there are changes, only those modules which have changes
180 * or those modules which failed or were unstable in the previous build will be built directly, using
181 * Maven's make-like reactor mode. Any modules depending on the directly built modules will also be built,
182 * but that's controlled by Maven.
183 *
184 * @since 1.318
185 */
186 private boolean incrementalBuild = false;
187
188 /**
189 * If true, the build will use its own local Maven repository
190 * via "-Dmaven.repo.local=...".
191 * <p>
192 * This would consume additional disk space, but provides isolation with other builds on the same machine,
193 * such as mixing SNAPSHOTS. Maven also doesn't try to coordinate the concurrent access to Maven repositories
194 * from multiple Maven process, so this helps there too.
195 *
196 * @since 1.223
197 * @deprecated as of 1.448
198 * Subsumed by {@link #localRepository}. false maps to {@link DefaultLocalRepositoryLocator},
199 * and true maps to {@link PerJobLocalRepositoryLocator}
200 */
201 private transient Boolean usePrivateRepository;
202
203 /**
204 * Encapsulates where to run the local repository.
205 *
206 * If null, inherited from the global configuration.
207 *
208 * @since 1.448
209 */
210 private LocalRepositoryLocator localRepository = null;
211
212 /**
213 * If true, the build will send a failure e-mail for each failing maven module.
214 * Defaults to <code>true</code> to simulate old behavior.
215 * <p>
216 * see JENKINS-5695.
217 */
218 private Boolean perModuleEmail = Boolean.TRUE;
219
220 /**
221 * If true, do not automatically schedule a build when one of the project dependencies is built.
222 * <p>
223 * See HUDSON-1714.
224 */
225 private boolean ignoreUpstremChanges = false;
226
227 /**
228 * If true, do not archive artifacts to the master.
229 */
230 private boolean archivingDisabled = false;
231
232 /**
233 * parameter for pom parsing by default <code>false</code> to be faster
234 * @since 1.394
235 */
236 private boolean resolveDependencies = false;
237
238 /**
239 * parameter for pom parsing by default <code>false</code> to be faster
240 * @since 1.394
241 */
242 private boolean processPlugins = false;
243
244 /**
245 * parameter for validation level during pom parsing by default the one corresponding
246 * to the maven version used (2 or 3)
247 * @since 1.394
248 */
249 private int mavenValidationLevel = -1;
250
251 /**
252 * Inform jenkins this build don't use UI code and can run without access to graphical environment. Could be used
253 * later to select a headless-slave from a pool, but first introduced for JENKINS-9785
254 */
255 private boolean runHeadless = false;
256
257 /**
258 * @since 1.426
259 * @deprecated since 1.484 settings are provided by {@link #settings}
260 */
261 private String settingConfigId;
262
263 /**
264 * @since 1.426
265 * @deprecated since 1.484 settings are provided by {@link #globalSettings}
266 */
267 private String globalSettingConfigId;
268
269 /**
270 * Whether to participate in triggering downstream projects.
271 * @since 1.494
272 */
273 private boolean disableTriggerDownstreamProjects;
274
275 /**
276 * used temporary during maven build to store file path
277 * @since 1.426
278 * @deprecated since 1.484 settings are provided by {@link #globalSettings}
279 */
280 protected transient String globalSettingConfigPath;
281
282 /**
283 * @since 1.491
284 */
285 private SettingsProvider settings = new DefaultSettingsProvider();
286
287 /**
288 * @since 1.491
289 */
290 private GlobalSettingsProvider globalSettings = new DefaultGlobalSettingsProvider();
291
292
293 /**
294 * @since 1.491
295 */
296 public Object readResolve() {
297 // backward compatibility, maven-plugin used to have a dependency to the config-file-provider plugin
298 Plugin plugin = null;
299 if(StringUtils.isNotBlank(this.settingConfigId) || StringUtils.isNotBlank(this.globalSettingConfigId)) {
300 plugin = Jenkins.getInstance().getPlugin("config-file-provider");
301 if(plugin == null || !plugin.getWrapper().isEnabled()){
302 LOGGER.severe(Messages.MavenModuleSet_readResolve_missingConfigProvider());
303 }
304 }
305
306 if (this.alternateSettings != null) {
307 this.settings = new FilePathSettingsProvider(alternateSettings);
308 this.alternateSettings = null;
309 } else if (plugin != null && StringUtils.isNotBlank(this.settingConfigId)) {
310 try {
311 Class<? extends SettingsProvider> legacySettings = plugin.getWrapper().classLoader.loadClass("org.jenkinsci.plugins.configfiles.maven.job.MvnSettingsProvider").asSubclass(SettingsProvider.class);
312 SettingsProvider newInstance = legacySettings.newInstance();
313 PropertyUtils.setProperty(newInstance, "settingsConfigId", this.settingConfigId);
314 this.settings = newInstance;
315 this.settingConfigId = null;
316 } catch (Exception e) {
317 // The PluginUpdateMonitor is also informing the admin about the update (via hudson.maven.PluginImpl.init())
318 LOGGER.severe(Messages.MavenModuleSet_readResolve_updateConfigProvider(settingConfigId));
319 e.printStackTrace();
320 }
321 }
322
323 if (plugin != null && StringUtils.isNotBlank(this.globalSettingConfigId)) {
324 try {
325 Class<? extends GlobalSettingsProvider> legacySettings = plugin.getWrapper().classLoader.loadClass("org.jenkinsci.plugins.configfiles.maven.job.MvnGlobalSettingsProvider").asSubclass(GlobalSettingsProvider.class);
326 GlobalSettingsProvider newInstance = legacySettings.newInstance();
327 PropertyUtils.setProperty(newInstance, "settingsConfigId", this.globalSettingConfigId);
328 this.globalSettings = newInstance;
329 this.globalSettingConfigId = null;
330 } catch (Exception e) {
331 // The PluginUpdateMonitor is also informing the admin about the update (via hudson.maven.PluginImpl.init())
332 LOGGER.severe(Messages.MavenModuleSet_readResolve_updateConfigProvider(globalSettingConfigId));
333 e.printStackTrace();
334 }
335 }
336 return this;
337 }
338
339 /**
340 * Reporters configured at {@link MavenModuleSet} level. Applies to all {@link MavenModule} builds.
341 */
342 private DescribableList<MavenReporter,Descriptor<MavenReporter>> reporters =
343 new DescribableList<MavenReporter,Descriptor<MavenReporter>>(this);
344
345 /**
346 * List of active {@link Publisher}s configured for this project.
347 * @since 1.176
348 */
349 private DescribableList<Publisher,Descriptor<Publisher>> publishers =
350 new DescribableList<Publisher,Descriptor<Publisher>>(this);
351
352 /**
353 * List of active {@link BuildWrapper}s configured for this project.
354 * @since 1.212
355 */
356 private DescribableList<BuildWrapper,Descriptor<BuildWrapper>> buildWrappers =
357 new DescribableList<BuildWrapper, Descriptor<BuildWrapper>>(this);
358
359 /**
360 * List of active {@link Builder}s configured for this project.
361 */
362 private DescribableList<Builder,Descriptor<Builder>> prebuilders =
363 new DescribableList<Builder,Descriptor<Builder>>(this);
364
365 private DescribableList<Builder,Descriptor<Builder>> postbuilders =
366 new DescribableList<Builder,Descriptor<Builder>>(this);
367
368 private Result runPostStepsIfResult;
369
370
371 /**
372 * @deprecated
373 * Use {@link #MavenModuleSet(ItemGroup, String)}
374 */
375 public MavenModuleSet(String name) {
376 this(Jenkins.getInstance(), name);
377 }
378
379 public MavenModuleSet(ItemGroup parent, String name) {
380 super(parent,name);
381 }
382
383 /**
384 * Builders that are run before the main Maven execution.
385 *
386 * @since 1.433
387 */
388 public DescribableList<Builder,Descriptor<Builder>> getPrebuilders() {
389 return prebuilders;
390 }
391
392 /**
393 * Builders that are run after the main Maven execution.
394 *
395 * @since 1.433
396 */
397 public DescribableList<Builder,Descriptor<Builder>> getPostbuilders() {
398 return postbuilders;
399 }
400
401 void addPostBuilder(Builder builder) throws IOException{
402 postbuilders.add(builder);
403 }
404
405 /**
406 * {@link #postbuilders} are run if the result is better or equal to this threshold.
407 *
408 * @return
409 * never null
410 * @since 1.433
411 */
412 public Result getRunPostStepsIfResult() {
413 return Functions.defaulted(runPostStepsIfResult,Result.FAILURE);
414 }
415
416 public void setRunPostStepsIfResult(Result v) {
417 this.runPostStepsIfResult = Functions.defaulted(v,Result.FAILURE);
418 }
419
420 public String getUrlChildPrefix() {
421 // seemingly redundant "./" is used to make sure that ':' is not interpreted as the scheme identifier
422 return ".";
423 }
424
425 public Collection<MavenModule> getItems() {
426 return modules.values();
427 }
428
429 @Exported
430 public Collection<MavenModule> getModules() {
431 return getItems();
432 }
433
434 public MavenModule getItem(String name) {
435 return modules.get(ModuleName.fromString(name));
436 }
437
438 public MavenModule getModule(String name) {
439 return getItem(name);
440 }
441
442 @Override // to make this accessible from MavenModuleSetBuild
443 protected void updateTransientActions() {
444 super.updateTransientActions();
445 }
446
447 protected List<Action> createTransientActions() {
448 List<Action> r = super.createTransientActions();
449
450 // Fix for ISSUE-1149
451 for (MavenModule module: modules.values()) {
452 module.updateTransientActions();
453 }
454
455 if(publishers!=null) // this method can be loaded from within the onLoad method, where this might be null
456 for (BuildStep step : publishers)
457 r.addAll(step.getProjectActions(this));
458
459 if (buildWrappers!=null)
460 for (BuildWrapper step : buildWrappers)
461 r.addAll(step.getProjectActions(this));
462
463 return r;
464 }
465
466 protected void addTransientActionsFromBuild(MavenModuleSetBuild build, List<Action> collection, Set<Class> added) {
467 if(build==null) return;
468
469 for (Action a : build.getActions())
470 if(a instanceof MavenAggregatedReport)
471 if(added.add(a.getClass()))
472 collection.add(((MavenAggregatedReport)a).getProjectAction(this));
473
474 List<MavenReporter> list = build.projectActionReporters;
475 if(list==null) return;
476
477 for (MavenReporter step : list) {
478 if(!added.add(step.getClass())) continue; // already added
479 Action a = step.getAggregatedProjectAction(this);
480 if(a!=null)
481 collection.add(a);
482 }
483 }
484
485 /**
486 * Called by {@link MavenModule#doDoDelete(StaplerRequest, StaplerResponse)}.
487 * Real deletion is done by the caller, and this method only adjusts the
488 * data structure the parent maintains.
489 */
490 /*package*/ void onModuleDeleted(MavenModule module) {
491 modules.remove(module.getModuleName());
492 }
493
494 /**
495 * Returns true if there's any disabled module.
496 */
497 public boolean hasDisabledModule() {
498 for (MavenModule m : modules.values()) {
499 if(m.isDisabled())
500 return true;
501 }
502 return false;
503 }
504
505 /**
506 * Possibly empty list of all disabled modules (if disabled==true)
507 * or all enabeld modules (if disabled==false)
508 */
509 public List<MavenModule> getDisabledModules(boolean disabled) {
510 if(!disabled && sortedActiveModules!=null)
511 return sortedActiveModules;
512
513 List<MavenModule> r = new ArrayList<MavenModule>();
514 for (MavenModule m : modules.values()) {
515 if(m.isDisabled()==disabled)
516 r.add(m);
517 }
518 return r;
519 }
520
521 public Indenter<MavenModule> createIndenter() {
522 return new Indenter<MavenModule>() {
523 protected int getNestLevel(MavenModule job) {
524 return job.nestLevel;
525 }
526 };
527 }
528
529 public boolean isIncrementalBuild() {
530 return incrementalBuild;
531 }
532
533 public boolean isAggregatorStyleBuild() {
534 return aggregatorStyleBuild;
535 }
536
537 /**
538 * @deprecated as of 1.448
539 * Use {@link #getLocalRepository()}
540 */
541 public boolean usesPrivateRepository() {
542 return !(getLocalRepository() instanceof DefaultLocalRepositoryLocator);
543 }
544
545 public boolean isPerModuleEmail() {
546 return perModuleEmail;
547 }
548
549 public boolean ignoreUpstremChanges() {
550 return ignoreUpstremChanges;
551 }
552
553 public boolean runHeadless() {
554 return runHeadless;
555 }
556
557 public boolean isArchivingDisabled() {
558 return archivingDisabled;
559 }
560
561 public void setIncrementalBuild(boolean incrementalBuild) {
562 this.incrementalBuild = incrementalBuild;
563 }
564
565 public void setAggregatorStyleBuild(boolean aggregatorStyleBuild) {
566 this.aggregatorStyleBuild = aggregatorStyleBuild;
567 }
568
569 /**
570 * @deprecated as of 1.448.
571 * Use {@link #setLocalRepository(LocalRepositoryLocator)} instead
572 */
573 public void setUsePrivateRepository(boolean usePrivateRepository) {
574 setLocalRepository(usePrivateRepository?new PerJobLocalRepositoryLocator() : new DefaultLocalRepositoryLocator());
575 }
576
577 /**
578 * @return
579 * never null
580 */
581 public LocalRepositoryLocator getLocalRepository() {
582 return localRepository!=null ? localRepository : getDescriptor().getLocalRepository();
583 }
584
585 /**
586 * Undefaulted locally configured value with taking inheritance from the global configuration into account.
587 */
588 public LocalRepositoryLocator getExplicitLocalRepository() {
589 return localRepository;
590 }
591
592 public void setLocalRepository(LocalRepositoryLocator localRepository) {
593 this.localRepository = localRepository;
594 }
595
596 /**
597 * @since 1.491
598 */
599 public void setSettings(SettingsProvider settings) {
600 this.settings = settings;
601 }
602
603 /**
604 * @since 1.491
605 */
606 public void setGlobalSettings(GlobalSettingsProvider globalSettings) {
607 this.globalSettings = globalSettings;
608 }
609
610 public void setIgnoreUpstremChanges(boolean ignoreUpstremChanges) {
611 this.ignoreUpstremChanges = ignoreUpstremChanges;
612 }
613
614 public void setRunHeadless(boolean runHeadless) {
615 this.runHeadless = runHeadless;
616 }
617
618 public void setIsArchivingDisabled(boolean archivingDisabled) {
619 this.archivingDisabled = archivingDisabled;
620 }
621
622 public boolean isResolveDependencies()
623 {
624 return resolveDependencies;
625 }
626
627 public void setResolveDependencies( boolean resolveDependencies ) {
628 this.resolveDependencies = resolveDependencies;
629 }
630
631 public boolean isProcessPlugins() {
632 return processPlugins;
633 }
634
635 public void setProcessPlugins( boolean processPlugins ) {
636 this.processPlugins = processPlugins;
637 }
638
639 public int getMavenValidationLevel() {
640 return mavenValidationLevel;
641 }
642
643 /**
644 * @since 1.481
645 */
646 public SettingsProvider getSettings() {
647 return settings != null ? settings : new DefaultSettingsProvider();
648 }
649
650 /**
651 * @since 1.481
652 */
653 public GlobalSettingsProvider getGlobalSettings() {
654 return globalSettings != null ? globalSettings : new DefaultGlobalSettingsProvider();
655 }
656
657 /**
658 * List of active {@link MavenReporter}s that should be applied to all module builds.
659 */
660 public DescribableList<MavenReporter, Descriptor<MavenReporter>> getReporters() {
661 return reporters;
662 }
663
664 /**
665 * List of active {@link Publisher}s. Can be empty but never null.
666 */
667 public DescribableList<Publisher, Descriptor<Publisher>> getPublishers() {
668 return publishers;
669 }
670
671 @Override
672 public DescribableList<Publisher, Descriptor<Publisher>> getPublishersList() {
673 return publishers;
674 }
675
676 public DescribableList<BuildWrapper, Descriptor<BuildWrapper>> getBuildWrappersList() {
677 return buildWrappers;
678 }
679
680 /**
681 * List of active {@link BuildWrapper}s. Can be empty but never null.
682 *
683 * @deprecated as of 1.335
684 * Use {@link #getBuildWrappersList()} to be consistent with other subtypes of {@link AbstractProject}.
685 */
686 public DescribableList<BuildWrapper, Descriptor<BuildWrapper>> getBuildWrappers() {
687 return buildWrappers;
688 }
689
690 public Object getDynamic(String token, StaplerRequest req, StaplerResponse rsp) {
691 if(ModuleName.isValid(token))
692 return getModule(token);
693 return super.getDynamic(token,req,rsp);
694 }
695
696 public File getRootDirFor(MavenModule child) {
697 return new File(getModulesDir(),child.getModuleName().toFileSystemName());
698 }
699
700 public void onRenamed(MavenModule item, String oldName, String newName) throws IOException {
701 throw new UnsupportedOperationException();
702 }
703
704 public void onDeleted(MavenModule item) throws IOException {
705 // noop
706 }
707
708 public Collection<Job> getAllJobs() {
709 Set<Job> jobs = new HashSet<Job>(getItems());
710 jobs.add(this);
711 return jobs;
712 }
713
714 @Override
715 protected Class<MavenModuleSetBuild> getBuildClass() {
716 return MavenModuleSetBuild.class;
717 }
718
719 @Override
720 protected SearchIndexBuilder makeSearchIndex() {
721 return super.makeSearchIndex()
722 .add(new CollectionSearchIndex<MavenModule>() {// for computers
723 protected MavenModule get(String key) {
724 for (MavenModule m : modules.values()) {
725 if(m.getDisplayName().equals(key))
726 return m;
727 }
728 return null;
729 }
730 protected Collection<MavenModule> all() {
731 return modules.values();
732 }
733 protected String getName(MavenModule o) {
734 return o.getName();
735 }
736 });
737 }
738
739 @Override
740 public boolean isFingerprintConfigured() {
741 return true;
742 }
743
744 public void onLoad(ItemGroup<? extends Item> parent, String name) throws IOException {
745 modules = Collections.emptyMap(); // needed during load
746 super.onLoad(parent, name);
747
748 modules = loadChildren(this, getModulesDir(),new Function1<ModuleName,MavenModule>() {
749 public ModuleName call(MavenModule module) {
750 return module.getModuleName();
751 }
752 });
753 // update the transient nest level field.
754 MavenModule root = getRootModule();
755 if(root!=null && root.getChildren()!=null) {
756 List<MavenModule> sortedList = new ArrayList<MavenModule>();
757 Stack<MavenModule> q = new Stack<MavenModule>();
758 root.nestLevel = 0;
759 q.push(root);
760 while(!q.isEmpty()) {
761 MavenModule p = q.pop();
762 sortedList.add(p);
763 List<MavenModule> children = p.getChildren();
764 if(children!=null) {
765 for (MavenModule m : children)
766 m.nestLevel = p.nestLevel+1;
767 for( int i=children.size()-1; i>=0; i--) // add them in the reverse order
768 q.push(children.get(i));
769 }
770 }
771 this.sortedActiveModules = sortedList;
772 } else {
773 this.sortedActiveModules = getDisabledModules(false);
774 }
775
776 if(reporters==null){
777 reporters = new DescribableList<MavenReporter, Descriptor<MavenReporter>>(this);
778 }
779 reporters.setOwner(this);
780 if(publishers==null){
781 publishers = new DescribableList<Publisher,Descriptor<Publisher>>(this);
782 }
783 publishers.setOwner(this);
784 if(buildWrappers==null){
785 buildWrappers = new DescribableList<BuildWrapper, Descriptor<BuildWrapper>>(this);
786 }
787 buildWrappers.setOwner(this);
788 if(prebuilders==null){
789 prebuilders = new DescribableList<Builder,Descriptor<Builder>>(this);
790 }
791 prebuilders.setOwner(this);
792 if(postbuilders==null){
793 postbuilders = new DescribableList<Builder,Descriptor<Builder>>(this);
794 }
795 postbuilders.setOwner(this);
796
797 if(perModuleEmail == null){
798 perModuleEmail = Boolean.TRUE;
799 }
800
801 if (Boolean.TRUE.equals(usePrivateRepository)) {
802 this.localRepository = new PerJobLocalRepositoryLocator();
803 usePrivateRepository = null;
804 }
805
806 updateTransientActions();
807 }
808
809 private File getModulesDir() {
810 return new File(getRootDir(),"modules");
811 }
812
813 /**
814 * To make it easy to grasp relationship among modules
815 * and the module set, we'll align the build numbers of
816 * all the modules.
817 *
818 * <p>
819 * This method is invoked from {@link Executor#run()},
820 * and because of the mutual exclusion among {@link MavenModuleSetBuild}
821 * and {@link MavenBuild}, we can safely touch all the modules.
822 */
823 public synchronized int assignBuildNumber() throws IOException {
824 // determine the next value
825 updateNextBuildNumber();
826
827 return super.assignBuildNumber();
828 }
829
830 public void logRotate() throws IOException, InterruptedException {
831 super.logRotate();
832 // perform the log rotation of modules
833 for (MavenModule m : modules.values())
834 m.logRotate();
835 }
836
837 /**
838 * The next build of {@link MavenModuleSet} must have
839 * the build number newer than any of the current module build.
840 */
841 /*package*/ void updateNextBuildNumber() throws IOException {
842 int next = this.nextBuildNumber;
843 for (MavenModule m : modules.values())
844 next = Math.max(next,m.getNextBuildNumber());
845
846 if(this.nextBuildNumber!=next) {
847 this.nextBuildNumber=next;
848 this.saveNextBuildNumber();
849 }
850 }
851
852 protected void buildDependencyGraph(DependencyGraph graph) {
853 // the modules are already rebuild by DependencyGraph#init !
854 // Collection<MavenModule> modules = getModules();
855 // for (MavenModule m : modules) {
856 // m.buildDependencyGraph(graph);
857 // }
858
859 publishers.buildDependencyGraph(this,graph);
860 buildWrappers.buildDependencyGraph(this,graph);
861 prebuilders.buildDependencyGraph(this,graph);
862 postbuilders.buildDependencyGraph(this,graph);
863 }
864
865 public boolean isDisableTriggerDownstreamProjects() {
866 return disableTriggerDownstreamProjects;
867 }
868
869 public void setDisableTriggerDownstreamProjects(boolean disableTriggerDownstreamProjects) {
870 this.disableTriggerDownstreamProjects = disableTriggerDownstreamProjects;
871 }
872
873 public MavenModule getRootModule() {
874 if(rootModule==null) return null;
875 return modules.get(rootModule);
876 }
877
878 public MavenInstallation inferMavenInstallation() {
879 return getMaven();
880 }
881
882 @Override
883 protected Set<ResourceActivity> getResourceActivities() {
884 final Set<ResourceActivity> activities = new HashSet<ResourceActivity>();
885
886 activities.addAll(super.getResourceActivities());
887 activities.addAll(Util.filter(publishers, ResourceActivity.class));
888 activities.addAll(Util.filter(buildWrappers, ResourceActivity.class));
889 activities.addAll(Util.filter(prebuilders, ResourceActivity.class));
890 activities.addAll(Util.filter(postbuilders, ResourceActivity.class));
891
892 return activities;
893 }
894
895 /**
896 * @deprecated for backward comp only
897 */
898 public String getRootPOM(){
899 return getRootPOM( null );
900 }
901
902 /**
903 * Gets the location of top-level <tt>pom.xml</tt> relative to the workspace root.
904 * @since 1.467
905 */
906 public String getRootPOM(EnvVars env) {
907 if (rootPOM == null) return "pom.xml";
908 // JENKINS-13822
909 if (env == null) return rootPOM;
910 return env.expand(rootPOM);
911 }
912
913 public void setRootPOM(String rootPOM) {
914 this.rootPOM = rootPOM;
915 }
916
917 public AbstractProject<?,?> asProject() {
918 return this;
919 }
920
921 /**
922 * Gets the list of goals to execute.
923 */
924 public String getGoals() {
925 if(goals==null) {
926 if(defaultGoals!=null) return defaultGoals;
927 return "install";
928 }
929 return goals;
930 }
931
932 public void setGoals(String goals) {
933 this.goals = goals;
934 }
935
936 private boolean checkMavenOption(String shortForm, String longForm) {
937 for (String t : Util.tokenize(getGoals())) {
938 if(t.equals(shortForm) || t.equals(longForm))
939 return true;
940 }
941 return false;
942 }
943
944 private List<String> getMavenArgument(String shortForm, String longForm) {
945 List<String> args = new ArrayList<String>();
946 boolean switchFound=false;
947 for (String t : Util.tokenize(getGoals())) {
948 if(switchFound) {
949 args.add(t);
950 switchFound = false;
951 }
952 else
953 if(t.equals(shortForm) || t.equals(longForm))
954 switchFound=true;
955 else
956 if(t.startsWith(shortForm)) {
957 args.add(t.substring(shortForm.length()));
958 }
959 else
960 if(t.startsWith(longForm)) {
961 args.add(t.substring(longForm.length()));
962 }
963 }
964 return args;
965 }
966
967 /**
968 * Gets the workspace-relative path to an alternative Maven settings.xml file.
969 * @deprecated as of 1.481
970 */
971 public String getAlternateSettings() {
972 return alternateSettings;
973 }
974
975 /**
976 * Sets the workspace-relative path to an alternative Maven settings.xml file.
977 * @deprecated as of 1.481
978 */
979 public void setAlternateSettings(String alternateSettings) throws IOException {
980 this.alternateSettings = alternateSettings;
981 }
982
983 /**
984 * If the list of configured goals contain the "-P" option,
985 * return the configured profiles. Otherwise null.
986 */
987 public String getProfiles() {
988 return Util.join(getMavenArgument("-P","--activate-profiles"),",");
989 }
990
991 /**
992 * Gets the system properties explicitly set in the Maven command line (the "-D" option.)
993 */
994 public Properties getMavenProperties() {
995 Properties props = new Properties();
996 for (String arg : getMavenArgument("-D","--define")) {
997 int idx = arg.indexOf('=');
998 if(idx<0) props.put(arg,"true");
999 else props.put(arg.substring(0,idx),arg.substring(idx+1));
1000 }
1001 return props;
1002 }
1003
1004 /**
1005 * Check for "-N" or "--non-recursive" in the Maven goals/options.
1006 */
1007 public boolean isNonRecursive() {
1008 return checkMavenOption("-N", "--non-recursive");
1009 }
1010
1011 /**
1012 * Possibly null, whitespace-separated (including TAB, NL, etc) VM options
1013 * to be used to launch Maven process.
1014 *
1015 * If mavenOpts is null or empty, we'll return the globally-defined MAVEN_OPTS.
1016 *
1017 * <p>
1018 * This method returns a configured value as-is, which can include variabl references.
1019 * At runtime, use {@link AbstractMavenBuild#getMavenOpts(TaskListener, EnvVars)} to obtain
1020 * a fully resolved value.
1021 */
1022 public String getMavenOpts() {
1023 if ((mavenOpts!=null) && (mavenOpts.trim().length()>0)) {
1024 return mavenOpts.replaceAll("[\t\r\n]+"," ");
1025 }
1026 else {
1027 String globalOpts = DESCRIPTOR.getGlobalMavenOpts();
1028 if (globalOpts!=null) {
1029 return globalOpts.replaceAll("[\t\r\n]+"," ");
1030 }
1031 else {
1032 return globalOpts;
1033 }
1034 }
1035 }
1036
1037 /**
1038 * Set mavenOpts.
1039 */
1040 public void setMavenOpts(String mavenOpts) {
1041 this.mavenOpts = mavenOpts;
1042 }
1043
1044 /**
1045 * Gets the Maven to invoke.
1046 * If null, we pick any random Maven installation.
1047 */
1048 public MavenInstallation getMaven() {
1049 MavenInstallation[] installations = DESCRIPTOR.getMavenDescriptor().getInstallations();
1050 for( MavenInstallation i : installations) {
1051 if(mavenName==null || i.getName().equals(mavenName))
1052 return i;
1053 }
1054 if (installations.length==1)
1055 return installations[0];
1056 return null;
1057 }
1058
1059 public void setMaven(String mavenName) {
1060 this.mavenName = mavenName;
1061 }
1062
1063 /**
1064 * Returns the {@link MavenModule}s that are in the queue.
1065 */
1066 public List<Queue.Item> getQueueItems() {
1067 return filter(Arrays.asList(Jenkins.getInstance().getQueue().getItems()));
1068 }
1069
1070 /**
1071 * Returns the {@link MavenModule}s that are in the queue.
1072 */
1073 public List<Queue.Item> getApproximateQueueItemsQuickly() {
1074 return filter(Jenkins.getInstance().getQueue().getApproximateItemsQuickly());
1075 }
1076
1077 private List<Queue.Item> filter(Collection<Queue.Item> base) {
1078 List<Queue.Item> r = new ArrayList<Queue.Item>();
1079 for( Queue.Item item : base) {
1080 Task t = item.task;
1081 if((t instanceof MavenModule && ((MavenModule)t).getParent()==this) || t ==this)
1082 r.add(item);
1083 }
1084 return r;
1085 }
1086
1087 /**
1088 * Gets the list of goals specified by the user,
1089 * without taking inheritance and POM default goals
1090 * into account.
1091 *
1092 * <p>
1093 * This is only used to present the UI screen, and in
1094 * all the other cases {@link #getGoals()} should be used.
1095 */
1096 public String getUserConfiguredGoals() {
1097 return goals;
1098 }
1099
1100 /*package*/ void reconfigure(PomInfo rootPom) throws IOException {
1101 if(this.rootModule!=null && this.rootModule.equals(rootPom.name))
1102 return; // no change
1103 this.rootModule = rootPom.name;
1104 this.defaultGoals = rootPom.defaultGoal;
1105 save();
1106 }
1107
1108 //
1109 //
1110 // Web methods
1111 //
1112 //
1113
1114 protected void submit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
1115 super.submit(req,rsp);
1116 JSONObject json = req.getSubmittedForm();
1117
1118 rootPOM = Util.fixEmpty(req.getParameter("rootPOM").trim());
1119 if(rootPOM!=null && rootPOM.equals("pom.xml")) rootPOM=null; // normalization
1120
1121 goals = Util.fixEmpty(req.getParameter("goals").trim());
1122 mavenOpts = Util.fixEmpty(req.getParameter("mavenOpts").trim());
1123 settings = SettingsProvider.parseSettingsProvider(req);
1124 globalSettings = GlobalSettingsProvider.parseSettingsProvider(req);
1125
1126 mavenName = req.getParameter("maven_version");
1127 aggregatorStyleBuild = !req.hasParameter("maven.perModuleBuild");
1128 if (json.optBoolean("usePrivateRepository"))
1129 localRepository = req.bindJSON(LocalRepositoryLocator.class,json.getJSONObject("explicitLocalRepository"));
1130 else
1131 localRepository = null;
1132 perModuleEmail = req.hasParameter("maven.perModuleEmail");
1133 ignoreUpstremChanges = !json.has("triggerByDependency");
1134 runHeadless = req.hasParameter("maven.runHeadless");
1135 incrementalBuild = req.hasParameter("maven.incrementalBuild");
1136 archivingDisabled = req.hasParameter("maven.archivingDisabled");
1137 resolveDependencies = req.hasParameter( "maven.resolveDependencies" );
1138 processPlugins = req.hasParameter( "maven.processPlugins" );
1139 mavenValidationLevel = NumberUtils.toInt(req.getParameter("maven.validationLevel"), -1);
1140 reporters.rebuild(req,json,MavenReporters.getConfigurableList());
1141 publishers.rebuildHetero(req, json, Publisher.all(), "publisher");
1142 buildWrappers.rebuild(req, json, BuildWrappers.getFor(this));
1143 disableTriggerDownstreamProjects = req.hasParameter("maven.disableTriggerDownstreamProjects");
1144
1145 runPostStepsIfResult = Result.fromString(req.getParameter( "post-steps.runIfResult"));
1146 prebuilders.rebuildHetero(req,json, Builder.all(), "prebuilder");
1147 postbuilders.rebuildHetero(req,json, Builder.all(), "postbuilder");
1148 }
1149
1150 /**
1151 * Delete all disabled modules.
1152 */
1153 public HttpResponse doDoDeleteAllDisabledModules() throws IOException, InterruptedException {
1154 checkPermission(DELETE);
1155 for( MavenModule m : getDisabledModules(true))
1156 m.delete();
1157 return HttpResponses.redirectToDot();
1158 }
1159
1160 /**
1161 * Check the location of the POM, alternate settings file, etc - any file.
1162 */
1163 public FormValidation doCheckFileInWorkspace(@QueryParameter String value) throws IOException, ServletException {
1164 MavenModuleSetBuild lb = getLastBuild();
1165 if (lb!=null) {
1166 FilePath ws = lb.getModuleRoot();
1167 if(ws!=null)
1168 return ws.validateRelativePath(value,true,true);
1169 }
1170 return FormValidation.ok();
1171 }
1172
1173 public DescriptorImpl getDescriptor() {
1174 return DESCRIPTOR;
1175 }
1176
1177 @Extension(ordinal=900)
1178 public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
1179
1180 public static final class DescriptorImpl extends AbstractProjectDescriptor {
1181 /**
1182 * Globally-defined MAVEN_OPTS.
1183 */
1184 private String globalMavenOpts;
1185
1186 /**
1187 * @since 1.394
1188 */
1189 private Map<String, Integer> mavenValidationLevels = new LinkedHashMap<String, Integer>();
1190
1191 /**
1192 * @since 1.448
1193 */
1194 private LocalRepositoryLocator localRepository = new DefaultLocalRepositoryLocator();
1195
1196 public DescriptorImpl() {
1197 super();
1198 load();
1199 mavenValidationLevels.put( "DEFAULT", -1 );
1200 mavenValidationLevels.put( "LEVEL_MINIMAL", ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
1201 mavenValidationLevels.put( "LEVEL_MAVEN_2_0", ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 );
1202 mavenValidationLevels.put( "LEVEL_MAVEN_3_0", ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
1203 mavenValidationLevels.put( "LEVEL_MAVEN_3_1", ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 );
1204 mavenValidationLevels.put( "LEVEL_STRICT", ModelBuildingRequest.VALIDATION_LEVEL_STRICT );
1205 }
1206
1207 @Override
1208 public String getHelpFile(String fieldName) {
1209 String v = super.getHelpFile(fieldName);
1210 if (v!=null) return v;
1211 return Jenkins.getInstance().getDescriptor(Maven.class).getHelpFile(fieldName);
1212 }
1213
1214 public List<SettingsProviderDescriptor> getSettingsProviders() {
1215 return Jenkins.getInstance().getDescriptorList(SettingsProvider.class);
1216 }
1217
1218 public List<GlobalSettingsProviderDescriptor> getGlobalSettingsProviders() {
1219 return Jenkins.getInstance().getDescriptorList(GlobalSettingsProvider.class);
1220 }
1221
1222 public String getGlobalMavenOpts() {
1223 return globalMavenOpts;
1224 }
1225
1226 public void setGlobalMavenOpts(String globalMavenOpts) {
1227 this.globalMavenOpts = globalMavenOpts;
1228 save();
1229 }
1230
1231 /**
1232 * @return never null.
1233 */
1234 public LocalRepositoryLocator getLocalRepository() {
1235 return localRepository!=null ? localRepository : new DefaultLocalRepositoryLocator();
1236 }
1237
1238 public void setLocalRepository(LocalRepositoryLocator localRepository) {
1239 this.localRepository = localRepository;
1240 save();
1241 }
1242
1243 public String getDisplayName() {
1244 return Messages.MavenModuleSet_DiplayName();
1245 }
1246
1247 public MavenModuleSet newInstance(ItemGroup parent, String name) {
1248 return new MavenModuleSet(parent,name);
1249 }
1250
1251 public Maven.DescriptorImpl getMavenDescriptor() {
1252 return Jenkins.getInstance().getDescriptorByType(Maven.DescriptorImpl.class);
1253 }
1254
1255 /**
1256 * @since 1.394
1257 * @return
1258 */
1259 public Map<String, Integer> getMavenValidationLevels() {
1260 return mavenValidationLevels;
1261 }
1262
1263 @Override
1264 public boolean configure( StaplerRequest req, JSONObject o ) {
1265 globalMavenOpts = Util.fixEmptyAndTrim(o.getString("globalMavenOpts"));
1266 localRepository = req.bindJSON(LocalRepositoryLocator.class,o.getJSONObject("localRepository"));
1267 save();
1268
1269 return true;
1270 }
1271
1272 @Override
1273 public boolean isApplicable(Descriptor descriptor) {
1274 return !NOT_APPLICABLE_TYPES.contains(descriptor.clazz);
1275 }
1276
1277 private static final Set<Class> NOT_APPLICABLE_TYPES = new HashSet<Class>(Arrays.asList(
1278 Fingerprinter.class, // this kicks in automatically
1279 JavadocArchiver.class, // this kicks in automatically
1280 Mailer.class, // for historical reasons, Maven uses MavenMailer
1281 JUnitResultArchiver.class // done by SurefireArchiver
1282 ));
1283 }
1284
1285 private static final Logger LOGGER = Logger.getLogger(MavenModuleSet.class.getName());
1286 }
1287