Merge "Option to create a new change for every commit not in target"

This commit is contained in:
David Pursehouse
2014-09-11 13:28:31 +00:00
committed by Gerrit Code Review
19 changed files with 191 additions and 27 deletions

View File

@@ -15,6 +15,7 @@ gerrit create-project - Create a new hosted project
[--use-contributor-agreements | --ca] [--use-contributor-agreements | --ca]
[--use-signed-off-by | --so] [--use-signed-off-by | --so]
[--use-content-merge] [--use-content-merge]
[--create-new-change-for-all-not-in-target]
[--require-change-id | --id] [--require-change-id | --id]
[[--branch <REF> | -b <REF>] ...] [[--branch <REF> | -b <REF>] ...]
[--empty-commit] [--empty-commit]
@@ -134,6 +135,15 @@ Submit Types].
from either the author or the uploader in the commit message. from either the author or the uploader in the commit message.
Disabled by default. Disabled by default.
--create-new-change-for-all-not-in-target::
--ncfa:
If enabled, a new change is created for every commit not in
target branch. If the pushed commit is merge commit, this flag is
ignored for that push. This option also does not accept merge
commits in commit chain to avoid accidental creation of a large
number of open changes.
Disabled by default.
--require-change-id:: --require-change-id::
--id:: --id::
Require a valid link:user-changeid.html[Change-Id] footer Require a valid link:user-changeid.html[Change-Id] footer

View File

@@ -150,6 +150,25 @@ The project is hidden and only visible to project owners. Other users
are not able to see the project even if they have read permissions are not able to see the project even if they have read permissions
granted on the project. granted on the project.
=== Use target branch when determining new changes to open
The `create-new-change-for-all-not-in-target` option provides a
convenience for selecting link:user-upload.html#base[the merge base]
by setting it automatically to the target branch's tip so you can
create new changes for all commits not in the target branch.
This option is disabled if the tip of the push is a merge commit.
This option also only works if there are no merge commits in the
commit chain, in such cases it fails warning the user that such
pushes can only be performed by manually specifying
link:user-upload.html#base[bases]
This option is useful if you want to push a change to your personal
branch first and for review to another branch for example. Or in cases
where a commit is already merged into a branch and you want to create
a new open change for that commit on another branch.
=== Require Change-Id === Require Change-Id
The `Require Change-Id in commit message` option defines whether a The `Require Change-Id in commit message` option defines whether a

View File

