View Javadoc
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 }