mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-12-24 01:09:48 +01:00
merge 2.0.0
This commit is contained in:
@@ -38,6 +38,7 @@ import com.google.common.base.Strings;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.Status;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.api.errors.RefNotFoundException;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
@@ -217,7 +218,8 @@ class AbstractGitCommand
|
||||
Optional<RevCommit> doCommit(String message, Person author) {
|
||||
Person authorToUse = determineAuthor(author);
|
||||
try {
|
||||
if (!clone.status().call().isClean()) {
|
||||
Status status = clone.status().call();
|
||||
if (!status.isClean() || isInMerge()) {
|
||||
return of(clone.commit()
|
||||
.setAuthor(authorToUse.getName(), authorToUse.getMail())
|
||||
.setMessage(message)
|
||||
@@ -225,11 +227,15 @@ class AbstractGitCommand
|
||||
} else {
|
||||
return empty();
|
||||
}
|
||||
} catch (GitAPIException e) {
|
||||
} catch (GitAPIException | IOException e) {
|
||||
throw new InternalRepositoryException(context.getRepository(), "could not commit changes", e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInMerge() throws IOException {
|
||||
return clone.getRepository().readMergeHeads() != null && !clone.getRepository().readMergeHeads().isEmpty();
|
||||
}
|
||||
|
||||
void push() {
|
||||
try {
|
||||
clone.push().call();
|
||||
|
||||
@@ -1,28 +1,23 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import type { Repository, Link } from "@scm-manager/ui-types";
|
||||
import { ButtonAddons, Button } from "@scm-manager/ui-components";
|
||||
import type { Repository } from "@scm-manager/ui-types";
|
||||
import CloneInformation from "./CloneInformation";
|
||||
import type { Link } from "@scm-manager/ui-types";
|
||||
import injectSheets from "react-jss";
|
||||
|
||||
const styles = {
|
||||
protocols: {
|
||||
position: "relative"
|
||||
},
|
||||
switcher: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0
|
||||
}
|
||||
};
|
||||
const Wrapper = styled.div`
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const Switcher = styled(ButtonAddons)`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
repository: Repository,
|
||||
|
||||
// context props
|
||||
classes: Object
|
||||
}
|
||||
repository: Repository
|
||||
};
|
||||
|
||||
type State = {
|
||||
selected?: Link
|
||||
@@ -43,8 +38,7 @@ function selectHttpOrFirst(repository: Repository) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
class ProtocolInformation extends React.Component<Props, State> {
|
||||
|
||||
export default class ProtocolInformation extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@@ -64,19 +58,19 @@ class ProtocolInformation extends React.Component<Props, State> {
|
||||
let color = null;
|
||||
|
||||
const { selected } = this.state;
|
||||
if ( selected && protocol.name === selected.name ) {
|
||||
if (selected && protocol.name === selected.name) {
|
||||
color = "link is-selected";
|
||||
}
|
||||
|
||||
return (
|
||||
<Button color={ color } action={() => this.selectProtocol(protocol)}>
|
||||
<Button color={color} action={() => this.selectProtocol(protocol)}>
|
||||
{name.toUpperCase()}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { repository, classes } = this.props;
|
||||
const { repository } = this.props;
|
||||
|
||||
const protocols = repository._links["protocol"];
|
||||
if (!protocols || protocols.length === 0) {
|
||||
@@ -84,25 +78,24 @@ class ProtocolInformation extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
if (protocols.length === 1) {
|
||||
return <CloneInformation url={protocols[0].href} repository={repository} />;
|
||||
return (
|
||||
<CloneInformation url={protocols[0].href} repository={repository} />
|
||||
);
|
||||
}
|
||||
|
||||
const { selected } = this.state;
|
||||
let cloneInformation = null;
|
||||
if (selected) {
|
||||
cloneInformation = <CloneInformation repository={repository} url={selected.href} />;
|
||||
cloneInformation = (
|
||||
<CloneInformation repository={repository} url={selected.href} />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes.protocols}>
|
||||
<ButtonAddons className={classes.switcher}>
|
||||
{protocols.map(this.renderProtocolButton)}
|
||||
</ButtonAddons>
|
||||
{ cloneInformation }
|
||||
</div>
|
||||
<Wrapper>
|
||||
<Switcher>{protocols.map(this.renderProtocolButton)}</Switcher>
|
||||
{cloneInformation}
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectSheets(styles)(ProtocolInformation);
|
||||
|
||||
@@ -12,8 +12,9 @@ import RepositoryConfig from "./RepositoryConfig";
|
||||
|
||||
// repository
|
||||
|
||||
const gitPredicate = (props: Object) => {
|
||||
return props.repository && props.repository.type === "git";
|
||||
// @visibleForTesting
|
||||
export const gitPredicate = (props: Object) => {
|
||||
return !!(props && props.repository && props.repository.type === "git");
|
||||
};
|
||||
|
||||
binder.bind(
|
||||
|
||||
16
scm-plugins/scm-git-plugin/src/main/js/index.test.js
Normal file
16
scm-plugins/scm-git-plugin/src/main/js/index.test.js
Normal file
@@ -0,0 +1,16 @@
|
||||
// @flow
|
||||
import "@scm-manager/ui-tests/i18n";
|
||||
import { gitPredicate } from "./index";
|
||||
|
||||
describe("test git predicate", () => {
|
||||
it("should return false", () => {
|
||||
expect(gitPredicate()).toBe(false);
|
||||
expect(gitPredicate({})).toBe(false);
|
||||
expect(gitPredicate({ repository: {} })).toBe(false);
|
||||
expect(gitPredicate({ repository: { type: "hg" } })).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true", () => {
|
||||
expect(gitPredicate({ repository: { type: "git" } })).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -55,5 +55,9 @@
|
||||
<conditions>
|
||||
<min-version>${project.parent.version}</min-version>
|
||||
</conditions>
|
||||
|
||||
<resources>
|
||||
<script>assets/scm-git-plugin.bundle.js</script>
|
||||
</resources>
|
||||
|
||||
</plugin>
|
||||
|
||||
@@ -82,6 +82,26 @@ public class GitMergeCommandTest extends AbstractGitCommandTestBase {
|
||||
assertThat(new String(contentOfFileB)).isEqualTo("b\ncontent from branch\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAllowEmptyMergeCommit() throws IOException, GitAPIException {
|
||||
GitMergeCommand command = createCommand();
|
||||
MergeCommandRequest request = new MergeCommandRequest();
|
||||
request.setTargetBranch("master");
|
||||
request.setBranchToMerge("empty_merge");
|
||||
request.setAuthor(new Person("Dirk Gently", "dirk@holistic.det"));
|
||||
|
||||
MergeCommandResult mergeCommandResult = command.merge(request);
|
||||
|
||||
assertThat(mergeCommandResult.isSuccess()).isTrue();
|
||||
|
||||
Repository repository = createContext().open();
|
||||
Iterable<RevCommit> commits = new Git(repository).log().add(repository.resolve("master")).setMaxCount(1).call();
|
||||
RevCommit mergeCommit = commits.iterator().next();
|
||||
assertThat(mergeCommit.getParentCount()).isEqualTo(2);
|
||||
assertThat(mergeCommit.getParent(0).name()).isEqualTo("fcd0ef1831e4002ac43ea539f4094334c79ea9ec");
|
||||
assertThat(mergeCommit.getParent(1).name()).isEqualTo("d81ad6c63d7e2162308d69637b339dedd1d9201c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotMergeTwice() throws IOException, GitAPIException {
|
||||
GitMergeCommand command = createCommand();
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user