Coverage Report - fr.paris.lutece.plugins.releaser.service.ComponentService
 
Classes in this File Line Coverage Branch Coverage Complexity
ComponentService
12 %
17/134
7 %
4/52
3
 
 1  
 /*
 2  
  * Copyright (c) 2002-2017, Mairie de Paris
 3  
  * All rights reserved.
 4  
  *
 5  
  * Redistribution and use in source and binary forms, with or without
 6  
  * modification, are permitted provided that the following conditions
 7  
  * are met:
 8  
  *
 9  
  *  1. Redistributions of source code must retain the above copyright notice
 10  
  *     and the following disclaimer.
 11  
  *
 12  
  *  2. Redistributions in binary form must reproduce the above copyright notice
 13  
  *     and the following disclaimer in the documentation and/or other materials
 14  
  *     provided with the distribution.
 15  
  *
 16  
  *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
 17  
  *     contributors may be used to endorse or promote products derived from
 18  
  *     this software without specific prior written permission.
 19  
  *
 20  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 21  
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 22  
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 23  
  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 24  
  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 25  
  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 26  
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 27  
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 28  
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 29  
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 30  
  * POSSIBILITY OF SUCH DAMAGE.
 31  
  *
 32  
  * License 1.0
 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  
  * ComponentService
 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  
      * Returns the LastAvailableVersion
 149  
      * 
 150  
      * @return The LastAvailableVersion
 151  
      */
 152  
     public String getLastReleaseVersion( String strArtifactId )
 153  
     {
 154  
 
 155  0
         return DatastoreService.getDataValue( ReleaserUtils.getLastReleaseVersionDataKey( strArtifactId ), null );
 156  
 
 157  
     }
 158  
 
 159  
     /**
 160  
      * set the LastAvailableVersion
 161  
      * 
 162  
      * set The LastAvailableVersion
 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  
      * Returns the LastAvailableVersion
 174  
      * 
 175  
      * @return The LastAvailableVersion
 176  
      */
 177  
     public String getLastReleaseNextSnapshotVersion( String strArtifactId )
 178  
     {
 179  
 
 180  0
         return DatastoreService.getDataValue( ReleaserUtils.getLastReleaseNextSnapshotVersionDataKey( strArtifactId ), null );
 181  
 
 182  
     }
 183  
 
 184  
     /**
 185  
      * set the LastAvailableVersion
 186  
      * 
 187  
      * set The LastAvailableVersion
 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  
         // Test if version already exist before release
 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  
         // Compare Latest vesion of component before rekease
 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  
             // Load only information on the current page
 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  
      * Change the next release version
 416  
      * 
 417  
      * @param site
 418  
      *            The site
 419  
      * @param strArtifactId
 420  
      *            The component artifact id
 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  
 }