View Javadoc

1   /*
2    * Copyright 2012 smartics, Kronseder & Reiner GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package de.smartics.ci.maven.mojo;
17  
18  import java.io.File;
19  import java.io.FileNotFoundException;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.net.MalformedURLException;
23  import java.net.URL;
24  
25  import org.apache.commons.io.FileUtils;
26  import org.apache.maven.execution.MavenSession;
27  import org.apache.maven.model.CiManagement;
28  import org.apache.maven.plugin.MojoExecutionException;
29  import org.apache.maven.project.MavenProject;
30  import org.apache.maven.settings.Server;
31  import org.apache.maven.settings.Settings;
32  import org.codehaus.plexus.util.StringUtils;
33  import org.xml.sax.InputSource;
34  
35  import de.smartics.ci.comm.LogHelper;
36  import de.smartics.ci.config.load.HudsonJobConfig;
37  import de.smartics.ci.config.load.LocationManager;
38  import de.smartics.ci.config.maven.MavenConfig;
39  import de.smartics.ci.config.maven.MavenPom;
40  import de.smartics.ci.config.maven.MavenSettings;
41  import de.smartics.ci.maven.CiServer;
42  import de.smartics.ci.maven.Logger;
43  
44  /**
45   * Base implementation for all CI build mojos.
46   */
47  public abstract class AbstractCiMojo extends AbstractLoggingMojo
48  {
49    // ********************************* Fields *********************************
50  
51    // --- constants ------------------------------------------------------------
52  
53    // --- members --------------------------------------------------------------
54  
55    // ... Mojo infrastructure ..................................................
56  
57    /**
58     * The Maven project.
59     *
60     * @parameter expression="${project}"
61     * @required
62     * @readonly
63     * @since 1.0
64     */
65    protected MavenProject project;
66  
67    /**
68     * The user's settings.
69     *
70     * @parameter expression="${settings}"
71     * @required
72     * @readonly
73     * @since 1.0
74     */
75    protected Settings settings;
76  
77    /**
78     * The Maven session instance.
79     *
80     * @parameter expression="${session}"
81     * @required
82     * @readonly
83     */
84    protected MavenSession session;
85  
86    /**
87     * The path to the project local configuration files for CI. If
88     * <code>${basedir}/src/etc/ci</code> exists, it is automatically added.
89     *
90     * @parameter
91     * @since 1.0
92     */
93    protected String[] hudsonConfigSourceLocations;
94  
95    /**
96     * The name of the server configuration in the <code>settings.xml</code> that
97     * provides credentials to access the Hudson server. Only used if no server
98     * matches the POM's <code>ciManagement/url</code> and
99     * <code>ciManagement/system</code>.
100    *
101    * @parameter default-value="hudson"
102    * @since 1.0
103    */
104   protected String ciServerId;
105 
106   /**
107    * The path to the configuration file for CI. Defaults to
108    * <code>${basedir}/src/etc/ci/ci-config.xml</code>.
109    *
110    * @parameter default-value= "${basedir}/src/etc/ci/ci-config.xml"
111    * @since 1.0
112    */
113   protected File ciConfigurationFile;
114 
115   /**
116    * The path to the destination folder to write the Hudson configurations to.
117    * Defaults to <code>${project.build.directory}/hudson</code>.
118    *
119    * @parameter default-value= "${project.build.directory}/hudson"
120    * @since 1.0
121    */
122   protected File hudsonTargetLocation;
123 
124   // ****************************** Initializer *******************************
125 
126   // ****************************** Constructors ******************************
127 
128   // ****************************** Inner Classes *****************************
129 
130   // ********************************* Methods ********************************
131 
132   // --- init -----------------------------------------------------------------
133 
134   // --- get&set --------------------------------------------------------------
135 
136   /**
137    * Returns the Maven project.
138    *
139    * @return the Maven project.
140    */
141   public final MavenProject getProject()
142   {
143     return project;
144   }
145 
146   /**
147    * Sets the Maven project.
148    *
149    * @param project the Maven project.
150    */
151   public final void setProject(final MavenProject project)
152   {
153     this.project = project;
154   }
155 
156   /**
157    * Sets the Maven session instance.
158    *
159    * @param session the Maven session instance.
160    */
161   public final void setSession(final MavenSession session)
162   {
163     this.session = session;
164   }
165 
166   // --- business -------------------------------------------------------------
167 
168   /**
169    * Creates a configured location manager to fetch Hudson configuration files.
170    *
171    * @return a configured location manager to fetch Hudson configuration files.
172    */
173   protected final LocationManager createLocationManager()
174   {
175     final ClassLoader classLoader =
176         Thread.currentThread().getContextClassLoader();
177     final LocationManager locationManager = new LocationManager(classLoader);
178 
179     provideDefaultLocation(locationManager);
180 
181     if (hudsonConfigSourceLocations != null)
182     {
183       for (final String location : hudsonConfigSourceLocations)
184       {
185         final File dir = new File(location);
186         if (dir.exists())
187         {
188           locationManager.addLocation(dir);
189         }
190         else
191         {
192           final File relativeDir = new File(project.getBasedir(), location);
193           if (relativeDir.exists())
194           {
195             locationManager.addLocation(relativeDir);
196           }
197           else
198           {
199             try
200             {
201               final URL url = new URL(location);
202               locationManager.addLocation(url);
203             }
204             catch (final MalformedURLException e)
205             {
206               final Logger logger = getLog();
207               LogHelper.logWarn(logger, logLevel, "Cannot add location '"
208                                                   + location + "'. Skipping.");
209             }
210           }
211         }
212       }
213     }
214 
215     return locationManager;
216   }
217 
218   private void provideDefaultLocation(final LocationManager locationManager)
219   {
220     final File defaultDir = new File(project.getBasedir(), "/src/etc/ci");
221     if (defaultDir.exists())
222     {
223       locationManager.addLocation(defaultDir);
224     }
225   }
226 
227   /**
228    * Creates a Maven configuration that contains the relevant information for
229    * the Hudson configuration files.
230    *
231    * @return a Maven configuration that contains the relevant information for
232    *         the Hudson configuration files.
233    */
234   protected final MavenConfig createMavenConfig()
235   {
236     final MavenPom pom = new MavenPom();
237     pom.setGroupId(project.getGroupId());
238     pom.setArtifactId(project.getArtifactId());
239     pom.setDescription(project.getDescription());
240     pom.setScmConnectionString(project.getScm().getDeveloperConnection());
241 
242     final MavenSettings settings = new MavenSettings();
243 
244     final MavenConfig mavenConfig = new MavenConfig(settings, pom);
245     return mavenConfig;
246   }
247 
248   /**
249    * Opens a stream to the {@link #ciConfigurationFile}.
250    * <p>
251    * The client is responsible to close the stream.
252    * </p>
253    *
254    * @return the stream inside an input source.
255    * @throws MojoExecutionException on any problem opening the stream.
256    */
257   protected final InputSource createInputSource() throws MojoExecutionException
258   {
259     final File ciConfigXml = ciConfigurationFile;
260     try
261     {
262       final InputSource is;
263       if (checkCiConfigXml(ciConfigXml))
264       {
265         is = fetchLocal(ciConfigXml);
266       }
267       else
268       {
269         is = fetchClassloader();
270       }
271       return is;
272     }
273     catch (final IOException e)
274     {
275       throw new MojoExecutionException("Cannot open file 'ci-config.xml'.", e);
276     }
277 
278   }
279 
280   private boolean checkCiConfigXml(final File ciConfigXml)
281   {
282     return ciConfigXml != null && ciConfigXml.exists();
283   }
284 
285   private InputSource fetchClassloader() throws FileNotFoundException
286   {
287     final InputSource is;
288     final ClassLoader classLoader =
289         Thread.currentThread().getContextClassLoader();
290     final LocationManager lm = new LocationManager(classLoader);
291     is = lm.open("ci-config.xml");
292     return is;
293   }
294 
295   private InputSource fetchLocal(final File ciConfigXml) throws IOException
296   {
297     final InputSource is;
298     is = new InputSource(ciConfigXml.getAbsolutePath());
299     final InputStream in = FileUtils.openInputStream(ciConfigXml);
300     is.setByteStream(in);
301     return is;
302   }
303 
304   /**
305    * Writes the Hudson job configuration XML file to its destination folder.
306    *
307    * @param hudsonJobConfig the Hudson job XML document.
308    * @throws MojoExecutionException on any problem writing the file.
309    */
310   protected final void writeHudsonConfigXml(
311       final HudsonJobConfig hudsonJobConfig) throws MojoExecutionException
312   {
313     ensureDirectoryExists(hudsonTargetLocation);
314 
315     final File file =
316         new File(hudsonTargetLocation, hudsonJobConfig.getId() + ".xml");
317     try
318     {
319       FileUtils.writeStringToFile(file, hudsonJobConfig.getConfigXml());
320     }
321     catch (final IOException e)
322     {
323       throw new MojoExecutionException(
324           "Cannot write Hudson configuration file to '" + file.getPath() + "'",
325           e);
326     }
327   }
328 
329   private static void ensureDirectoryExists(final File dir)
330     throws MojoExecutionException
331   {
332     if (!dir.exists())
333     {
334       if (!dir.mkdirs()) // NOPMD
335       {
336         throw new MojoExecutionException("Cannot generate directory '"
337                                          + dir.getPath() + "'");
338       }
339     }
340   }
341 
342   /**
343    * Returns the Hudson server configuration to run a remote access.
344    *
345    * @return the server information. If no access information is found, only the
346    *         URL to the CI server is returned.
347    * @throws MojoExecutionException if no CI URL is specified.
348    */
349   protected final CiServer getCiServer() throws MojoExecutionException
350   {
351     final CiManagement ciManagement = project.getCiManagement();
352     final Server server = getCiServerFromSettings(ciManagement);
353     final String ciUrl = ciManagement.getUrl();
354     return new CiServer(logger, server, ciUrl);
355   }
356 
357   private Server getCiServerFromSettings(final CiManagement ciManagement)
358     throws MojoExecutionException
359   {
360     Server server;
361 
362     if (StringUtils.isNotBlank(ciServerId))
363     {
364       server = settings.getServer(ciServerId);
365     }
366     else
367     {
368       final String ciUrl = ciManagement.getUrl();
369       server = settings.getServer(ciUrl);
370       if (server != null)
371       {
372         return server;
373       }
374 
375       final String ciName = ciManagement.getSystem();
376       if (StringUtils.isNotBlank(ciName))
377       {
378         server = settings.getServer(ciName);
379       }
380     }
381 
382     return server;
383   }
384 
385   // CHECKSTYLE:OFF
386   /**
387    * Provides a check for conditions to be met to run this plugin successfully.
388    * <p>
389    * Subclasses may add additional checks by overriding this method and calling
390    * this it in their implementation.
391    * </p>
392    *
393    * @throws MojoExecutionException if the preconditions are not met.
394    */
395   protected void checkPreconditions() throws MojoExecutionException
396   {
397     // CHECKSTYLE:ON
398     if (project == null)
399     {
400       throw new MojoExecutionException(
401           "No project information provided. Please run this plugin on"
402               + " a project that provides a POM.");
403     }
404 
405     final CiManagement ciManagement = project.getCiManagement();
406     if (ciManagement == null)
407     {
408       throw new MojoExecutionException(
409           "No CI management specified. Please provide CI information"
410               + " within the 'ciManagement' block of your POM.");
411     }
412 
413     final String ciUrl = ciManagement.getUrl();
414     if (StringUtils.isBlank(ciUrl))
415     {
416       throw new MojoExecutionException(
417           "No CI URL specified. Please provide CI information within the"
418               + " 'ciManagement/url' block of your POM.");
419     }
420   }
421 
422 }