View Javadoc

1   package org.apache.continuum.buildagent.action;
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 org.apache.continuum.buildagent.configuration.BuildAgentConfigurationService;
23  import org.apache.continuum.buildagent.utils.ContinuumBuildAgentUtil;
24  import org.apache.continuum.scm.ContinuumScm;
25  import org.apache.continuum.scm.ContinuumScmConfiguration;
26  import org.apache.continuum.scm.ContinuumScmUtils;
27  import org.apache.maven.continuum.model.project.Project;
28  import org.apache.maven.continuum.model.scm.ChangeFile;
29  import org.apache.maven.continuum.model.scm.ChangeSet;
30  import org.apache.maven.continuum.model.scm.ScmResult;
31  import org.apache.maven.scm.ScmException;
32  import org.apache.maven.scm.ScmFile;
33  import org.apache.maven.scm.command.update.UpdateScmResult;
34  import org.apache.maven.scm.manager.NoSuchScmProviderException;
35  import org.apache.maven.scm.repository.ScmRepositoryException;
36  import org.codehaus.plexus.action.AbstractAction;
37  
38  import java.io.File;
39  import java.util.Date;
40  import java.util.Iterator;
41  import java.util.List;
42  import java.util.Map;
43  
44  /**
45   * @plexus.component role="org.codehaus.plexus.action.Action" role-hint="update-agent-working-directory"
46   */
47  public class UpdateWorkingDirectoryAction
48      extends AbstractAction
49  {
50      /**
51       * @plexus.requirement
52       */
53      private BuildAgentConfigurationService buildAgentConfigurationService;
54  
55      /**
56       * @plexus.requirement
57       */
58      private ContinuumScm scm;
59  
60      public void execute( Map context )
61          throws Exception
62      {
63          Project project = ContinuumBuildAgentUtil.getProject( context );
64  
65          UpdateScmResult scmResult;
66  
67          ScmResult result;
68  
69          try
70          {
71              File workingDirectory = buildAgentConfigurationService.getWorkingDirectory( project.getId() );
72              ContinuumScmConfiguration config = createScmConfiguration( project, workingDirectory );
73              config.setLatestUpdateDate( ContinuumBuildAgentUtil.getLatestUpdateDate( context ) );
74              String tag = config.getTag();
75              String msg = project.getName() + "', id: '" + project.getId() + "' to '" +
76                  workingDirectory.getAbsolutePath() + "'" + ( tag != null ? " with branch/tag " + tag + "." : "." );
77              getLogger().info( "Updating project: " + msg );
78              scmResult = scm.update( config );
79  
80              if ( !scmResult.isSuccess() )
81              {
82                  getLogger().warn( "Error while updating the code for project: '" + msg );
83  
84                  getLogger().warn( "Command output: " + scmResult.getCommandOutput() );
85  
86                  getLogger().warn( "Provider message: " + scmResult.getProviderMessage() );
87              }
88  
89              if ( scmResult.getUpdatedFiles() != null && scmResult.getUpdatedFiles().size() > 0 )
90              {
91                  getLogger().info( "Updated " + scmResult.getUpdatedFiles().size() + " files." );
92              }
93  
94              result = convertScmResult( scmResult );
95          }
96          catch ( ScmRepositoryException e )
97          {
98              result = new ScmResult();
99  
100             result.setSuccess( false );
101 
102             result.setProviderMessage( e.getMessage() + ": " + getValidationMessages( e ) );
103 
104             getLogger().error( e.getMessage(), e );
105         }
106         catch ( NoSuchScmProviderException e )
107         {
108             // TODO: this is not making it back into a result of any kind - log it at least. Same is probably the case for ScmException
109             result = new ScmResult();
110 
111             result.setSuccess( false );
112 
113             result.setProviderMessage( e.getMessage() );
114 
115             getLogger().error( e.getMessage(), e );
116         }
117         catch ( ScmException e )
118         {
119             result = new ScmResult();
120 
121             result.setSuccess( false );
122 
123             result.setException( ContinuumBuildAgentUtil.throwableMessagesToString( e ) );
124 
125             getLogger().error( e.getMessage(), e );
126         }
127 
128         context.put( ContinuumBuildAgentUtil.KEY_UPDATE_SCM_RESULT, result );
129 
130         Date latestUpdateDate = getLatestUpdateDate( result );
131 
132         if ( latestUpdateDate == null )
133         {
134             latestUpdateDate = ContinuumBuildAgentUtil.getLatestUpdateDate( context );
135         }
136 
137         context.put( ContinuumBuildAgentUtil.KEY_LATEST_UPDATE_DATE, latestUpdateDate );
138     }
139 
140     private ContinuumScmConfiguration createScmConfiguration( Project project, File workingDirectory )
141     {
142         ContinuumScmConfiguration config = new ContinuumScmConfiguration();
143         config.setUrl( project.getScmUrl() );
144 
145         // CONTINUUM-2628
146         config = ContinuumScmUtils.setSCMCredentialsforSSH( config, project.getScmUrl(), project.getScmUsername(),
147                                                             project.getScmPassword() );
148 
149         config.setUseCredentialsCache( project.isScmUseCache() );
150         config.setWorkingDirectory( workingDirectory );
151         config.setTag( project.getScmTag() );
152         return config;
153     }
154 
155     private ScmResult convertScmResult( UpdateScmResult scmResult )
156     {
157         ScmResult result = new ScmResult();
158 
159         result.setCommandLine( maskPassword( scmResult.getCommandLine() ) );
160 
161         result.setSuccess( scmResult.isSuccess() );
162 
163         result.setCommandOutput( scmResult.getCommandOutput() );
164 
165         result.setProviderMessage( scmResult.getProviderMessage() );
166 
167         if ( scmResult.getChanges() != null && !scmResult.getChanges().isEmpty() )
168         {
169             for ( org.apache.maven.scm.ChangeSet scmChangeSet : (List<org.apache.maven.scm.ChangeSet>) scmResult.getChanges() )
170             {
171                 ChangeSet change = new ChangeSet();
172 
173                 change.setAuthor( scmChangeSet.getAuthor() );
174 
175                 change.setComment( scmChangeSet.getComment() );
176 
177                 if ( scmChangeSet.getDate() != null )
178                 {
179                     change.setDate( scmChangeSet.getDate().getTime() );
180                 }
181 
182                 if ( scmChangeSet.getFiles() != null )
183                 {
184                     for ( org.apache.maven.scm.ChangeFile f : (List<org.apache.maven.scm.ChangeFile>) scmChangeSet.getFiles() )
185                     {
186                         ChangeFile file = new ChangeFile();
187 
188                         file.setName( f.getName() );
189 
190                         file.setRevision( f.getRevision() );
191 
192                         change.addFile( file );
193                     }
194                 }
195 
196                 result.addChange( change );
197             }
198         }
199         else
200         {
201             // We don't have a changes information probably because provider doesn't have a changelog command
202             // so we use the updated list that contains only the updated files list
203             ChangeSet changeSet = convertScmFileSetToChangeSet( scmResult.getUpdatedFiles() );
204 
205             if ( changeSet != null )
206             {
207                 result.addChange( changeSet );
208             }
209         }
210         return result;
211     }
212 
213     private static ChangeSet convertScmFileSetToChangeSet( List<ScmFile> files )
214     {
215         ChangeSet changeSet = null;
216 
217         if ( files != null && !files.isEmpty() )
218         {
219             changeSet = new ChangeSet();
220 
221             // TODO: author, etc.
222             for ( ScmFile scmFile : files )
223             {
224                 ChangeFile file = new ChangeFile();
225 
226                 file.setName( scmFile.getPath() );
227 
228                 // TODO: revision?
229 
230                 file.setStatus( scmFile.getStatus().toString() );
231 
232                 changeSet.addFile( file );
233             }
234         }
235         return changeSet;
236     }
237 
238     // TODO: migrate to the SvnCommandLineUtils version (preferably properly encapsulated in the provider)
239     private String maskPassword( String commandLine )
240     {
241         String cmd = commandLine;
242 
243         if ( cmd != null && cmd.startsWith( "svn" ) )
244         {
245             String pwdString = "--password";
246 
247             if ( cmd.indexOf( pwdString ) > 0 )
248             {
249                 int index = cmd.indexOf( pwdString ) + pwdString.length() + 1;
250 
251                 int nextSpace = cmd.indexOf( " ", index );
252 
253                 cmd = cmd.substring( 0, index ) + "********" + cmd.substring( nextSpace );
254             }
255         }
256 
257         return cmd;
258     }
259 
260     private String getValidationMessages( ScmRepositoryException ex )
261     {
262         List<String> messages = ex.getValidationMessages();
263 
264         StringBuffer message = new StringBuffer();
265 
266         if ( messages != null && !messages.isEmpty() )
267         {
268             for ( Iterator<String> i = messages.iterator(); i.hasNext(); )
269             {
270                 message.append( i.next() );
271 
272                 if ( i.hasNext() )
273                 {
274                     message.append( System.getProperty( "line.separator" ) );
275                 }
276             }
277         }
278         return message.toString();
279     }
280 
281     private Date getLatestUpdateDate( ScmResult result )
282     {
283         List<ChangeSet> changes = result.getChanges();
284 
285         if ( changes != null && !changes.isEmpty() )
286         {
287             long date = 0;
288 
289             for ( ChangeSet change : changes )
290             {
291                 if ( date < change.getDate() )
292                 {
293                     date = change.getDate();
294                 }
295             }
296 
297             if ( date != 0 )
298             {
299                 return new Date( date );
300             }
301         }
302 
303         return null;
304     }
305 }