@@ -671,6 +671,11 @@ read access to `refs/meta/config`.
"configured_value": "INHERIT", "configured_value": "INHERIT",
"inherited_value": false "inherited_value": false
}, },
"create_new_change_for_all_not_in_target": {
"value": false,
"configured_value": "INHERIT",
"inherited_value": false
},
"require_change_id": { "require_change_id": {
"value": false, "value": false,
"configured_value": "FALSE", "configured_value": "FALSE",
@@ -725,6 +730,7 @@ link:#config-input[ConfigInput] entity.
"use_contributor_agreements": "FALSE", "use_contributor_agreements": "FALSE",
"use_content_merge": "INHERIT", "use_content_merge": "INHERIT",
"use_signed_off_by": "INHERIT", "use_signed_off_by": "INHERIT",
"create_new_change_for_all_not_in_target": "INHERIT",
"require_change_id": "TRUE", "require_change_id": "TRUE",
"max_object_size_limit": "10m", "max_object_size_limit": "10m",
"submit_type": "REBASE_IF_NECESSARY", "submit_type": "REBASE_IF_NECESSARY",
@@ -758,6 +764,11 @@ ConfigInfo] entity.
"configured_value": "INHERIT", "configured_value": "INHERIT",
"inherited_value": false "inherited_value": false
}, },
"create_new_change_for_all_not_in_target": {
"value": true,
"configured_value": "INHERIT",
"inherited_value": false
},
"require_change_id": { "require_change_id": {
"value": true, "value": true,
"configured_value": "TRUE", "configured_value": "TRUE",
@@ -1625,11 +1636,11 @@ The `ConfigInfo` entity contains information about the effective project
configuration. configuration.
[options="header",width="50%",cols="1,^2,4"] [options="header",width="50%",cols="1,^2,4"]
|========================================= |=======================================================
|Field Name ||Description |Field Name ||Description
|`description` |optional| |`description` |optional|
The description of the project. The description of the project.
|`use_contributor_agreements`|optional| |`use_contributor_agreements` |optional|
link:#inherited-boolean-info[InheritedBooleanInfo] that tells whether link:#inherited-boolean-info[InheritedBooleanInfo] that tells whether
authors must complete a contributor agreement on the site before authors must complete a contributor agreement on the site before
pushing any commits or changes to this project. pushing any commits or changes to this project.
@@ -1643,6 +1654,9 @@ FAST_FORWARD_ONLY.
link:#inherited-boolean-info[InheritedBooleanInfo] that tells whether link:#inherited-boolean-info[InheritedBooleanInfo] that tells whether
each change must contain a Signed-off-by line from either the author or each change must contain a Signed-off-by line from either the author or
the uploader in the commit message. the uploader in the commit message.
|`create_new_change_for_all_not_in_target` |optional|
link:#inherited-boolean-info[InheritedBooleanInfo] that tells whether
a new change is created for every commit not in target branch.
|`require_change_id` |optional| |`require_change_id` |optional|
link:#inherited-boolean-info[InheritedBooleanInfo] that tells whether a link:#inherited-boolean-info[InheritedBooleanInfo] that tells whether a
valid link:user-changeid.html[Change-Id] footer in any commit uploaded valid link:user-changeid.html[Change-Id] footer in any commit uploaded
@@ -1683,12 +1697,12 @@ link:rest-api-changes.html#action-info[ActionInfo] entities.
The `ConfigInput` entity describes a new project configuration. The `ConfigInput` entity describes a new project configuration.
[options="header",width="50%",cols="1,^2,4"] [options="header",width="50%",cols="1,^2,4"]
|========================================= |======================================================
|Field Name ||Description |Field Name ||Description
|`description` |optional| |`description` |optional|
The new description of the project. + The new description of the project. +
If not set, the description is removed. If not set, the description is removed.
|`use_contributor_agreements`|optional| |`use_contributor_agreements` |optional|
Whether authors must complete a contributor agreement on the site Whether authors must complete a contributor agreement on the site
before pushing any commits or changes to this project. + before pushing any commits or changes to this project. +
Can be `TRUE`, `FALSE` or `INHERIT`. + Can be `TRUE`, `FALSE` or `INHERIT`. +
@@ -1705,6 +1719,11 @@ Whether each change must contain a Signed-off-by line from either the
author or the uploader in the commit message. + author or the uploader in the commit message. +
Can be `TRUE`, `FALSE` or `INHERIT`. + Can be `TRUE`, `FALSE` or `INHERIT`. +
If not set, this setting is not updated. If not set, this setting is not updated.
|`create_new_change_for_all_not_in_target` |optional|
Whether a new change will be created for every commit not in target
branch. +
Can be `TRUE`, `FALSE` or `INHERIT`. +
If not set, this setting is not updated.
|`require_change_id` |optional| |`require_change_id` |optional|
Whether a valid link:user-changeid.html[Change-Id] footer in any commit Whether a valid link:user-changeid.html[Change-Id] footer in any commit
uploaded for review is required. This does not apply to commits pushed uploaded for review is required. This does not apply to commits pushed
@@ -1973,12 +1992,15 @@ link:rest-api-groups.html#group-id[group-id]. +
If not set, the link:config-gerrit.html#repository.name.ownerGroup[ If not set, the link:config-gerrit.html#repository.name.ownerGroup[
groups that are configured as default owners] are set as project groups that are configured as default owners] are set as project
owners. owners.
|`use_contributor_agreements`|`INHERIT` if not set| |`use_contributor_agreements` |`INHERIT` if not set|
Whether contributor agreements should be used for the project (`TRUE`, Whether contributor agreements should be used for the project (`TRUE`,
`FALSE`, `INHERIT`). `FALSE`, `INHERIT`).
|`use_signed_off_by` |`INHERIT` if not set| |`use_signed_off_by` |`INHERIT` if not set|
Whether the usage of 'Signed-Off-By' footers is required for the Whether the usage of 'Signed-Off-By' footers is required for the
project (`TRUE`, `FALSE`, `INHERIT`). project (`TRUE`, `FALSE`, `INHERIT`).
|`create_new_change_for_all_not_in_target` |`INHERIT` if not set|
Whether a new change is created for every commit not in target branch
for the project (`TRUE`, `FALSE`, `INHERIT`).
|`use_content_merge` |`INHERIT` if not set| |`use_content_merge` |`INHERIT` if not set|
Whether content merge should be enabled for the project (`TRUE`, Whether content merge should be enabled for the project (`TRUE`,
`FALSE`, `INHERIT`). + `FALSE`, `INHERIT`). +

View File

