1 package org.apache.continuum.buildagent.taskqueue.execution;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.Date;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26
27 import org.apache.continuum.buildagent.buildcontext.BuildContext;
28 import org.apache.continuum.buildagent.configuration.BuildAgentConfigurationService;
29 import org.apache.continuum.buildagent.manager.BuildAgentManager;
30 import org.apache.continuum.buildagent.taskqueue.PrepareBuildProjectsTask;
31 import org.apache.continuum.buildagent.utils.BuildContextToBuildDefinition;
32 import org.apache.continuum.buildagent.utils.BuildContextToProject;
33 import org.apache.continuum.buildagent.utils.ContinuumBuildAgentUtil;
34 import org.apache.maven.continuum.ContinuumException;
35 import org.apache.maven.continuum.model.project.BuildDefinition;
36 import org.apache.maven.continuum.model.project.Project;
37 import org.apache.maven.continuum.model.scm.ChangeSet;
38 import org.apache.maven.continuum.model.scm.ScmResult;
39 import org.apache.maven.continuum.project.ContinuumProjectState;
40 import org.codehaus.plexus.action.ActionManager;
41 import org.codehaus.plexus.action.ActionNotFoundException;
42 import org.codehaus.plexus.taskqueue.Task;
43 import org.codehaus.plexus.taskqueue.execution.TaskExecutionException;
44 import org.codehaus.plexus.taskqueue.execution.TaskExecutor;
45 import org.codehaus.plexus.util.StringUtils;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49
50
51
52
53 public class PrepareBuildProjectsTaskExecutor
54 implements TaskExecutor
55 {
56 private static final Logger log = LoggerFactory.getLogger( PrepareBuildProjectsTaskExecutor.class );
57
58
59
60
61 private ActionManager actionManager;
62
63
64
65
66 private BuildAgentConfigurationService buildAgentConfigurationService;
67
68
69
70
71 private BuildAgentManager buildAgentManager;
72
73 public void executeTask( Task task )
74 throws TaskExecutionException
75 {
76 List<BuildContext> buildContexts = ( (PrepareBuildProjectsTask) task ).getBuildContexts();
77
78 Map<String, Object> context = null;
79
80 if ( buildContexts != null && buildContexts.size() > 0 )
81 {
82 try
83 {
84 for ( BuildContext buildContext : buildContexts )
85 {
86 BuildDefinition buildDef = BuildContextToBuildDefinition.getBuildDefinition( buildContext );
87
88 log.info( "Check scm root state" );
89 if ( !checkProjectScmRoot( context ) )
90 {
91 break;
92 }
93
94 log.info( "Starting prepare build" );
95 startPrepareBuild( buildContext );
96
97 log.info( "Initializing prepare build" );
98 initializeActionContext( buildContext );
99
100 try
101 {
102 if ( buildDef.isBuildFresh() )
103 {
104 log.info( "Clean up working directory" );
105 cleanWorkingDirectory( buildContext );
106 }
107
108 log.info( "Updating working directory" );
109 updateWorkingDirectory( buildContext );
110
111 log.info( "Merging SCM results" );
112
113 if ( !buildDef.isBuildFresh() )
114 {
115 mergeScmResults( buildContext );
116 }
117 }
118 finally
119 {
120 endProjectPrepareBuild( buildContext );
121 context = buildContext.getActionContext();
122 }
123 }
124 }
125 finally
126 {
127 endPrepareBuild( context );
128 }
129
130 if ( checkProjectScmRoot( context ) )
131 {
132 buildProjects( buildContexts );
133 }
134 }
135 else
136 {
137 throw new TaskExecutionException( "No project build context" );
138 }
139 }
140
141 private void startPrepareBuild( BuildContext buildContext )
142 throws TaskExecutionException
143 {
144 Map<String, Object> actionContext = buildContext.getActionContext();
145
146 if ( actionContext == null ||
147 !( ContinuumBuildAgentUtil.getScmRootState( actionContext ) == ContinuumProjectState.UPDATING ) )
148 {
149 Map<String, Object> map = new HashMap<String, Object>();
150 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_GROUP_ID, buildContext.getProjectGroupId() );
151 map.put( ContinuumBuildAgentUtil.KEY_SCM_ROOT_ADDRESS, buildContext.getScmRootAddress() );
152
153 try
154 {
155 buildAgentManager.startPrepareBuild( map );
156 }
157 catch ( ContinuumException e )
158 {
159 throw new TaskExecutionException( e.getMessage(), e );
160 }
161 }
162 }
163
164 private void initializeActionContext( BuildContext buildContext )
165 {
166 Map<String, Object> actionContext = new HashMap<String, Object>();
167
168 actionContext.put( ContinuumBuildAgentUtil.KEY_PROJECT_ID, buildContext.getProjectId() );
169 actionContext.put( ContinuumBuildAgentUtil.KEY_PROJECT, BuildContextToProject.getProject( buildContext ) );
170 actionContext.put( ContinuumBuildAgentUtil.KEY_BUILD_DEFINITION,
171 BuildContextToBuildDefinition.getBuildDefinition( buildContext ) );
172 actionContext.put( ContinuumBuildAgentUtil.KEY_SCM_ROOT_STATE, ContinuumProjectState.UPDATING );
173 actionContext.put( ContinuumBuildAgentUtil.KEY_PROJECT_GROUP_ID, buildContext.getProjectGroupId() );
174 actionContext.put( ContinuumBuildAgentUtil.KEY_SCM_ROOT_ADDRESS, buildContext.getScmRootAddress() );
175 actionContext.put( ContinuumBuildAgentUtil.KEY_OLD_SCM_RESULT, buildContext.getOldScmResult() );
176 actionContext.put( ContinuumBuildAgentUtil.KEY_LATEST_UPDATE_DATE, buildContext.getLatestUpdateDate() );
177
178 buildContext.setActionContext( actionContext );
179 }
180
181 private boolean checkProjectScmRoot( Map<String, Object> context )
182 {
183 return !( context != null &&
184 ContinuumBuildAgentUtil.getScmRootState( context ) == ContinuumProjectState.ERROR );
185
186 }
187
188 private void cleanWorkingDirectory( BuildContext buildContext )
189 throws TaskExecutionException
190 {
191 performAction( "clean-agent-working-directory", buildContext );
192 }
193
194 private void updateWorkingDirectory( BuildContext buildContext )
195 throws TaskExecutionException
196 {
197 Map<String, Object> actionContext = buildContext.getActionContext();
198
199 performAction( "check-agent-working-directory", buildContext );
200
201 boolean workingDirectoryExists =
202 ContinuumBuildAgentUtil.getBoolean( actionContext, ContinuumBuildAgentUtil.KEY_WORKING_DIRECTORY_EXISTS );
203
204 ScmResult scmResult;
205
206 Date date;
207
208 if ( workingDirectoryExists )
209 {
210 performAction( "update-agent-working-directory", buildContext );
211
212 scmResult = ContinuumBuildAgentUtil.getUpdateScmResult( actionContext, null );
213
214 date = ContinuumBuildAgentUtil.getLatestUpdateDate( actionContext );
215
216 if ( date == null )
217 {
218
219 performAction( "changelog-agent-project", buildContext );
220
221 date = ContinuumBuildAgentUtil.getLatestUpdateDate( actionContext );
222 }
223 }
224 else
225 {
226 Project project = ContinuumBuildAgentUtil.getProject( actionContext );
227
228 actionContext.put( ContinuumBuildAgentUtil.KEY_WORKING_DIRECTORY,
229 buildAgentConfigurationService.getWorkingDirectory(
230 project.getId() ).getAbsolutePath() );
231
232 performAction( "checkout-agent-project", buildContext );
233
234 scmResult = ContinuumBuildAgentUtil.getCheckoutScmResult( actionContext, null );
235
236 performAction( "changelog-agent-project", buildContext );
237
238 date = ContinuumBuildAgentUtil.getLatestUpdateDate( actionContext );
239 }
240
241 buildContext.setScmResult( scmResult );
242 buildContext.setLatestUpdateDate( date );
243 actionContext.put( ContinuumBuildAgentUtil.KEY_SCM_RESULT, scmResult );
244 }
245
246 private void endProjectPrepareBuild( BuildContext buildContext )
247 throws TaskExecutionException
248 {
249 Map<String, Object> context = buildContext.getActionContext();
250
251 ScmResult scmResult = ContinuumBuildAgentUtil.getScmResult( context, null );
252
253 if ( scmResult == null || !scmResult.isSuccess() )
254 {
255 context.put( ContinuumBuildAgentUtil.KEY_SCM_ROOT_STATE, ContinuumProjectState.ERROR );
256 }
257 else
258 {
259 buildContext.setScmResult( scmResult );
260 }
261 }
262
263 private void endPrepareBuild( Map<String, Object> context )
264 throws TaskExecutionException
265 {
266 if ( context != null )
267 {
268 Map<String, Object> result = new HashMap<String, Object>();
269 result.put( ContinuumBuildAgentUtil.KEY_PROJECT_GROUP_ID,
270 ContinuumBuildAgentUtil.getProjectGroupId( context ) );
271 result.put( ContinuumBuildAgentUtil.KEY_SCM_ROOT_ADDRESS,
272 ContinuumBuildAgentUtil.getScmRootAddress( context ) );
273 result.put( ContinuumBuildAgentUtil.KEY_SCM_ROOT_STATE,
274 ContinuumBuildAgentUtil.getScmRootState( context ) );
275
276 if ( ContinuumBuildAgentUtil.getScmRootState( context ) == ContinuumProjectState.ERROR )
277 {
278 String error = convertScmResultToError( ContinuumBuildAgentUtil.getScmResult( context, null ) );
279
280 if ( StringUtils.isEmpty( error ) )
281 {
282 result.put( ContinuumBuildAgentUtil.KEY_SCM_ERROR, "" );
283 }
284 else
285 {
286 result.put( ContinuumBuildAgentUtil.KEY_SCM_ERROR, error );
287 }
288 }
289 else
290 {
291 result.put( ContinuumBuildAgentUtil.KEY_SCM_ERROR, "" );
292 }
293
294 try
295 {
296 buildAgentManager.endPrepareBuild( result );
297 }
298 catch ( ContinuumException e )
299 {
300 throw new TaskExecutionException( e.getMessage(), e );
301 }
302 }
303 else
304 {
305 throw new TaskExecutionException( "No project build context" );
306 }
307 }
308
309 private String convertScmResultToError( ScmResult result )
310 {
311 String error = "";
312
313 if ( result == null )
314 {
315 error = "Scm result is null.";
316 }
317 else
318 {
319 if ( result.getCommandLine() != null )
320 {
321 error = "Command line: " + StringUtils.clean( result.getCommandLine() ) +
322 System.getProperty( "line.separator" );
323 }
324
325 if ( result.getProviderMessage() != null )
326 {
327 error = "Provider message: " + StringUtils.clean( result.getProviderMessage() ) +
328 System.getProperty( "line.separator" );
329 }
330
331 if ( result.getCommandOutput() != null )
332 {
333 error += "Command output: " + System.getProperty( "line.separator" );
334 error += "-------------------------------------------------------------------------------" +
335 System.getProperty( "line.separator" );
336 error += StringUtils.clean( result.getCommandOutput() ) + System.getProperty( "line.separator" );
337 error += "-------------------------------------------------------------------------------" +
338 System.getProperty( "line.separator" );
339 }
340
341 if ( result.getException() != null )
342 {
343 error += "Exception:" + System.getProperty( "line.separator" );
344 error += result.getException();
345 }
346 }
347
348 return error;
349 }
350
351 private void performAction( String actionName, BuildContext buildContext )
352 throws TaskExecutionException
353 {
354 TaskExecutionException exception;
355
356 try
357 {
358 log.info( "Performing action " + actionName );
359 actionManager.lookup( actionName ).execute( buildContext.getActionContext() );
360 return;
361 }
362 catch ( ActionNotFoundException e )
363 {
364 exception = new TaskExecutionException( "Error looking up action '" + actionName + "'", e );
365 }
366 catch ( Exception e )
367 {
368 exception = new TaskExecutionException( "Error executing action '" + actionName + "'", e );
369 }
370
371 ScmResult result = new ScmResult();
372
373 result.setSuccess( false );
374
375 result.setException( ContinuumBuildAgentUtil.throwableToString( exception ) );
376
377 buildContext.setScmResult( result );
378 buildContext.getActionContext().put( ContinuumBuildAgentUtil.KEY_UPDATE_SCM_RESULT, result );
379
380 throw exception;
381 }
382
383 private void mergeScmResults( BuildContext buildContext )
384 {
385 Map<String, Object> context = buildContext.getActionContext();
386 ScmResult oldScmResult = ContinuumBuildAgentUtil.getOldScmResult( context, null );
387 ScmResult newScmResult = ContinuumBuildAgentUtil.getScmResult( context, null );
388
389 if ( oldScmResult != null )
390 {
391 if ( newScmResult == null )
392 {
393 context.put( ContinuumBuildAgentUtil.KEY_SCM_RESULT, oldScmResult );
394 }
395 else
396 {
397 List<ChangeSet> oldChanges = oldScmResult.getChanges();
398
399 List<ChangeSet> newChanges = newScmResult.getChanges();
400
401 for ( ChangeSet change : newChanges )
402 {
403 if ( !oldChanges.contains( change ) )
404 {
405 oldChanges.add( change );
406 }
407 }
408
409 newScmResult.setChanges( oldChanges );
410 }
411 }
412 }
413
414 private void buildProjects( List<BuildContext> buildContexts )
415 throws TaskExecutionException
416 {
417 Map<String, Object> map = new HashMap<String, Object>();
418 map.put( ContinuumBuildAgentUtil.KEY_BUILD_CONTEXTS, buildContexts );
419
420 BuildContext context = new BuildContext();
421 context.setActionContext( map );
422
423 performAction( "create-agent-build-project-task", context );
424 }
425 }