GitResourceService.java
/*
* Copyright (c) 2002-2021, City of Paris
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright notice
* and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice
* and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* License 1.0
*/
package fr.paris.lutece.plugins.releaser.service.github;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.LogCommand;
import org.eclipse.jgit.api.PullResult;
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import fr.paris.lutece.plugins.releaser.business.Site;
import fr.paris.lutece.plugins.releaser.business.WorkflowReleaseContext;
import fr.paris.lutece.plugins.releaser.service.ComponentService;
import fr.paris.lutece.plugins.releaser.util.CommandResult;
import fr.paris.lutece.plugins.releaser.util.ConstanteUtils;
import fr.paris.lutece.plugins.releaser.util.IVCSResourceService;
import fr.paris.lutece.plugins.releaser.util.ReleaserUtils;
import fr.paris.lutece.plugins.releaser.util.file.FileUtils;
import fr.paris.lutece.plugins.releaser.util.github.GitUtils;
import fr.paris.lutece.portal.service.util.AppException;
// TODO: Auto-generated Javadoc
/**
* SvnSiteService.
*/
public class GitResourceService implements IVCSResourceService
{
/**
* Fetch the pom.xml content from a repository
*
* @param site
* the site
* @param strGitLogin
* the str git login
* @param strGitPwd
* the str git pwd
* @return The POM content
*/
public String fetchPom( Site site, String strGitLogin, String strGitPwd )
{
String strPom = null;
CommandResult commandResult = new CommandResult( );
WorkflowReleaseContext context = new WorkflowReleaseContext( );
commandResult.setLog( new StringBuffer( ) );
context.setCommandResult( commandResult );
context.setSite( site );
doCheckoutRepository( context, strGitLogin, strGitPwd );
strPom = FileUtils.readFile( ReleaserUtils.getLocalPomPath( context ) );
return strPom;
}
/**
* Gets the last release found in the SVN repository.
*
* @param site
* the site
* @param strGitLogin
* the str git login
* @param strGitPwd
* the str git pwd
* @return The version if found otherwise null
*/
public String getLastRelease( Site site, String strGitLogin, String strGitPwd )
{
WorkflowReleaseContext context = new WorkflowReleaseContext( );
context.setSite( site );
Git git = GitUtils.getGit( ReleaserUtils.getLocalPath( context ) );
List<String> listTags = GitUtils.getTagNameList( git );
String strLastRelease = null;
if ( !CollectionUtils.isEmpty( listTags ) )
{
strLastRelease = listTags.get( 0 );
}
if ( strLastRelease != null && strLastRelease.contains( "-" ) )
{
String [ ] tabRelease = strLastRelease.split( "-" );
strLastRelease = tabRelease [tabRelease.length - 1];
}
else
{
strLastRelease = "";
}
return strLastRelease;
}
/**
* Do checkout repository.
*
* @param context
* the context
* @param strLogin
* the str login
* @param strPassword
* the str password
* @return the string
*/
@Override
public String doCheckoutRepository( WorkflowReleaseContext context, String strLogin, String strPassword )
{
Git git = null;
String strBranchReleaseFrom = null;
CommandResult commandResult = context.getCommandResult( );
ReleaserUtils.logStartAction( context, " Clone Repository" );
String strLocalComponentPath = ReleaserUtils.getLocalPath( context );
File file = new File( strLocalComponentPath );
if ( file.exists( ) )
{
commandResult.getLog( ).append( "Local repository " + strLocalComponentPath + " exist\nCleaning Local folder...\n" );
if ( !FileUtils.delete( file, commandResult.getLog( ) ) )
{
commandResult.setError( commandResult.getLog( ).toString( ) );
}
commandResult.getLog( ).append( "Local repository has been cleaned\n" );
}
commandResult.getLog( ).append( "Cloning repository ...\n" );
try
{
// PROGRESS 5%
commandResult.setProgressValue( commandResult.getProgressValue( ) + 5 );
git = GitUtils.cloneRepo( strLocalComponentPath, context.getReleaserResource( ).getScmUrl( ), commandResult, strLogin, strLogin, strPassword );
GitUtils.createLocalBranch( git, GitUtils.MASTER_BRANCH, commandResult );
strBranchReleaseFrom = ReleaserUtils.getBranchReleaseFrom( context );
if ( !strBranchReleaseFrom.equals( GitUtils.DEFAULT_RELEASE_BRANCH ) )
{
GitUtils.createLocalBranch( git, strBranchReleaseFrom, commandResult );
context.setRefBranchReleaseFrom( GitUtils.getRefBranch( git, strBranchReleaseFrom, commandResult ) );
}
else
{
GitUtils.createLocalBranch( git, GitUtils.DEFAULT_RELEASE_BRANCH, commandResult );
context.setRefBranchReleaseFrom( GitUtils.getRefBranch( git, GitUtils.DEFAULT_RELEASE_BRANCH, commandResult ) );
context.setRefBranchRelease( GitUtils.getRefBranch( git, GitUtils.MASTER_BRANCH, commandResult ) );
}
commandResult.getLog( ).append( "the repository has been successfully cloned.\n" );
commandResult.getLog( ).append( "Checkout branch \"" + strBranchReleaseFrom + "\" ...\n" );
GitUtils.checkoutRepoBranch( git, strBranchReleaseFrom, commandResult );
// PROGRESS 10%
commandResult.setProgressValue( commandResult.getProgressValue( ) + 5 );
if ( context.getSite( ) == null && context.getComponent( ) != null && ComponentService.getService( )
.isErrorSnapshotComponentInformations( context.getComponent( ), ReleaserUtils.getLocalPomPath( context ) ) )
{
ReleaserUtils.addTechnicalError( commandResult, "The cloned component does not match the release informations" );
}
}
catch( AppException e )
{
if ( e.getCause( ) != null && e.getCause( ) instanceof TransportException )
{
ReleaserUtils.addTechnicalError( commandResult, ConstanteUtils.ERROR_TYPE_AUTHENTICATION_ERROR, e );
}
}
finally
{
if ( git != null )
{
git.close( );
}
}
commandResult.getLog( ).append( "Checkout branch develop successfull\n" );
ReleaserUtils.logEndAction( context, " Clone Repository" );
return ConstanteUtils.CONSTANTE_EMPTY_STRING;
}
/**
* Update develop branch.
*
* @param context
* the context
* @param locale
* the locale
* @param strMessage
* the str message
*/
@Override
public void updateDevelopBranch( WorkflowReleaseContext context, Locale locale, String strMessage )
{
updateBranch( context, GitUtils.DEFAULT_RELEASE_BRANCH, locale, strMessage );
}
/**
* Update branch.
*
* @param context
* the context
* @param locale
* the locale
* @param strMessage
* the str message
*/
@Override
public void updateBranch( WorkflowReleaseContext context, String strBranch, Locale locale, String strMessage )
{
String strLogin = context.getReleaserUser( ).getCredential( context.getReleaserResource( ).getRepoType( ) ).getLogin( );
String strPassword = context.getReleaserUser( ).getCredential( context.getReleaserResource( ).getRepoType( ) ).getPassword( );
FileRepository fLocalRepo = null;
Git git = null;
CommandResult commandResult = context.getCommandResult( );
String strLocalComponentPath = ReleaserUtils.getLocalPath( context );
try
{
fLocalRepo = new FileRepository( strLocalComponentPath + "/.git" );
git = new Git( fLocalRepo );
git.checkout( ).setName( strBranch ).call( );
git.add( ).addFilepattern( "." ).setUpdate( true ).call( );
git.commit( ).setCommitter( strLogin, strLogin ).setMessage( strMessage ).call( );
git.push( ).setCredentialsProvider( new UsernamePasswordCredentialsProvider( strLogin, strPassword ) ).call( );
}
catch( InvalidRemoteException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
catch( TransportException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
catch( IOException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
catch( GitAPIException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
finally
{
if ( fLocalRepo != null )
{
fLocalRepo.close( );
}
if ( git != null )
{
git.close( );
}
}
}
/**
* Update master branch.
*
* @param context
* the context
* @param locale
* the locale
*/
@Override
public void updateMasterBranch( WorkflowReleaseContext context, Locale locale )
{
String strLogin = context.getReleaserUser( ).getCredential( context.getReleaserResource( ).getRepoType( ) ).getLogin( );
String strPassword = context.getReleaserUser( ).getCredential( context.getReleaserResource( ).getRepoType( ) ).getPassword( );
FileRepository fLocalRepo = null;
Git git = null;
CommandResult commandResult = context.getCommandResult( );
String strLocalComponentPath = ReleaserUtils.getLocalPath( context );
try
{
fLocalRepo = new FileRepository( strLocalComponentPath + "/.git" );
git = new Git( fLocalRepo );
git.checkout( ).setName( GitUtils.DEFAULT_RELEASE_BRANCH ).call( );
GitUtils.mergeBack( git, strLogin, strPassword, commandResult );
}
catch( InvalidRemoteException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
catch( TransportException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
catch( IOException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
catch( GitAPIException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
finally
{
if ( fLocalRepo != null )
{
fLocalRepo.close( );
}
if ( git != null )
{
git.close( );
}
}
}
/**
* Rollback release.
*
* @param context
* the context
* @param locale
* the locale
*/
@Override
public void rollbackRelease( WorkflowReleaseContext context, Locale locale )
{
ReleaserUtils.logStartAction( context, " Rollback Release prepare" );
FileRepository fLocalRepo = null;
Git git = null;
CommandResult commandResult = context.getCommandResult( );
String strLocalComponentPath = ReleaserUtils.getLocalPath( context );
String strLogin = context.getReleaserUser( ).getCredential( context.getReleaserResource( ).getRepoType( ) ).getLogin( );
String strPassword = context.getReleaserUser( ).getCredential( context.getReleaserResource( ).getRepoType( ) ).getPassword( );
try
{
fLocalRepo = new FileRepository( strLocalComponentPath + "/.git" );
git = new Git( fLocalRepo );
// RESET commit on release branch from
if ( !StringUtils.isEmpty( context.getRefBranchReleaseFrom( ) ) )
{
git.checkout( ).setName( ReleaserUtils.getBranchReleaseFrom( context ) ).call( );
git.reset( ).setRef( context.getRefBranchReleaseFrom( ) ).setMode( ResetType.HARD ).call( );
git.push( ).setForce( true ).setCredentialsProvider( new UsernamePasswordCredentialsProvider( strLogin, strPassword ) ).call( );
}
// Reset Commit on Master (only if the releasing from develop branch)
if ( !StringUtils.isEmpty( context.getRefBranchRelease( ) ) && context.getRefBranchReleaseFrom( ).equals( GitUtils.DEFAULT_RELEASE_BRANCH ) )
{
git.checkout( ).setName( GitUtils.MASTER_BRANCH ).call( );
git.reset( ).setRef( context.getRefBranchRelease( ) ).setMode( ResetType.HARD ).call( );
git.push( ).setForce( true ).setCredentialsProvider( new UsernamePasswordCredentialsProvider( strLogin, strPassword ) ).call( );
}
// Delete Tag if exist
List<Ref> call = git.tagList( ).call( );
String strTagName = context.getReleaserResource( ).getArtifactId( ) + "-" + context.getReleaserResource( ).getTargetVersion( );
for ( Ref refTag : call )
{
if ( refTag.getName( ).contains( strTagName ) )
{
LogCommand log = git.log( ).setMaxCount( 1 );
Ref peeledRef = git.getRepository( ).peel( refTag );
if ( peeledRef.getPeeledObjectId( ) != null )
{
log.add( peeledRef.getPeeledObjectId( ) );
}
else
{
log.add( refTag.getObjectId( ) );
}
Iterable<RevCommit> logs = log.call( );
for ( RevCommit rev : logs )
{
// Test if the tag was created by the release
if ( !rev.getName( ).equals( context.getRefBranchRelease( ) ) )
{
git.branchDelete( ).setBranchNames( refTag.getName( ) ).setForce( true ).call( );
RefSpec refSpec = new RefSpec( ).setSource( null ).setDestination( refTag.getName( ) );
git.push( ).setRefSpecs( refSpec ).setCredentialsProvider( new UsernamePasswordCredentialsProvider( strLogin, strPassword ) )
.setRemote( "origin" ).call( );
}
}
}
}
}
catch( InvalidRemoteException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
catch( TransportException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
catch( IOException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
catch( GitAPIException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
finally
{
if ( fLocalRepo != null )
{
fLocalRepo.close( );
}
if ( git != null )
{
git.close( );
}
}
ReleaserUtils.logEndAction( context, " Rollback Release prepare" );
}
/**
* Checkout develop branch.
*
* @param context
* the context
* @param locale
* the locale
*/
@Override
public void checkoutDevelopBranch( WorkflowReleaseContext context, Locale locale )
{
checkoutBranch( context, GitUtils.DEFAULT_RELEASE_BRANCH, locale );
}
/**
* Checkout branch.
*
* @param context
* the context
* @param locale
* the locale
*/
@Override
public void checkoutBranch( WorkflowReleaseContext context, String strBranch, Locale locale )
{
FileRepository fLocalRepo = null;
Git git = null;
CommandResult commandResult = context.getCommandResult( );
String strLocalComponentPath = ReleaserUtils.getLocalPath( context );
String strLogin = context.getReleaserUser( ).getCredential( context.getReleaserResource( ).getRepoType( ) ).getLogin( );
String strPassword = context.getReleaserUser( ).getCredential( context.getReleaserResource( ).getRepoType( ) ).getPassword( );
try
{
fLocalRepo = new FileRepository( strLocalComponentPath + "/.git" );
git = new Git( fLocalRepo );
git.checkout( ).setName( strBranch ).call( );
PullResult result = GitUtils.pullRepoBranch( git, strBranch, strLogin, strPassword );
if ( !result.isSuccessful( ) )
{
ReleaserUtils.addTechnicalError( commandResult, "error during checkout " + strBranch + " branch" );
}
}
catch( InvalidRemoteException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
catch( TransportException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
catch( IOException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
catch( GitAPIException e )
{
ReleaserUtils.addTechnicalError( commandResult, e.getMessage( ), e );
}
finally
{
if ( fLocalRepo != null )
{
fLocalRepo.close( );
}
if ( git != null )
{
git.close( );
}
}
}
}