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 org.apache.commons.lang.StringUtils;
19  import org.apache.maven.model.IssueManagement;
20  import org.apache.maven.plugin.AbstractMojo;
21  import org.apache.maven.plugin.MojoExecutionException;
22  import org.apache.maven.plugin.MojoFailureException;
23  import org.apache.maven.plugin.logging.Log;
24  import org.apache.maven.project.MavenProject;
25  import org.apache.maven.settings.Server;
26  import org.apache.maven.settings.Settings;
27  import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
28  import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException;
29  
30  import de.smartics.maven.issue.command.CommandTarget;
31  import de.smartics.maven.issue.util.LogLevel;
32  import de.smartics.maven.issue.util.MavenProjectWrapper;
33  import de.smartics.maven.issue.util.SettingsDecrypter;
34  
35  /**
36   * Base implementation for Bugzilla mojos.
37   */
38  public abstract class AbstractIssueMojo extends AbstractMojo
39  {
40    // ********************************* Fields *********************************
41  
42    // --- constants ------------------------------------------------------------
43  
44    // --- members --------------------------------------------------------------
45  
46    // ... Mojo infrastructure ..................................................
47  
48    /**
49     * The Maven project.
50     *
51     * @parameter expression="${project}"
52     * @required
53     * @readonly
54     * @since 1.0
55     */
56    private MavenProject project;
57  
58    /**
59     * The user's settings.
60     *
61     * @parameter expression="${settings}"
62     * @required
63     * @readonly
64     * @since 1.0
65     */
66    protected Settings settings;
67  
68    /**
69     * Helper to decrypt passwords from the settings.
70     *
71     * @component
72     *            role="org.sonatype.plexus.components.sec.dispatcher.SecDispatcher"
73     * @since 1.0
74     */
75    private SecDispatcher securityDispatcher;
76  
77    /**
78     * The location of the <code>settings-security.xml</code>.
79     *
80     * @parameter expression="${user.home}/.m2/settings-security.xml"
81     * @required
82     * @since 1.0
83     */
84    private String settingsSecurityLocation;
85  
86    /**
87     * Helper to decrypt passwords from the settings handling the location of the
88     * <code>settings-security.xml</code> file.
89     */
90    private SettingsDecrypter settingsDecrypter;
91  
92    // ... parameter ............................................................
93  
94    /**
95     * The name of the server configuration in the <code>settings.xml</code> that
96     * provides credentials to access the issues server. Only used if no server
97     * matches the POM's <code>issueManagement/url</code> and
98     * <code>issueManagement/system</code>.
99     *
100    * @parameter default-value="bugzilla"
101    * @since 1.0
102    */
103   protected String issueServerId;
104 
105   // ... command ..............................................................
106 
107   /**
108    * Information about the issue server.
109    */
110   protected IssueServer server;
111 
112   /**
113    * The console to execute commands.
114    */
115   protected Console console;
116 
117   /**
118    * Defines the verboseness of the output.
119    * <ul>
120    * <li><code>QUIET</code> - prints no info messages.</li>
121    * <li><code>NORMAL</code> - only prints the returned page titles.</li>
122    * <li><code>VERBOSE</code> - adds information about the called service and
123    * parameters.</li>
124    * <li><code>TRACE</code> - provides the most verbose output with dumping the
125    * contents of the returned pages.</li>
126    * </ul>
127    *
128    * @parameter expression="${verbose}" default-value="NORMAL"
129    * @since 1.0
130    */
131   protected String verbose;
132 
133   // ... fixes ................................................................
134 
135   // ****************************** Initializer *******************************
136 
137   // ****************************** Constructors ******************************
138 
139   // ****************************** Inner Classes *****************************
140 
141   /**
142    * Provides access information for the continuous integration server.
143    */
144   protected static final class IssueServer extends Server
145   {
146     /**
147      * The class version identifier.
148      * <p>
149      * The value of this constant is {@value}.
150      * </p>
151      */
152     private static final long serialVersionUID = 1L;
153 
154     /**
155      * The URL to the server.
156      */
157     private final String url;
158 
159     private IssueServer(final SettingsDecrypter settingsDecrypter,
160         final Server server, final String url) throws MojoExecutionException
161     {
162       this.url = url;
163 
164       if (server != null)
165       {
166         this.setId(server.getId());
167         this.setUsername(server.getUsername());
168 
169         try
170         {
171           final String plain = server.getPassword();
172           final String decrypted = settingsDecrypter.decrypt(plain);
173 
174           this.setPassword(decrypted);
175           this.setPassphrase(server.getPassphrase());
176           this.setPrivateKey(server.getPrivateKey());
177 
178           this.setDirectoryPermissions(server.getDirectoryPermissions());
179           this.setFilePermissions(server.getFilePermissions());
180           this.setConfiguration(server.getConfiguration());
181 
182           this.setSourceLevel(server.getSourceLevel());
183         }
184         catch (final SecDispatcherException e)
185         {
186           throw new MojoExecutionException(
187               "Cannot decrypt '" + server.getId()
188                   + "' server password for user name '" + server.getUsername()
189                   + "'.", e);
190         }
191       }
192     }
193 
194     /**
195      * Returns the URL to the server.
196      *
197      * @return the URL to the server.
198      */
199     public String getUrl()
200     {
201       return url;
202     }
203   }
204 
205   // ********************************* Methods ********************************
206 
207   // --- init -----------------------------------------------------------------
208 
209   // --- get&set --------------------------------------------------------------
210 
211   /**
212    * Returns the Maven project.
213    *
214    * @return the Maven project.
215    */
216   protected final MavenProject getProject()
217   {
218     return new MavenProjectWrapper(project);
219   }
220 
221   // --- business -------------------------------------------------------------
222 
223   /**
224    * Returns the issue server configuration to run a remote access.
225    *
226    * @return the server information. If no access information is found, only the
227    *         URL to the issue server is returned.
228    * @throws MojoExecutionException if no issue server URL is specified.
229    */
230   protected final IssueServer getIssueServer() throws MojoExecutionException
231   {
232     final IssueManagement issueManagement = project.getIssueManagement();
233     if (issueManagement == null)
234     {
235       throw new MojoExecutionException(
236           "No issue management specified. Please provide issue information"
237               + " within the 'issueManagement' block of your POM.");
238     }
239 
240     final Server server = getIssueServerFromSettings(issueManagement);
241     final String ciUrl = issueManagement.getUrl();
242     return new IssueServer(settingsDecrypter, server, ciUrl);
243   }
244 
245   // CHECKSTYLE:OFF
246   /**
247    * {@inheritDoc}
248    *
249    * @see org.apache.maven.plugin.Mojo#execute()
250    */
251   @Override
252   public void execute() throws MojoExecutionException, MojoFailureException
253   // CHECKSTYLE:ON
254   {
255     final Log log = getLog();
256 
257     settingsDecrypter =
258         new SettingsDecrypter(securityDispatcher, settingsSecurityLocation);
259 
260     server = getIssueServer();
261     final String url = server.getUrl();
262     final LogLevel logLevel = new LogLevel(verbose);
263     final CommandTarget target = new CommandTarget(url);
264 
265     console = new Console(target, log, logLevel);
266   }
267 
268   private Server getIssueServerFromSettings(
269       final IssueManagement issueManagement) throws MojoExecutionException
270   {
271     final String issueUrl = issueManagement.getUrl();
272     if (StringUtils.isBlank(issueUrl))
273     {
274       throw new MojoExecutionException(
275           "No issue URL specified. Please provide issue information within the"
276               + " 'issueManagement/url' block of your POM.");
277     }
278 
279     Server server;
280     if (StringUtils.isNotBlank(issueServerId))
281     {
282       server = settings.getServer(issueServerId);
283       if (server != null)
284       {
285         return server;
286       }
287     }
288 
289     final String ciName = issueManagement.getSystem();
290     if (StringUtils.isNotBlank(ciName))
291     {
292       server = settings.getServer(ciName);
293       if (server != null)
294       {
295         return server;
296       }
297     }
298 
299     server = settings.getServer(issueUrl);
300 
301     return server;
302   }
303 
304   /**
305    * Checks whether or not the plugin should execute.
306    *
307    * @return <code>true</code> if the execution of the plugin should be skipped,
308    *         <code>false</code> if it should run.
309    */
310   protected final boolean isToSkip()
311   {
312     return !project.isExecutionRoot();
313   }
314 
315   // --- object basics --------------------------------------------------------
316 
317 }