CHE-9418: Fix Git status message if the repository is checkouted to tag or commit. (#10172)

Fix Git status message if the repository is checkouted to tag or commit.
Changed getCurrentBranch method in the Git API to getCurrentReference that returns Reference object that contains reference and type (branch, tag or commit).
6.19.x
Igor Vinokur 2018-07-05 11:33:07 +03:00 committed by GitHub
parent d767fd4668
commit b071721ad3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 261 additions and 40 deletions

View File

@ -263,6 +263,7 @@ public class ProjectExplorerViewImpl extends BaseView<ProjectExplorerView.Action
DivElement divElement = Document.get().createDivElement();
divElement.setInnerText("(" + head + ")");
divElement.setClassName(treeStyles.treeStylesCss().vcsHeadContainer());
divElement.setId("git.reference.name");
nodeContainer.insertBefore(divElement, nodeContainer.getLastChild());
}
}

View File

@ -151,7 +151,7 @@ public class GitVcsService implements VcsService {
public Promise<String> getBranchName(ProjectConfig project) {
return service
.getStatus(Path.valueOf(project.getPath()), emptyList())
.then((Function<Status, String>) status -> status.getBranchName());
.then((Function<Status, String>) status -> status.getRefName());
}
@Override

View File

@ -69,6 +69,7 @@ import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -89,6 +90,9 @@ public class ProjectExplorer {
private final NotificationsPopupPanel notificationsPopupPanel;
private final int DEFAULT_TIMEOUT;
@FindBy(id = "git.reference.name")
WebElement projectReference;
@Inject
public ProjectExplorer(
SeleniumWebDriver seleniumWebDriver,
@ -291,6 +295,17 @@ public class ProjectExplorer {
By.xpath(format(PROJECT_EXPLORER_ITEM_TEMPLATE, path)), timeout);
}
/**
* Wait the specified reference to be present near the project name in the project explorer.
*
* @param reference git reference e.g. branch, tag or commit
*/
public void waitReferenceName(String reference) {
loader.waitOnClosed();
seleniumWebDriverHelper.waitTextEqualsTo(projectReference, "(" + reference + ")");
}
/**
* Waits until library will be present in External Libraries folder
*

View File

@ -10,10 +10,7 @@
*/
package org.eclipse.che.selenium.git;
import static org.eclipse.che.selenium.core.constant.TestMenuCommandsConstants.Git.BRANCHES;
import static org.eclipse.che.selenium.core.constant.TestMenuCommandsConstants.Git.CHECKOUT_REFERENCE;
import static org.eclipse.che.selenium.core.constant.TestMenuCommandsConstants.Git.GIT;
import static org.eclipse.che.selenium.core.constant.TestMenuCommandsConstants.Git.SHOW_HISTORY;
import static org.eclipse.che.selenium.core.constant.TestMenuCommandsConstants.Git.*;
import static org.eclipse.che.selenium.pageobject.Wizard.TypeProject.BLANK;
import static org.testng.Assert.assertTrue;
@ -26,10 +23,7 @@ import org.eclipse.che.selenium.core.client.TestGitHubRepository;
import org.eclipse.che.selenium.core.client.TestUserPreferencesServiceClient;
import org.eclipse.che.selenium.core.user.DefaultTestUser;
import org.eclipse.che.selenium.core.workspace.TestWorkspace;
import org.eclipse.che.selenium.pageobject.CodenvyEditor;
import org.eclipse.che.selenium.pageobject.Ide;
import org.eclipse.che.selenium.pageobject.Menu;
import org.eclipse.che.selenium.pageobject.ProjectExplorer;
import org.eclipse.che.selenium.pageobject.*;
import org.eclipse.che.selenium.pageobject.git.Git;
import org.eclipse.che.selenium.pageobject.git.GitHistory;
import org.testng.annotations.BeforeClass;
@ -114,6 +108,12 @@ public class CheckoutReferenceTest {
editor.waitActive();
editor.waitTextIntoEditor(UPDATE_FILE);
// check current reference
menu.runCommand(GIT, STATUS);
git.waitGitStatusBarWithMess("On branch " + DEFAULT_BRANCH);
projectExplorer.waitReferenceName(DEFAULT_BRANCH);
// check the name of the default branch
openBranchPanelAndWaitRefHeadName(DEFAULT_BRANCH);
@ -134,6 +134,12 @@ public class CheckoutReferenceTest {
editor.waitTextIntoEditor(CHANGE_FILE);
editor.waitTextNotPresentIntoEditor(UPDATE_FILE);
// check current reference
menu.runCommand(GIT, STATUS);
git.waitGitStatusBarWithMess("HEAD detached at " + hashCommit);
projectExplorer.waitReferenceName(sha1);
// switch to default branch
projectExplorer.waitAndSelectItem(PROJECT_NAME);
menu.runCommand(GIT, BRANCHES);
@ -175,6 +181,12 @@ public class CheckoutReferenceTest {
editor.selectTabByName(JS_FILE);
editor.waitTextIntoEditor(CHANGE_FILE_1);
// check current reference
menu.runCommand(GIT, STATUS);
git.waitGitStatusBarWithMess("HEAD detached at " + TAG_NAME_1);
projectExplorer.waitReferenceName(TAG_NAME_1);
// check the git history
openGitHistoryForm();

View File

@ -20,10 +20,17 @@ public interface Status {
void setClean(boolean isClean);
/** @deprecated Use {@link #getRefName()} instead. */
String getBranchName();
/** @deprecated Use #setRefName(String) instead. */
void setBranchName(String branchName);
/** Returns reference name e.g. branch, tag or commit id */
String getRefName();
void setRefName(String refName);
/** New files that are staged in index. */
List<String> getAdded();

View File

@ -396,11 +396,20 @@ public interface GitConnection extends Closeable {
/**
* Get the current branch on the current directory
*
* @return the name of the branch
* @deprecated Use {@link #getCurrentReference()} instead.
* @return the name of the branch or <i>HEAD</i> if the repo points to tag or commit
* @throws GitException if any exception occurs
*/
String getCurrentBranch() throws GitException;
/**
* Get the current reference on the current directory
*
* @return reference object with branch, tag or commit id
* @throws GitException if any exception occurs
*/
Reference getCurrentReference() throws GitException;
/**
* Revert the specified commit
*

View File

@ -23,7 +23,6 @@ import java.util.stream.Collectors;
import javax.inject.Singleton;
import org.eclipse.che.api.core.ApiException;
import org.eclipse.che.api.fs.server.PathTransformer;
import org.eclipse.che.api.git.params.LogParams;
import org.eclipse.che.api.git.shared.Remote;
import org.eclipse.che.api.project.server.type.ReadonlyValueProvider;
import org.eclipse.che.api.project.server.type.ValueProvider;
@ -59,15 +58,7 @@ public class GitValueProviderFactory implements ValueProviderFactory {
case VCS_PROVIDER_NAME:
return singletonList("git");
case GIT_CURRENT_HEAD_NAME:
String currentBranch = gitConnection.getCurrentBranch();
return singletonList(
"HEAD".equals(currentBranch)
? gitConnection
.log(LogParams.create().withMaxCount(1))
.getCommits()
.get(0)
.getId()
: currentBranch);
return singletonList(gitConnection.getCurrentReference().getName());
case GIT_REPOSITORY_REMOTES:
return gitConnection
.remoteList(null, false)

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.api.git;
/** @author Igor Vinokur */
public class Reference {
private final String refName;
private final ReferenceType type;
/**
* Represents Git reference e.g. branch, tag or commit id.
*
* @param refName reference name
* @param type reference type
*/
protected Reference(String refName, ReferenceType type) {
this.refName = refName;
this.type = type;
}
/** Returns reference name. */
public String getName() {
return refName;
}
/** Returns reference type */
public ReferenceType getType() {
return type;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Reference)) return false;
Reference reference = (Reference) o;
if (refName != null ? !refName.equals(reference.refName) : reference.refName != null)
return false;
return getType() == reference.getType();
}
@Override
public int hashCode() {
int result = refName != null ? refName.hashCode() : 0;
result = 31 * result + (getType() != null ? getType().hashCode() : 0);
return result;
}
}

View File

@ -0,0 +1,17 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.api.git;
public enum ReferenceType {
BRANCH,
TAG,
COMMIT
}

View File

@ -14,6 +14,7 @@ import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.eclipse.che.git.impl.GitTestUtil.addFile;
import static org.eclipse.che.git.impl.GitTestUtil.cleanupTestRepo;
import static org.eclipse.che.git.impl.GitTestUtil.connectToGitRepositoryWithContent;
import static org.eclipse.che.git.impl.GitTestUtil.connectToInitializedGitRepository;
import static org.eclipse.che.git.impl.GitTestUtil.deleteFile;
import static org.testng.Assert.assertEquals;
@ -27,8 +28,10 @@ import org.eclipse.che.api.git.GitConnectionFactory;
import org.eclipse.che.api.git.params.AddParams;
import org.eclipse.che.api.git.params.CheckoutParams;
import org.eclipse.che.api.git.params.CommitParams;
import org.eclipse.che.api.git.params.LogParams;
import org.eclipse.che.api.git.params.RmParams;
import org.eclipse.che.api.git.shared.*;
import org.eclipse.che.api.git.params.TagCreateParams;
import org.eclipse.che.api.git.shared.Status;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@ -325,4 +328,57 @@ public class StatusTest {
assertTrue(status.getUntracked().isEmpty());
assertTrue(status.getUntrackedFolders().isEmpty());
}
@Test(
dataProvider = "GitConnectionFactory",
dataProviderClass = org.eclipse.che.git.impl.GitConnectionFactoryProvider.class
)
public void shouldReturnCurrentBranch(GitConnectionFactory connectionFactory) throws Exception {
// given
GitConnection connection = connectToGitRepositoryWithContent(connectionFactory, repository);
final String branchName = "newBranch";
connection.branchCreate(branchName, null);
connection.checkout(CheckoutParams.create(branchName));
// when
final Status status = connection.status(emptyList());
// then
assertEquals(status.getRefName(), branchName);
}
@Test(
dataProvider = "GitConnectionFactory",
dataProviderClass = org.eclipse.che.git.impl.GitConnectionFactoryProvider.class
)
public void shouldReturnTagName(GitConnectionFactory connectionFactory) throws Exception {
// given
GitConnection connection = connectToGitRepositoryWithContent(connectionFactory, repository);
final String tagName = "newTag";
connection.tagCreate(TagCreateParams.create(tagName));
connection.checkout(CheckoutParams.create(tagName));
// when
final Status status = connection.status(emptyList());
// then
assertEquals(status.getRefName(), tagName);
}
@Test(
dataProvider = "GitConnectionFactory",
dataProviderClass = org.eclipse.che.git.impl.GitConnectionFactoryProvider.class
)
public void shouldReturnCommitId(GitConnectionFactory connectionFactory) throws Exception {
// given
GitConnection connection = connectToGitRepositoryWithContent(connectionFactory, repository);
final String commitId = connection.log(LogParams.create()).getCommits().get(0).getId();
connection.checkout(CheckoutParams.create(commitId));
// when
final Status status = connection.status(emptyList());
// then
assertEquals(status.getRefName(), commitId);
}
}

View File

@ -21,6 +21,9 @@ import static java.util.Collections.singletonList;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.stream.Collectors.toList;
import static org.eclipse.che.api.git.ReferenceType.BRANCH;
import static org.eclipse.che.api.git.ReferenceType.COMMIT;
import static org.eclipse.che.api.git.ReferenceType.TAG;
import static org.eclipse.che.api.git.params.CommitParams.create;
import static org.eclipse.che.api.git.shared.BranchListMode.LIST_ALL;
import static org.eclipse.che.api.git.shared.BranchListMode.LIST_LOCAL;
@ -92,8 +95,16 @@ import org.eclipse.che.api.git.GitConnection;
import org.eclipse.che.api.git.GitUrlUtils;
import org.eclipse.che.api.git.GitUserResolver;
import org.eclipse.che.api.git.LogPage;
import org.eclipse.che.api.git.Reference;
import org.eclipse.che.api.git.UserCredential;
import org.eclipse.che.api.git.exception.*;
import org.eclipse.che.api.git.exception.GitCheckoutInProgressException;
import org.eclipse.che.api.git.exception.GitCommitInProgressException;
import org.eclipse.che.api.git.exception.GitConflictException;
import org.eclipse.che.api.git.exception.GitException;
import org.eclipse.che.api.git.exception.GitInvalidRefNameException;
import org.eclipse.che.api.git.exception.GitInvalidRepositoryException;
import org.eclipse.che.api.git.exception.GitRefAlreadyExistsException;
import org.eclipse.che.api.git.exception.GitRefNotFoundException;
import org.eclipse.che.api.git.params.AddParams;
import org.eclipse.che.api.git.params.CheckoutParams;
import org.eclipse.che.api.git.params.CloneParams;
@ -783,7 +794,7 @@ class JGitConnection implements GitConnection {
GitUser gitUser = newDto(GitUser.class).withName(committerName).withEmail(committerEmail);
return newDto(Revision.class)
.withBranch(getCurrentBranch())
.withBranch(getCurrentReference().getName())
.withId(result.getId().getName())
.withMessage(result.getFullMessage())
.withCommitTime(MILLISECONDS.convert(result.getCommitTime(), SECONDS))
@ -1453,7 +1464,7 @@ class JGitConnection implements GitConnection {
@Override
public PushResponse push(PushParams params) throws GitException, UnauthorizedException {
List<Map<String, String>> updates = new ArrayList<>();
String currentBranch = getCurrentBranch();
String currentRefName = getCurrentReference().getName();
String remoteName = params.getRemote();
String remoteUri =
getRepository()
@ -1493,8 +1504,8 @@ class JGitConnection implements GitConnection {
remoteRefName.startsWith("refs/for/")
? remoteRefName.substring("refs/for/".length())
: remoteRefName;
if (!currentBranch.equals(Repository.shortenRefName(remoteRefName))
&& !currentBranch.equals(shortenRefFor)
if (!currentRefName.equals(Repository.shortenRefName(remoteRefName))
&& !currentRefName.equals(shortenRefFor)
&& !remoteRefName.startsWith(R_TAGS)) {
continue;
}
@ -1510,7 +1521,7 @@ class JGitConnection implements GitConnection {
String errorMessage =
format(
ERROR_PUSH_CONFLICTS_PRESENT,
currentBranch + BRANCH_REFSPEC_SEPERATOR + remoteBranch,
currentRefName + BRANCH_REFSPEC_SEPERATOR + remoteBranch,
remoteUri);
if (remoteRefUpdate.getMessage() != null) {
errorMessage += "\nError errorMessage: " + remoteRefUpdate.getMessage() + ".";
@ -1878,12 +1889,11 @@ class JGitConnection implements GitConnection {
if (CHECKOUT_REPOSITORIES.contains(repositoryPath)) {
throw new GitCheckoutInProgressException(CHECKOUT_IN_PROGRESS_ERROR);
}
String branchName = getCurrentBranch();
StatusCommand statusCommand = getGit().status();
if (filter != null) {
filter.forEach(statusCommand::addPath);
}
return new JGitStatusImpl(branchName, statusCommand);
return new JGitStatusImpl(getCurrentReference(), statusCommand);
}
@Override
@ -2241,12 +2251,7 @@ class JGitConnection implements GitConnection {
return getRepository().getDirectory().getPath();
}
/**
* Get the current branch on the current directory
*
* @return the name of the branch
* @throws GitException if any exception occurs
*/
@Override
public String getCurrentBranch() throws GitException {
try {
return Repository.shortenRefName(repository.exactRef(HEAD).getLeaf().getName());
@ -2255,6 +2260,33 @@ class JGitConnection implements GitConnection {
}
}
/**
* Get the current reference on the current directory
*
* @return reference object with branch, tag or commit id
* @throws GitException if any exception occurs
*/
public Reference getCurrentReference() throws GitException {
try {
String reference = Repository.shortenRefName(repository.exactRef(HEAD).getLeaf().getName());
if (HEAD.equals(reference)) {
reference = repository.resolve(HEAD).getName();
try (RevWalk revWalk = new RevWalk(repository)) {
for (Tag tag : tagList(null)) {
String tagName = tag.getName();
if (revWalk.parseCommit(repository.resolve(tagName)).getName().equals(reference)) {
return new Reference(tagName, TAG) {};
}
}
}
return new Reference(reference, COMMIT) {};
}
return new Reference(reference, BRANCH) {};
} catch (IOException exception) {
throw new GitException(exception.getMessage(), exception);
}
}
/**
* Method for cleaning name of remote branch to be checked out. I.e. it takes something like
* "origin/testBranch" and returns "testBranch". This is needed for view-compatibility with

View File

@ -12,12 +12,16 @@
package org.eclipse.che.git.impl.jgit;
import static java.lang.System.lineSeparator;
import static org.eclipse.che.api.git.ReferenceType.BRANCH;
import static org.eclipse.che.api.git.ReferenceType.COMMIT;
import static org.eclipse.jgit.lib.Constants.HEAD;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.che.api.git.InfoPage;
import org.eclipse.che.api.git.Reference;
import org.eclipse.che.api.git.exception.GitException;
import org.eclipse.che.api.git.shared.Status;
import org.eclipse.jgit.api.StatusCommand;
@ -30,7 +34,9 @@ import org.eclipse.jgit.api.errors.GitAPIException;
*/
public class JGitStatusImpl implements Status, InfoPage {
private final Reference reference;
private String branchName;
private String refName;
private boolean clean;
private List<String> added;
private List<String> changed;
@ -43,12 +49,14 @@ public class JGitStatusImpl implements Status, InfoPage {
private String repositoryState;
/**
* @param branchName current repository branch name
* @param reference current reference
* @param statusCommand Jgit status command
* @throws GitException when any error occurs
*/
public JGitStatusImpl(String branchName, StatusCommand statusCommand) throws GitException {
this.branchName = branchName;
JGitStatusImpl(Reference reference, StatusCommand statusCommand) throws GitException {
this.reference = reference;
this.refName = reference.getName();
this.branchName = reference.getType() == BRANCH ? refName : HEAD;
org.eclipse.jgit.api.Status gitStatus;
try {
@ -72,7 +80,13 @@ public class JGitStatusImpl implements Status, InfoPage {
public void writeTo(OutputStream out) throws IOException {
StringBuilder status = new StringBuilder();
status.append("On branch ").append(branchName).append(lineSeparator());
status
.append(reference.getType() == BRANCH ? "On branch " : "HEAD detached at ")
.append(
reference.getType() == COMMIT
? reference.getName().substring(0, 8)
: reference.getName())
.append(lineSeparator());
if (isClean()) {
status.append(lineSeparator()).append("nothing to commit, working directory clean");
} else {
@ -118,6 +132,16 @@ public class JGitStatusImpl implements Status, InfoPage {
this.clean = clean;
}
@Override
public String getRefName() {
return refName;
}
@Override
public void setRefName(String refName) {
this.refName = refName;
}
@Override
public String getBranchName() {
return branchName;

View File

@ -223,7 +223,7 @@ public class JGitConnectionTest {
when(repository.exactRef(Constants.HEAD)).thenReturn(ref);
when(ref.getLeaf()).thenReturn(ref);
when(ref.getName()).thenReturn(branchTest);
String branchName = jGitConnection.getCurrentBranch();
String branchName = jGitConnection.getCurrentReference().getName();
assertEquals(branchName, branchTest);
}