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