1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
|
23 | |
|
24 | |
|
25 | |
|
26 | |
|
27 | |
|
28 | |
|
29 | |
|
30 | |
|
31 | |
|
32 | |
|
33 | |
|
34 | |
|
35 | |
package fr.paris.lutece.plugins.releaser.service; |
36 | |
|
37 | |
import java.io.FileInputStream; |
38 | |
import java.io.FileNotFoundException; |
39 | |
import java.io.IOException; |
40 | |
import java.text.MessageFormat; |
41 | |
import java.util.ArrayList; |
42 | |
import java.util.List; |
43 | |
import java.util.Locale; |
44 | |
import java.util.concurrent.ExecutorService; |
45 | |
import java.util.concurrent.Executors; |
46 | |
|
47 | |
import javax.servlet.http.HttpServletRequest; |
48 | |
|
49 | |
import org.apache.commons.lang.StringUtils; |
50 | |
|
51 | |
import com.fasterxml.jackson.databind.JsonNode; |
52 | |
import com.fasterxml.jackson.databind.ObjectMapper; |
53 | |
|
54 | |
import fr.paris.lutece.plugins.releaser.business.Component; |
55 | |
import fr.paris.lutece.plugins.releaser.business.ReleaserUser; |
56 | |
import fr.paris.lutece.plugins.releaser.business.WorkflowReleaseContext; |
57 | |
import fr.paris.lutece.plugins.releaser.util.ConstanteUtils; |
58 | |
import fr.paris.lutece.plugins.releaser.util.ReleaserUtils; |
59 | |
import fr.paris.lutece.plugins.releaser.util.github.GitUtils; |
60 | |
import fr.paris.lutece.plugins.releaser.util.github.GithubSearchRepoItem; |
61 | |
import fr.paris.lutece.plugins.releaser.util.github.GithubSearchResult; |
62 | |
import fr.paris.lutece.plugins.releaser.util.pom.PomParser; |
63 | |
import fr.paris.lutece.plugins.releaser.util.version.Version; |
64 | |
import fr.paris.lutece.plugins.releaser.util.version.VersionParsingException; |
65 | |
import fr.paris.lutece.portal.business.user.AdminUser; |
66 | |
import fr.paris.lutece.portal.service.datastore.DatastoreService; |
67 | |
import fr.paris.lutece.portal.service.spring.SpringContextService; |
68 | |
import fr.paris.lutece.portal.service.util.AppLogService; |
69 | |
import fr.paris.lutece.portal.service.util.AppPropertiesService; |
70 | |
import fr.paris.lutece.portal.web.util.LocalizedPaginator; |
71 | |
import fr.paris.lutece.util.html.Paginator; |
72 | |
import fr.paris.lutece.util.httpaccess.HttpAccess; |
73 | |
import fr.paris.lutece.util.httpaccess.HttpAccessException; |
74 | |
|
75 | |
|
76 | |
|
77 | |
|
78 | 1 | public class ComponentService implements IComponentService |
79 | |
{ |
80 | |
private ExecutorService _executor; |
81 | |
private ObjectMapper _mapper; |
82 | |
private static final String PROPERTY_COMPONENT_WEBSERVICE = "releaser.component.webservice.url"; |
83 | 1 | private static final String URL_COMPONENT_WEBSERVICE = AppPropertiesService.getProperty( PROPERTY_COMPONENT_WEBSERVICE ); |
84 | |
private static final String FIELD_COMPONENT = "component"; |
85 | |
private static final String FIELD_VERSION = "version"; |
86 | |
private static final String FIELD_SNAPSHOT_VERSION = "snapshot_version"; |
87 | |
|
88 | |
private static final String FIELD_JIRA_CODE = "jira_code"; |
89 | |
private static final String FIELD_ROADMAP_URL = "jira_roadmap_url"; |
90 | |
private static final String FIELD_CLOSED_ISSUES = "jira_current_version_closed_issues"; |
91 | |
private static final String FIELD_OPENED_ISSUES = "jira_current_version_opened_issues"; |
92 | |
private static final String FIELD_SCM_DEVELOPER_CONNECTION = "scm_developer_connection"; |
93 | |
private static final String RELEASE_NOT_FOUND="Release not found"; |
94 | |
|
95 | |
private static IComponentService _instance; |
96 | |
|
97 | |
public static IComponentService getService( ) |
98 | |
{ |
99 | 1 | if ( _instance == null ) |
100 | |
{ |
101 | 1 | _instance = SpringContextService.getBean( ConstanteUtils.BEAN_COMPONENT_SERVICE ); |
102 | 1 | _instance.init( ); |
103 | |
} |
104 | |
|
105 | 1 | return _instance; |
106 | |
|
107 | |
} |
108 | |
|
109 | |
public void setRemoteInformations( Component component, boolean bCache ) throws HttpAccessException, IOException |
110 | |
{ |
111 | |
try |
112 | |
{ |
113 | 0 | HttpAccess httpAccess = new HttpAccess( ); |
114 | |
String strInfosJSON; |
115 | 0 | String strUrl = MessageFormat.format( URL_COMPONENT_WEBSERVICE, component.getArtifactId( ), bCache, component.getType( ) ); |
116 | 0 | if ( component.getType( ) == null ) |
117 | |
{ |
118 | 0 | strUrl = strUrl.replace( "&type=null", "" ); |
119 | |
} |
120 | 0 | strInfosJSON = httpAccess.doGet( strUrl ); |
121 | 0 | JsonNode nodeRoot = _mapper.readTree( strInfosJSON ); |
122 | 0 | JsonNode nodeComponent = nodeRoot.path( FIELD_COMPONENT ); |
123 | |
|
124 | 0 | String strVersion= nodeComponent.get( FIELD_VERSION ).asText( ); |
125 | 0 | if(!RELEASE_NOT_FOUND.equals( strVersion )) |
126 | |
{ |
127 | 0 | component.setLastAvailableVersion( nodeComponent.get( FIELD_VERSION ).asText( ) ); |
128 | |
} |
129 | 0 | component.setLastAvailableSnapshotVersion( nodeComponent.get( FIELD_SNAPSHOT_VERSION ).asText( ) ); |
130 | 0 | component.setJiraCode( nodeComponent.get( FIELD_JIRA_CODE ).asText( ) ); |
131 | 0 | component.setJiraRoadmapUrl( nodeComponent.get( FIELD_ROADMAP_URL ).asText( ) ); |
132 | 0 | component.setJiraCurrentVersionOpenedIssues( nodeComponent.get( FIELD_OPENED_ISSUES ).asInt( ) ); |
133 | 0 | component.setJiraCurrentVersionClosedIssues( nodeComponent.get( FIELD_CLOSED_ISSUES ).asInt( ) ); |
134 | 0 | String strScmDeveloperConnection = nodeComponent.get( FIELD_SCM_DEVELOPER_CONNECTION ).asText( ); |
135 | 0 | if ( !StringUtils.isEmpty( strScmDeveloperConnection ) && !strScmDeveloperConnection.equals( "null" ) ) |
136 | |
{ |
137 | 0 | component.setScmDeveloperConnection( strScmDeveloperConnection ); |
138 | |
} |
139 | |
} |
140 | 0 | catch( HttpAccessException | IOException ex ) |
141 | |
{ |
142 | 0 | AppLogService.error( "Error getting Remote informations : " + ex.getMessage( ), ex ); |
143 | 0 | } |
144 | |
|
145 | 0 | } |
146 | |
|
147 | |
|
148 | |
|
149 | |
|
150 | |
|
151 | |
|
152 | |
public String getLastReleaseVersion( String strArtifactId ) |
153 | |
{ |
154 | |
|
155 | 0 | return DatastoreService.getDataValue( ReleaserUtils.getLastReleaseVersionDataKey( strArtifactId ), null ); |
156 | |
|
157 | |
} |
158 | |
|
159 | |
|
160 | |
|
161 | |
|
162 | |
|
163 | |
|
164 | |
public void setLastReleaseVersion( String strArtifactId, String strVersion ) |
165 | |
{ |
166 | |
|
167 | 0 | DatastoreService.setDataValue( ReleaserUtils.getLastReleaseVersionDataKey( strArtifactId ), strVersion ); |
168 | |
|
169 | 0 | } |
170 | |
|
171 | |
|
172 | |
|
173 | |
|
174 | |
|
175 | |
|
176 | |
|
177 | |
public String getLastReleaseNextSnapshotVersion( String strArtifactId ) |
178 | |
{ |
179 | |
|
180 | 0 | return DatastoreService.getDataValue( ReleaserUtils.getLastReleaseNextSnapshotVersionDataKey( strArtifactId ), null ); |
181 | |
|
182 | |
} |
183 | |
|
184 | |
|
185 | |
|
186 | |
|
187 | |
|
188 | |
|
189 | |
public void setLastReleaseNextSnapshotVersion( String strArtifactId, String strVersion ) |
190 | |
{ |
191 | |
|
192 | 0 | DatastoreService.setDataValue( ReleaserUtils.getLastReleaseNextSnapshotVersionDataKey( strArtifactId ), strVersion ); |
193 | 0 | } |
194 | |
|
195 | |
|
196 | |
|
197 | |
@Override |
198 | |
public int release( Component component, Locale locale, AdminUser user, HttpServletRequest request, boolean forceRelease ) |
199 | |
{ |
200 | |
|
201 | |
|
202 | |
|
203 | |
|
204 | 0 | if ( !forceRelease &&( !component.isProject( ) || !component.shouldBeReleased( )) ) |
205 | |
{ |
206 | 0 | return -1; |
207 | |
} |
208 | |
|
209 | 0 | WorkflowReleaseContext context = new WorkflowReleaseContext( ); |
210 | 0 | context.setComponent( component ); |
211 | 0 | context.setReleaserUser( ReleaserUtils.getReleaserUser( request, locale ) ); |
212 | |
|
213 | 0 | int nIdWorkflow = WorkflowReleaseContextService.getService( ).getIdWorkflow( context ); |
214 | 0 | WorkflowReleaseContextService.getService( ).addWorkflowReleaseContext( context ); |
215 | |
|
216 | |
|
217 | 0 | WorkflowReleaseContextService.getService( ).startWorkflowReleaseContext( context, nIdWorkflow, locale, request, user ); |
218 | |
|
219 | 0 | return context.getId( ); |
220 | |
} |
221 | |
|
222 | |
public int release( Component component, Locale locale, AdminUser user, HttpServletRequest request ) |
223 | |
{ |
224 | 0 | return release( component, locale, user, request, false ); |
225 | |
} |
226 | |
|
227 | |
public boolean isGitComponent( Component component ) |
228 | |
{ |
229 | 0 | return !StringUtils.isEmpty( component.getScmDeveloperConnection( ) ) |
230 | 0 | && component.getScmDeveloperConnection( ).trim( ).startsWith( ConstanteUtils.CONSTANTE_SUFFIX_GIT ); |
231 | |
} |
232 | |
|
233 | |
public void init( ) |
234 | |
{ |
235 | |
|
236 | 1 | _mapper = new ObjectMapper( ); |
237 | 1 | _executor = Executors.newFixedThreadPool( AppPropertiesService.getPropertyInt( ConstanteUtils.PROPERTY_THREAD_RELEASE_POOL_MAX_SIZE, 10 ) ); |
238 | |
|
239 | 1 | } |
240 | |
|
241 | |
@Override |
242 | |
public void updateRemoteInformations( Component component ) |
243 | |
{ |
244 | 0 | String strLastReleaseVersion = ComponentService.getService( ).getLastReleaseVersion( component.getArtifactId( ) ); |
245 | 0 | String strLastReleaseNextSnapshotVersion = ComponentService.getService( ).getLastReleaseNextSnapshotVersion( component.getArtifactId( ) ); |
246 | 0 | if ( component.getLastAvailableVersion( ) == null ) |
247 | |
{ |
248 | 0 | component.setLastAvailableVersion( strLastReleaseVersion ); |
249 | |
} |
250 | |
|
251 | 0 | if ( component.getLastAvailableSnapshotVersion( ) == null ) |
252 | |
{ |
253 | 0 | component.setLastAvailableVersion( strLastReleaseNextSnapshotVersion ); |
254 | |
} |
255 | |
|
256 | 0 | if ( component.getLastAvailableVersion( ) != null && strLastReleaseVersion != null ) |
257 | |
{ |
258 | |
try |
259 | |
{ |
260 | 0 | Version vLastReleaseVersion = Version.parse( strLastReleaseVersion ); |
261 | 0 | Version vLastAvailableVersion = Version.parse( component.getLastAvailableVersion( ) ); |
262 | 0 | if ( vLastReleaseVersion.compareTo( vLastAvailableVersion ) > 0 ) |
263 | |
{ |
264 | 0 | component.setLastAvailableVersion( strLastReleaseVersion ); |
265 | |
} |
266 | |
|
267 | |
} |
268 | 0 | catch( VersionParsingException e ) |
269 | |
{ |
270 | 0 | AppLogService.error( e ); |
271 | 0 | } |
272 | |
} |
273 | 0 | if ( component.getLastAvailableSnapshotVersion( ) != null && strLastReleaseNextSnapshotVersion != null ) |
274 | |
{ |
275 | |
try |
276 | |
{ |
277 | 0 | Version vLastReleaseNextSnapshotVersionVersion = Version.parse( strLastReleaseNextSnapshotVersion ); |
278 | 0 | Version vLastAvailableSnapshotVersion = Version.parse( component.getLastAvailableSnapshotVersion( ) ); |
279 | 0 | if ( vLastReleaseNextSnapshotVersionVersion.compareTo( vLastAvailableSnapshotVersion ) > 0 ) |
280 | |
{ |
281 | 0 | component.setLastAvailableSnapshotVersion( strLastReleaseNextSnapshotVersion ); |
282 | |
} |
283 | |
|
284 | |
} |
285 | 0 | catch( VersionParsingException e ) |
286 | |
{ |
287 | 0 | AppLogService.error( e ); |
288 | 0 | } |
289 | |
} |
290 | 0 | } |
291 | |
|
292 | |
public LocalizedPaginator<Component> getSearchComponent( String strSearch, HttpServletRequest request, Locale locale, String strPaginateUrl, |
293 | |
String strCurrentPageIndex ) |
294 | |
{ |
295 | |
|
296 | 0 | int nItemsPerPageLoad = AppPropertiesService.getPropertyInt( ConstanteUtils.PROPERTY_NB_SEARCH_ITEM_PER_PAGE_LOAD, 10 ); |
297 | 0 | ReleaserUser user = ReleaserUtils.getReleaserUser( request, locale ); |
298 | 0 | String strUserLogin = user.getGithubComponentAccountLogin( ); |
299 | 0 | String strUserPassword = user.getGithubComponentAccountPassword( ); |
300 | 0 | List<Component> listResult = getListComponent( |
301 | 0 | GitUtils.searchRepo( strSearch, ConstanteUtils.CONSTANTE_GITHUB_ORG_LUTECE_PLATFORM, strUserLogin, strUserPassword ), strUserLogin, |
302 | |
strUserPassword ); |
303 | 0 | listResult.addAll( getListComponent( |
304 | 0 | GitUtils.searchRepo( strSearch, ConstanteUtils.CONSTANTE_GITHUB_ORG_LUTECE_SECTEUR_PUBLIC, strUserLogin, strUserPassword ), strUserLogin, |
305 | |
strUserPassword ) ); |
306 | |
|
307 | 0 | LocalizedPaginator<Component> paginator = new LocalizedPaginator<Component>( listResult, nItemsPerPageLoad, strPaginateUrl, |
308 | |
LocalizedPaginator.PARAMETER_PAGE_INDEX, strCurrentPageIndex, locale ); |
309 | |
|
310 | 0 | for ( Component component : paginator.getPageItems( ) ) |
311 | |
{ |
312 | |
|
313 | 0 | loadComponent( component, GitUtils.getFileContent( component.getFullName( ), "pom.xml", GitUtils.DEVELOP_BRANCH, strUserLogin, strUserPassword ), |
314 | |
strUserLogin, strUserPassword ); |
315 | |
|
316 | 0 | } |
317 | |
|
318 | 0 | return paginator; |
319 | |
} |
320 | |
|
321 | |
private List<Component> getListComponent( GithubSearchResult searchResult, String strUser, String strPassword ) |
322 | |
{ |
323 | |
|
324 | 0 | List<Component> listComponent = new ArrayList<>( ); |
325 | 0 | Component component = null; |
326 | |
|
327 | 0 | if ( searchResult != null && searchResult.getListRepoItem( ) != null ) |
328 | |
{ |
329 | 0 | for ( GithubSearchRepoItem item : searchResult.getListRepoItem( ) ) |
330 | |
{ |
331 | |
|
332 | 0 | component = new Component( ); |
333 | 0 | component.setFullName( item.getFullName( ) ); |
334 | 0 | component.setName( item.getName( ) ); |
335 | 0 | listComponent.add( component ); |
336 | 0 | } |
337 | |
|
338 | |
} |
339 | 0 | return listComponent; |
340 | |
|
341 | |
} |
342 | |
|
343 | |
public Component loadComponent( Component component, String strPom, String stUser, String strPassword ) |
344 | |
{ |
345 | |
|
346 | 0 | PomParser parser = new PomParser( ); |
347 | 0 | parser.parse( component, strPom ); |
348 | |
|
349 | |
try |
350 | |
{ |
351 | 0 | ComponentService.getService( ).setRemoteInformations( component, true ); |
352 | |
|
353 | |
} |
354 | 0 | catch( HttpAccessException | IOException e ) |
355 | |
{ |
356 | 0 | AppLogService.error( e ); |
357 | 0 | } |
358 | 0 | ComponentService.getService( ).updateRemoteInformations( component ); |
359 | 0 | component.setTargetVersions( Version.getNextReleaseVersions( component.getCurrentVersion( ) ) ); |
360 | 0 | component.setTargetVersion( Version.getReleaseVersion( component.getCurrentVersion( ) ) ); |
361 | |
|
362 | 0 | String strNextSnapshotVersion = null; |
363 | |
try |
364 | |
{ |
365 | 0 | Version version = Version.parse( component.getTargetVersion( ) ); |
366 | 0 | boolean bSnapshot = true; |
367 | 0 | strNextSnapshotVersion = version.nextPatch( bSnapshot ).toString( ); |
368 | |
} |
369 | 0 | catch( VersionParsingException ex ) |
370 | |
{ |
371 | 0 | AppLogService.error( "Error parsing version for component " + component.getArtifactId( ) + " : " + ex.getMessage( ), ex ); |
372 | |
|
373 | 0 | } |
374 | 0 | component.setNextSnapshotVersion( strNextSnapshotVersion ); |
375 | 0 | component.setLastAvailableSnapshotVersion( component.getCurrentVersion( ) ); |
376 | |
|
377 | 0 | return component; |
378 | |
|
379 | |
} |
380 | |
|
381 | |
public boolean isErrorSnapshotComponentInformations( Component component ,String strComponentPomPath) |
382 | |
{ |
383 | |
|
384 | 1 | boolean bError = true; |
385 | |
|
386 | 1 | ReleaserUtils.getLocalComponentPomPath( ReleaserUtils.getGitComponentName( component.getScmDeveloperConnection( ) ) ); |
387 | 1 | PomParser parser = new PomParser( ); |
388 | 1 | Component componentPom = new Component( ); |
389 | |
|
390 | |
FileInputStream inputStream; |
391 | |
try |
392 | |
{ |
393 | 1 | inputStream = new FileInputStream( strComponentPomPath ); |
394 | 1 | parser.parse( componentPom, inputStream ); |
395 | |
|
396 | 1 | if ( component != null && componentPom != null && component.getArtifactId( ).equals( componentPom.getArtifactId( ) ) |
397 | 1 | && component.getLastAvailableSnapshotVersion( ).equals( componentPom.getCurrentVersion( ) ) ) |
398 | |
{ |
399 | |
|
400 | 0 | bError = false; |
401 | |
|
402 | |
} |
403 | |
|
404 | |
} |
405 | 0 | catch( FileNotFoundException e ) |
406 | |
{ |
407 | 0 | AppLogService.error( e ); |
408 | |
|
409 | 0 | } |
410 | |
|
411 | 0 | return bError; |
412 | |
} |
413 | |
|
414 | |
|
415 | |
|
416 | |
|
417 | |
|
418 | |
|
419 | |
|
420 | |
|
421 | |
|
422 | |
public void changeNextReleaseVersion( Component component ) |
423 | |
{ |
424 | |
|
425 | 0 | List<String> listTargetVersions = component.getTargetVersions( ); |
426 | 0 | int nNewIndex = ( component.getTargetVersionIndex( ) + 1 ) % listTargetVersions.size( ); |
427 | 0 | String strTargetVersion = listTargetVersions.get( nNewIndex ); |
428 | 0 | component.setTargetVersion( strTargetVersion ); |
429 | 0 | component.setTargetVersionIndex( nNewIndex ); |
430 | 0 | component.setNextSnapshotVersion( Version.getNextSnapshotVersion( strTargetVersion ) ); |
431 | |
|
432 | 0 | } |
433 | |
|
434 | |
|
435 | |
} |