View Javadoc
1   package org.apache.maven.plugin.changes;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.text.ParseException;
24  import java.text.SimpleDateFormat;
25  import java.util.Locale;
26  
27  import org.apache.commons.lang.StringUtils;
28  import org.apache.maven.plugin.MojoExecutionException;
29  import org.apache.maven.plugins.annotations.Mojo;
30  import org.apache.maven.plugins.annotations.Parameter;
31  import org.apache.maven.plugins.changes.model.Release;
32  
33  /**
34   * Goal which checks that the changes.xml file has the necessary data to generate an announcement or a report for the
35   * current release.
36   *
37   * @author Justin Edelson
38   * @author Dennis Lundberg
39   * @since 2.4
40   */
41  @Mojo( name = "changes-check", threadSafe = true )
42  public class ChangesCheckMojo
43      extends AbstractChangesMojo
44  {
45      /**
46       * The format that a correct release date should have. This value will be used as a pattern to try to parse a date.
47       */
48      @Parameter( property = "changes.releaseDateFormat", defaultValue = "yyyy-MM-dd" )
49      private String releaseDateFormat;
50  
51      /**
52       * The locale that a correct release date should have. This value will be used as a locale to try to parse a date.
53       *
54       * @since 2.10
55       */
56      @Parameter( property = "changes.releaseDateLocale" )
57      private String releaseDateLocale;
58  
59      /**
60       * Version of the artifact.
61       */
62      @Parameter( property = "changes.version", defaultValue = "${project.version}", required = true )
63      private String version;
64  
65      /**
66       * The path of the <code>changes.xml</code> file that will be checked.
67       */
68      @Parameter( property = "changes.xmlPath", defaultValue = "src/changes/changes.xml" )
69      private File xmlPath;
70  
71      /**
72       * Flag controlling snapshot processing. If set, versions ending with <code>-SNAPSHOT</code> won't be checked.
73       *
74       * @since 2.7
75       */
76      @Parameter( property = "changes.skipSnapshots", defaultValue = "false" )
77      private boolean skipSnapshots;
78  
79      /**
80       * Check that the latest release contains a valid release date.
81       *
82       * @throws MojoExecutionException
83       */
84      public void execute()
85          throws MojoExecutionException
86      {
87          // Run only at the execution root
88          if ( runOnlyAtExecutionRoot && !isThisTheExecutionRoot() )
89          {
90              getLog().info( "Skipping the changes check in this project because it's not the Execution Root" );
91          }
92          else
93          {
94              if ( this.version.endsWith( "-SNAPSHOT" ) && this.skipSnapshots )
95              {
96                  getLog().info( "Skipping snapshot version '" + this.version + "'." );
97              }
98              else if ( xmlPath.exists() )
99              {
100                 ChangesXML xml = new ChangesXML( xmlPath, getLog() );
101                 ReleaseUtils releaseUtils = new ReleaseUtils( getLog() );
102                 Release release =
103                     releaseUtils.getLatestRelease( releaseUtils.convertReleaseList( xml.getReleaseList() ), version );
104 
105                 if ( !isValidDate( release.getDateRelease(), releaseDateFormat, releaseDateLocale ) )
106                 {
107                     throw new MojoExecutionException( "The file " + xmlPath.getAbsolutePath()
108                         + " has an invalid release date." );
109 
110                 }
111             }
112             else
113             {
114                 getLog().warn( "The file " + xmlPath.getAbsolutePath() + " does not exist." );
115             }
116         }
117     }
118 
119     /**
120      * Use the pattern to try to parse a Date from the given string. Kept for backward compatibility with existing unit
121      * tests.
122      *
123      * @param string A date as text
124      * @param pattern A pattern that can be used by {@link SimpleDateFormat}
125      * @return <code>true</code> if the string can be parsed as a date using the pattern, otherwise <code>false</code>
126      */
127     protected static boolean isValidDate( String string, String pattern )
128     {
129         return isValidDate( string, pattern, null );
130     }
131 
132     /**
133      * Use the pattern to try to parse a Date from the given string using the given Locale.
134      *
135      * @param string A date as text
136      * @param pattern A pattern that can be used by {@link SimpleDateFormat}
137      * @param locale A locale that can be used by {@link SimpleDateFormat}
138      * @return <code>true</code> if the string can be parsed as a date using the pattern, otherwise <code>false</code>
139      */
140     protected static boolean isValidDate( String string, String pattern, String locale )
141     {
142         if ( StringUtils.isEmpty( string ) )
143         {
144             return false;
145         }
146 
147         if ( StringUtils.isEmpty( pattern ) )
148         {
149             return false;
150         }
151 
152         try
153         {
154             Locale usedLocale = null;
155 
156             if ( StringUtils.isEmpty( locale ) )
157             {
158                 // No locale specified, use the default locale as default value
159                 // The same behavior as before the locale parameter was added
160                 usedLocale = Locale.getDefault();
161             }
162             else
163             {
164                 // Try to find the specified locale on this system
165                 Locale[] locales = Locale.getAvailableLocales();
166                 for ( int i = 0; i < locales.length; i++ )
167                 {
168                     if ( locales[i].toString().equals( locale ) )
169                     {
170                         usedLocale = locales[i];
171                         break;
172                     }
173                 }
174 
175                 if ( usedLocale == null )
176                 {
177                     // The use specified locale was not found on this system,
178                     // use the default locale as default value
179                     usedLocale = Locale.getDefault();
180                 }
181             }
182 
183             SimpleDateFormat df = new SimpleDateFormat( pattern, usedLocale );
184             df.parse( string );
185             return true;
186         }
187         catch ( ParseException e )
188         {
189             return false;
190         }
191     }
192 }