Option to create a new change for every commit not in target
One not-so-well-known feature of gerrit is that, you can set a %base for the RevWalk in ReceiveCommits when pushing changes to Gerrit. This makes it possible to push a commit for review and override Gerrits default algorithm for creating new changes on push to refs/for/*. For instance, one could submit a commit in a private branch and, afterward, push the same commit to a release branch. Specifying the tip of the destination branch as the %base would have an effect of creating a new change for every commit reachable from the pushed commit and not reachable from the target branch. This behavior seems to be wanted by some Gerrit users and is implemented as a project config option by this change (although it contradicts the Gerrit's philosophy of reviewing one commit once). If a %base is explicitly set on during uploading changes, new-change-for-all-not-in-target is ignored. To avoid incidental pushes with merges, new-change-for-all-not-in-target rejects uploads if changes contain merge commits. In such cases to push a merge commit, you need to explicitly set the %base parameter as described in Uploading Changes / Selecting Merge Base documentation. Bug: issue 1195 Change-Id: Ifa90184352c912885e52d2060356fcc039d0ef03
This commit is contained in:
@@ -15,6 +15,7 @@ gerrit create-project - Create a new hosted project
|
||||
[--use-contributor-agreements | --ca]
|
||||
[--use-signed-off-by | --so]
|
||||
[--use-content-merge]
|
||||
[--create-new-change-for-all-not-in-target]
|
||||
[--require-change-id | --id]
|
||||
[[--branch <REF> | -b <REF>] ...]
|
||||
[--empty-commit]
|
||||
@@ -134,6 +135,15 @@ Submit Types].
|
||||
from either the author or the uploader in the commit message.
|
||||
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::
|
||||
--id::
|
||||
Require a valid link:user-changeid.html[Change-Id] footer
|
||||
|
||||
@@ -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
|
||||
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
|
||||
|
||||
The `Require Change-Id in commit message` option defines whether a
|
||||
|
||||
@@ -671,6 +671,11 @@ read access to `refs/meta/config`.
|
||||
"configured_value": "INHERIT",
|
||||
"inherited_value": false
|
||||
},
|
||||
"create_new_change_for_all_not_in_target": {
|
||||
"value": false,
|
||||
"configured_value": "INHERIT",
|
||||
"inherited_value": false
|
||||
},
|
||||
"require_change_id": {
|
||||
"value": false,
|
||||
"configured_value": "FALSE",
|
||||
@@ -725,6 +730,7 @@ link:#config-input[ConfigInput] entity.
|
||||
"use_contributor_agreements": "FALSE",
|
||||
"use_content_merge": "INHERIT",
|
||||
"use_signed_off_by": "INHERIT",
|
||||
"create_new_change_for_all_not_in_target": "INHERIT",
|
||||
"require_change_id": "TRUE",
|
||||
"max_object_size_limit": "10m",
|
||||
"submit_type": "REBASE_IF_NECESSARY",
|
||||
@@ -758,6 +764,11 @@ ConfigInfo] entity.
|
||||
"configured_value": "INHERIT",
|
||||
"inherited_value": false
|
||||
},
|
||||
"create_new_change_for_all_not_in_target": {
|
||||
"value": true,
|
||||
"configured_value": "INHERIT",
|
||||
"inherited_value": false
|
||||
},
|
||||
"require_change_id": {
|
||||
"value": true,
|
||||
"configured_value": "TRUE",
|
||||
@@ -1622,25 +1633,28 @@ The `ConfigInfo` entity contains information about the effective project
|
||||
configuration.
|
||||
|
||||
[options="header",width="50%",cols="1,^2,4"]
|
||||
|=========================================
|
||||
|Field Name ||Description
|
||||
|`description` |optional|
|
||||
|=======================================================
|
||||
|Field Name ||Description
|
||||
|`description` |optional|
|
||||
The description of the project.
|
||||
|`use_contributor_agreements`|optional|
|
||||
|`use_contributor_agreements` |optional|
|
||||
link:#inherited-boolean-info[InheritedBooleanInfo] that tells whether
|
||||
authors must complete a contributor agreement on the site before
|
||||
pushing any commits or changes to this project.
|
||||
|`use_content_merge` |optional|
|
||||
|`use_content_merge` |optional|
|
||||
link:#inherited-boolean-info[InheritedBooleanInfo] that tells whether
|
||||
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_signed_off_by` |optional|
|
||||
|`use_signed_off_by` |optional|
|
||||
link:#inherited-boolean-info[InheritedBooleanInfo] that tells whether
|
||||
each change must contain a Signed-off-by line from either the author or
|
||||
the uploader in the commit message.
|
||||
|`require_change_id` |optional|
|
||||
|`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|
|
||||
link:#inherited-boolean-info[InheritedBooleanInfo] that tells 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 directly
|
||||
@@ -1662,14 +1676,14 @@ the comment link configuration is mapped to the comment link
|
||||
configuration, which has the same format as the
|
||||
link:config-gerrit.html#_a_id_commentlink_a_section_commentlink[
|
||||
commentlink section] of `gerrit.config`.
|
||||
|`theme` |optional|
|
||||
|`theme` |optional|
|
||||
The theme that is configured for the project as a link:#theme-info[
|
||||
ThemeInfo] entity.
|
||||
|`plugin_config` |optional|
|
||||
|`plugin_config` |optional|
|
||||
Plugin configuration as map which maps the plugin name to a map of
|
||||
parameter names to link:#config-parameter-info[ConfigParameterInfo]
|
||||
entities.
|
||||
|`actions` |optional|
|
||||
|`actions` |optional|
|
||||
Actions the caller might be able to perform on this project. The
|
||||
information is a map of view names to
|
||||
link:rest-api-changes.html#action-info[ActionInfo] entities.
|
||||
@@ -1680,50 +1694,55 @@ link:rest-api-changes.html#action-info[ActionInfo] entities.
|
||||
The `ConfigInput` entity describes a new project configuration.
|
||||
|
||||
[options="header",width="50%",cols="1,^2,4"]
|
||||
|=========================================
|
||||
|Field Name ||Description
|
||||
|`description` |optional|
|
||||
|======================================================
|
||||
|Field Name ||Description
|
||||
|`description` |optional|
|
||||
The new description of the project. +
|
||||
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
|
||||
before pushing any commits or changes to this project. +
|
||||
Can be `TRUE`, `FALSE` or `INHERIT`. +
|
||||
If not set, this setting is not updated.
|
||||
|`use_content_merge` |optional|
|
||||
|`use_content_merge` |optional|
|
||||
Whether 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. +
|
||||
Can be `TRUE`, `FALSE` or `INHERIT`. +
|
||||
If not set, this setting is not updated.
|
||||
|`use_signed_off_by` |optional|
|
||||
|`use_signed_off_by` |optional|
|
||||
Whether each change must contain a Signed-off-by line from either the
|
||||
author or the uploader in the commit message. +
|
||||
Can be `TRUE`, `FALSE` or `INHERIT`. +
|
||||
If not set, this setting is not updated.
|
||||
|`require_change_id` |optional|
|
||||
|`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|
|
||||
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
|
||||
directly to a branch or tag. +
|
||||
Can be `TRUE`, `FALSE` or `INHERIT`. +
|
||||
If not set, this setting is not updated.
|
||||
|`max_object_size_limit` |optional|
|
||||
|`max_object_size_limit` |optional|
|
||||
The link:config-gerrit.html#receive.maxObjectSizeLimit[max object size
|
||||
limit] of this project as a link:#max-object-size-limit-info[
|
||||
MaxObjectSizeLimitInfo] entity. +
|
||||
If set to `0`, the max object size limit is removed. +
|
||||
If not set, this setting is not updated.
|
||||
|`submit_type` |optional|
|
||||
|`submit_type` |optional|
|
||||
The default submit type of the project, can be `MERGE_IF_NECESSARY`,
|
||||
`FAST_FORWARD_ONLY`, `REBASE_IF_NECESSARY`, `MERGE_ALWAYS` or
|
||||
`CHERRY_PICK`. +
|
||||
If not set, the submit type is not updated.
|
||||
|`state` |optional|
|
||||
|`state` |optional|
|
||||
The state of the project, can be `ACTIVE`, `READ_ONLY` or `HIDDEN`. +
|
||||
Not set if the project state is `ACTIVE`. +
|
||||
If not set, the project state is not updated.
|
||||
|`plugin_config_values` |optional|
|
||||
|`plugin_config_values` |optional|
|
||||
Plugin configuration values as map which maps the plugin name to a map
|
||||
of parameter names to values.
|
||||
|=========================================
|
||||
@@ -1970,17 +1989,20 @@ link:rest-api-groups.html#group-id[group-id]. +
|
||||
If not set, the link:config-gerrit.html#repository.name.ownerGroup[
|
||||
groups that are configured as default owners] are set as project
|
||||
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`,
|
||||
`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
|
||||
project (`TRUE`, `FALSE`, `INHERIT`).
|
||||
|`use_content_merge` |`INHERIT` if not set|
|
||||
|`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|
|
||||
Whether content merge should be enabled for the project (`TRUE`,
|
||||
`FALSE`, `INHERIT`). +
|
||||
`FALSE`, if the `submit_type` is `FAST_FORWARD_ONLY`.
|
||||
|`require_change_id` |`INHERIT` if not set|
|
||||
|`require_change_id` |`INHERIT` if not set|
|
||||
Whether the usage of Change-Ids is required for the project (`TRUE`,
|
||||
`FALSE`, `INHERIT`).
|
||||
|`max_object_size_limit` |optional|
|
||||
|
||||
@@ -33,6 +33,7 @@ public class ProjectInput {
|
||||
public InheritableBoolean useSignedOffBy;
|
||||
public InheritableBoolean useContentMerge;
|
||||
public InheritableBoolean requireChangeId;
|
||||
public InheritableBoolean createNewChangeForAllNotInTarget;
|
||||
public String maxObjectSizeLimit;
|
||||
public Map<String, Map<String, ConfigValue>> pluginConfigValues;
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ public interface AdminConstants extends Constants {
|
||||
String useContentMerge();
|
||||
String useContributorAgreements();
|
||||
String useSignedOffBy();
|
||||
String createNewChangeForAllNotInTarget();
|
||||
String requireChangeID();
|
||||
String headingMaxObjectSizeLimit();
|
||||
String headingGroupOptions();
|
||||
|
||||
@@ -23,6 +23,7 @@ projectRepoBrowser = Repository Browser
|
||||
useContentMerge = Automatically resolve conflicts
|
||||
useContributorAgreements = Require a valid contributor agreement to upload
|
||||
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
|
||||
headingMaxObjectSizeLimit = Maximum Git object size limit
|
||||
headingGroupOptions = Group Options
|
||||
|
||||
@@ -79,6 +79,7 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
private ListBox submitType;
|
||||
private ListBox state;
|
||||
private ListBox contentMerge;
|
||||
private ListBox newChangeForAllNotInTarget;
|
||||
private NpTextBox maxObjectSizeLimit;
|
||||
private Label effectiveMaxObjectSizeLimit;
|
||||
private Map<String, Map<String, HasEnabled>> pluginConfigWidgets;
|
||||
@@ -157,6 +158,7 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
state.setEnabled(isOwner);
|
||||
submitType.setEnabled(isOwner);
|
||||
setEnabledForUseContentMerge();
|
||||
newChangeForAllNotInTarget.setEnabled(isOwner);
|
||||
descTxt.setEnabled(isOwner);
|
||||
contributorAgreements.setEnabled(isOwner);
|
||||
signedOffBy.setEnabled(isOwner);
|
||||
@@ -213,6 +215,10 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
saveEnabler.listenTo(contentMerge);
|
||||
grid.add(Util.C.useContentMerge(), contentMerge);
|
||||
|
||||
newChangeForAllNotInTarget = newInheritedBooleanBox();
|
||||
saveEnabler.listenTo(newChangeForAllNotInTarget);
|
||||
grid.add(Util.C.createNewChangeForAllNotInTarget(), newChangeForAllNotInTarget);
|
||||
|
||||
requireChangeID = newInheritedBooleanBox();
|
||||
saveEnabler.listenTo(requireChangeID);
|
||||
grid.addHtml(Util.C.requireChangeID(), requireChangeID);
|
||||
@@ -338,6 +344,7 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
setBool(contributorAgreements, result.use_contributor_agreements());
|
||||
setBool(signedOffBy, result.use_signed_off_by());
|
||||
setBool(contentMerge, result.use_content_merge());
|
||||
setBool(newChangeForAllNotInTarget, result.create_new_change_for_all_not_in_target());
|
||||
setBool(requireChangeID, result.require_change_id());
|
||||
setSubmitType(result.submit_type());
|
||||
setState(result.state());
|
||||
@@ -569,7 +576,7 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
saveProject.setEnabled(false);
|
||||
ProjectApi.setConfig(getProjectKey(), descTxt.getText().trim(),
|
||||
getBool(contributorAgreements), getBool(contentMerge),
|
||||
getBool(signedOffBy), getBool(requireChangeID),
|
||||
getBool(signedOffBy), getBool(newChangeForAllNotInTarget), getBool(requireChangeID),
|
||||
maxObjectSizeLimit.getText().trim(),
|
||||
SubmitType.valueOf(submitType.getValue(submitType.getSelectedIndex())),
|
||||
ProjectState.valueOf(state.getValue(state.getSelectedIndex())),
|
||||
|
||||
@@ -44,6 +44,9 @@ public class ConfigInfo extends JavaScriptObject {
|
||||
public final native InheritedBooleanInfo 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()
|
||||
/*-{ return this.use_signed_off_by; }-*/;
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ public class ProjectApi {
|
||||
public static void setConfig(Project.NameKey name, String description,
|
||||
InheritableBoolean useContributorAgreements,
|
||||
InheritableBoolean useContentMerge, InheritableBoolean useSignedOffBy,
|
||||
InheritableBoolean createNewChangeForAllNotInTarget,
|
||||
InheritableBoolean requireChangeId, String maxObjectSizeLimit,
|
||||
SubmitType submitType, ProjectState state,
|
||||
Map<String, Map<String, ConfigParameterValue>> pluginConfigValues,
|
||||
@@ -95,6 +96,7 @@ public class ProjectApi {
|
||||
in.setUseContentMerge(useContentMerge);
|
||||
in.setUseSignedOffBy(useSignedOffBy);
|
||||
in.setRequireChangeId(requireChangeId);
|
||||
in.setCreateNewChangeForAllNotInTarget(createNewChangeForAllNotInTarget);
|
||||
in.setMaxObjectSizeLimit(maxObjectSizeLimit);
|
||||
in.setSubmitType(submitType);
|
||||
in.setState(state);
|
||||
@@ -209,6 +211,12 @@ public class ProjectApi {
|
||||
private final native void setRequireChangeIdRaw(String 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)
|
||||
/*-{ if(l)this.max_object_size_limit=l; }-*/;
|
||||
|
||||
|
||||
@@ -94,6 +94,8 @@ public final class Project {
|
||||
|
||||
protected String themeName;
|
||||
|
||||
protected InheritableBoolean createNewChangeForAllNotInTarget;
|
||||
|
||||
protected Project() {
|
||||
}
|
||||
|
||||
@@ -105,6 +107,7 @@ public final class Project {
|
||||
useSignedOffBy = InheritableBoolean.INHERIT;
|
||||
requireChangeID = InheritableBoolean.INHERIT;
|
||||
useContentMerge = InheritableBoolean.INHERIT;
|
||||
createNewChangeForAllNotInTarget = InheritableBoolean.INHERIT;
|
||||
}
|
||||
|
||||
public Project.NameKey getNameKey() {
|
||||
@@ -159,6 +162,15 @@ public final class Project {
|
||||
requireChangeID = cid;
|
||||
}
|
||||
|
||||
public InheritableBoolean getCreateNewChangeForAllNotInTarget() {
|
||||
return createNewChangeForAllNotInTarget;
|
||||
}
|
||||
|
||||
public void setCreateNewChangeForAllNotInTarget(
|
||||
InheritableBoolean useAllNotInTarget) {
|
||||
this.createNewChangeForAllNotInTarget = useAllNotInTarget;
|
||||
}
|
||||
|
||||
public void setMaxObjectSizeLimit(final String limit) {
|
||||
maxObjectSizeLimit = limit;
|
||||
}
|
||||
@@ -212,6 +224,7 @@ public final class Project {
|
||||
submitType = update.submitType;
|
||||
state = update.state;
|
||||
maxObjectSizeLimit = update.maxObjectSizeLimit;
|
||||
createNewChangeForAllNotInTarget = update.createNewChangeForAllNotInTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -115,6 +115,8 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
private static final String RECEIVE = "receive";
|
||||
private static final String KEY_REQUIRE_SIGNED_OFF_BY = "requireSignedOffBy";
|
||||
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_REQUIRE_CONTRIBUTOR_AGREEMENT =
|
||||
"requireContributorAgreement";
|
||||
@@ -419,6 +421,7 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
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.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.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_SIGNED_OFF_BY, p.getUseSignedOffBy(), 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, SUBMIT, null, KEY_ACTION, p.getSubmitType(), defaultSubmitAction);
|
||||
|
||||
@@ -311,6 +311,7 @@ public class ReceiveCommits {
|
||||
private final ReceivePack rp;
|
||||
private final NoteMap rejectCommits;
|
||||
private MagicBranchInput magicBranch;
|
||||
private boolean newChangeForAllNotInTarget;
|
||||
|
||||
private List<CreateRequest> newChanges = Collections.emptyList();
|
||||
private final Map<Change.Id, ReplaceRequest> replaceByChange =
|
||||
@@ -428,6 +429,7 @@ public class ReceiveCommits {
|
||||
|
||||
ProjectState ps = projectControl.getProjectState();
|
||||
|
||||
this.newChangeForAllNotInTarget = ps.isCreateNewChangeForAllNotInTarget();
|
||||
rp.setAllowCreates(true);
|
||||
rp.setAllowDeletes(true);
|
||||
rp.setAllowNonFastForwards(true);
|
||||
@@ -1293,6 +1295,21 @@ public class ReceiveCommits {
|
||||
}
|
||||
|
||||
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) {
|
||||
magicBranch.baseCommit = Lists.newArrayListWithCapacity(
|
||||
magicBranch.base.size());
|
||||
@@ -1313,6 +1330,18 @@ public class ReceiveCommits {
|
||||
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
|
||||
@@ -1321,7 +1350,6 @@ public class ReceiveCommits {
|
||||
// commits and the target branch head.
|
||||
//
|
||||
try {
|
||||
final RevCommit tip = walk.parseCommit(magicBranch.cmd.getNewId());
|
||||
Ref targetRef = rp.getAdvertisedRefs().get(magicBranch.ctl.getRefName());
|
||||
if (targetRef == null || targetRef.getObjectId() == null) {
|
||||
// The destination branch does not yet exist. Assume the
|
||||
@@ -1462,6 +1490,13 @@ public class ReceiveCommits {
|
||||
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());
|
||||
final List<String> idList = c.getFooterLines(CHANGE_ID);
|
||||
if (idList.isEmpty()) {
|
||||
|
||||
@@ -43,6 +43,7 @@ public class ConfigInfo {
|
||||
public InheritedBooleanInfo useContributorAgreements;
|
||||
public InheritedBooleanInfo useContentMerge;
|
||||
public InheritedBooleanInfo useSignedOffBy;
|
||||
public InheritedBooleanInfo createNewChangeForAllNotInTarget;
|
||||
public InheritedBooleanInfo requireChangeId;
|
||||
public MaxObjectSizeLimitInfo maxObjectSizeLimit;
|
||||
public SubmitType submitType;
|
||||
@@ -68,17 +69,23 @@ public class ConfigInfo {
|
||||
InheritedBooleanInfo useSignedOffBy = new InheritedBooleanInfo();
|
||||
InheritedBooleanInfo useContentMerge = new InheritedBooleanInfo();
|
||||
InheritedBooleanInfo requireChangeId = new InheritedBooleanInfo();
|
||||
InheritedBooleanInfo createNewChangeForAllNotInTarget =
|
||||
new InheritedBooleanInfo();
|
||||
|
||||
useContributorAgreements.value = projectState.isUseContributorAgreements();
|
||||
useSignedOffBy.value = projectState.isUseSignedOffBy();
|
||||
useContentMerge.value = projectState.isUseContentMerge();
|
||||
requireChangeId.value = projectState.isRequireChangeID();
|
||||
createNewChangeForAllNotInTarget.value =
|
||||
projectState.isCreateNewChangeForAllNotInTarget();
|
||||
|
||||
useContributorAgreements.configuredValue =
|
||||
p.getUseContributorAgreements();
|
||||
useSignedOffBy.configuredValue = p.getUseSignedOffBy();
|
||||
useContentMerge.configuredValue = p.getUseContentMerge();
|
||||
requireChangeId.configuredValue = p.getRequireChangeID();
|
||||
createNewChangeForAllNotInTarget.configuredValue =
|
||||
p.getCreateNewChangeForAllNotInTarget();
|
||||
|
||||
ProjectState parentState = Iterables.getFirst(projectState
|
||||
.parents(), null);
|
||||
@@ -88,12 +95,15 @@ public class ConfigInfo {
|
||||
useSignedOffBy.inheritedValue = parentState.isUseSignedOffBy();
|
||||
useContentMerge.inheritedValue = parentState.isUseContentMerge();
|
||||
requireChangeId.inheritedValue = parentState.isRequireChangeID();
|
||||
createNewChangeForAllNotInTarget.inheritedValue =
|
||||
parentState.isCreateNewChangeForAllNotInTarget();
|
||||
}
|
||||
|
||||
this.useContributorAgreements = useContributorAgreements;
|
||||
this.useSignedOffBy = useSignedOffBy;
|
||||
this.useContentMerge = useContentMerge;
|
||||
this.requireChangeId = requireChangeId;
|
||||
this.createNewChangeForAllNotInTarget = createNewChangeForAllNotInTarget;
|
||||
|
||||
MaxObjectSizeLimitInfo maxObjectSizeLimit = new MaxObjectSizeLimitInfo();
|
||||
maxObjectSizeLimit.value =
|
||||
|
||||
@@ -124,6 +124,9 @@ public class CreateProject implements RestModifyView<TopLevelResource, ProjectIn
|
||||
? InheritableBoolean.FALSE : MoreObjects.firstNonNull(
|
||||
input.useContentMerge,
|
||||
InheritableBoolean.INHERIT);
|
||||
args.newChangeForAllNotInTarget =
|
||||
MoreObjects.firstNonNull(input.createNewChangeForAllNotInTarget,
|
||||
InheritableBoolean.INHERIT);
|
||||
args.changeIdRequired =
|
||||
MoreObjects.firstNonNull(input.requireChangeId, InheritableBoolean.INHERIT);
|
||||
try {
|
||||
|
||||
@@ -33,6 +33,7 @@ public class CreateProjectArgs {
|
||||
public boolean permissionsOnly;
|
||||
public List<String> branch;
|
||||
public InheritableBoolean contentMerge;
|
||||
public InheritableBoolean newChangeForAllNotInTarget;
|
||||
public InheritableBoolean changeIdRequired;
|
||||
public boolean createEmptyCommit;
|
||||
public String maxObjectSizeLimit;
|
||||
@@ -42,6 +43,7 @@ public class CreateProjectArgs {
|
||||
signedOffBy = InheritableBoolean.INHERIT;
|
||||
contentMerge = InheritableBoolean.INHERIT;
|
||||
changeIdRequired = InheritableBoolean.INHERIT;
|
||||
newChangeForAllNotInTarget = InheritableBoolean.INHERIT;
|
||||
submitType = SubmitType.MERGE_IF_NECESSARY;
|
||||
}
|
||||
|
||||
|
||||
@@ -193,6 +193,7 @@ public class PerformCreateProject {
|
||||
.setUseContributorAgreements(createProjectArgs.contributorAgreements);
|
||||
newProject.setUseSignedOffBy(createProjectArgs.signedOffBy);
|
||||
newProject.setUseContentMerge(createProjectArgs.contentMerge);
|
||||
newProject.setCreateNewChangeForAllNotInTarget(createProjectArgs.newChangeForAllNotInTarget);
|
||||
newProject.setRequireChangeID(createProjectArgs.changeIdRequired);
|
||||
newProject.setMaxObjectSizeLimit(createProjectArgs.maxObjectSizeLimit);
|
||||
if (createProjectArgs.newParent != null) {
|
||||
|
||||
@@ -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() {
|
||||
Map<String, LabelType> types = Maps.newLinkedHashMap();
|
||||
for (ProjectState s : treeInOrder()) {
|
||||
|
||||
@@ -66,6 +66,7 @@ public class PutConfig implements RestModifyView<ProjectResource, Input> {
|
||||
public InheritableBoolean useContributorAgreements;
|
||||
public InheritableBoolean useContentMerge;
|
||||
public InheritableBoolean useSignedOffBy;
|
||||
public InheritableBoolean createNewChangeForAllNotInTarget;
|
||||
public InheritableBoolean requireChangeId;
|
||||
public String maxObjectSizeLimit;
|
||||
public SubmitType submitType;
|
||||
@@ -146,6 +147,11 @@ public class PutConfig implements RestModifyView<ProjectResource, Input> {
|
||||
if (input.useSignedOffBy != null) {
|
||||
p.setUseSignedOffBy(input.useSignedOffBy);
|
||||
}
|
||||
|
||||
if (input.createNewChangeForAllNotInTarget != null) {
|
||||
p.setCreateNewChangeForAllNotInTarget(input.createNewChangeForAllNotInTarget);
|
||||
}
|
||||
|
||||
if (input.requireChangeId != null) {
|
||||
p.setRequireChangeID(input.requireChangeId);
|
||||
}
|
||||
|
||||
@@ -87,6 +87,9 @@ final class CreateProjectCommand extends SshCommand {
|
||||
@Option(name = "--change-id", usage = "if change-id is required")
|
||||
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")
|
||||
void setUseContributorArgreements(boolean on) {
|
||||
contributorAgreements = InheritableBoolean.TRUE;
|
||||
@@ -107,6 +110,11 @@ final class CreateProjectCommand extends SshCommand {
|
||||
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"
|
||||
+ "(default: master)")
|
||||
private List<String> branch;
|
||||
@@ -166,6 +174,7 @@ final class CreateProjectCommand extends SshCommand {
|
||||
input.useSignedOffBy = signedOffBy;
|
||||
input.useContentMerge = contentMerge;
|
||||
input.requireChangeId = requireChangeID;
|
||||
input.createNewChangeForAllNotInTarget = createNewChangeForAllNotInTarget;
|
||||
input.branches = branch;
|
||||
input.createEmptyCommit = createEmptyCommit;
|
||||
input.maxObjectSizeLimit = maxObjectSizeLimit;
|
||||
|
||||
Reference in New Issue
Block a user