View Javadoc

1   /*
2    * Copyright 2012-2013 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.maven.bugzilla;
17  
18  import static de.smartics.maven.issue.util.PackagingUtils.mapToExtension;
19  
20  import org.apache.commons.httpclient.HttpClient;
21  import org.apache.maven.model.DeploymentRepository;
22  import org.apache.maven.model.DistributionManagement;
23  import org.apache.maven.plugin.MojoExecutionException;
24  import org.apache.maven.plugin.MojoFailureException;
25  import org.apache.maven.plugin.logging.Log;
26  import org.apache.maven.project.MavenProject;
27  import org.codehaus.plexus.util.StringUtils;
28  
29  import de.smartics.maven.issue.command.CommandException;
30  import de.smartics.maven.issue.util.LogLevel;
31  import de.smartics.maven.issue.util.VersionHelper;
32  import de.smartics.maven.nexus.NexusClient;
33  import de.smartics.maven.nexus.NexusRequest;
34  import de.smartics.maven.nexus.NexusUtils;
35  
36  /**
37   * Used after a release: Updates a product on the issue management server with
38   * information from this project and initializes the version information for
39   * that project.
40   *
41   * @goal sync
42   * @requiresProject
43   * @threadSafe
44   * @since 1.0
45   * @description Synchronizes the product information after a release according
46   *              to best practices.
47   */
48  public class SyncProductMojo extends UpdateProductMojo
49  {
50    // ********************************* Fields *********************************
51  
52    // --- constants ------------------------------------------------------------
53  
54    // --- members --------------------------------------------------------------
55  
56    /**
57     * The released version to add. Also the major, minor and micro increment
58     * milestones are added. If for e.g. the released version is
59     * <code>1.2.3</code>, this version and the milestones <code>1.2.4</code>,
60     * <code>1.3.0</code> and <code>2.0.0</code> are initialized.
61     * <p>
62     * If the released version cannot be recognized by Maven's standard
63     * implementation of a version parser, increment versions will not be added.
64     * </p>
65     * <p>
66     * It is allowed to use the tokens MICRO, MINOR, MAJOR to let the plugin
67     * calculate the previous version by the current version in the POM. For
68     * instance:
69     * </p>
70     * <ul>
71     * <li>1.2.3-SNAPSHOT MICRO -> 1.2.2</li>
72     * <li>1.2.0-SNAPSHOT MINOR -> 1.1.0</li>
73     * <li>1.2.1-SNAPSHOT MINOR -> 1.2.0</li>
74     * <li>2.0.0-SNAPSHOT MAJOR -> 1.0.0</li>
75     * <li>2.0.1-SNAPSHOT MAJOR -> 2.0.0</li>
76     * </ul>
77     * <p>
78     * The following example contexts raise an exception:
79     * </p>
80     * <ul>
81     * <li>1.2.0-SNAPSHOT MICRO -> Failure</li>
82     * <li>1.0.0-SNAPSHOT MINOR -> Failure</li>
83     * <li>0.0.0-SNAPSHOT MAJOR -> Failure</li>
84     * <li>0.1.2-SNAPSHOT MAJOR -> Failure</li>
85     * </ul>
86     * <p>
87     * If the version is not provided, the nexus server will be queried for the
88     * released version.
89     * </p>
90     *
91     * @parameter expression="${releasedVersion}" default-value="NEXUS"
92     * @since 1.0
93     */
94    private String releasedVersion;
95  
96    /**
97     * If <code>releasedVersion</code> is set to <code>NEXUS</code> and the
98     * default searching for the release repository's HTTP URL ending with
99     * <code>/</code> or <code>/nexus</code> would not determine the correct URL,
100    * override it here. This value will take precedence.
101    *
102    * @parameter expression="${nexusServer}"
103    * @since 1.0
104    */
105   private String nexusServer;
106 
107   /**
108    * The extension to use for querying the Nexus server for the latest released
109    * version, if <code>releasedVersion</code> is set to <code>NEXUS</code>. Per
110    * default the extension will be derived from the POM's packaging information.
111    *
112    * @parameter
113    * @since 1.0
114    */
115   private String extension;
116 
117   /**
118    * The repository ID to use to query the Nexus server for the latest released
119    * version, if <code>releasedVersion</code> is set to <code>NEXUS</code>. Per
120    * default the plugin will use the identifier of the release repository found
121    * in the <code>distributionManagement</code>. This value overrides the
122    * default behavior.
123    *
124    * @parameter expression="${repositoryId}"
125    * @since 1.0
126    */
127   private String repositoryId;
128 
129   /**
130    * If set to <code>true</code> the Bugzilla product will not be updated.
131    * Usually there are no changes to the components, so that skipping is the
132    * default.
133    *
134    * @parameter expression="${skipProductUpdate}" default-value="true"
135    * @since 1.0
136    */
137   private boolean skipProductUpdate;
138 
139   // ****************************** Initializer *******************************
140 
141   // ****************************** Constructors ******************************
142 
143   // ****************************** Inner Classes *****************************
144 
145   // ********************************* Methods ********************************
146 
147   // --- init -----------------------------------------------------------------
148 
149   // --- get&set --------------------------------------------------------------
150 
151   // --- business -------------------------------------------------------------
152 
153   /**
154    * {@inheritDoc}
155    */
156   @Override
157   public final void run() throws MojoExecutionException, MojoFailureException
158   {
159     if (!skipProductUpdate)
160     {
161       super.run();
162     }
163 
164     final MavenProject project = getProject();
165     final MojoHelperSync helper =
166         new MojoHelperSync(project, commandFactory, console);
167 
168     final String previousVersion = calculatePreviousVersion(project);
169     helper.execute(previousVersion);
170   }
171 
172   // --- object basics --------------------------------------------------------
173 
174   private String calculatePreviousVersion(final MavenProject project)
175     throws MojoExecutionException, MojoFailureException
176   {
177     final Log log = getLog();
178     final LogLevel logLevel = new LogLevel(verbose);
179 
180     final String previousVersion;
181     if ("NEXUS".equals(releasedVersion))
182     {
183       final NexusClient client =
184           new NexusClient(new HttpClient(), log, logLevel);
185       final NexusRequest request = createNexusRequest(project);
186       try
187       {
188         previousVersion = client.getLatestReleaseVersion(request);
189       }
190       catch (final CommandException e)
191       {
192         throw new MojoFailureException(
193             "Cannot determine latest release version on Nexus.", e);
194       }
195     }
196     else
197     {
198       final VersionHelper versionHelper = new VersionHelper(project);
199       try
200       {
201         previousVersion =
202             versionHelper.calculatePreviousVersion(releasedVersion);
203 
204       }
205       catch (final IllegalArgumentException e)
206       {
207         throw new MojoExecutionException("Cannot calculate previous version: "
208                                          + e.getMessage(), e);
209       }
210     }
211 
212     return previousVersion;
213   }
214 
215   private NexusRequest createNexusRequest(final MavenProject project)
216     throws MojoExecutionException
217   {
218     final DeploymentRepository repository =
219         getDeploymentRepository(project.getDistributionManagement());
220     final String nexusServerUrl = getNexusServerUrl(repository);
221     final String repositoryId = getRepositoryId(repository);
222     final String groupId = project.getGroupId();
223     final String artifactId = project.getArtifactId();
224     final String extension = map(project.getPackaging(), this.extension);
225     return new NexusRequest(nexusServerUrl, repositoryId, groupId, artifactId,
226         extension);
227   }
228 
229   private static String map(final String packaging, final String extension)
230   {
231     if (StringUtils.isNotBlank(extension))
232     {
233       return extension;
234     }
235     return mapToExtension(packaging);
236   }
237 
238   private static DeploymentRepository getDeploymentRepository(
239       final DistributionManagement distributionManagement)
240   {
241     if (distributionManagement != null)
242     {
243       final DeploymentRepository repository =
244           distributionManagement.getRepository();
245       return repository;
246     }
247     return null;
248   }
249 
250   private String getNexusServerUrl(final DeploymentRepository repository)
251     throws MojoExecutionException
252   {
253     if (StringUtils.isNotBlank(nexusServer))
254     {
255       return nexusServer;
256     }
257 
258     if (repository != null)
259     {
260       final String url = repository.getUrl();
261 
262       if (StringUtils.isBlank(url))
263       {
264         throw new MojoExecutionException(
265             "No valid Nexus server URL can be determined. Neiter deployment"
266                 + " repository in the POM specified an URL nor is it specified"
267                 + " via nexusServer.");
268       }
269 
270       final String nexusServer = NexusUtils.calcNexusServerUrl(url);
271       if (StringUtils.isNotBlank(nexusServer))
272       {
273         return nexusServer;
274       }
275     }
276 
277     throw new MojoExecutionException(
278         "No valid Nexus server URL can be determined.  Neither a deployment"
279             + " repository specified in the POM nor specified via nexusServer.");
280   }
281 
282   private String getRepositoryId(final DeploymentRepository repository)
283     throws MojoExecutionException
284   {
285     final String id;
286 
287     if (StringUtils.isNotBlank(repositoryId))
288     {
289       id = repositoryId;
290     }
291     else if (repository != null)
292     {
293       id = repository.getId();
294       if (StringUtils.isBlank(id))
295       {
296         throw new MojoExecutionException(
297             "No valid repository ID can be determined. Not found in the"
298                 + " release repository's element nor specified via repositoryId.");
299       }
300     }
301     else
302     {
303       throw new MojoExecutionException(
304           "No valid repository ID can be determined. Neither a deployment"
305               + " repository specified in the POM nor specified via repositoryId.");
306     }
307 
308     return id;
309   }
310 
311 }