1 package fr.paris.lutece.plugins.deployment.util.vcs; 2 3 import fr.paris.lutece.plugins.deployment.business.CommandResult; 4 import fr.paris.lutece.plugins.deployment.business.vcs.GitUser; 5 import fr.paris.lutece.plugins.deployment.util.DeploymentUtils; 6 import java.io.File; 7 import java.io.IOException; 8 import java.util.Iterator; 9 import java.util.List; 10 11 import org.eclipse.jgit.api.CloneCommand; 12 import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode; 13 import org.eclipse.jgit.api.Git; 14 import org.eclipse.jgit.api.MergeResult; 15 import org.eclipse.jgit.api.PullResult; 16 import org.eclipse.jgit.api.errors.CanceledException; 17 import org.eclipse.jgit.api.errors.CheckoutConflictException; 18 import org.eclipse.jgit.api.errors.DetachedHeadException; 19 import org.eclipse.jgit.api.errors.GitAPIException; 20 import org.eclipse.jgit.api.errors.InvalidConfigurationException; 21 import org.eclipse.jgit.api.errors.InvalidRefNameException; 22 import org.eclipse.jgit.api.errors.InvalidRemoteException; 23 import org.eclipse.jgit.api.errors.NoHeadException; 24 import org.eclipse.jgit.api.errors.RefAlreadyExistsException; 25 import org.eclipse.jgit.api.errors.RefNotFoundException; 26 import org.eclipse.jgit.api.errors.TransportException; 27 import org.eclipse.jgit.api.errors.WrongRepositoryStateException; 28 import org.eclipse.jgit.lib.Ref; 29 import org.eclipse.jgit.lib.Repository; 30 import org.eclipse.jgit.revwalk.RevCommit; 31 import org.eclipse.jgit.storage.file.FileRepositoryBuilder; 32 import org.eclipse.jgit.transport.RefSpec; 33 import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; 34 35 import fr.paris.lutece.portal.service.util.AppLogService; 36 import fr.paris.lutece.util.httpaccess.HttpAccess; 37 import fr.paris.lutece.util.httpaccess.HttpAccessException; 38 import fr.paris.lutece.util.signrequest.BasicAuthorizationAuthenticator; 39 import java.nio.file.Files; 40 import java.nio.file.Path; 41 import java.nio.file.Paths; 42 import java.util.ArrayList; 43 import java.util.Collection; 44 import org.apache.commons.io.FileUtils; 45 46 public class GitUtils 47 { 48 49 public static final String MASTER_BRANCH = "master"; 50 public static final String DEVELOP_BRANCH = "develop"; 51 private static final String CONSTANTE_REF_TAG = "refs/tags/"; 52 53 public static Collection<String> getTagNameList( Git git ) 54 { 55 List<String> listTagName = new ArrayList<>( ); 56 Collection<Ref> colTags = git.getRepository( ).getTags( ).values( ); 57 for ( Ref ref : colTags ) 58 { 59 listTagName.add( ref.getName( ).replace( CONSTANTE_REF_TAG, "" ) ); 60 } 61 return listTagName; 62 63 } 64 65 public static Git cloneOrReturnGit( String sClonePath, String sRepoURL, CommandResult commandResult, GitUser user, String strBranch, String strTagName ) 66 { 67 Git git = null; 68 Repository repository = null; 69 try 70 { 71 FileRepositoryBuilder builder = new FileRepositoryBuilder( ); 72 File fGitDir = new File( sClonePath ); 73 74 File gitFile = new File( sClonePath + "/.git" ); 75 repository = builder.setGitDir( fGitDir ).readEnvironment( ).findGitDir( ).build( ); 76 77 if ( gitFile.exists( ) ) 78 { 79 git = Git.open( gitFile ); 80 checkout( git, strBranch, strTagName, commandResult ); 81 return git; 82 } 83 84 CloneCommand clone = Git.cloneRepository( ).setBare( false ).setCloneAllBranches( true ).setDirectory( fGitDir ).setURI( getRepoUrl( sRepoURL ) ); 85 86 if ( user.getLogin( ) != null && user.getPassword( ) != null ) 87 { 88 clone.setCredentialsProvider( new UsernamePasswordCredentialsProvider( user.getLogin( ), user.getPassword( ) ) ); 89 } 90 git = clone.call( ); 91 92 createLocalBranch( git, DEVELOP_BRANCH, commandResult ); 93 createLocalBranch( git, MASTER_BRANCH, commandResult ); 94 repository.getConfig( ).setString( "user", null, "name", user.getLogin( ) ); 95 repository.getConfig( ).save( ); 96 97 } 98 catch( InvalidRemoteException e ) 99 { 100 101 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 102 103 } 104 catch( TransportException e ) 105 { 106 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 107 108 } 109 catch( IOException e ) 110 { 111 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 112 } 113 catch( GitAPIException e ) 114 { 115 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 116 } 117 finally 118 { 119 repository.close( ); 120 } 121 return git; 122 123 } 124 125 public static void checkoutRepoBranch( Git git, String sBranchName, CommandResult commandResult ) 126 { 127 try 128 { 129 git.checkout( ).setName( sBranchName ).setForce( true ).call( ); 130 } 131 catch( InvalidRemoteException e ) 132 { 133 134 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 135 136 } 137 catch( TransportException e ) 138 { 139 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 140 141 } 142 143 catch( GitAPIException e ) 144 { 145 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 146 } 147 148 } 149 150 public static void createLocalBranch( Git git, String sBranchName, CommandResult commandResult ) 151 { 152 try 153 { 154 git.branchCreate( ).setName( sBranchName ).setUpstreamMode( SetupUpstreamMode.SET_UPSTREAM ).setStartPoint( "origin/" + sBranchName ) 155 .setForce( true ).call( ); 156 } 157 catch( InvalidRemoteException e ) 158 { 159 160 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 161 162 } 163 catch( TransportException e ) 164 { 165 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 166 167 } 168 169 catch( GitAPIException e ) 170 { 171 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 172 } 173 174 } 175 176 public static String getRefBranch( Git git, String sBranchName, CommandResult commandResult ) 177 { 178 179 String refLastCommit = null; 180 try 181 { 182 git.checkout( ).setName( sBranchName ).call( ); 183 refLastCommit = getLastCommitId( git ); 184 } 185 186 catch( RefAlreadyExistsException e ) 187 { 188 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 189 } 190 catch( RefNotFoundException e ) 191 { 192 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 193 } 194 catch( InvalidRefNameException e ) 195 { 196 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 197 } 198 catch( CheckoutConflictException e ) 199 { 200 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 201 } 202 catch( GitAPIException e ) 203 { 204 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 205 } 206 return refLastCommit; 207 } 208 209 public static void pushForce( Git git, String strRefSpec, String strUserName, String strPassword ) throws InvalidRemoteException, TransportException, 210 GitAPIException 211 { 212 213 git.push( ).setRemote( "origin" ).setRefSpecs( new RefSpec( strRefSpec ) ).setForce( true ) 214 .setCredentialsProvider( new UsernamePasswordCredentialsProvider( strUserName, strPassword ) ).call( ); 215 216 } 217 218 public static PullResult pullRepoBranch( Git git, String sRepoURL, String sBranchName ) throws IOException, WrongRepositoryStateException, 219 InvalidConfigurationException, DetachedHeadException, InvalidRemoteException, CanceledException, RefNotFoundException, NoHeadException, 220 TransportException, GitAPIException 221 { 222 PullResult pPullResult = git.pull( ).call( ); 223 return pPullResult; 224 } 225 226 public static MergeResult mergeRepoBranch( Git git, String strBranchToMerge ) throws IOException, WrongRepositoryStateException, 227 InvalidConfigurationException, DetachedHeadException, InvalidRemoteException, CanceledException, RefNotFoundException, NoHeadException, 228 TransportException, GitAPIException 229 { 230 List<Ref> call = git.branchList( ).call( ); 231 Ref mergedBranchRef = null; 232 for ( Ref ref : call ) 233 { 234 if ( ref.getName( ).equals( "refs/heads/" + strBranchToMerge ) ) 235 { 236 mergedBranchRef = ref; 237 break; 238 } 239 } 240 MergeResult mergeResult = git.merge( ).include( mergedBranchRef ).call( ); 241 return mergeResult; 242 } 243 244 public static String getLastLog( Git git, int nMaxCommit ) throws NoHeadException, GitAPIException 245 { 246 Iterable<RevCommit> logList = git.log( ).setMaxCount( 1 ).call( ); 247 Iterator i = logList.iterator( ); 248 String sCommitMessages = ""; 249 while ( i.hasNext( ) ) 250 { 251 RevCommit revCommit = (RevCommit) i.next( ); 252 sCommitMessages += revCommit.getFullMessage( ); 253 sCommitMessages += "\n"; 254 sCommitMessages += revCommit.getCommitterIdent( ); 255 } 256 return sCommitMessages; 257 } 258 259 public static String getLastCommitId( Git git ) throws NoHeadException, GitAPIException 260 { 261 Iterable<RevCommit> logList = git.log( ).setMaxCount( 1 ).call( ); 262 Iterator i = logList.iterator( ); 263 String strCommitId = null; 264 while ( i.hasNext( ) ) 265 { 266 RevCommit revCommit = (RevCommit) i.next( ); 267 strCommitId = revCommit.getName( ); 268 269 } 270 return strCommitId; 271 } 272 273 public static MergeResult mergeBack( Git git, String strUserName, String strPassword, CommandResult commandResult ) throws IOException, GitAPIException 274 { 275 276 Ref tag = getTagLinkedToLastRelease( git ); 277 278 git.checkout( ).setName( MASTER_BRANCH ).call( ); 279 List<Ref> call = git.branchList( ).call( ); 280 281 Ref mergedBranchRef = null; 282 for ( Ref ref : call ) 283 { 284 if ( ref.getName( ).equals( "refs/heads/" + DEVELOP_BRANCH ) ) 285 { 286 mergedBranchRef = ref; 287 break; 288 } 289 } 290 291 if ( tag != null ) 292 { 293 mergedBranchRef = tag; 294 } 295 MergeResult mergeResult = git.merge( ).include( mergedBranchRef ).call( ); 296 if ( mergeResult.getMergeStatus( ).equals( MergeResult.MergeStatus.CHECKOUT_CONFLICT ) 297 || mergeResult.getMergeStatus( ).equals( MergeResult.MergeStatus.CONFLICTING ) 298 || mergeResult.getMergeStatus( ).equals( MergeResult.MergeStatus.FAILED ) 299 || mergeResult.getMergeStatus( ).equals( MergeResult.MergeStatus.NOT_SUPPORTED ) ) 300 { 301 302 DeploymentUtils.addTechnicalError( commandResult, mergeResult.getMergeStatus( ).toString( ) + "\nPlease merge manually master into" 303 + DEVELOP_BRANCH + "branch." ); 304 } 305 else 306 { 307 git.push( ).setCredentialsProvider( new UsernamePasswordCredentialsProvider( strUserName, strPassword ) ).call( ); 308 commandResult.getLog( ).append( mergeResult.getMergeStatus( ) ); 309 } 310 return mergeResult; 311 312 } 313 314 public static String getFileContent( String strFullName, String strPathFile, String strBranch, String strUserName, String strPassword ) 315 { 316 HttpAccess httpAccess = new HttpAccess( ); 317 String strUrl = "https://raw.githubusercontent.com/" + strFullName + "/" + strBranch + "/" + strPathFile; 318 String strResponse = ""; 319 320 try 321 { 322 strResponse = httpAccess.doGet( strUrl, new BasicAuthorizationAuthenticator( strUserName, strPassword ), null ); 323 } 324 catch( HttpAccessException ex ) 325 { 326 AppLogService.error( ex ); 327 } 328 329 return strResponse; 330 } 331 332 private static Ref getTagLinkedToLastRelease( Git git ) throws GitAPIException 333 { 334 final String TOKEN = "[maven-release-plugin] prepare release "; 335 Ref res = null; 336 String sTagName = null; 337 338 Iterable<RevCommit> logList = git.log( ).setMaxCount( 10 ).call( ); 339 Iterator i = logList.iterator( ); 340 String sCommitMessages = ""; 341 while ( i.hasNext( ) ) 342 { 343 RevCommit revCommit = (RevCommit) i.next( ); 344 sCommitMessages = revCommit.getFullMessage( ); 345 int index = sCommitMessages.indexOf( TOKEN ); 346 if ( index >= 0 ) 347 { 348 sTagName = sCommitMessages.replace( TOKEN, "" ); 349 break; 350 } 351 } 352 353 if ( ( sTagName != null ) && ( !( sTagName.trim( ).equals( "" ) ) ) ) 354 { 355 List<Ref> tags = git.tagList( ).call( ); 356 for ( int j = 0; j < tags.size( ); j++ ) 357 { 358 Ref tag = tags.get( tags.size( ) - 1 - j ); 359 String tagName = tag.getName( ); 360 if ( tagName.equals( "refs/tags/" + sTagName ) ) 361 { 362 res = tag; 363 break; 364 } 365 } 366 } 367 368 return res; 369 } 370 371 private static String getRepoUrl( String strRepoUrl ) 372 { 373 374 if ( strRepoUrl != null && strRepoUrl.startsWith( "scm:git:" ) ) 375 { 376 strRepoUrl = strRepoUrl.substring( 8 ); 377 378 } 379 380 return strRepoUrl; 381 } 382 383 private static void checkout( Git git, String strBranch, String strTagName, CommandResult commandResult ) 384 { 385 if ( strBranch == null && strTagName == null ) 386 { 387 checkoutRepoBranch( git, DEVELOP_BRANCH, commandResult ); 388 return; 389 } 390 if ( strBranch != null && strTagName != null ) 391 { 392 DeploymentUtils.addTechnicalError( commandResult, "A branch name and a tag name are provided while checkouting the git repo" ); 393 return; 394 } 395 if ( strBranch != null ) 396 { 397 checkoutRepoBranch( git, strBranch, commandResult ); 398 } 399 if ( strTagName != null ) 400 { 401 checkoutTag( git, strTagName, commandResult ); 402 } 403 } 404 405 private static void checkoutTag( Git git, String strTagName, CommandResult commandResult ) 406 { 407 408 try 409 { 410 git.checkout( ).setName( CONSTANTE_REF_TAG + strTagName ).call( ); 411 412 } 413 catch( InvalidRemoteException e ) 414 { 415 416 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 417 418 } 419 catch( TransportException e ) 420 { 421 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 422 423 } 424 425 catch( GitAPIException e ) 426 { 427 DeploymentUtils.addTechnicalError( commandResult, e.getMessage( ), e ); 428 } 429 } 430 431 public static boolean checkAuthentication( String strRepoUrl, String strLocalTempPath, String strLocalTempDir, GitUser user ) 432 { 433 boolean bAuth = true; 434 Path localPath = null; 435 try 436 { 437 Path basePath = Paths.get( strLocalTempPath ); 438 localPath = Files.createTempDirectory( basePath, strLocalTempDir ); 439 Git.cloneRepository( ).setURI( strRepoUrl ) 440 .setCredentialsProvider( new UsernamePasswordCredentialsProvider( user.getLogin( ), user.getPassword( ) ) ) 441 .setDirectory( localPath.toFile( ) ).call( ); 442 } 443 catch( Exception e ) 444 { 445 bAuth = false; 446 } 447 finally 448 { 449 if ( localPath != null ) 450 { 451 try 452 { 453 FileUtils.forceDelete( new File( localPath.toString( ) ) ); 454 } 455 catch( IOException e ) 456 { 457 AppLogService.error( "Unable to delete dir " + localPath.toString( ), e ); 458 } 459 } 460 } 461 return bAuth; 462 } 463 }