<commit_before>/*
 *  Copyright 2013-2017 the original author or authors.
 *
 *  Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.springframework.cloud.release.internal.git;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.URI;
import java.util.List;

import org.eclipse.jgit.api.CheckoutCommand;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.CreateBranchCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ListBranchCommand;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.api.TransportConfigCallback;
import org.eclipse.jgit.api.errors.EmtpyCommitException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.OpenSshConfig;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.SshTransport;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.release.internal.ReleaserProperties;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

import com.jcraft.jsch.IdentityRepository;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.agentproxy.AgentProxyException;
import com.jcraft.jsch.agentproxy.Connector;
import com.jcraft.jsch.agentproxy.RemoteIdentityRepository;
import com.jcraft.jsch.agentproxy.USocketFactory;
import com.jcraft.jsch.agentproxy.connector.SSHAgentConnector;
import com.jcraft.jsch.agentproxy.usocket.JNAUSocketFactory;

/**
 * Abstraction over a Git repo. Can cloned repo from a given location
 * and check its branch.
 *
 * @author <NAME>
 */
class GitRepo {

	private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

	private final GitRepo.JGitFactory gitFactory;

	private final File basedir;

	GitRepo(File basedir, ReleaserProperties properties) {
		this.basedir = basedir;
		this.gitFactory = new GitRepo.JGitFactory(properties);
	}

	// for tests
	GitRepo(File basedir) {
		this.basedir = basedir;
		this.gitFactory = new GitRepo.JGitFactory();
	}

	// for tests
	GitRepo(File basedir, GitRepo.JGitFactory factory) {
		this.basedir = basedir;
		this.gitFactory = factory;
	}

	/**
	 * Clones the project
	 * @param projectUri - URI of the project
	 * @return file where the project was cloned
	 */
	File cloneProject(URIish projectUri) {
		try {
			log.info("Cloning repo from [{}] to [{}]", projectUri,
					humanishDestination(projectUri, this.basedir));
			Git git = cloneToBasedir(projectUri, this.basedir);
			if (git != null) {
				git.close();
			}
			File clonedRepo = git.getRepository().getWorkTree();
			log.info("Cloned repo to [{}]", clonedRepo);
			return clonedRepo;
		}
		catch (Exception e) {
			throw new IllegalStateException("Exception occurred while cloning repo", e);
		}
	}

