com.denimgroup.threadfix.service.repository.GitServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.denimgroup.threadfix.service.repository.GitServiceImpl.java

Source

////////////////////////////////////////////////////////////////////////
//
//     Copyright (c) 2009-2015 Denim Group, Ltd.
//
//     The contents of this file are subject to the Mozilla Public License
//     Version 2.0 (the "License"); you may not use this file except in
//     compliance with the License. You may obtain a copy of the License at
//     http://www.mozilla.org/MPL/
//
//     Software distributed under the License is distributed on an "AS IS"
//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//     License for the specific language governing rights and limitations
//     under the License.
//
//     The Original Code is ThreadFix.
//
//     The Initial Developer of the Original Code is Denim Group, Ltd.
//     Portions created by Denim Group, Ltd. are Copyright (C)
//     Denim Group, Ltd. All Rights Reserved.
//
//     Contributor(s): Denim Group, Ltd.
//
////////////////////////////////////////////////////////////////////////
package com.denimgroup.threadfix.service.repository;

import com.denimgroup.threadfix.DiskUtils;
import com.denimgroup.threadfix.data.entities.Application;
import com.denimgroup.threadfix.data.entities.ExceptionLog;
import com.denimgroup.threadfix.logging.SanitizedLogger;
import com.denimgroup.threadfix.service.ApplicationService;
import com.denimgroup.threadfix.service.ExceptionLogService;
import com.denimgroup.threadfix.service.RepositoryService;
import org.eclipse.jgit.api.*;
import org.eclipse.jgit.api.errors.*;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindingResult;

import java.io.File;
import java.io.IOException;
import java.util.List;

@Service
public class GitServiceImpl extends RepositoryServiceImpl implements RepositoryService {

    private static final SanitizedLogger log = new SanitizedLogger(GitServiceImpl.class);
    private static final String EXCEPTION_MESSAGE = "Failed to clone application from repository";

    @Autowired
    private ApplicationService applicationService;
    @Autowired
    private ExceptionLogService exceptionLogService;

    @Override
    public boolean testConfiguration(Application application) throws GitAPIException {
        return testConfiguration(application, application.getRepositoryUrl(), application.getRepositoryBranch());
    }

    @Override
    public boolean testConfiguration(Application application, String repo, String branch) throws GitAPIException {
        InitCommand initCommand = new InitCommand();
        File applicationDirectory = DiskUtils.getScratchFile(baseDirectory + application.getId() + "-test");
        initCommand.setDirectory(applicationDirectory);

        Git otherGit = initCommand.call();

        otherGit.getRepository().getConfig().setString("remote", "origin", "url", repo);

        String targetRefSpec = branch == null || branch.isEmpty() ? Constants.R_HEADS + "*:refs/remotes/origin/*"
                : Constants.R_HEADS + branch;

        FetchCommand fetchCommand = otherGit.fetch()
                .setCredentialsProvider(getUnencryptedApplicationCredentials(application)).setDryRun(true)
                .setRefSpecs(new RefSpec(targetRefSpec)).setRemote("origin");

        fetchCommand.call();

        return true;
    }

    @Override
    public void handleException(Exception e, Application application, BindingResult result) {
        if (e instanceof GitAPIException || e instanceof JGitInternalException) {

            boolean shouldLog = true;

            if (e instanceof JGitInternalException) {
                result.rejectValue("repositoryUrl", null, null, "Unable to connect to this URL.");
            }

            if (e.getMessage().contains("not authorized")) {
                result.rejectValue("repositoryUrl", null, null, "Authorization failed.");
            }

            if (application.getRepositoryBranch() != null) {
                String missingBranchError = "Remote does not have " + application.getRepositoryBranch()
                        + " available for fetch";
                if (e.getMessage().contains(missingBranchError)) {
                    result.rejectValue("repositoryUrl", null, null, "Supplied branch wasn't found.");
                }
            } else if (e.getMessage().contains("Remote does not have fakebranch available for fetch")) {
                // this is expected behavior, let's not return an error.
                shouldLog = false;
            } else {
                result.rejectValue("repositoryUrl", null, null, "Unable to clone repository");
            }

            if (shouldLog) {
                log.info("Got an error from the Git server, logging to database (visible under Error Messages)");
                exceptionLogService.storeExceptionLog(new ExceptionLog(e));
            }
        } else {
            log.info("Got an error, logging to database (visible under Error Messages)");
            exceptionLogService.storeExceptionLog(new ExceptionLog(e));
        }
    }

