1 package org.apache.continuum.builder.distributed.executor;
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.builder.utils.ContinuumBuildConstant;
23 import org.apache.continuum.dao.BuildDefinitionDao;
24 import org.apache.continuum.dao.BuildResultDao;
25 import org.apache.continuum.dao.ProjectDao;
26 import org.apache.continuum.dao.ProjectScmRootDao;
27 import org.apache.continuum.distributed.transport.slave.SlaveBuildAgentTransportClient;
28 import org.apache.continuum.model.project.ProjectScmRoot;
29 import org.apache.continuum.model.repository.LocalRepository;
30 import org.apache.continuum.taskqueue.PrepareBuildProjectsTask;
31 import org.apache.continuum.utils.ContinuumUtils;
32 import org.apache.continuum.utils.ProjectSorter;
33 import org.apache.continuum.utils.build.BuildTrigger;
34 import org.apache.maven.continuum.ContinuumException;
35 import org.apache.maven.continuum.configuration.ConfigurationService;
36 import org.apache.maven.continuum.model.project.BuildDefinition;
37 import org.apache.maven.continuum.model.project.BuildResult;
38 import org.apache.maven.continuum.model.project.Project;
39 import org.apache.maven.continuum.model.scm.ChangeFile;
40 import org.apache.maven.continuum.model.scm.ChangeSet;
41 import org.apache.maven.continuum.model.scm.ScmResult;
42 import org.apache.maven.continuum.project.ContinuumProjectState;
43 import org.apache.maven.continuum.store.ContinuumStoreException;
44 import org.codehaus.plexus.taskqueue.Task;
45 import org.codehaus.plexus.taskqueue.execution.TaskExecutionException;
46 import org.codehaus.plexus.util.StringUtils;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 import java.net.MalformedURLException;
51 import java.net.URL;
52 import java.util.ArrayList;
53 import java.util.Date;
54 import java.util.HashMap;
55 import java.util.List;
56 import java.util.Map;
57
58 public class DistributedBuildProjectTaskExecutor
59 implements DistributedBuildTaskExecutor
60 {
61 private static final Logger log = LoggerFactory.getLogger( DistributedBuildProjectTaskExecutor.class );
62
63 private String buildAgentUrl;
64
65 private long startTime;
66
67 private long endTime;
68
69
70
71
72 private ProjectDao projectDao;
73
74
75
76
77 private ProjectScmRootDao projectScmRootDao;
78
79
80
81
82 private BuildDefinitionDao buildDefinitionDao;
83
84
85
86
87 private BuildResultDao buildResultDao;
88
89
90
91
92 private ConfigurationService configurationService;
93
94 public void setBuildAgentUrl( String buildAgentUrl )
95 {
96 this.buildAgentUrl = buildAgentUrl;
97 }
98
99 public String getBuildAgentUrl()
100 {
101 return buildAgentUrl;
102 }
103
104 public void executeTask( Task task )
105 throws TaskExecutionException
106 {
107 PrepareBuildProjectsTask prepareBuildTask = (PrepareBuildProjectsTask) task;
108
109 try
110 {
111 SlaveBuildAgentTransportClient client = new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ), "",
112 configurationService.getSharedSecretPassword() );
113
114 log.info( "initializing buildContext for projectGroupId=" + prepareBuildTask.getProjectGroupId() );
115 List<Map<String, Object>> buildContext = initializeBuildContext(
116 prepareBuildTask.getProjectsBuildDefinitionsMap(), prepareBuildTask.getBuildTrigger(),
117 prepareBuildTask.getScmRootAddress(), prepareBuildTask.getProjectScmRootId() );
118
119 startTime = System.currentTimeMillis();
120 client.buildProjects( buildContext );
121 endTime = System.currentTimeMillis();
122 }
123 catch ( MalformedURLException e )
124 {
125 log.error( "Invalid URL " + buildAgentUrl + ", not building" );
126 throw new TaskExecutionException( "Invalid URL " + buildAgentUrl, e );
127 }
128 catch ( Exception e )
129 {
130 log.error( "Error occurred while building task", e );
131 endTime = System.currentTimeMillis();
132 createResult( prepareBuildTask, ContinuumUtils.throwableToString( e ) );
133 }
134 }
135
136 private List<Map<String, Object>> initializeBuildContext( Map<Integer, Integer> projectsAndBuildDefinitions,
137 BuildTrigger buildTrigger, String scmRootAddress,
138 int scmRootId )
139 throws ContinuumException
140 {
141 List<Map<String, Object>> buildContext = new ArrayList<Map<String, Object>>();
142
143 try
144 {
145 ProjectScmRoot scmRoot = projectScmRootDao.getProjectScmRoot( scmRootId );
146
147 List<Project> projects = projectDao.getProjectsWithDependenciesByGroupId(
148 scmRoot.getProjectGroup().getId() );
149 List<Project> sortedProjects = ProjectSorter.getSortedProjects( projects, null );
150
151 for ( Project project : sortedProjects )
152 {
153 if ( !projectsAndBuildDefinitions.containsKey( project.getId() ) )
154 {
155 continue;
156 }
157
158 int buildDefinitionId = projectsAndBuildDefinitions.get( project.getId() );
159 BuildDefinition buildDef = buildDefinitionDao.getBuildDefinition( buildDefinitionId );
160 BuildResult buildResult = buildResultDao.getLatestBuildResultForProject( project.getId() );
161
162 Map<String, Object> context = new HashMap<String, Object>();
163
164 context.put( ContinuumBuildConstant.KEY_PROJECT_GROUP_ID, project.getProjectGroup().getId() );
165 context.put( ContinuumBuildConstant.KEY_PROJECT_GROUP_NAME, project.getProjectGroup().getName() );
166 context.put( ContinuumBuildConstant.KEY_SCM_ROOT_ID, scmRootId );
167 context.put( ContinuumBuildConstant.KEY_SCM_ROOT_ADDRESS, scmRootAddress );
168 context.put( ContinuumBuildConstant.KEY_PROJECT_ID, project.getId() );
169 context.put( ContinuumBuildConstant.KEY_PROJECT_NAME, project.getName() );
170 context.put( ContinuumBuildConstant.KEY_PROJECT_VERSION, project.getVersion() );
171 context.put( ContinuumBuildConstant.KEY_EXECUTOR_ID, project.getExecutorId() );
172 context.put( ContinuumBuildConstant.KEY_PROJECT_BUILD_NUMBER, project.getBuildNumber() );
173 context.put( ContinuumBuildConstant.KEY_SCM_URL, project.getScmUrl() );
174 context.put( ContinuumBuildConstant.KEY_PROJECT_STATE, project.getState() );
175 if ( buildResult != null )
176 {
177 context.put( ContinuumBuildConstant.KEY_LATEST_UPDATE_DATE, new Date(
178 buildResult.getLastChangedDate() ) );
179 }
180
181 LocalRepository localRepo = project.getProjectGroup().getLocalRepository();
182
183 if ( localRepo != null )
184 {
185
186 context.put( ContinuumBuildConstant.KEY_LOCAL_REPOSITORY, localRepo.getName() );
187 }
188 else
189 {
190 context.put( ContinuumBuildConstant.KEY_LOCAL_REPOSITORY, "" );
191 }
192
193 if ( project.getScmUsername() == null )
194 {
195 context.put( ContinuumBuildConstant.KEY_SCM_USERNAME, "" );
196 }
197 else
198 {
199 context.put( ContinuumBuildConstant.KEY_SCM_USERNAME, project.getScmUsername() );
200 }
201
202 if ( project.getScmPassword() == null )
203 {
204 context.put( ContinuumBuildConstant.KEY_SCM_PASSWORD, "" );
205 }
206 else
207 {
208 context.put( ContinuumBuildConstant.KEY_SCM_PASSWORD, project.getScmPassword() );
209 }
210
211 if ( project.getScmTag() != null )
212 {
213 context.put( ContinuumBuildConstant.KEY_SCM_TAG, project.getScmTag() );
214 }
215 else
216 {
217 context.put( ContinuumBuildConstant.KEY_SCM_TAG, "" );
218 }
219
220 context.put( ContinuumBuildConstant.KEY_BUILD_DEFINITION_ID, buildDefinitionId );
221 String buildDefinitionLabel = buildDef.getDescription();
222 if ( StringUtils.isEmpty( buildDefinitionLabel ) )
223 {
224 buildDefinitionLabel = buildDef.getGoals();
225 }
226 context.put( ContinuumBuildConstant.KEY_BUILD_DEFINITION_LABEL, buildDefinitionLabel );
227
228 context.put( ContinuumBuildConstant.KEY_BUILD_FILE, buildDef.getBuildFile() );
229
230 if ( buildDef.getGoals() == null )
231 {
232 context.put( ContinuumBuildConstant.KEY_GOALS, "" );
233 }
234 else
235 {
236 context.put( ContinuumBuildConstant.KEY_GOALS, buildDef.getGoals() );
237 }
238
239 if ( buildDef.getArguments() == null )
240 {
241 context.put( ContinuumBuildConstant.KEY_ARGUMENTS, "" );
242 }
243 else
244 {
245 context.put( ContinuumBuildConstant.KEY_ARGUMENTS, buildDef.getArguments() );
246 }
247 context.put( ContinuumBuildConstant.KEY_TRIGGER, buildTrigger.getTrigger() );
248
249 if ( buildTrigger.getTrigger() == ContinuumProjectState.TRIGGER_FORCED )
250 {
251 context.put( ContinuumBuildConstant.KEY_USERNAME, buildTrigger.getTriggeredBy() );
252 }
253 else
254 {
255 context.put( ContinuumBuildConstant.KEY_USERNAME, buildDef.getSchedule().getName() );
256 }
257
258 context.put( ContinuumBuildConstant.KEY_BUILD_FRESH, buildDef.isBuildFresh() );
259 context.put( ContinuumBuildConstant.KEY_ALWAYS_BUILD, buildDef.isAlwaysBuild() );
260 context.put( ContinuumBuildConstant.KEY_OLD_SCM_CHANGES, getOldScmChanges( project.getId(),
261 buildDefinitionId ) );
262 context.put( ContinuumBuildConstant.KEY_BUILD_AGENT_URL, buildAgentUrl );
263 context.put( ContinuumBuildConstant.KEY_MAX_JOB_EXEC_TIME,
264 buildDef.getSchedule().getMaxJobExecutionTime() );
265
266 buildContext.add( context );
267 }
268
269 return buildContext;
270 }
271 catch ( ContinuumStoreException e )
272 {
273 throw new ContinuumException( "Error while initializing build context", e );
274 }
275 }
276
277 private void createResult( PrepareBuildProjectsTask task, String error )
278 throws TaskExecutionException
279 {
280 try
281 {
282 ProjectScmRoot scmRoot = projectScmRootDao.getProjectScmRootByProjectGroupAndScmRootAddress(
283 task.getProjectGroupId(), task.getScmRootAddress() );
284
285 if ( scmRoot.getState() == ContinuumProjectState.UPDATING )
286 {
287 scmRoot.setState( ContinuumProjectState.ERROR );
288 scmRoot.setError( error );
289 projectScmRootDao.updateProjectScmRoot( scmRoot );
290 }
291 else
292 {
293 Map<Integer, Integer> map = task.getProjectsBuildDefinitionsMap();
294 for ( Integer projectId : map.keySet() )
295 {
296 int buildDefinitionId = map.get( projectId );
297 Project project = projectDao.getProject( projectId );
298 BuildDefinition buildDef = buildDefinitionDao.getBuildDefinition( buildDefinitionId );
299 BuildResult latestBuildResult = buildResultDao.
300 getLatestBuildResultForBuildDefinition( projectId, buildDefinitionId );
301 if ( latestBuildResult == null ||
302 ( latestBuildResult.getStartTime() >= startTime && latestBuildResult.getEndTime() > 0 &&
303 latestBuildResult.getEndTime() < endTime ) || latestBuildResult.getStartTime() < startTime )
304 {
305 BuildResult buildResult = new BuildResult();
306 buildResult.setBuildDefinition( buildDef );
307 buildResult.setError( error );
308 buildResult.setState( ContinuumProjectState.ERROR );
309 buildResult.setTrigger( task.getBuildTrigger().getTrigger() );
310 buildResult.setUsername( task.getBuildTrigger().getTriggeredBy() );
311 buildResult.setStartTime( startTime );
312 buildResult.setEndTime( endTime );
313
314 buildResultDao.addBuildResult( project, buildResult );
315 }
316 }
317
318 }
319 }
320 catch ( ContinuumStoreException e )
321 {
322 throw new TaskExecutionException( "Error while creating result", e );
323 }
324 }
325
326 private List<Map<String, Object>> getOldScmChanges( int projectId, int buildDefinitionId )
327 throws ContinuumStoreException
328 {
329 List<Map<String, Object>> scmChanges = new ArrayList<Map<String, Object>>();
330
331 BuildResult oldBuildResult = buildResultDao.getLatestBuildResultForBuildDefinition( projectId,
332 buildDefinitionId );
333
334 if ( oldBuildResult != null )
335 {
336 ScmResult scmResult = getOldScmResults( projectId, oldBuildResult.getBuildNumber(),
337 oldBuildResult.getEndTime() );
338
339 scmChanges = getScmChanges( scmResult );
340 }
341
342 return scmChanges;
343 }
344
345 private List<Map<String, Object>> getScmChanges( ScmResult scmResult )
346 {
347 List<Map<String, Object>> scmChanges = new ArrayList<Map<String, Object>>();
348
349 if ( scmResult != null && scmResult.getChanges() != null )
350 {
351 for ( Object obj : scmResult.getChanges() )
352 {
353 ChangeSet changeSet = (ChangeSet) obj;
354
355 Map<String, Object> map = new HashMap<String, Object>();
356 if ( StringUtils.isNotEmpty( changeSet.getAuthor() ) )
357 {
358 map.put( ContinuumBuildConstant.KEY_CHANGESET_AUTHOR, changeSet.getAuthor() );
359 }
360 else
361 {
362 map.put( ContinuumBuildConstant.KEY_CHANGESET_AUTHOR, "" );
363 }
364 if ( StringUtils.isNotEmpty( changeSet.getComment() ) )
365 {
366 map.put( ContinuumBuildConstant.KEY_CHANGESET_COMMENT, changeSet.getComment() );
367 }
368 else
369 {
370 map.put( ContinuumBuildConstant.KEY_CHANGESET_COMMENT, "" );
371 }
372 if ( changeSet.getDateAsDate() != null )
373 {
374 map.put( ContinuumBuildConstant.KEY_CHANGESET_DATE, changeSet.getDateAsDate() );
375 }
376 map.put( ContinuumBuildConstant.KEY_CHANGESET_FILES, getScmChangeFiles( changeSet.getFiles() ) );
377 scmChanges.add( map );
378 }
379 }
380
381 return scmChanges;
382 }
383
384 private List<Map<String, String>> getScmChangeFiles( List<ChangeFile> files )
385 {
386 List<Map<String, String>> scmChangeFiles = new ArrayList<Map<String, String>>();
387
388 if ( files != null )
389 {
390 for ( ChangeFile changeFile : files )
391 {
392 Map<String, String> map = new HashMap<String, String>();
393
394 if ( StringUtils.isNotEmpty( changeFile.getName() ) )
395 {
396 map.put( ContinuumBuildConstant.KEY_CHANGEFILE_NAME, changeFile.getName() );
397 }
398 else
399 {
400 map.put( ContinuumBuildConstant.KEY_CHANGEFILE_NAME, "" );
401 }
402 if ( StringUtils.isNotEmpty( changeFile.getRevision() ) )
403 {
404 map.put( ContinuumBuildConstant.KEY_CHANGEFILE_REVISION, changeFile.getRevision() );
405 }
406 else
407 {
408 map.put( ContinuumBuildConstant.KEY_CHANGEFILE_REVISION, "" );
409 }
410 if ( StringUtils.isNotEmpty( changeFile.getStatus() ) )
411 {
412 map.put( ContinuumBuildConstant.KEY_CHANGEFILE_STATUS, changeFile.getStatus() );
413 }
414 else
415 {
416 map.put( ContinuumBuildConstant.KEY_CHANGEFILE_STATUS, "" );
417 }
418 scmChangeFiles.add( map );
419 }
420 }
421 return scmChangeFiles;
422 }
423
424 private ScmResult getOldScmResults( int projectId, long startId, long fromDate )
425 throws ContinuumStoreException
426 {
427 List<BuildResult> results = buildResultDao.getBuildResultsForProjectFromId( projectId, startId );
428
429 ScmResult res = new ScmResult();
430
431 if ( results != null && results.size() > 0 )
432 {
433 for ( BuildResult result : results )
434 {
435 ScmResult scmResult = result.getScmResult();
436
437 if ( scmResult != null )
438 {
439 List<ChangeSet> changes = scmResult.getChanges();
440
441 if ( changes != null )
442 {
443 for ( ChangeSet changeSet : changes )
444 {
445 if ( changeSet.getDate() < fromDate )
446 {
447 continue;
448 }
449 if ( !res.getChanges().contains( changeSet ) )
450 {
451 res.addChange( changeSet );
452 }
453 }
454 }
455 }
456 }
457 }
458
459 return res;
460 }
461 }