@@ -33,6 +33,7 @@ public class ProjectInput {
public InheritableBoolean useSignedOffBy; public InheritableBoolean useSignedOffBy;
public InheritableBoolean useContentMerge; public InheritableBoolean useContentMerge;
public InheritableBoolean requireChangeId; public InheritableBoolean requireChangeId;
public InheritableBoolean createNewChangeForAllNotInTarget;
public String maxObjectSizeLimit; public String maxObjectSizeLimit;
public Map<String, Map<String, ConfigValue>> pluginConfigValues; public Map<String, Map<String, ConfigValue>> pluginConfigValues;

View File

@@ -41,6 +41,7 @@ public interface AdminConstants extends Constants {
String useContentMerge(); String useContentMerge();
String useContributorAgreements(); String useContributorAgreements();
String useSignedOffBy(); String useSignedOffBy();
String createNewChangeForAllNotInTarget();
String requireChangeID(); String requireChangeID();
String headingMaxObjectSizeLimit(); String headingMaxObjectSizeLimit();
String headingGroupOptions(); String headingGroupOptions();

View File

@@ -23,6 +23,7 @@ projectRepoBrowser = Repository Browser
useContentMerge = Automatically resolve conflicts useContentMerge = Automatically resolve conflicts
useContributorAgreements = Require a valid contributor agreement to upload useContributorAgreements = Require a valid contributor agreement to upload
useSignedOffBy = Require <code>Signed-off-by</code> in commit message useSignedOffBy = Require <code>Signed-off-by</code> in commit message
createNewChangeForAllNotInTarget = Create a new change for every commit not in the target branch
requireChangeID = Require <code>Change-Id</code> in commit message requireChangeID = Require <code>Change-Id</code> in commit message
headingMaxObjectSizeLimit = Maximum Git object size limit headingMaxObjectSizeLimit = Maximum Git object size limit
headingGroupOptions = Group Options headingGroupOptions = Group Options

View File

@@ -79,6 +79,7 @@ public class ProjectInfoScreen extends ProjectScreen {
private ListBox submitType; private ListBox submitType;
private ListBox state; private ListBox state;
private ListBox contentMerge; private ListBox contentMerge;
private ListBox newChangeForAllNotInTarget;
private NpTextBox maxObjectSizeLimit; private NpTextBox maxObjectSizeLimit;
private Label effectiveMaxObjectSizeLimit; private Label effectiveMaxObjectSizeLimit;
private Map<String, Map<String, HasEnabled>> pluginConfigWidgets; private Map<String, Map<String, HasEnabled>> pluginConfigWidgets;
@@ -157,6 +158,7 @@ public class ProjectInfoScreen extends ProjectScreen {
state.setEnabled(isOwner); state.setEnabled(isOwner);
submitType.setEnabled(isOwner); submitType.setEnabled(isOwner);
setEnabledForUseContentMerge(); setEnabledForUseContentMerge();
newChangeForAllNotInTarget.setEnabled(isOwner);
descTxt.setEnabled(isOwner); descTxt.setEnabled(isOwner);
contributorAgreements.setEnabled(isOwner); contributorAgreements.setEnabled(isOwner);
signedOffBy.setEnabled(isOwner); signedOffBy.setEnabled(isOwner);
@@ -213,6 +215,10 @@ public class ProjectInfoScreen extends ProjectScreen {
saveEnabler.listenTo(contentMerge); saveEnabler.listenTo(contentMerge);
grid.add(Util.C.useContentMerge(), contentMerge); grid.add(Util.C.useContentMerge(), contentMerge);
newChangeForAllNotInTarget = newInheritedBooleanBox();
saveEnabler.listenTo(newChangeForAllNotInTarget);
grid.add(Util.C.createNewChangeForAllNotInTarget(), newChangeForAllNotInTarget);
requireChangeID = newInheritedBooleanBox(); requireChangeID = newInheritedBooleanBox();
saveEnabler.listenTo(requireChangeID); saveEnabler.listenTo(requireChangeID);
grid.addHtml(Util.C.requireChangeID(), requireChangeID); grid.addHtml(Util.C.requireChangeID(), requireChangeID);
@@ -338,6 +344,7 @@ public class ProjectInfoScreen extends ProjectScreen {
setBool(contributorAgreements, result.use_contributor_agreements()); setBool(contributorAgreements, result.use_contributor_agreements());
setBool(signedOffBy, result.use_signed_off_by()); setBool(signedOffBy, result.use_signed_off_by());
setBool(contentMerge, result.use_content_merge()); setBool(contentMerge, result.use_content_merge());
setBool(newChangeForAllNotInTarget, result.create_new_change_for_all_not_in_target());
setBool(requireChangeID, result.require_change_id()); setBool(requireChangeID, result.require_change_id());
setSubmitType(result.submit_type()); setSubmitType(result.submit_type());
setState(result.state()); setState(result.state());
@@ -569,7 +576,7 @@ public class ProjectInfoScreen extends ProjectScreen {
saveProject.setEnabled(false); saveProject.setEnabled(false);
ProjectApi.setConfig(getProjectKey(), descTxt.getText().trim(), ProjectApi.setConfig(getProjectKey(), descTxt.getText().trim(),
getBool(contributorAgreements), getBool(contentMerge), getBool(contributorAgreements), getBool(contentMerge),
getBool(signedOffBy), getBool(requireChangeID), getBool(signedOffBy), getBool(newChangeForAllNotInTarget), getBool(requireChangeID),
maxObjectSizeLimit.getText().trim(), maxObjectSizeLimit.getText().trim(),
SubmitType.valueOf(submitType.getValue(submitType.getSelectedIndex())), SubmitType.valueOf(submitType.getValue(submitType.getSelectedIndex())),
ProjectState.valueOf(state.getValue(state.getSelectedIndex())), ProjectState.valueOf(state.getValue(state.getSelectedIndex())),

View File

@@ -44,6 +44,9 @@ public class ConfigInfo extends JavaScriptObject {
public final native InheritedBooleanInfo use_contributor_agreements() public final native InheritedBooleanInfo use_contributor_agreements()
/*-{ return this.use_contributor_agreements; }-*/; /*-{ return this.use_contributor_agreements; }-*/;
public final native InheritedBooleanInfo create_new_change_for_all_not_in_target()
/*-{ return this.create_new_change_for_all_not_in_target; }-*/;
public final native InheritedBooleanInfo use_signed_off_by() public final native InheritedBooleanInfo use_signed_off_by()
/*-{ return this.use_signed_off_by; }-*/; /*-{ return this.use_signed_off_by; }-*/;

View File

@@ -85,6 +85,7 @@ public class ProjectApi {
public static void setConfig(Project.NameKey name, String description, public static void setConfig(Project.NameKey name, String description,
InheritableBoolean useContributorAgreements, InheritableBoolean useContributorAgreements,
InheritableBoolean useContentMerge, InheritableBoolean useSignedOffBy, InheritableBoolean useContentMerge, InheritableBoolean useSignedOffBy,
InheritableBoolean createNewChangeForAllNotInTarget,
InheritableBoolean requireChangeId, String maxObjectSizeLimit, InheritableBoolean requireChangeId, String maxObjectSizeLimit,
SubmitType submitType, ProjectState state, SubmitType submitType, ProjectState state,
Map<String, Map<String, ConfigParameterValue>> pluginConfigValues, Map<String, Map<String, ConfigParameterValue>> pluginConfigValues,
@@ -95,6 +96,7 @@ public class ProjectApi {
in.setUseContentMerge(useContentMerge); in.setUseContentMerge(useContentMerge);
in.setUseSignedOffBy(useSignedOffBy); in.setUseSignedOffBy(useSignedOffBy);
in.setRequireChangeId(requireChangeId); in.setRequireChangeId(requireChangeId);
in.setCreateNewChangeForAllNotInTarget(createNewChangeForAllNotInTarget);
in.setMaxObjectSizeLimit(maxObjectSizeLimit); in.setMaxObjectSizeLimit(maxObjectSizeLimit);
in.setSubmitType(submitType); in.setSubmitType(submitType);
in.setState(state); in.setState(state);
@@ -209,6 +211,12 @@ public class ProjectApi {
private final native void setRequireChangeIdRaw(String v) private final native void setRequireChangeIdRaw(String v)
/*-{ if(v)this.require_change_id=v; }-*/; /*-{ if(v)this.require_change_id=v; }-*/;
final void setCreateNewChangeForAllNotInTarget(InheritableBoolean v) {
setCreateNewChangeForAllNotInTargetRaw(v.name());
}
private final native void setCreateNewChangeForAllNotInTargetRaw(String v)
/*-{ if(v)this.create_new_change_for_all_not_in_target=v; }-*/;
final native void setMaxObjectSizeLimit(String l) final native void setMaxObjectSizeLimit(String l)
/*-{ if(l)this.max_object_size_limit=l; }-*/; /*-{ if(l)this.max_object_size_limit=l; }-*/;

View File

@@ -94,6 +94,8 @@ public final class Project {
protected String themeName; protected String themeName;
protected InheritableBoolean createNewChangeForAllNotInTarget;
protected Project() { protected Project() {
} }
@@ -105,6 +107,7 @@ public final class Project {
useSignedOffBy = InheritableBoolean.INHERIT; useSignedOffBy = InheritableBoolean.INHERIT;
requireChangeID = InheritableBoolean.INHERIT; requireChangeID = InheritableBoolean.INHERIT;
useContentMerge = InheritableBoolean.INHERIT; useContentMerge = InheritableBoolean.INHERIT;
createNewChangeForAllNotInTarget = InheritableBoolean.INHERIT;
} }
public Project.NameKey getNameKey() { public Project.NameKey getNameKey() {
@@ -159,6 +162,15 @@ public final class Project {
requireChangeID = cid; requireChangeID = cid;
} }
public InheritableBoolean getCreateNewChangeForAllNotInTarget() {
return createNewChangeForAllNotInTarget;
}
public void setCreateNewChangeForAllNotInTarget(
InheritableBoolean useAllNotInTarget) {
this.createNewChangeForAllNotInTarget = useAllNotInTarget;
}
public void setMaxObjectSizeLimit(final String limit) { public void setMaxObjectSizeLimit(final String limit) {
maxObjectSizeLimit = limit; maxObjectSizeLimit = limit;
} }
@@ -212,6 +224,7 @@ public final class Project {
submitType = update.submitType; submitType = update.submitType;
state = update.state; state = update.state;
maxObjectSizeLimit = update.maxObjectSizeLimit; maxObjectSizeLimit = update.maxObjectSizeLimit;
createNewChangeForAllNotInTarget = update.createNewChangeForAllNotInTarget;
} }
/** /**

View File

@@ -115,6 +115,8 @@ public class ProjectConfig extends VersionedMetaData {
private static final String RECEIVE = "receive"; private static final String RECEIVE = "receive";
private static final String KEY_REQUIRE_SIGNED_OFF_BY = "requireSignedOffBy"; private static final String KEY_REQUIRE_SIGNED_OFF_BY = "requireSignedOffBy";
private static final String KEY_REQUIRE_CHANGE_ID = "requireChangeId"; private static final String KEY_REQUIRE_CHANGE_ID = "requireChangeId";
private static final String KEY_USE_ALL_NOT_IN_TARGET =
"createNewChangeForAllNotInTarget";
private static final String KEY_MAX_OBJECT_SIZE_LIMIT = "maxObjectSizeLimit"; private static final String KEY_MAX_OBJECT_SIZE_LIMIT = "maxObjectSizeLimit";
private static final String KEY_REQUIRE_CONTRIBUTOR_AGREEMENT = private static final String KEY_REQUIRE_CONTRIBUTOR_AGREEMENT =
"requireContributorAgreement"; "requireContributorAgreement";
@@ -419,6 +421,7 @@ public class ProjectConfig extends VersionedMetaData {
p.setUseContributorAgreements(getEnum(rc, RECEIVE, null, KEY_REQUIRE_CONTRIBUTOR_AGREEMENT, InheritableBoolean.INHERIT)); p.setUseContributorAgreements(getEnum(rc, RECEIVE, null, KEY_REQUIRE_CONTRIBUTOR_AGREEMENT, InheritableBoolean.INHERIT));
p.setUseSignedOffBy(getEnum(rc, RECEIVE, null, KEY_REQUIRE_SIGNED_OFF_BY, InheritableBoolean.INHERIT)); p.setUseSignedOffBy(getEnum(rc, RECEIVE, null, KEY_REQUIRE_SIGNED_OFF_BY, InheritableBoolean.INHERIT));
p.setRequireChangeID(getEnum(rc, RECEIVE, null, KEY_REQUIRE_CHANGE_ID, InheritableBoolean.INHERIT)); p.setRequireChangeID(getEnum(rc, RECEIVE, null, KEY_REQUIRE_CHANGE_ID, InheritableBoolean.INHERIT));
p.setCreateNewChangeForAllNotInTarget(getEnum(rc, RECEIVE, null, KEY_USE_ALL_NOT_IN_TARGET, InheritableBoolean.INHERIT));
p.setMaxObjectSizeLimit(rc.getString(RECEIVE, null, KEY_MAX_OBJECT_SIZE_LIMIT)); p.setMaxObjectSizeLimit(rc.getString(RECEIVE, null, KEY_MAX_OBJECT_SIZE_LIMIT));
p.setSubmitType(getEnum(rc, SUBMIT, null, KEY_ACTION, defaultSubmitAction)); p.setSubmitType(getEnum(rc, SUBMIT, null, KEY_ACTION, defaultSubmitAction));
@@ -818,6 +821,7 @@ public class ProjectConfig extends VersionedMetaData {
set(rc, RECEIVE, null, KEY_REQUIRE_CONTRIBUTOR_AGREEMENT, p.getUseContributorAgreements(), InheritableBoolean.INHERIT); set(rc, RECEIVE, null, KEY_REQUIRE_CONTRIBUTOR_AGREEMENT, p.getUseContributorAgreements(), InheritableBoolean.INHERIT);
set(rc, RECEIVE, null, KEY_REQUIRE_SIGNED_OFF_BY, p.getUseSignedOffBy(), InheritableBoolean.INHERIT); set(rc, RECEIVE, null, KEY_REQUIRE_SIGNED_OFF_BY, p.getUseSignedOffBy(), InheritableBoolean.INHERIT);
set(rc, RECEIVE, null, KEY_REQUIRE_CHANGE_ID, p.getRequireChangeID(), InheritableBoolean.INHERIT); set(rc, RECEIVE, null, KEY_REQUIRE_CHANGE_ID, p.getRequireChangeID(), InheritableBoolean.INHERIT);
set(rc, RECEIVE, null, KEY_USE_ALL_NOT_IN_TARGET, p.getCreateNewChangeForAllNotInTarget(), InheritableBoolean.INHERIT);
set(rc, RECEIVE, null, KEY_MAX_OBJECT_SIZE_LIMIT, validMaxObjectSizeLimit(p.getMaxObjectSizeLimit())); set(rc, RECEIVE, null, KEY_MAX_OBJECT_SIZE_LIMIT, validMaxObjectSizeLimit(p.getMaxObjectSizeLimit()));
set(rc, SUBMIT, null, KEY_ACTION, p.getSubmitType(), defaultSubmitAction); set(rc, SUBMIT, null, KEY_ACTION, p.getSubmitType(), defaultSubmitAction);

View File

@@ -311,6 +311,7 @@ public class ReceiveCommits {
private final ReceivePack rp; private final ReceivePack rp;
private final NoteMap rejectCommits; private final NoteMap rejectCommits;
private MagicBranchInput magicBranch; private MagicBranchInput magicBranch;
private boolean newChangeForAllNotInTarget;
private List<CreateRequest> newChanges = Collections.emptyList(); private List<CreateRequest> newChanges = Collections.emptyList();
private final Map<Change.Id, ReplaceRequest> replaceByChange = private final Map<Change.Id, ReplaceRequest> replaceByChange =
@@ -428,6 +429,7 @@ public class ReceiveCommits {
ProjectState ps = projectControl.getProjectState(); ProjectState ps = projectControl.getProjectState();
this.newChangeForAllNotInTarget = ps.isCreateNewChangeForAllNotInTarget();
rp.setAllowCreates(true); rp.setAllowCreates(true);
rp.setAllowDeletes(true); rp.setAllowDeletes(true);
rp.setAllowNonFastForwards(true); rp.setAllowNonFastForwards(true);
@@ -1293,6 +1295,21 @@ public class ReceiveCommits {
} }
RevWalk walk = rp.getRevWalk(); RevWalk walk = rp.getRevWalk();
RevCommit tip;
try {
tip = walk.parseCommit(magicBranch.cmd.getNewId());
} catch (IOException ex) {
magicBranch.cmd.setResult(REJECTED_MISSING_OBJECT);
log.error("Invalid pack upload; one or more objects weren't sent", ex);
return;
}
// If tip is a merge commit or %base was specified,
// ignore newChangeForAllNotInTarget
if (tip.getParentCount() > 1 || magicBranch.base != null) {
newChangeForAllNotInTarget = false;
}
if (magicBranch.base != null) { if (magicBranch.base != null) {
magicBranch.baseCommit = Lists.newArrayListWithCapacity( magicBranch.baseCommit = Lists.newArrayListWithCapacity(
magicBranch.base.size()); magicBranch.base.size());
@@ -1313,6 +1330,18 @@ public class ReceiveCommits {
return; return;
} }
} }
} else if (newChangeForAllNotInTarget) {
String destBranch = magicBranch.dest.get();
try {
ObjectId baseHead = repo.getRef(destBranch).getObjectId();
magicBranch.baseCommit =
Collections.singletonList(walk.parseCommit(baseHead));
} catch (IOException ex) {
log.warn(String.format("Project %s cannot read %s", project.getName(),
destBranch), ex);
reject(cmd, "internal server error");
return;
}
} }
// Validate that the new commits are connected with the target // Validate that the new commits are connected with the target
@@ -1321,7 +1350,6 @@ public class ReceiveCommits {
// commits and the target branch head. // commits and the target branch head.
// //
try { try {
final RevCommit tip = walk.parseCommit(magicBranch.cmd.getNewId());
Ref targetRef = rp.getAdvertisedRefs().get(magicBranch.ctl.getRefName()); Ref targetRef = rp.getAdvertisedRefs().get(magicBranch.ctl.getRefName());
if (targetRef == null || targetRef.getObjectId() == null) { if (targetRef == null || targetRef.getObjectId() == null) {
// The destination branch does not yet exist. Assume the // The destination branch does not yet exist. Assume the
@@ -1462,6 +1490,13 @@ public class ReceiveCommits {
return Collections.emptyList(); return Collections.emptyList();
} }
// Don't allow merges to be uploaded in commit chain via all-not-in-target
if (newChangeForAllNotInTarget && c.getParentCount() > 1) {
reject(magicBranch.cmd,
"Pushing merges in commit chains with 'all not in target' is not allowed,\n"
+ "to override please set the base manually");
}
Change.Key changeKey = new Change.Key("I" + c.name()); Change.Key changeKey = new Change.Key("I" + c.name());
final List<String> idList = c.getFooterLines(CHANGE_ID); final List<String> idList = c.getFooterLines(CHANGE_ID);
if (idList.isEmpty()) { if (idList.isEmpty()) {

View File

@@ -43,6 +43,7 @@ public class ConfigInfo {
public InheritedBooleanInfo useContributorAgreements; public InheritedBooleanInfo useContributorAgreements;
public InheritedBooleanInfo useContentMerge; public InheritedBooleanInfo useContentMerge;
public InheritedBooleanInfo useSignedOffBy; public InheritedBooleanInfo useSignedOffBy;
public InheritedBooleanInfo createNewChangeForAllNotInTarget;
public InheritedBooleanInfo requireChangeId; public InheritedBooleanInfo requireChangeId;
public MaxObjectSizeLimitInfo maxObjectSizeLimit; public MaxObjectSizeLimitInfo maxObjectSizeLimit;
public SubmitType submitType; public SubmitType submitType;
@@ -68,17 +69,23 @@ public class ConfigInfo {
InheritedBooleanInfo useSignedOffBy = new InheritedBooleanInfo(); InheritedBooleanInfo useSignedOffBy = new InheritedBooleanInfo();
InheritedBooleanInfo useContentMerge = new InheritedBooleanInfo(); InheritedBooleanInfo useContentMerge = new InheritedBooleanInfo();
InheritedBooleanInfo requireChangeId = new InheritedBooleanInfo(); InheritedBooleanInfo requireChangeId = new InheritedBooleanInfo();
InheritedBooleanInfo createNewChangeForAllNotInTarget =
new InheritedBooleanInfo();
useContributorAgreements.value = projectState.isUseContributorAgreements(); useContributorAgreements.value = projectState.isUseContributorAgreements();
useSignedOffBy.value = projectState.isUseSignedOffBy(); useSignedOffBy.value = projectState.isUseSignedOffBy();
useContentMerge.value = projectState.isUseContentMerge(); useContentMerge.value = projectState.isUseContentMerge();
requireChangeId.value = projectState.isRequireChangeID(); requireChangeId.value = projectState.isRequireChangeID();
createNewChangeForAllNotInTarget.value =
projectState.isCreateNewChangeForAllNotInTarget();
useContributorAgreements.configuredValue = useContributorAgreements.configuredValue =
p.getUseContributorAgreements(); p.getUseContributorAgreements();
useSignedOffBy.configuredValue = p.getUseSignedOffBy(); useSignedOffBy.configuredValue = p.getUseSignedOffBy();
useContentMerge.configuredValue = p.getUseContentMerge(); useContentMerge.configuredValue = p.getUseContentMerge();
requireChangeId.configuredValue = p.getRequireChangeID(); requireChangeId.configuredValue = p.getRequireChangeID();
createNewChangeForAllNotInTarget.configuredValue =
p.getCreateNewChangeForAllNotInTarget();
ProjectState parentState = Iterables.getFirst(projectState ProjectState parentState = Iterables.getFirst(projectState
.parents(), null); .parents(), null);
@@ -88,12 +95,15 @@ public class ConfigInfo {
useSignedOffBy.inheritedValue = parentState.isUseSignedOffBy(); useSignedOffBy.inheritedValue = parentState.isUseSignedOffBy();
useContentMerge.inheritedValue = parentState.isUseContentMerge(); useContentMerge.inheritedValue = parentState.isUseContentMerge();
requireChangeId.inheritedValue = parentState.isRequireChangeID(); requireChangeId.inheritedValue = parentState.isRequireChangeID();
createNewChangeForAllNotInTarget.inheritedValue =
parentState.isCreateNewChangeForAllNotInTarget();
} }
this.useContributorAgreements = useContributorAgreements; this.useContributorAgreements = useContributorAgreements;
this.useSignedOffBy = useSignedOffBy; this.useSignedOffBy = useSignedOffBy;
this.useContentMerge = useContentMerge; this.useContentMerge = useContentMerge;
this.requireChangeId = requireChangeId; this.requireChangeId = requireChangeId;
this.createNewChangeForAllNotInTarget = createNewChangeForAllNotInTarget;
MaxObjectSizeLimitInfo maxObjectSizeLimit = new MaxObjectSizeLimitInfo(); MaxObjectSizeLimitInfo maxObjectSizeLimit = new MaxObjectSizeLimitInfo();
maxObjectSizeLimit.value = maxObjectSizeLimit.value =

View File

@@ -124,6 +124,9 @@ public class CreateProject implements RestModifyView<TopLevelResource, ProjectIn
? InheritableBoolean.FALSE : MoreObjects.firstNonNull( ? InheritableBoolean.FALSE : MoreObjects.firstNonNull(
input.useContentMerge, input.useContentMerge,
InheritableBoolean.INHERIT); InheritableBoolean.INHERIT);
args.newChangeForAllNotInTarget =
MoreObjects.firstNonNull(input.createNewChangeForAllNotInTarget,
InheritableBoolean.INHERIT);
args.changeIdRequired = args.changeIdRequired =
MoreObjects.firstNonNull(input.requireChangeId, InheritableBoolean.INHERIT); MoreObjects.firstNonNull(input.requireChangeId, InheritableBoolean.INHERIT);
try { try {

View File

@@ -33,6 +33,7 @@ public class CreateProjectArgs {
public boolean permissionsOnly; public boolean permissionsOnly;
public List<String> branch; public List<String> branch;
public InheritableBoolean contentMerge; public InheritableBoolean contentMerge;
public InheritableBoolean newChangeForAllNotInTarget;
public InheritableBoolean changeIdRequired; public InheritableBoolean changeIdRequired;
public boolean createEmptyCommit; public boolean createEmptyCommit;
public String maxObjectSizeLimit; public String maxObjectSizeLimit;
@@ -42,6 +43,7 @@ public class CreateProjectArgs {
signedOffBy = InheritableBoolean.INHERIT; signedOffBy = InheritableBoolean.INHERIT;
contentMerge = InheritableBoolean.INHERIT; contentMerge = InheritableBoolean.INHERIT;
changeIdRequired = InheritableBoolean.INHERIT; changeIdRequired = InheritableBoolean.INHERIT;
newChangeForAllNotInTarget = InheritableBoolean.INHERIT;
submitType = SubmitType.MERGE_IF_NECESSARY; submitType = SubmitType.MERGE_IF_NECESSARY;
} }

View File

@@ -193,6 +193,7 @@ public class PerformCreateProject {
.setUseContributorAgreements(createProjectArgs.contributorAgreements); .setUseContributorAgreements(createProjectArgs.contributorAgreements);
newProject.setUseSignedOffBy(createProjectArgs.signedOffBy); newProject.setUseSignedOffBy(createProjectArgs.signedOffBy);
newProject.setUseContentMerge(createProjectArgs.contentMerge); newProject.setUseContentMerge(createProjectArgs.contentMerge);
newProject.setCreateNewChangeForAllNotInTarget(createProjectArgs.newChangeForAllNotInTarget);
newProject.setRequireChangeID(createProjectArgs.changeIdRequired); newProject.setRequireChangeID(createProjectArgs.changeIdRequired);
newProject.setMaxObjectSizeLimit(createProjectArgs.maxObjectSizeLimit); newProject.setMaxObjectSizeLimit(createProjectArgs.maxObjectSizeLimit);
if (createProjectArgs.newParent != null) { if (createProjectArgs.newParent != null) {

View File

@@ -404,6 +404,15 @@ public class ProjectState {
}); });
} }
public boolean isCreateNewChangeForAllNotInTarget() {
return getInheritableBoolean(new Function<Project, InheritableBoolean>() {
@Override
public InheritableBoolean apply(Project input) {
return input.getCreateNewChangeForAllNotInTarget();
}
});
}
public LabelTypes getLabelTypes() { public LabelTypes getLabelTypes() {
Map<String, LabelType> types = Maps.newLinkedHashMap(); Map<String, LabelType> types = Maps.newLinkedHashMap();
for (ProjectState s : treeInOrder()) { for (ProjectState s : treeInOrder()) {

View File

@@ -66,6 +66,7 @@ public class PutConfig implements RestModifyView<ProjectResource, Input> {
public InheritableBoolean useContributorAgreements; public InheritableBoolean useContributorAgreements;
public InheritableBoolean useContentMerge; public InheritableBoolean useContentMerge;
public InheritableBoolean useSignedOffBy; public InheritableBoolean useSignedOffBy;
public InheritableBoolean createNewChangeForAllNotInTarget;
public InheritableBoolean requireChangeId; public InheritableBoolean requireChangeId;
public String maxObjectSizeLimit; public String maxObjectSizeLimit;
public SubmitType submitType; public SubmitType submitType;
@@ -146,6 +147,11 @@ public class PutConfig implements RestModifyView<ProjectResource, Input> {
if (input.useSignedOffBy != null) { if (input.useSignedOffBy != null) {
p.setUseSignedOffBy(input.useSignedOffBy); p.setUseSignedOffBy(input.useSignedOffBy);
} }
if (input.createNewChangeForAllNotInTarget != null) {
p.setCreateNewChangeForAllNotInTarget(input.createNewChangeForAllNotInTarget);
}
if (input.requireChangeId != null) { if (input.requireChangeId != null) {
p.setRequireChangeID(input.requireChangeId); p.setRequireChangeID(input.requireChangeId);
} }

View File

@@ -87,6 +87,9 @@ final class CreateProjectCommand extends SshCommand {
@Option(name = "--change-id", usage = "if change-id is required") @Option(name = "--change-id", usage = "if change-id is required")
private InheritableBoolean requireChangeID = InheritableBoolean.INHERIT; private InheritableBoolean requireChangeID = InheritableBoolean.INHERIT;
@Option(name = "--new-change-for-all-not-in-target", usage = "if a new change will be created for every commit not in target branch")
private InheritableBoolean createNewChangeForAllNotInTarget = InheritableBoolean.INHERIT;
@Option(name = "--use-contributor-agreements", aliases = {"--ca"}, usage = "if contributor agreement is required") @Option(name = "--use-contributor-agreements", aliases = {"--ca"}, usage = "if contributor agreement is required")
void setUseContributorArgreements(boolean on) { void setUseContributorArgreements(boolean on) {
contributorAgreements = InheritableBoolean.TRUE; contributorAgreements = InheritableBoolean.TRUE;
@@ -107,6 +110,11 @@ final class CreateProjectCommand extends SshCommand {
requireChangeID = InheritableBoolean.TRUE; requireChangeID = InheritableBoolean.TRUE;
} }
@Option(name = "--create-new-change-for-all-not-in-target", aliases = {"--ncfa"}, usage = "if a new change will be created for every commit not in target branch")
void setNewChangeForAllNotInTarget(boolean on) {
createNewChangeForAllNotInTarget = InheritableBoolean.TRUE;
}
@Option(name = "--branch", aliases = {"-b"}, metaVar = "BRANCH", usage = "initial branch name\n" @Option(name = "--branch", aliases = {"-b"}, metaVar = "BRANCH", usage = "initial branch name\n"
+ "(default: master)") + "(default: master)")
private List<String> branch; private List<String> branch;
@@ -166,6 +174,7 @@ final class CreateProjectCommand extends SshCommand {
input.useSignedOffBy = signedOffBy; input.useSignedOffBy = signedOffBy;
input.useContentMerge = contentMerge; input.useContentMerge = contentMerge;
input.requireChangeId = requireChangeID; input.requireChangeId = requireChangeID;
input.createNewChangeForAllNotInTarget = createNewChangeForAllNotInTarget;
input.branches = branch; input.branches = branch;
input.createEmptyCommit = createEmptyCommit; input.createEmptyCommit = createEmptyCommit;
input.maxObjectSizeLimit = maxObjectSizeLimit; input.maxObjectSizeLimit = maxObjectSizeLimit;