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