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