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      /**
100      * <p>getScmProvider.</p>
101      *
102      * @param releaseDescriptor a {@link org.apache.maven.shared.release.config.ReleaseDescriptor} object
103      * @param releaseEnvironment a {@link org.apache.maven.shared.release.env.ReleaseEnvironment} object
104      * @return a {@link org.apache.maven.scm.provider.ScmProvider} object
105      * @throws org.apache.maven.shared.release.scm.ReleaseScmRepositoryException if any.
106      * @throws org.apache.maven.shared.release.ReleaseExecutionException if any.
107      */
108     protected ScmProvider getScmProvider( ReleaseDescriptor releaseDescriptor, ReleaseEnvironment releaseEnvironment )
109         throws ReleaseScmRepositoryException, ReleaseExecutionException
110     {
111         try
112         {
113             ScmRepository repository =
114                 scmRepositoryConfigurator.getConfiguredRepository( releaseDescriptor,
115                                                                    releaseEnvironment.getSettings() );
116 
117             return scmRepositoryConfigurator.getRepositoryProvider( repository );
118         }
119         catch ( ScmRepositoryException e )
120         {
121             throw new ReleaseScmRepositoryException(
122                 e.getMessage() + " for URL: " + releaseDescriptor.getScmSourceUrl(), e.getValidationMessages() );
123         }
124         catch ( NoSuchScmProviderException e )
125         {
126             throw new ReleaseExecutionException( "Unable to configure SCM repository: " + e.getMessage(), e );
127         }
128     }
129 
130     @Override
131     public ReleaseResult execute( ReleaseDescriptor releaseDescriptor, ReleaseEnvironment releaseEnvironment,
132                                   List<MavenProject> reactorProjects )
133         throws ReleaseExecutionException
134     {
135         ReleaseResult result = new ReleaseResult();
136 
137         // get the root project
138         MavenProject project = ReleaseUtil.getRootProject( reactorProjects );
139 
140         String tag = releaseDescriptor.getScmReleaseLabel();
141 
142         if ( tag == null )
143         {
144             // Must get default version from mapped versions, as the project will be the incorrect snapshot
145             String key = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
146             String releaseVersion = releaseDescriptor.getProjectReleaseVersion( key );
147             if ( releaseVersion == null )
148             {
149                 throw new ReleaseExecutionException( "Project tag cannot be selected if version is not yet mapped" );
150             }
151 
152             String suggestedName;
153             String scmTagNameFormat = releaseDescriptor.getScmTagNameFormat();
154             if ( releaseDescriptor.getProjectNamingPolicyId() != null )
155             {
156                 try
157                 {
158                     suggestedName =
159                         resolveSuggestedName( releaseDescriptor.getProjectNamingPolicyId(), releaseVersion, project );
160                 }
161                 catch ( PolicyException e )
162                 {
163                     throw new ReleaseExecutionException( e.getMessage(), e );
164                 }
165             }
166             else if ( scmTagNameFormat != null )
167             {
168                 Interpolator interpolator = new StringSearchInterpolator( "@{", "}" );
169                 List<String> possiblePrefixes = java.util.Arrays.asList( "project", "pom" );
170                 Properties values = new Properties();
171                 values.setProperty( "artifactId", project.getArtifactId() );
172                 values.setProperty( "groupId", project.getGroupId() );
173                 values.setProperty( "version", releaseVersion );
174                 interpolator.addValueSource( new PrefixedPropertiesValueSource( possiblePrefixes, values, true ) );
175                 RecursionInterceptor recursionInterceptor = new PrefixAwareRecursionInterceptor( possiblePrefixes );
176                 try
177                 {
178                     suggestedName = interpolator.interpolate( scmTagNameFormat, recursionInterceptor );
179                 }
180                 catch ( InterpolationException e )
181                 {
182                     throw new ReleaseExecutionException(
183                         "Could not interpolate specified tag name format: " + scmTagNameFormat, e );
184                 }
185             }
186             else
187             {
188                 try
189                 {
190                     suggestedName = resolveSuggestedName( defaultNamingPolicy, releaseVersion, project );
191                 }
192                 catch ( PolicyException e )
193                 {
194                     throw new ReleaseExecutionException( e.getMessage(), e );
195                 }
196             }
197 
198             ScmProvider provider = null;
199             try
200             {
201                 provider = getScmProvider( releaseDescriptor, releaseEnvironment );
202             }
203             catch ( ReleaseScmRepositoryException e )
204             {
205                 throw new ReleaseExecutionException(
206                     "No scm provider can be found for url: " + releaseDescriptor.getScmSourceUrl(), e );
207             }
208 
209             suggestedName = provider.sanitizeTagName( suggestedName );
210 
211             if ( releaseDescriptor.isInteractive() )
212             {
213                 try
214                 {
215                     if ( branchOperation )
216                     {
217                         tag = prompter.prompt( "What is the branch name for \"" + project.getName() + "\"? ("
218                             + project.getGroupId() + ":" + project.getArtifactId() + ")" );
219                         if ( StringUtils.isEmpty( tag ) )
220                         {
221                             throw new ReleaseExecutionException( "No branch name was given." );
222                         }
223                     }
224                     else
225                     {
226                         tag = prompter.prompt( "What is the SCM release tag or label for \"" + project.getName()
227                             + "\"? (" + project.getGroupId() + ":" + project.getArtifactId() + ")", suggestedName );
228                     }
229                 }
230                 catch ( PrompterException e )
231                 {
232                     throw new ReleaseExecutionException( "Error reading version from input handler: " + e.getMessage(),
233                                                          e );
234                 }
235             }
236             else if ( suggestedName == null )
237             {
238                 if ( isBranchOperation() )
239                 {
240                     throw new ReleaseExecutionException( "No branch name was given." );
241                 }
242                 else
243                 {
244                     throw new ReleaseExecutionException( "No tag name was given." );
245                 }
246             }
247             else
248             {
249                 tag = suggestedName;
250             }
251             releaseDescriptor.setScmReleaseLabel( tag );
252         }
253 
254         result.setResultCode( ReleaseResult.SUCCESS );
255 
256         return result;
257     }
258 
259     @Override
260     public ReleaseResult simulate( ReleaseDescriptor releaseDescriptor, ReleaseEnvironment releaseEnvironment,
261                                    List<MavenProject> reactorProjects )
262         throws ReleaseExecutionException
263     {
264         ReleaseResult result = new ReleaseResult();
265 
266         // It makes no modifications, so simulate is the same as execute
267         execute( releaseDescriptor, releaseEnvironment, reactorProjects );
268 
269         result.setResultCode( ReleaseResult.SUCCESS );
270 
271         return result;
272     }
273 
274     private String resolveSuggestedName( String policyId, String version, MavenProject project )
275         throws PolicyException
276     {
277         if ( policyId == null )
278         {
279             return null;
280         }
281 
282         NamingPolicy policy = namingPolicies.get( policyId );
283         if ( policy == null )
284         {
285             throw new PolicyException( "Policy '" + policyId + "' is unknown, available: "
286                 + namingPolicies.keySet() );
287         }
288 
289         NamingPolicyRequest request = new NamingPolicyRequest()
290                         .setGroupId( project.getGroupId() )
291                         .setArtifactId( project.getArtifactId() )
292                         .setVersion( version );
293         return policy.getName( request ).getName();
294     }
295 }