All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.chutneytesting.admin.infra.gitbackup.GitClientImpl Maven / Gradle / Ivy

There is a newer version: 3.0.0
Show newest version
package com.chutneytesting.admin.infra.gitbackup;

import com.chutneytesting.admin.domain.gitbackup.GitClient;
import com.chutneytesting.admin.domain.gitbackup.RemoteRepository;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Optional;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.LsRemoteCommand;
import org.eclipse.jgit.api.MergeCommand;
import org.eclipse.jgit.api.TransportConfigCallback;
import org.eclipse.jgit.api.errors.EmptyCommitException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.RefNotAdvertisedException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.OpenSshConfig;
import org.eclipse.jgit.transport.SshTransport;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.FS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class GitClientImpl implements GitClient {

    private static final Logger LOGGER = LoggerFactory.getLogger(GitClientImpl.class);

    @Override
    public boolean hasAccess(RemoteRepository remote) {
        try {
            LsRemoteCommand lsRemoteCommand = Git.lsRemoteRepository()
                .setRemote(remote.url)
                .setTags(true)
                .setHeads(true)
                .setTimeout(5)
                .setTransportConfigCallback(getTransportConfigCallback(remote));

            Collection remoteRefs = lsRemoteCommand.call();

            if (remoteRefs.isEmpty() || remoteRefs.stream().noneMatch(ref -> ref.getName().contains(remote.branch))) {
                LOGGER.warn("No branch " + remote.branch + " found on remote " + remote.url);
            }

        } catch (GitAPIException e) {
            LOGGER.warn("Remote " + remote.url + " is not accessible. " + e.getMessage(), e);
            return false;
        }

        return true;
    }

    @Override
    public boolean isGitDir(Path workingDirectory) {
        return Files.exists(workingDirectory.resolve(".git"));
    }

    @Override
    public void addAll(Path workingDirectory) {
        try (Repository repository = FileRepositoryBuilder.create(workingDirectory.resolve(".git").toFile());
             Git git = Git.wrap(repository)
        ) {
            git.add().addFilepattern(".").call(); // stage all modified and untracked files
            git.add().setUpdate(true).addFilepattern(".").call(); // stage all deleted files
        } catch (Exception e) {
            throw new RuntimeException("Cannot stage all files at path : " + workingDirectory + ". " + e.getMessage(), e);
        }
    }

    @Override
    public void clone(RemoteRepository remote, Path cloningPath) {
        try {
            Files.createDirectories(cloningPath);
        } catch (IOException e) {
            throw new RuntimeException("Cannot create repository for cloning : " + remote.url + ". " + e.getMessage(), e);
        }

        Git git = null;
        try {
            git = Git.cloneRepository()
                .setRemote(remote.name)
                .setURI(remote.url)
                .setDirectory(cloningPath.toFile())
                .setBranch(remote.branch)
                .setNoCheckout(true)
                .setNoTags()
                .setTransportConfigCallback(getTransportConfigCallback(remote))
                .call();
        } catch (GitAPIException e) {
            throw new RuntimeException("Cannot clone repository: " + remote.url + ". " + e.getMessage(), e);
        } finally {
            Optional.ofNullable(git)
                .ifPresent(Git::close);
        }
    }

    @Override
    public void commit(Path workingDirectory, String message) {
        try (Repository repository = FileRepositoryBuilder.create(workingDirectory.resolve(".git").toFile());
             Git git = Git.wrap(repository)
        ) {
            git.commit()
                .setSign(false)
                .setAllowEmpty(false)
                .setAuthor("Chutney", "[email protected]")
                .setMessage(message)
                .call();
        } catch (EmptyCommitException e) {
            // do nothing
        } catch (IOException | GitAPIException e) {
            throw new RuntimeException("Cannot commit files at path : " + workingDirectory + ". " + e.getMessage(), e);
        }
    }

    @Override
    public void createBranch(RemoteRepository remote, Path workingDirectory) {
        try (Repository repository = FileRepositoryBuilder.create(workingDirectory.resolve(".git").toFile());
             Git git = Git.wrap(repository)
        ) {
            git.branchCreate()
                .setName(remote.branch)
                .call();
        } catch (RefNotFoundException e) {
            // falling here might mean that the remote repo is new and empty
            initRepository(remote, workingDirectory);
        } catch (Exception e) {
            throw new RuntimeException("Cannot create branch " + remote.url + ". " + e.getMessage(), e);
        }
    }

    @Override
    public void initRepository(RemoteRepository remote, Path workingDirectory) {
        try (Git git = Git.init().setInitialBranch(remote.branch).setDirectory(workingDirectory.toFile()).call()) {
            git.remoteAdd()
                .setName(remote.name)
                .setUri(new URIish(remote.url))
                .call();
        } catch (GitAPIException | URISyntaxException e) {
            throw new RuntimeException("Cannot create git repository at path : " + workingDirectory + ". " + e.getMessage(), e);
        }
    }

    @Override
    public void push(RemoteRepository remote, Path workingDirectory) {
        try (Repository repository = FileRepositoryBuilder.create(workingDirectory.resolve(".git").toFile());
             Git git = Git.wrap(repository)
        ) {
            git.push()
                .setRemote(remote.name)
                .setTransportConfigCallback(getTransportConfigCallback(remote))
                .call();

        } catch (IOException | GitAPIException e) {
            throw new RuntimeException("Cannot push to remote : " + remote.url + ". " + e.getMessage(), e);
        }
    }

    @Override
    public void update(RemoteRepository remote, Path workingDirectory) {
        try (Repository repository = FileRepositoryBuilder.create(workingDirectory.resolve(".git").toFile());
             Git git = Git.wrap(repository)
        ) {
            git.pull()
                .setRemote(remote.name)
                .setFastForward(MergeCommand.FastForwardMode.FF_ONLY)
                .setTransportConfigCallback(getTransportConfigCallback(remote))
                .call();
        } catch (RefNotAdvertisedException e) {
            createBranch(remote, workingDirectory);
        } catch (Exception e) {
            throw new RuntimeException("Cannot update repository " + remote.url + ". " + e.getMessage(), e);
        }
    }

    @Override
    public void updateRemote(RemoteRepository remote, Path workingDirectory) {
        try (Repository repository = FileRepositoryBuilder.create(workingDirectory.resolve(".git").toFile());
             Git git = Git.wrap(repository)
        ) {
            git.remoteRemove()
                .setRemoteName(remote.name)
                .call();
        } catch (Exception e) {
            throw new RuntimeException("Cannot update remote : " + remote.url + ". " + e.getMessage(), e);
        }
    }

    private TransportConfigCallback getTransportConfigCallback(RemoteRepository remote) {
        return transport -> {
            SshTransport sshTransport = (SshTransport) transport;
            sshTransport.setSshSessionFactory(new JschConfigSessionFactory() {

                @Override
                protected void configure(OpenSshConfig.Host host, Session session) {
                    session.setConfig("StrictHostKeyChecking", "no");
                }

                @Override
                protected JSch createDefaultJSch(FS fs) throws JSchException {
                    JSch defaultJSch = super.createDefaultJSch(fs);
                    defaultJSch.removeAllIdentity();
                    if (Files.exists(Paths.get(remote.privateKeyPath))) {
                        defaultJSch.addIdentity(remote.privateKeyPath, remote.privateKeyPassphrase);
                    }
                    return defaultJSch;
                }

            });
        };
    }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy