Permit booleans in project.config to be inherited
Allow the parent project to supply the value for properties: * use content merge * require contributor agreement * require change id * require signed off by This makes it easier to configure a large number of projects, as the properties can be defined once on the parent and inherited. This commit modifies the default behavior when the variable is not defined in project.config, it now inherits from the parent rather than being false. Change-Id: Ic4a6ea6ff23ad16f1fc82b70cc89a480f59db010
This commit is contained in:
parent
8b5154fbac
commit
2462ccb8df
@ -11,11 +11,11 @@ SYNOPSIS
|
||||
'ssh' -p <port> <host> 'gerrit set-project'
|
||||
[--description <DESC> | -d <DESC>]
|
||||
[--submit-type <TYPE> | -t <TYPE>]
|
||||
[--use|no-contributor-agreements | --ca|nca]
|
||||
[--use|no-signed-off-by | --so|nso]
|
||||
[--use|no-content-merge]
|
||||
[--require|no-change-id | --id|nid]
|
||||
[--project-state | --ps]
|
||||
[--contributor-agreements <true|false|inherit>]
|
||||
[--signed-off-by <true|false|inherit>]
|
||||
[--content-merge <true|false|inherit>]
|
||||
[--change-id <true|false|inherit>]
|
||||
[--project-state <STATE> | --ps <STATE>]
|
||||
<NAME>
|
||||
|
||||
DESCRIPTION
|
||||
@ -63,26 +63,23 @@ Description values containing spaces should be quoted in single quotes
|
||||
For more details see
|
||||
link:project-setup.html#submit_type[Change Submit Actions].
|
||||
|
||||
--use|no-content-merge::
|
||||
--content-merge::
|
||||
If enabled, Gerrit will try to perform a 3-way merge of text
|
||||
file content when a file has been modified by both the
|
||||
destination branch and the change being submitted. This
|
||||
option only takes effect if submit type is not
|
||||
FAST_FORWARD_ONLY.
|
||||
|
||||
--use|no-contributor-agreements::
|
||||
--ca|nca::
|
||||
--contributor-agreements::
|
||||
If enabled, authors must complete a contributor agreement
|
||||
on the site before pushing any commits or changes to this
|
||||
project.
|
||||
|
||||
--use|no-signed-off-by::
|
||||
--so|nso:
|
||||
--signed-off-by::
|
||||
If enabled, each change must contain a Signed-off-by line
|
||||
from either the author or the uploader in the commit message.
|
||||
|
||||
--require|no-change-id::
|
||||
--id|nid::
|
||||
--change-id::
|
||||
Require a valid link:user-changeid.html[Change-Id] footer
|
||||
in any commit uploaded for review. This does not apply to
|
||||
commits pushed directly to a branch or tag.
|
||||
@ -103,7 +100,7 @@ and use 'merge if necessary' as merge strategy:
|
||||
|
||||
====
|
||||
$ ssh -p 29418 review.example.com gerrit set-project example --submit-type MERGE_IF_NECESSARY\
|
||||
--require-change-id --no-content-merge --project-state HIDDEN
|
||||
--change-id true --content-merge false --project-state HIDDEN
|
||||
====
|
||||
|
||||
GERRIT
|
||||
|
@ -21,13 +21,16 @@ import com.google.gerrit.client.ui.OnEditEnabler;
|
||||
import com.google.gerrit.client.ui.SmallHeading;
|
||||
import com.google.gerrit.common.data.ProjectDetail;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.Project.InheritedBoolean;
|
||||
import com.google.gerrit.reviewdb.client.Project.SubmitType;
|
||||
import com.google.gwt.event.dom.client.ChangeEvent;
|
||||
import com.google.gwt.event.dom.client.ChangeHandler;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.CheckBox;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.InlineHTML;
|
||||
import com.google.gwt.user.client.ui.InlineLabel;
|
||||
import com.google.gwt.user.client.ui.ListBox;
|
||||
import com.google.gwt.user.client.ui.Panel;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
@ -37,14 +40,14 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
private Project project;
|
||||
|
||||
private Panel projectOptionsPanel;
|
||||
private CheckBox requireChangeID;
|
||||
private ListBox requireChangeID;
|
||||
private ListBox submitType;
|
||||
private ListBox state;
|
||||
private CheckBox useContentMerge;
|
||||
private ListBox contentMerge;
|
||||
|
||||
private Panel agreementsPanel;
|
||||
private CheckBox useContributorAgreements;
|
||||
private CheckBox useSignedOffBy;
|
||||
private ListBox contributorAgreements;
|
||||
private ListBox signedOffBy;
|
||||
|
||||
private NpTextArea descTxt;
|
||||
private Button saveProject;
|
||||
@ -96,10 +99,10 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
final boolean canModifyState) {
|
||||
submitType.setEnabled(canModifyMergeType);
|
||||
state.setEnabled(canModifyState);
|
||||
useContentMerge.setEnabled(canModifyMergeType);
|
||||
contentMerge.setEnabled(canModifyMergeType);
|
||||
descTxt.setEnabled(canModifyDescription);
|
||||
useContributorAgreements.setEnabled(canModifyAgreements);
|
||||
useSignedOffBy.setEnabled(canModifyAgreements);
|
||||
contributorAgreements.setEnabled(canModifyAgreements);
|
||||
signedOffBy.setEnabled(canModifyAgreements);
|
||||
requireChangeID.setEnabled(canModifyMergeType);
|
||||
}
|
||||
|
||||
@ -142,19 +145,33 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
saveEnabler.listenTo(state);
|
||||
projectOptionsPanel.add(state);
|
||||
|
||||
useContentMerge = new CheckBox(Util.C.useContentMerge(), true);
|
||||
saveEnabler.listenTo(useContentMerge);
|
||||
projectOptionsPanel.add(useContentMerge);
|
||||
contentMerge = newInheritedBooleanBox();
|
||||
FlowPanel fp = new FlowPanel();
|
||||
fp.add(contentMerge);
|
||||
fp.add(new InlineLabel(Util.C.useContentMerge()));
|
||||
saveEnabler.listenTo(contentMerge);
|
||||
projectOptionsPanel.add(fp);
|
||||
|
||||
requireChangeID = new CheckBox(Util.C.requireChangeID(), true);
|
||||
requireChangeID = newInheritedBooleanBox();
|
||||
fp = new FlowPanel();
|
||||
fp.add(requireChangeID);
|
||||
fp.add(new InlineHTML(Util.C.requireChangeID()));
|
||||
saveEnabler.listenTo(requireChangeID);
|
||||
projectOptionsPanel.add(requireChangeID);
|
||||
projectOptionsPanel.add(fp);
|
||||
|
||||
add(projectOptionsPanel);
|
||||
}
|
||||
|
||||
private static ListBox newInheritedBooleanBox() {
|
||||
ListBox box = new ListBox();
|
||||
for (InheritedBoolean b : InheritedBoolean.values()) {
|
||||
box.addItem(b.name(), b.name());
|
||||
}
|
||||
return box;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the {@link #useContentMerge} checkbox if the selected submit type
|
||||
* Enables the {@link #contentMerge} checkbox if the selected submit type
|
||||
* allows the usage of content merge.
|
||||
* If the submit type (currently only 'Fast Forward Only') does not allow
|
||||
* content merge the useContentMerge checkbox gets disabled.
|
||||
@ -162,10 +179,10 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
private void setEnabledForUseContentMerge() {
|
||||
if (SubmitType.FAST_FORWARD_ONLY.equals(Project.SubmitType
|
||||
.valueOf(submitType.getValue(submitType.getSelectedIndex())))) {
|
||||
useContentMerge.setEnabled(false);
|
||||
useContentMerge.setValue(false);
|
||||
contentMerge.setEnabled(false);
|
||||
setBool(contentMerge, InheritedBoolean.FALSE);
|
||||
} else {
|
||||
useContentMerge.setEnabled(submitType.isEnabled());
|
||||
contentMerge.setEnabled(submitType.isEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,13 +190,21 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
agreementsPanel = new VerticalPanel();
|
||||
agreementsPanel.add(new SmallHeading(Util.C.headingAgreements()));
|
||||
|
||||
useContributorAgreements = new CheckBox(Util.C.useContributorAgreements());
|
||||
saveEnabler.listenTo(useContributorAgreements);
|
||||
agreementsPanel.add(useContributorAgreements);
|
||||
contributorAgreements = newInheritedBooleanBox();
|
||||
if (Gerrit.getConfig().isUseContributorAgreements()) {
|
||||
FlowPanel fp = new FlowPanel();
|
||||
fp.add(contributorAgreements);
|
||||
fp.add(new InlineLabel(Util.C.useContributorAgreements()));
|
||||
saveEnabler.listenTo(contributorAgreements);
|
||||
agreementsPanel.add(fp);
|
||||
}
|
||||
|
||||
useSignedOffBy = new CheckBox(Util.C.useSignedOffBy(), true);
|
||||
saveEnabler.listenTo(useSignedOffBy);
|
||||
agreementsPanel.add(useSignedOffBy);
|
||||
signedOffBy = newInheritedBooleanBox();
|
||||
FlowPanel fp = new FlowPanel();
|
||||
fp.add(signedOffBy);
|
||||
fp.add(new InlineHTML(Util.C.useSignedOffBy()));
|
||||
saveEnabler.listenTo(signedOffBy);
|
||||
agreementsPanel.add(fp);
|
||||
|
||||
add(agreementsPanel);
|
||||
}
|
||||
@ -209,21 +234,31 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
}
|
||||
}
|
||||
|
||||
private static void setBool(ListBox box, InheritedBoolean val) {
|
||||
for (int i = 0; i < box.getItemCount(); i++) {
|
||||
if (val.name().equals(box.getValue(i))) {
|
||||
box.setSelectedIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static InheritedBoolean getBool(ListBox box) {
|
||||
int i = box.getSelectedIndex();
|
||||
if (i >= 0) {
|
||||
return InheritedBoolean.valueOf(box.getValue(i));
|
||||
}
|
||||
return InheritedBoolean.INHERIT;
|
||||
}
|
||||
|
||||
void display(final ProjectDetail result) {
|
||||
project = result.project;
|
||||
|
||||
final boolean isall =
|
||||
Gerrit.getConfig().getWildProject().equals(project.getNameKey());
|
||||
projectOptionsPanel.setVisible(!isall);
|
||||
agreementsPanel.setVisible(!isall);
|
||||
useContributorAgreements.setVisible(Gerrit.getConfig()
|
||||
.isUseContributorAgreements());
|
||||
|
||||
descTxt.setText(project.getDescription());
|
||||
useContributorAgreements.setValue(project.isUseContributorAgreements());
|
||||
useSignedOffBy.setValue(project.isUseSignedOffBy());
|
||||
useContentMerge.setValue(project.isUseContentMerge());
|
||||
requireChangeID.setValue(project.isRequireChangeID());
|
||||
setBool(contributorAgreements, project.getUseContributorAgreements());
|
||||
setBool(signedOffBy, project.getUseSignedOffBy());
|
||||
setBool(contentMerge, project.getUseContentMerge());
|
||||
setBool(requireChangeID, project.getRequireChangeID());
|
||||
setSubmitType(project.getSubmitType());
|
||||
setState(project.getState());
|
||||
|
||||
@ -232,10 +267,10 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
|
||||
private void doSave() {
|
||||
project.setDescription(descTxt.getText().trim());
|
||||
project.setUseContributorAgreements(useContributorAgreements.getValue());
|
||||
project.setUseSignedOffBy(useSignedOffBy.getValue());
|
||||
project.setUseContentMerge(useContentMerge.getValue());
|
||||
project.setRequireChangeID(requireChangeID.getValue());
|
||||
project.setUseContributorAgreements(getBool(contributorAgreements));
|
||||
project.setUseSignedOffBy(getBool(signedOffBy));
|
||||
project.setUseContentMerge(getBool(contentMerge));
|
||||
project.setRequireChangeID(getBool(requireChangeID));
|
||||
if (submitType.getSelectedIndex() >= 0) {
|
||||
project.setSubmitType(Project.SubmitType.valueOf(submitType
|
||||
.getValue(submitType.getSelectedIndex())));
|
||||
|
@ -85,13 +85,19 @@ public final class Project {
|
||||
HIDDEN;
|
||||
}
|
||||
|
||||
public static enum InheritedBoolean {
|
||||
TRUE,
|
||||
FALSE,
|
||||
INHERIT;
|
||||
}
|
||||
|
||||
protected NameKey name;
|
||||
|
||||
protected String description;
|
||||
|
||||
protected boolean useContributorAgreements;
|
||||
protected InheritedBoolean useContributorAgreements;
|
||||
|
||||
protected boolean useSignedOffBy;
|
||||
protected InheritedBoolean useSignedOffBy;
|
||||
|
||||
protected SubmitType submitType;
|
||||
|
||||
@ -99,9 +105,9 @@ public final class Project {
|
||||
|
||||
protected NameKey parent;
|
||||
|
||||
protected boolean requireChangeID;
|
||||
protected InheritedBoolean requireChangeID;
|
||||
|
||||
protected boolean useContentMerge;
|
||||
protected InheritedBoolean useContentMerge;
|
||||
|
||||
protected Project() {
|
||||
}
|
||||
@ -110,6 +116,10 @@ public final class Project {
|
||||
name = nameKey;
|
||||
submitType = SubmitType.MERGE_IF_NECESSARY;
|
||||
state = State.ACTIVE;
|
||||
useContributorAgreements = InheritedBoolean.INHERIT;
|
||||
useSignedOffBy = InheritedBoolean.INHERIT;
|
||||
requireChangeID = InheritedBoolean.INHERIT;
|
||||
useContentMerge = InheritedBoolean.INHERIT;
|
||||
}
|
||||
|
||||
public Project.NameKey getNameKey() {
|
||||
@ -128,35 +138,35 @@ public final class Project {
|
||||
description = d;
|
||||
}
|
||||
|
||||
public boolean isUseContributorAgreements() {
|
||||
public InheritedBoolean getUseContributorAgreements() {
|
||||
return useContributorAgreements;
|
||||
}
|
||||
|
||||
public void setUseContributorAgreements(final boolean u) {
|
||||
useContributorAgreements = u;
|
||||
}
|
||||
|
||||
public boolean isUseSignedOffBy() {
|
||||
public InheritedBoolean getUseSignedOffBy() {
|
||||
return useSignedOffBy;
|
||||
}
|
||||
|
||||
public boolean isUseContentMerge() {
|
||||
public InheritedBoolean getUseContentMerge() {
|
||||
return useContentMerge;
|
||||
}
|
||||
|
||||
public boolean isRequireChangeID() {
|
||||
public InheritedBoolean getRequireChangeID() {
|
||||
return requireChangeID;
|
||||
}
|
||||
|
||||
public void setUseSignedOffBy(final boolean sbo) {
|
||||
public void setUseContributorAgreements(final InheritedBoolean u) {
|
||||
useContributorAgreements = u;
|
||||
}
|
||||
|
||||
public void setUseSignedOffBy(final InheritedBoolean sbo) {
|
||||
useSignedOffBy = sbo;
|
||||
}
|
||||
|
||||
public void setUseContentMerge(final boolean cm) {
|
||||
public void setUseContentMerge(final InheritedBoolean cm) {
|
||||
useContentMerge = cm;
|
||||
}
|
||||
|
||||
public void setRequireChangeID(final boolean cid) {
|
||||
public void setRequireChangeID(final InheritedBoolean cid) {
|
||||
requireChangeID = cid;
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ public class MergeOp {
|
||||
|
||||
private final PersonIdent myIdent;
|
||||
private final Branch.NameKey destBranch;
|
||||
private Project destProject;
|
||||
private ProjectState destProject;
|
||||
private final ListMultimap<SubmitType, CodeReviewCommit> toMerge;
|
||||
private final List<CodeReviewCommit> potentiallyStillSubmittable;
|
||||
private final Map<Change.Id, CodeReviewCommit> commits;
|
||||
@ -253,11 +253,10 @@ public class MergeOp {
|
||||
}
|
||||
|
||||
private void setDestProject() throws MergeException {
|
||||
final ProjectState pe = projectCache.get(destBranch.getParentKey());
|
||||
if (pe == null) {
|
||||
destProject = projectCache.get(destBranch.getParentKey());
|
||||
if (destProject == null) {
|
||||
throw new MergeException("No such project: " + destBranch.getParentKey());
|
||||
}
|
||||
destProject = pe.getProject();
|
||||
}
|
||||
|
||||
private void openSchema() throws OrmException {
|
||||
@ -602,12 +601,13 @@ public class MergeOp {
|
||||
if (mergeTip != null && (branchTip == null || branchTip != mergeTip)) {
|
||||
if (GitRepositoryManager.REF_CONFIG.equals(branchUpdate.getName())) {
|
||||
try {
|
||||
ProjectConfig cfg = new ProjectConfig(destProject.getNameKey());
|
||||
ProjectConfig cfg =
|
||||
new ProjectConfig(destProject.getProject().getNameKey());
|
||||
cfg.load(repo, mergeTip);
|
||||
} catch (Exception e) {
|
||||
throw new MergeException("Submit would store invalid"
|
||||
+ " project configuration " + mergeTip.name() + " for "
|
||||
+ destProject.getName(), e);
|
||||
+ destProject.getProject().getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -627,10 +627,11 @@ public class MergeOp {
|
||||
}
|
||||
|
||||
if (GitRepositoryManager.REF_CONFIG.equals(branchUpdate.getName())) {
|
||||
projectCache.evict(destProject);
|
||||
ProjectState ps = projectCache.get(destProject.getNameKey());
|
||||
repoManager.setProjectDescription(destProject.getNameKey(), //
|
||||
ps.getProject().getDescription());
|
||||
projectCache.evict(destProject.getProject());
|
||||
destProject = projectCache.get(destProject.getProject().getNameKey());
|
||||
repoManager.setProjectDescription(
|
||||
destProject.getProject().getNameKey(),
|
||||
destProject.getProject().getDescription());
|
||||
}
|
||||
|
||||
replication.fire(destBranch.getParentKey(), branchUpdate.getName());
|
||||
@ -732,8 +733,8 @@ public class MergeOp {
|
||||
private void updateSubscriptions(final List<Change> submitted) {
|
||||
if (mergeTip != null && (branchTip == null || branchTip != mergeTip)) {
|
||||
SubmoduleOp subOp =
|
||||
subOpFactory.create(destBranch, mergeTip, rw, repo, destProject,
|
||||
submitted, commits);
|
||||
subOpFactory.create(destBranch, mergeTip, rw, repo,
|
||||
destProject.getProject(), submitted, commits);
|
||||
try {
|
||||
subOp.update();
|
||||
} catch (SubmoduleException e) {
|
||||
|
@ -282,12 +282,12 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
}
|
||||
p.setParentName(rc.getString(ACCESS, null, KEY_INHERIT_FROM));
|
||||
|
||||
p.setUseContributorAgreements(getBoolean(rc, RECEIVE, KEY_REQUIRE_CONTRIBUTOR_AGREEMENT, false));
|
||||
p.setUseSignedOffBy(getBoolean(rc, RECEIVE, KEY_REQUIRE_SIGNED_OFF_BY, false));
|
||||
p.setRequireChangeID(getBoolean(rc, RECEIVE, KEY_REQUIRE_CHANGE_ID, false));
|
||||
p.setUseContributorAgreements(getEnum(rc, RECEIVE, null, KEY_REQUIRE_CONTRIBUTOR_AGREEMENT, Project.InheritedBoolean.INHERIT));
|
||||
p.setUseSignedOffBy(getEnum(rc, RECEIVE, null, KEY_REQUIRE_SIGNED_OFF_BY, Project.InheritedBoolean.INHERIT));
|
||||
p.setRequireChangeID(getEnum(rc, RECEIVE, null, KEY_REQUIRE_CHANGE_ID, Project.InheritedBoolean.INHERIT));
|
||||
|
||||
p.setSubmitType(getEnum(rc, SUBMIT, null, KEY_ACTION, defaultSubmitAction));
|
||||
p.setUseContentMerge(getBoolean(rc, SUBMIT, KEY_MERGE_CONTENT, false));
|
||||
p.setUseContentMerge(getEnum(rc, SUBMIT, null, KEY_MERGE_CONTENT, Project.InheritedBoolean.INHERIT));
|
||||
p.setState(getEnum(rc, PROJECT, null, KEY_STATE, defaultStateValue));
|
||||
|
||||
loadAccountsSection(rc, groupsByName);
|
||||
@ -525,12 +525,12 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
}
|
||||
set(rc, ACCESS, null, KEY_INHERIT_FROM, p.getParentName());
|
||||
|
||||
set(rc, RECEIVE, null, KEY_REQUIRE_CONTRIBUTOR_AGREEMENT, p.isUseContributorAgreements());
|
||||
set(rc, RECEIVE, null, KEY_REQUIRE_SIGNED_OFF_BY, p.isUseSignedOffBy());
|
||||
set(rc, RECEIVE, null, KEY_REQUIRE_CHANGE_ID, p.isRequireChangeID());
|
||||
set(rc, RECEIVE, null, KEY_REQUIRE_CONTRIBUTOR_AGREEMENT, p.getUseContributorAgreements(), Project.InheritedBoolean.INHERIT);
|
||||
set(rc, RECEIVE, null, KEY_REQUIRE_SIGNED_OFF_BY, p.getUseSignedOffBy(), Project.InheritedBoolean.INHERIT);
|
||||
set(rc, RECEIVE, null, KEY_REQUIRE_CHANGE_ID, p.getRequireChangeID(), Project.InheritedBoolean.INHERIT);
|
||||
|
||||
set(rc, SUBMIT, null, KEY_ACTION, p.getSubmitType(), defaultSubmitAction);
|
||||
set(rc, SUBMIT, null, KEY_MERGE_CONTENT, p.isUseContentMerge());
|
||||
set(rc, SUBMIT, null, KEY_MERGE_CONTENT, p.getUseContentMerge(), Project.InheritedBoolean.INHERIT);
|
||||
|
||||
set(rc, PROJECT, null, KEY_STATE, p.getState(), null);
|
||||
|
||||
@ -734,16 +734,6 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
saveUTF8(GROUP_LIST, buf.toString());
|
||||
}
|
||||
|
||||
private boolean getBoolean(Config rc, String section, String name,
|
||||
boolean defaultValue) {
|
||||
try {
|
||||
return rc.getBoolean(section, name, defaultValue);
|
||||
} catch (IllegalArgumentException err) {
|
||||
error(new ValidationError(PROJECT_CONFIG, err.getMessage()));
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
private <E extends Enum<?>> E getEnum(Config rc, String section,
|
||||
String subsection, String name, E defaultValue) {
|
||||
try {
|
||||
|
@ -14,8 +14,8 @@
|
||||
|
||||
package com.google.gerrit.server.git;
|
||||
|
||||
import static org.eclipse.jgit.lib.Constants.R_HEADS;
|
||||
import static com.google.gerrit.server.git.MultiProgressMonitor.UNKNOWN;
|
||||
import static org.eclipse.jgit.lib.Constants.R_HEADS;
|
||||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
|
||||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.OK;
|
||||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_MISSING_OBJECT;
|
||||
@ -79,6 +79,7 @@ import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
import com.jcraft.jsch.HostKey;
|
||||
|
||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
||||
import org.eclipse.jgit.errors.MissingObjectException;
|
||||
import org.eclipse.jgit.lib.AbbreviatedObjectId;
|
||||
@ -1868,7 +1869,7 @@ public class ReceiveCommits {
|
||||
&& ctl.canForgeCommitter()
|
||||
&& ctl.canForgeGerritServerIdentity()
|
||||
&& ctl.canUploadMerges()
|
||||
&& !project.isUseSignedOffBy()
|
||||
&& !projectControl.getProjectState().isUseSignedOffBy()
|
||||
&& Iterables.isEmpty(rejectCommits)
|
||||
&& !GitRepositoryManager.REF_CONFIG.equals(ctl.getRefName())
|
||||
&& !(MagicBranch.isMagicBranch(cmd.getRefName())
|
||||
@ -1954,7 +1955,7 @@ public class ReceiveCommits {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (project.isUseSignedOffBy()) {
|
||||
if (projectControl.getProjectState().isUseSignedOffBy()) {
|
||||
// If the project wants Signed-off-by / Acked-by lines, verify we
|
||||
// have them for the blamable parties involved on this change.
|
||||
//
|
||||
@ -1978,7 +1979,7 @@ public class ReceiveCommits {
|
||||
final List<String> idList = c.getFooterLines(CHANGE_ID);
|
||||
if (MagicBranch.isMagicBranch(cmd.getRefName()) || NEW_PATCHSET.matcher(cmd.getRefName()).matches()) {
|
||||
if (idList.isEmpty()) {
|
||||
if (project.isRequireChangeID()) {
|
||||
if (projectControl.getProjectState().isRequireChangeID()) {
|
||||
String errMsg = "missing Change-Id in commit message";
|
||||
reject(cmd, errMsg);
|
||||
addMessage(getFixedCommitMsgWithChangeId(errMsg, c));
|
||||
|
@ -16,6 +16,7 @@ package com.google.gerrit.server.project;
|
||||
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.Project.InheritedBoolean;
|
||||
import com.google.gerrit.reviewdb.client.Project.SubmitType;
|
||||
|
||||
import java.util.List;
|
||||
@ -27,12 +28,12 @@ public class CreateProjectArgs {
|
||||
public ProjectControl newParent;
|
||||
public String projectDescription;
|
||||
public SubmitType submitType;
|
||||
public boolean contributorAgreements;
|
||||
public boolean signedOffBy;
|
||||
public InheritedBoolean contributorAgreements;
|
||||
public InheritedBoolean signedOffBy;
|
||||
public boolean permissionsOnly;
|
||||
public List<String> branch;
|
||||
public boolean contentMerge;
|
||||
public boolean changeIdRequired;
|
||||
public InheritedBoolean contentMerge;
|
||||
public InheritedBoolean changeIdRequired;
|
||||
public boolean createEmptyCommit;
|
||||
|
||||
public CreateProjectArgs() {
|
||||
|
@ -232,8 +232,7 @@ public class ProjectControl {
|
||||
String pName = state.getProject().getName();
|
||||
return new Capable("Upload denied for project '" + pName + "'");
|
||||
}
|
||||
Project project = state.getProject();
|
||||
if (project.isUseContributorAgreements()) {
|
||||
if (state.isUseContributorAgreements()) {
|
||||
return verifyActiveContributorAgreement();
|
||||
}
|
||||
return Capable.OK;
|
||||
|
@ -14,13 +14,16 @@
|
||||
|
||||
package com.google.gerrit.server.project;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.Project.InheritedBoolean;
|
||||
import com.google.gerrit.rules.PrologEnvironment;
|
||||
import com.google.gerrit.rules.RulesCache;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
@ -295,4 +298,63 @@ public class ProjectState {
|
||||
public boolean isAllProjects() {
|
||||
return isAllProjects;
|
||||
}
|
||||
|
||||
public boolean isUseContributorAgreements() {
|
||||
return getInheritedBoolean(new Function<Project, InheritedBoolean>() {
|
||||
@Override
|
||||
public InheritedBoolean apply(Project input) {
|
||||
return input.getUseContributorAgreements();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isUseContentMerge() {
|
||||
return getInheritedBoolean(new Function<Project, InheritedBoolean>() {
|
||||
@Override
|
||||
public InheritedBoolean apply(Project input) {
|
||||
return input.getUseContentMerge();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isUseSignedOffBy() {
|
||||
return getInheritedBoolean(new Function<Project, InheritedBoolean>() {
|
||||
@Override
|
||||
public InheritedBoolean apply(Project input) {
|
||||
return input.getUseSignedOffBy();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isRequireChangeID() {
|
||||
return getInheritedBoolean(new Function<Project, InheritedBoolean>() {
|
||||
@Override
|
||||
public InheritedBoolean apply(Project input) {
|
||||
return input.getRequireChangeID();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean getInheritedBoolean(Function<Project, InheritedBoolean> func) {
|
||||
Set<Project.NameKey> seen = Sets.newHashSet();
|
||||
seen.add(getProject().getNameKey());
|
||||
ProjectState s = this;
|
||||
do {
|
||||
switch (func.apply(s.getProject())) {
|
||||
case TRUE:
|
||||
return true;
|
||||
case FALSE:
|
||||
return false;
|
||||
case INHERIT:
|
||||
default:
|
||||
Project.NameKey parent = s.getProject().getParent(allProjectsName);
|
||||
if (parent != null && seen.add(parent)) {
|
||||
s = projectCache.get(parent);
|
||||
} else {
|
||||
s = null;
|
||||
}
|
||||
}
|
||||
} while (s != null);
|
||||
return false;
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ import com.google.gerrit.reviewdb.client.ApprovalCategory;
|
||||
import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
|
||||
import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.Project.InheritedBoolean;
|
||||
import com.google.gerrit.reviewdb.client.SystemConfig;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.GerritPersonIdent;
|
||||
@ -209,7 +210,10 @@ public class SchemaCreator {
|
||||
ProjectConfig config = ProjectConfig.read(md);
|
||||
Project p = config.getProject();
|
||||
p.setDescription("Rights inherited by all other projects");
|
||||
p.setUseContributorAgreements(false);
|
||||
p.setRequireChangeID(InheritedBoolean.TRUE);
|
||||
p.setUseContentMerge(InheritedBoolean.FALSE);
|
||||
p.setUseContributorAgreements(InheritedBoolean.FALSE);
|
||||
p.setUseSignedOffBy(InheritedBoolean.FALSE);
|
||||
|
||||
AccessSection cap = config.getAccessSection(AccessSection.GLOBAL_CAPABILITIES, true);
|
||||
AccessSection all = config.getAccessSection(AccessSection.ALL, true);
|
||||
|
@ -33,6 +33,7 @@ import com.google.gerrit.common.data.PermissionRule;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.ApprovalCategory;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.Project.InheritedBoolean;
|
||||
import com.google.gerrit.reviewdb.client.SystemConfig;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.GerritPersonIdent;
|
||||
@ -200,8 +201,7 @@ class Schema_53 extends SchemaVersion {
|
||||
private void loadProject(ResultSet rs, Project project) throws SQLException,
|
||||
OrmException {
|
||||
project.setDescription(rs.getString("description"));
|
||||
project.setUseContributorAgreements("Y".equals(rs
|
||||
.getString("use_contributor_agreements")));
|
||||
project.setUseContributorAgreements(asInheritedBoolean(rs, "use_contributor_agreements"));
|
||||
|
||||
switch (rs.getString("submit_type").charAt(0)) {
|
||||
case 'F':
|
||||
@ -221,12 +221,19 @@ class Schema_53 extends SchemaVersion {
|
||||
+ rs.getString("submit_type") + " on project " + project.getName());
|
||||
}
|
||||
|
||||
project.setUseSignedOffBy("Y".equals(rs.getString("use_signed_off_by")));
|
||||
project.setRequireChangeID("Y".equals(rs.getString("require_change_id")));
|
||||
project.setUseContentMerge("Y".equals(rs.getString("use_content_merge")));
|
||||
project.setUseSignedOffBy(asInheritedBoolean(rs, "use_signed_off_by"));
|
||||
project.setRequireChangeID(asInheritedBoolean(rs, "require_change_id"));
|
||||
project.setUseContentMerge(asInheritedBoolean(rs, "use_content_merge"));
|
||||
project.setParentName(rs.getString("parent_name"));
|
||||
}
|
||||
|
||||
private static InheritedBoolean asInheritedBoolean(ResultSet rs, String col)
|
||||
throws SQLException {
|
||||
return "Y".equals(rs.getString(col))
|
||||
? Project.InheritedBoolean.TRUE
|
||||
: Project.InheritedBoolean.INHERIT;
|
||||
}
|
||||
|
||||
private void readOldRefRights(ReviewDb db) throws SQLException {
|
||||
rightsByProject = new HashMap<Project.NameKey, List<OldRefRight>>();
|
||||
|
||||
|
@ -19,6 +19,7 @@ import com.google.gerrit.common.errors.ProjectCreationFailedException;
|
||||
import com.google.gerrit.extensions.annotations.RequiresCapability;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.Project.InheritedBoolean;
|
||||
import com.google.gerrit.reviewdb.client.Project.SubmitType;
|
||||
import com.google.gerrit.server.project.CreateProject;
|
||||
import com.google.gerrit.server.project.CreateProjectArgs;
|
||||
@ -64,17 +65,37 @@ final class CreateProjectCommand extends SshCommand {
|
||||
+ "(default: MERGE_IF_NECESSARY)")
|
||||
private SubmitType submitType = SubmitType.MERGE_IF_NECESSARY;
|
||||
|
||||
@Option(name = "--contributor-agreements", usage = "if contributor agreement is required")
|
||||
private InheritedBoolean contributorAgreements;
|
||||
|
||||
@Option(name = "--signed-off-by", usage = "if signed-off-by is required")
|
||||
private InheritedBoolean signedOffBy = InheritedBoolean.INHERIT;
|
||||
|
||||
@Option(name = "--content-merge", usage = "allow automatic conflict resolving within files")
|
||||
private InheritedBoolean contentMerge = InheritedBoolean.INHERIT;
|
||||
|
||||
@Option(name = "--change-id", usage = "if change-id is required")
|
||||
private InheritedBoolean requireChangeID = InheritedBoolean.INHERIT;
|
||||
|
||||
@Option(name = "--use-contributor-agreements", aliases = {"--ca"}, usage = "if contributor agreement is required")
|
||||
private boolean contributorAgreements;
|
||||
void setUseContributorArgreements(boolean on) {
|
||||
contributorAgreements = InheritedBoolean.TRUE;
|
||||
}
|
||||
|
||||
@Option(name = "--use-signed-off-by", aliases = {"--so"}, usage = "if signed-off-by is required")
|
||||
private boolean signedOffBy;
|
||||
void setUseSignedOffBy(boolean on) {
|
||||
signedOffBy = InheritedBoolean.TRUE;
|
||||
}
|
||||
|
||||
@Option(name = "--use-content-merge", usage = "allow automatic conflict resolving within files")
|
||||
private boolean contentMerge;
|
||||
void setUseContentMerge(boolean on) {
|
||||
contentMerge = InheritedBoolean.TRUE;
|
||||
}
|
||||
|
||||
@Option(name = "--require-change-id", aliases = {"--id"}, usage = "if change-id is required")
|
||||
private boolean requireChangeID;
|
||||
void setRequireChangeId(boolean on) {
|
||||
requireChangeID = InheritedBoolean.TRUE;
|
||||
}
|
||||
|
||||
@Option(name = "--branch", aliases = {"-b"}, metaVar = "BRANCH", usage = "initial branch name\n"
|
||||
+ "(default: master)")
|
||||
|
@ -17,6 +17,7 @@ package com.google.gerrit.sshd.commands;
|
||||
import com.google.gerrit.common.data.GlobalCapability;
|
||||
import com.google.gerrit.extensions.annotations.RequiresCapability;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.Project.InheritedBoolean;
|
||||
import com.google.gerrit.reviewdb.client.Project.State;
|
||||
import com.google.gerrit.reviewdb.client.Project.SubmitType;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
@ -50,29 +51,57 @@ final class SetProjectCommand extends SshCommand {
|
||||
+ "(default: MERGE_IF_NECESSARY)")
|
||||
private SubmitType submitType;
|
||||
|
||||
@Option(name = "--contributor-agreements", usage = "if contributor agreement is required")
|
||||
private InheritedBoolean contributorAgreements;
|
||||
|
||||
@Option(name = "--signed-off-by", usage = "if signed-off-by is required")
|
||||
private InheritedBoolean signedOffBy;
|
||||
|
||||
@Option(name = "--content-merge", usage = "allow automatic conflict resolving within files")
|
||||
private InheritedBoolean contentMerge;
|
||||
|
||||
@Option(name = "--change-id", usage = "if change-id is required")
|
||||
private InheritedBoolean requireChangeID;
|
||||
|
||||
@Option(name = "--use-contributor-agreements", aliases = {"--ca"}, usage = "if contributor agreement is required")
|
||||
private Boolean contributorAgreements;
|
||||
void setUseContributorArgreements(boolean on) {
|
||||
contributorAgreements = InheritedBoolean.TRUE;
|
||||
}
|
||||
|
||||
@Option(name = "--no-contributor-agreements", aliases = {"--nca"}, usage = "if contributor agreement is not required")
|
||||
private Boolean noContributorAgreements;
|
||||
void setNoContributorArgreements(boolean on) {
|
||||
contributorAgreements = InheritedBoolean.FALSE;
|
||||
}
|
||||
|
||||
@Option(name = "--use-signed-off-by", aliases = {"--so"}, usage = "if signed-off-by is required")
|
||||
private Boolean signedOffBy;
|
||||
void setUseSignedOffBy(boolean on) {
|
||||
signedOffBy = InheritedBoolean.TRUE;
|
||||
}
|
||||
|
||||
@Option(name = "--no-signed-off-by", aliases = {"--nso"}, usage = "if signed-off-by is not required")
|
||||
private Boolean noSignedOffBy;
|
||||
void setNoSignedOffBy(boolean on) {
|
||||
signedOffBy = InheritedBoolean.FALSE;
|
||||
}
|
||||
|
||||
@Option(name = "--use-content-merge", usage = "allow automatic conflict resolving within files")
|
||||
private Boolean contentMerge;
|
||||
void setUseContentMerge(boolean on) {
|
||||
contentMerge = InheritedBoolean.TRUE;
|
||||
}
|
||||
|
||||
@Option(name = "--no-content-merge", usage = "don't allow automatic conflict resolving within files")
|
||||
private Boolean noContentMerge;
|
||||
void setNoContentMerge(boolean on) {
|
||||
contentMerge = InheritedBoolean.FALSE;
|
||||
}
|
||||
|
||||
@Option(name = "--require-change-id", aliases = {"--id"}, usage = "if change-id is required")
|
||||
private Boolean requireChangeID;
|
||||
void setRequireChangeId(boolean on) {
|
||||
requireChangeID = InheritedBoolean.TRUE;
|
||||
}
|
||||
|
||||
@Option(name = "--no-change-id", aliases = {"--nid"}, usage = "if change-id is not required")
|
||||
private Boolean noRequireChangeID;
|
||||
void setNoChangeId(boolean on) {
|
||||
requireChangeID = InheritedBoolean.FALSE;
|
||||
}
|
||||
|
||||
@Option(name = "--project-state", aliases = {"--ps"}, usage = "project's visibility state")
|
||||
private State state;
|
||||
@ -85,7 +114,6 @@ final class SetProjectCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Failure {
|
||||
validate();
|
||||
Project ctlProject = projectControl.getProject();
|
||||
Project.NameKey nameKey = ctlProject.getNameKey();
|
||||
String name = ctlProject.getName();
|
||||
@ -97,38 +125,27 @@ final class SetProjectCommand extends SshCommand {
|
||||
ProjectConfig config = ProjectConfig.read(md);
|
||||
Project project = config.getProject();
|
||||
|
||||
project.setRequireChangeID(requireChangeID != null ? requireChangeID
|
||||
: project.isRequireChangeID());
|
||||
|
||||
project.setRequireChangeID(noRequireChangeID != null
|
||||
? !noRequireChangeID : project.isRequireChangeID());
|
||||
|
||||
project.setSubmitType(submitType != null ? submitType : project
|
||||
.getSubmitType());
|
||||
|
||||
project.setUseContentMerge(contentMerge != null ? contentMerge
|
||||
: project.isUseContentMerge());
|
||||
|
||||
project.setUseContentMerge(noContentMerge != null ? !noContentMerge
|
||||
: project.isUseContentMerge());
|
||||
|
||||
project.setUseContributorAgreements(contributorAgreements != null
|
||||
? contributorAgreements : project.isUseContributorAgreements());
|
||||
|
||||
project.setUseContributorAgreements(noContributorAgreements != null
|
||||
? !noContributorAgreements : project.isUseContributorAgreements());
|
||||
|
||||
project.setUseSignedOffBy(signedOffBy != null ? signedOffBy : project
|
||||
.isUseSignedOffBy());
|
||||
|
||||
project.setUseContentMerge(noSignedOffBy != null ? !noSignedOffBy
|
||||
: project.isUseContentMerge());
|
||||
|
||||
project.setDescription(projectDescription != null ? projectDescription
|
||||
: project.getDescription());
|
||||
|
||||
project.setState(state != null ? state : project.getState());
|
||||
|
||||
if (requireChangeID != null) {
|
||||
project.setRequireChangeID(requireChangeID);
|
||||
}
|
||||
if (submitType != null) {
|
||||
project.setSubmitType(submitType);
|
||||
}
|
||||
if (contentMerge != null) {
|
||||
project.setUseContentMerge(contentMerge);
|
||||
}
|
||||
if (contributorAgreements != null) {
|
||||
project.setUseContributorAgreements(contributorAgreements);
|
||||
}
|
||||
if (signedOffBy != null) {
|
||||
project.setUseSignedOffBy(signedOffBy);
|
||||
}
|
||||
if (projectDescription != null) {
|
||||
project.setDescription(projectDescription);
|
||||
}
|
||||
if (state != null) {
|
||||
project.setState(state);
|
||||
}
|
||||
md.setMessage("Project settings updated");
|
||||
config.commit(md);
|
||||
} finally {
|
||||
@ -154,18 +171,4 @@ final class SetProjectCommand extends SshCommand {
|
||||
throw new UnloggedFailure(1, err.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void validate() throws UnloggedFailure {
|
||||
checkExclusivity(contentMerge, "--use-content-merge",
|
||||
noContentMerge, "--no-content-merge");
|
||||
|
||||
checkExclusivity(contributorAgreements, "--use-contributor-agreements",
|
||||
noContributorAgreements, "--no-contributor-agreements");
|
||||
|
||||
checkExclusivity(signedOffBy, "--use-signed-off-by",
|
||||
noSignedOffBy, "--no-signed-off-by");
|
||||
|
||||
checkExclusivity(requireChangeID, "--require-change-id",
|
||||
noRequireChangeID, "--no-change-id");
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user