    @Override
    public File cloneRepoToDirectory(Application application, File dirLocation) {

        if (dirLocation.exists()) {
            File gitDirectoryFile = new File(dirLocation.getAbsolutePath() + File.separator + ".git");

            try {
                if (!gitDirectoryFile.exists()) {
                    Git newRepo = clone(application, dirLocation);
                    if (newRepo != null)
                        return newRepo.getRepository().getWorkTree();
                } else {
                    Repository localRepo = new FileRepository(gitDirectoryFile);
                    Git git = new Git(localRepo);

                    if (application.getRepositoryRevision() != null
                            && !application.getRepositoryRevision().isEmpty()) {
                        //remote checkout
                        git.checkout().setCreateBranch(true).setStartPoint(application.getRepositoryRevision())
                                .setName(application.getRepositoryRevision()).call();
                    } else {

                        List<Ref> refs = git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call();

                        String repoBranch = (application.getRepositoryBranch() != null
                                && !application.getRepositoryBranch().isEmpty()) ? application.getRepositoryBranch()
                                        : "master";

                        boolean localCheckout = false;

                        for (Ref ref : refs) {
                            String refName = ref.getName();
                            if (refName.contains(repoBranch) && !refName.contains(Constants.R_REMOTES)) {
                                localCheckout = true;
                            }
                        }

                        String HEAD = localRepo.getFullBranch();

                        if (HEAD.contains(repoBranch)) {
                            git.pull().setRemote("origin").setRemoteBranchName(repoBranch)
                                    .setCredentialsProvider(getApplicationCredentials(application)).call();
                        } else {
                            if (localCheckout) {
                                //local checkout
                                git.checkout().setName(application.getRepositoryBranch()).call();
                                git.pull().setRemote("origin").setRemoteBranchName(repoBranch)
                                        .setCredentialsProvider(getApplicationCredentials(application)).call();
                            } else {
                                //remote checkout
                                git.checkout().setCreateBranch(true).setName(repoBranch)
                                        .setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.SET_UPSTREAM)
                                        .setStartPoint("origin/" + repoBranch).call();
                            }
                        }
                    }

                    return git.getRepository().getWorkTree();
                }
            } catch (JGitInternalException e) {
                log.error(EXCEPTION_MESSAGE, e);
            } catch (IOException e) {
                log.error(EXCEPTION_MESSAGE, e);
            } catch (WrongRepositoryStateException e) {
                log.error(EXCEPTION_MESSAGE, e);
            } catch (InvalidConfigurationException e) {
                log.error(EXCEPTION_MESSAGE, e);
            } catch (DetachedHeadException e) {
                log.error(EXCEPTION_MESSAGE, e);
            } catch (InvalidRemoteException e) {
                log.error(EXCEPTION_MESSAGE, e);
            } catch (CanceledException e) {
                log.error(EXCEPTION_MESSAGE, e);
            } catch (RefNotFoundException e) {
                log.error(EXCEPTION_MESSAGE, e);
            } catch (NoHeadException e) {
                log.error(EXCEPTION_MESSAGE, e);
            } catch (RefAlreadyExistsException e) {
                log.error(EXCEPTION_MESSAGE, e);
            } catch (CheckoutConflictException e) {
                log.error(EXCEPTION_MESSAGE, e);
            } catch (InvalidRefNameException e) {
                log.error(EXCEPTION_MESSAGE, e);
            } catch (TransportException e) {
                log.error(EXCEPTION_MESSAGE, e);
            } catch (GitAPIException e) {
                log.error(EXCEPTION_MESSAGE, e);
            }
        } else {
            try {
                log.info("Attempting to clone application from repository.");
                Git result = clone(application, dirLocation);
                if (result != null) {
                    log.info("Application was successfully cloned from repository.");
                    return result.getRepository().getWorkTree();
                }
                log.error(EXCEPTION_MESSAGE);
            } catch (JGitInternalException e) {
                log.error(EXCEPTION_MESSAGE, e);
            }
        }
        return null;
    }

    private Git clone(Application application, File dirLocation) {
        Git git = null;
        try {
            CloneCommand clone = Git.cloneRepository();

            clone.setURI(application.getRepositoryUrl()).setDirectory(dirLocation)
                    .setCredentialsProvider(getApplicationCredentials(application));

            if (application.getRepositoryBranch() != null && !application.getRepositoryBranch().isEmpty()) {
                clone.setBranch(application.getRepositoryBranch());
            }

            // clone git repo
            git = clone.call();

            // checkout specific revision
            if (application.getRepositoryRevision() != null && !application.getRepositoryRevision().isEmpty()) {
                git.checkout().setCreateBranch(true).setStartPoint(application.getRepositoryRevision())
                        .setName(application.getRepositoryRevision()).call();
            }

        } catch (WrongRepositoryStateException e) {
            log.error(EXCEPTION_MESSAGE, e);
        } catch (InvalidConfigurationException e) {
            log.error(EXCEPTION_MESSAGE, e);
        } catch (DetachedHeadException e) {
            log.error(EXCEPTION_MESSAGE, e);
        } catch (InvalidRemoteException e) {
            log.error(EXCEPTION_MESSAGE, e);
        } catch (CanceledException e) {
            log.error(EXCEPTION_MESSAGE, e);
        } catch (RefNotFoundException e) {
            log.error(EXCEPTION_MESSAGE, e);
        } catch (NoHeadException e) {
            log.error(EXCEPTION_MESSAGE, e);
        } catch (RefAlreadyExistsException e) {
            log.error(EXCEPTION_MESSAGE, e);
        } catch (CheckoutConflictException e) {
            log.error(EXCEPTION_MESSAGE, e);
        } catch (InvalidRefNameException e) {
            log.error(EXCEPTION_MESSAGE, e);
        } catch (TransportException e) {
            log.error(EXCEPTION_MESSAGE, e);
        } catch (GitAPIException e) {
            log.error(EXCEPTION_MESSAGE, e);
        }

        return git;
    }

    private UsernamePasswordCredentialsProvider getApplicationCredentials(Application application) {
        if (application.getRepositoryEncryptedUserName() != null
                && application.getRepositoryEncryptedPassword() != null) {
            applicationService.decryptRepositoryCredentials(application);
            return new UsernamePasswordCredentialsProvider(application.getRepositoryUserName(),
                    application.getRepositoryPassword());
        }
        return null;
    }

    private CredentialsProvider getUnencryptedApplicationCredentials(Application application) {
        if (application.getRepositoryUserName() != null && application.getRepositoryPassword() != null) {
            return new UsernamePasswordCredentialsProvider(application.getRepositoryUserName(),
                    application.getRepositoryPassword());
        }

        return null;
    }

}