	/**
	 * Checks out a branch for a project
	 * @param branch - branch to check out
	 */
	void checkout(String branch) {
		try {
			log.info("Checking out branch [{}] for repo [{}]", branch, this.basedir);
			checkoutBranch(this.basedir, branch);
			log.info("Successfully checked out the branch [{}]", branch);
		}
		catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	/**
	 * Performs a commit
	 * @param message - commit message
	 */
	void commit(String message) {
		try(Git git = this.gitFactory.open(file(this.basedir))) {
			git.add().addFilepattern(".").call();
			git.commit().setAllowEmpty(false).setMessage(message).call();
			printLog(git);
		} catch (EmtpyCommitException e) {
			log.info("There were no changes detected. Will not commit an empty commit");
		} catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	boolean hasBranch(String branch) {
		try(Git git = this.gitFactory.open(file(this.basedir))) {
			List<Ref> refs = git.branchList().setListMode(ListBranchCommand.ListMode.ALL)
					.call();
			return refs.stream().anyMatch(ref -> ref.getName().contains(branch));
		} catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	private void printLog(Git git) throws GitAPIException, IOException {
		int maxCount = 5;
		String currentBranch = git.getRepository().getBranch();
		log.info("Printing [{}] last commits for branch [{}]", maxCount, currentBranch);
		Iterable<RevCommit> commits = git.log().setMaxCount(maxCount).call();
		for (RevCommit commit : commits) {
			log.info("Name [{}], msg [{}]", commit.getId().name(), commit.getShortMessage());
		}
	}

	/**
	 * Creates a tag with a given name
	 * @param tagName
	 */
	void tag(String tagName) {
		try(Git git = this.gitFactory.open(file(this.basedir))) {
			git.tag().setName(tagName).call();
		} catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	/**<commit_msg>Fixed invalid branch existance verification<commit_after>/*
 *  Copyright 2013-2017 the original author or authors.
 *
 *  Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.springframework.cloud.release.internal.git;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.List;

import org.eclipse.jgit.api.CheckoutCommand;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.CreateBranchCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ListBranchCommand;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.api.TransportConfigCallback;
import org.eclipse.jgit.api.errors.EmtpyCommitException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.OpenSshConfig;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.SshTransport;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.release.internal.ReleaserProperties;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

import com.jcraft.jsch.IdentityRepository;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.agentproxy.AgentProxyException;
import com.jcraft.jsch.agentproxy.Connector;
import com.jcraft.jsch.agentproxy.RemoteIdentityRepository;
import com.jcraft.jsch.agentproxy.USocketFactory;
import com.jcraft.jsch.agentproxy.connector.SSHAgentConnector;
import com.jcraft.jsch.agentproxy.usocket.JNAUSocketFactory;

/**
 * Abstraction over a Git repo. Can cloned repo from a given location
 * and check its branch.
 *
 * @author <NAME>
 */
class GitRepo {

	private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

	private final GitRepo.JGitFactory gitFactory;

	private final File basedir;

	GitRepo(File basedir, ReleaserProperties properties) {
		this.basedir = basedir;
		this.gitFactory = new GitRepo.JGitFactory(properties);
	}

	// for tests
	GitRepo(File basedir) {
		this.basedir = basedir;
		this.gitFactory = new GitRepo.JGitFactory();
	}

	// for tests
	GitRepo(File basedir, GitRepo.JGitFactory factory) {
		this.basedir = basedir;
		this.gitFactory = factory;
	}

	/**
	 * Clones the project
	 * @param projectUri - URI of the project
	 * @return file where the project was cloned
	 */
	File cloneProject(URIish projectUri) {
		try {
			log.info("Cloning repo from [{}] to [{}]", projectUri,
					humanishDestination(projectUri, this.basedir));
			Git git = cloneToBasedir(projectUri, this.basedir);
			if (git != null) {
				git.close();
			}
			File clonedRepo = git.getRepository().getWorkTree();
			log.info("Cloned repo to [{}]", clonedRepo);
			return clonedRepo;
		}
		catch (Exception e) {
			throw new IllegalStateException("Exception occurred while cloning repo", e);
		}
	}

	/**
	 * Checks out a branch for a project
	 * @param branch - branch to check out
	 */
	void checkout(String branch) {
		try {
			log.info("Checking out branch [{}] for repo [{}]", branch, this.basedir);
			checkoutBranch(this.basedir, branch);
			log.info("Successfully checked out the branch [{}]", branch);
		}
		catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	/**
	 * Performs a commit
	 * @param message - commit message
	 */
	void commit(String message) {
		try(Git git = this.gitFactory.open(file(this.basedir))) {
			git.add().addFilepattern(".").call();
			git.commit().setAllowEmpty(false).setMessage(message).call();
			printLog(git);
		} catch (EmtpyCommitException e) {
			log.info("There were no changes detected. Will not commit an empty commit");
		} catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	boolean hasBranch(String branch) {
		try(Git git = this.gitFactory.open(file(this.basedir))) {
			List<Ref> refs = git.branchList().setListMode(ListBranchCommand.ListMode.ALL)
					.call();
			return refs.stream().anyMatch(ref -> branch.equals(nameOfBranch(ref.getName())));
		} catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	private String nameOfBranch(String branch) {
		return branch.substring(branch.lastIndexOf("/") + 1);
	}

	private void printLog(Git git) throws GitAPIException, IOException {
		int maxCount = 5;
		String currentBranch = git.getRepository().getBranch();
		log.info("Printing [{}] last commits for branch [{}]", maxCount, currentBranch);
		Iterable<RevCommit> commits = git.log().setMaxCount(maxCount).call();
		for (RevCommit commit : commits) {
			log.info("Name [{}], msg [{}]", commit.getId().name(), commit.getShortMessage());
		}
	}

	/**
	 * Creates a tag with a given name
	 * @param tagName
	 */
	void tag(String tagName) {
		try(Git git = this.gitFactory.open(file(this.basedir))) {
			git.tag().setName(tagName).call();
		} catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	/**
{'fraction_non_alphanumeric': 0.12091981741452071, 'fraction_numerical': 0.002669882008440272, 'mean_word_length': 4.469618464437117, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '382448', 'n_tokens_mistral': 3854, 'n_tokens_neox': 3618, 'n_words': 875}