View Javadoc
1   package org.apache.maven.shared.release.phase;
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.util.List;
23  import java.util.Map;
24  import java.util.Properties;
25  
26  import org.apache.maven.artifact.ArtifactUtils;
27  import org.apache.maven.project.MavenProject;
28  import org.apache.maven.scm.manager.NoSuchScmProviderException;
29  import org.apache.maven.scm.provider.ScmProvider;
30  import org.apache.maven.scm.repository.ScmRepository;
31  import org.apache.maven.scm.repository.ScmRepositoryException;
32  import org.apache.maven.shared.release.ReleaseExecutionException;
33  import org.apache.maven.shared.release.ReleaseResult;
34  import org.apache.maven.shared.release.config.ReleaseDescriptor;
35  import org.apache.maven.shared.release.env.ReleaseEnvironment;
36  import org.apache.maven.shared.release.policy.PolicyException;
37  import org.apache.maven.shared.release.policy.naming.NamingPolicy;
38  import org.apache.maven.shared.release.policy.naming.NamingPolicyRequest;
39  import org.apache.maven.shared.release.scm.ReleaseScmRepositoryException;
40  import org.apache.maven.shared.release.scm.ScmRepositoryConfigurator;
41  import org.apache.maven.shared.release.util.ReleaseUtil;
42  import org.codehaus.plexus.component.annotations.Requirement;
43  import org.codehaus.plexus.components.interactivity.Prompter;
44  import org.codehaus.plexus.components.interactivity.PrompterException;
45  import org.codehaus.plexus.interpolation.InterpolationException;
46  import org.codehaus.plexus.interpolation.Interpolator;
47  import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
48  import org.codehaus.plexus.interpolation.PrefixedPropertiesValueSource;
49  import org.codehaus.plexus.interpolation.RecursionInterceptor;
50  import org.codehaus.plexus.interpolation.StringSearchInterpolator;
51  import org.codehaus.plexus.util.StringUtils;
52  
53  /**
54   * Input any variables that were not yet configured.
55   *
56   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
57   */
58  public class InputVariablesPhase
59      extends AbstractReleasePhase
60  {
61      /**
62       * Component used to prompt for input.
63       */
64      @Requirement
65      private Prompter prompter;
66  
67      /**
68       * Whether this is a branch or a tag operation.
69       */
70      private boolean branchOperation;
71  
72      /**
73       * Tool that gets a configured SCM repository from release configuration.
74       */
75      @Requirement
76      private ScmRepositoryConfigurator scmRepositoryConfigurator;
77  
78      /**
79       * Component used for custom or default naming policy
80       */
81      @Requirement
82      private Map<String, NamingPolicy> namingPolicies;
83  
84      /**
85       * The default naming policy to apply, if any
86       */
87      private String defaultNamingPolicy;
88  
89      void setPrompter( Prompter prompter )
90      {
91          this.prompter = prompter;
92      }
93  
94      boolean isBranchOperation()
95      {
96          return branchOperation;
97      }
98  
99      protected ScmProvider getScmProvider( ReleaseDescriptor releaseDescriptor, ReleaseEnvironment releaseEnvironment )
100         throws ReleaseScmRepositoryException, ReleaseExecutionException
101     {
102         try
103         {
104             ScmRepository repository =
105                 scmRepositoryConfigurator.getConfiguredRepository( releaseDescriptor,
106                                                                    releaseEnvironment.getSettings() );
107 
108             return scmRepositoryConfigurator.getRepositoryProvider( repository );
109         }
110         catch ( ScmRepositoryException e )
111         {
112             throw new ReleaseScmRepositoryException(
113                 e.getMessage() + " for URL: " + releaseDescriptor.getScmSourceUrl(), e.getValidationMessages() );
114         }
115         catch ( NoSuchScmProviderException e )
116         {
117             throw new ReleaseExecutionException( "Unable to configure SCM repository: " + e.getMessage(), e );
118         }
119     }
120 
121     @Override
122     public ReleaseResult execute( ReleaseDescriptor releaseDescriptor, ReleaseEnvironment releaseEnvironment,
123                                   List<MavenProject> reactorProjects )
124         throws ReleaseExecutionException
125     {
126         ReleaseResult result = new ReleaseResult();
127 
128         // get the root project
129         MavenProject project = ReleaseUtil.getRootProject( reactorProjects );
130 
131         String tag = releaseDescriptor.getScmReleaseLabel();
132 
133         if ( tag == null )
134         {
135             // Must get default version from mapped versions, as the project will be the incorrect snapshot
136             String key = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
137             String releaseVersion = releaseDescriptor.getProjectReleaseVersion( key );
138             if ( releaseVersion == null )
139             {
140                 throw new ReleaseExecutionException( "Project tag cannot be selected if version is not yet mapped" );
141             }
142 
143             String suggestedName;
144             String scmTagNameFormat = releaseDescriptor.getScmTagNameFormat();
145             if ( releaseDescriptor.getProjectNamingPolicyId() != null )
146             {
147                 try
148                 {
149                     suggestedName =
150                         resolveSuggestedName( releaseDescriptor.getProjectNamingPolicyId(), releaseVersion, project );
151                 }
152                 catch ( PolicyException e )
153                 {
154                     throw new ReleaseExecutionException( e.getMessage(), e );
155                 }
156             }
157             else if ( scmTagNameFormat != null )
158             {
159                 Interpolator interpolator = new StringSearchInterpolator( "@{", "}" );
160                 List<String> possiblePrefixes = java.util.Arrays.asList( "project", "pom" );
161                 Properties values = new Properties();
162                 values.setProperty( "artifactId", project.getArtifactId() );
163                 values.setProperty( "groupId", project.getGroupId() );
164                 values.setProperty( "version", releaseVersion );
165                 interpolator.addValueSource( new PrefixedPropertiesValueSource( possiblePrefixes, values, true ) );
166                 RecursionInterceptor recursionInterceptor = new PrefixAwareRecursionInterceptor( possiblePrefixes );
167                 try
168                 {
169                     suggestedName = interpolator.interpolate( scmTagNameFormat, recursionInterceptor );
170                 }
171                 catch ( InterpolationException e )
172                 {
173                     throw new ReleaseExecutionException(
174                         "Could not interpolate specified tag name format: " + scmTagNameFormat, e );
175                 }
176             }
177             else
178             {
179                 try
180                 {
181                     suggestedName = resolveSuggestedName( defaultNamingPolicy, releaseVersion, project );
182                 }
183                 catch ( PolicyException e )
184                 {
185                     throw new ReleaseExecutionException( e.getMessage(), e );
186                 }
187             }
188 
189             ScmProvider provider = null;
190             try
191             {
192                 provider = getScmProvider( releaseDescriptor, releaseEnvironment );
193             }
194             catch ( ReleaseScmRepositoryException e )
195             {
196                 throw new ReleaseExecutionException(
197                     "No scm provider can be found for url: " + releaseDescriptor.getScmSourceUrl(), e );
198             }
199 
200             suggestedName = provider.sanitizeTagName( suggestedName );
201 
202             if ( releaseDescriptor.isInteractive() )
203             {
204                 try
205                 {
206                     if ( branchOperation )
207                     {
208                         tag = prompter.prompt( "What is the branch name for \"" + project.getName() + "\"? ("
209                             + project.getGroupId() + ":" + project.getArtifactId() + ")" );
210                         if ( StringUtils.isEmpty( tag ) )
211                         {
212                             throw new ReleaseExecutionException( "No branch name was given." );
213                         }
214                     }
215                     else
216                     {
217                         tag = prompter.prompt( "What is the SCM release tag or label for \"" + project.getName()
218                             + "\"? (" + project.getGroupId() + ":" + project.getArtifactId() + ")", suggestedName );
219                     }
220                 }
221                 catch ( PrompterException e )
222                 {
223                     throw new ReleaseExecutionException( "Error reading version from input handler: " + e.getMessage(),
224                                                          e );
225                 }
226             }
227             else if ( suggestedName == null )
228             {
229                 if ( isBranchOperation() )
230                 {
231                     throw new ReleaseExecutionException( "No branch name was given." );
232                 }
233                 else
234                 {
235                     throw new ReleaseExecutionException( "No tag name was given." );
236                 }
237             }
238             else
239             {
240                 tag = suggestedName;
241             }
242             releaseDescriptor.setScmReleaseLabel( tag );
243         }
244 
245         result.setResultCode( ReleaseResult.SUCCESS );
246 
247         return result;
248     }
249 
250     @Override
251     public ReleaseResult simulate( ReleaseDescriptor releaseDescriptor, ReleaseEnvironment releaseEnvironment,
252                                    List<MavenProject> reactorProjects )
253         throws ReleaseExecutionException
254     {
255         ReleaseResult result = new ReleaseResult();
256 
257         // It makes no modifications, so simulate is the same as execute
258         execute( releaseDescriptor, releaseEnvironment, reactorProjects );
259 
260         result.setResultCode( ReleaseResult.SUCCESS );
261 
262         return result;
263     }
264 
265     private String resolveSuggestedName( String policyId, String version, MavenProject project )
266         throws PolicyException
267     {
268         if ( policyId == null )
269         {
270             return null;
271         }
272 
273         NamingPolicy policy = namingPolicies.get( policyId );
274         if ( policy == null )
275         {
276             throw new PolicyException( "Policy '" + policyId + "' is unknown, available: "
277                 + namingPolicies.keySet() );
278         }
279 
280         NamingPolicyRequest request = new NamingPolicyRequest()
281                         .setGroupId( project.getGroupId() )
282                         .setArtifactId( project.getArtifactId() )
283                         .setVersion( version );
284         return policy.getName( request ).getName();
285     }
286 }