Merge branch 'stable-2.15'

* stable-2.15:
  ProjectTagsScreen: Base visibility on the create refs/tags/* permission
  Upgrade JGit to 4.9.4.201809090327-r
  Upgrade JGit to 4.7.3.201809090215-r
  Set version to 2.14.13-SNAPSHOT
  ProjectTagsScreen: Base visibility on the create refs/tags/* permission
  Set version to 2.15.4-SNAPSHOT
  Set version to 2.14.12
  [project.config] Allow to add commentLink entries
  ElasticVersionTest: Align tested versions w/ ElasticContainer last ones
  Assume correct relative or absolute URL from Weblink provider
  AbstractSubmit: Remove redundant assertion about null IOException
  ListMailFilter: Fix operator precedence warning raised by ErrorProne
  ListProjects: Fix operator precedence warning raised by ErrorProne
  ChangeBundle: Fix operator precedence warning raised by ErrorProne
  Bazel: fix error_prone_warnings_toolchain rule
  Elastic{Index|ReindexIT} Remove tests for 6.2 and 6.3
  ElasticVersionTest#version6: Add missing test for V6_4
  Allow more email RFC accepted chars in username
  Make inheritance of receive.maxObjectSizeLimit optional
  Allow to inherit receive.maxObjectSizeLimit from parent project
  RestApiServlet: Skip capability check for administrators
  CreateAccount: Simplify error message when username is invalid
  Bazel: Provide toolchain with activated error prone warnings
  Use ExternalId.isValidUsername instead of ExternalId.USER_NAME_PATTERN_REGEX
  Move regular expressions for user name from Account to ExternalId
  AccountIT: Add basic tests for creating user with {in}valid username
  Revert refactoring of Account.USER_NAME_PATTERN
  Fix code that caused changes to break in MS Edge
  Add support for Elasticsearch 6.4.0
  Upgrade elasticsearch-rest-client to 6.4.0
  ElasticVersion: Say 'Unsupported' rather than 'Invalid'
  ElasticQueryAdapter: Move isV6 method to ElasticVersion and simplify
  Account.java: introduce compiled pattern and use where applicable
  Optimize USER_NAME_PATTERN string and its usage
  ElasticContainer: Test against Elasticsearch version 5.6.11
  rest-api-accounts: Fix documentation of "Get Active" response
  GetCapabilities#CheckOne: Return json content type
  ConfigSuite: Instantiate class via getDeclaredConstructor()

Change-Id: I08136f1d27da08ce8a523f2dc062316723e17c45
This commit is contained in:
David Pursehouse 2018-09-11 13:51:03 +09:00
commit 7f04237529
46 changed files with 400 additions and 139 deletions

View File

@ -3748,6 +3748,14 @@ Default is zero.
+ +
Common unit suffixes of 'k', 'm', or 'g' are supported. Common unit suffixes of 'k', 'm', or 'g' are supported.
[[receive.inheritProjectMaxObjectSizeLimit]]receive.inheritProjectMaxObjectSizeLimit::
+
Controls whether the project-level link:config-project-config.html[`receive.maxObjectSizeLimit`]
value is inherited from the parent project. When `true`, the value is
inherited, otherwise it is not inherited.
+
Default is false, the value is not inherited.
[[receive.maxTrustDepth]]receive.maxTrustDepth:: [[receive.maxTrustDepth]]receive.maxTrustDepth::
+ +
If signed push validation is link:#receive.enableSignedPush[enabled], If signed push validation is link:#receive.enableSignedPush[enabled],

View File

@ -148,8 +148,10 @@ The project specific setting in `project.config` may not set a value higher
than the global limit (if configured). In other words, it is only honored when than the global limit (if configured). In other words, it is only honored when
it further reduces the global limit. it further reduces the global limit.
+ +
The setting is not inherited from the parent project; it must be explicitly When link:config-gerrit.html#receive.inheritProjectMaxObjectSizeLimit[
set per project. `receive.inheritProjectmaxObjectSizeLimit`] is enabled in the global config,
the value is inherited from the parent project. Otherwise, it is not inherited
and must be explicitly set per project.
+ +
Default is zero. Default is zero.
+ +

View File

@ -263,6 +263,7 @@ The entries in the map are sorted by project name.
], ],
"can_upload": true, "can_upload": true,
"can_add": true, "can_add": true,
"can_add_tags": true,
"config_visible": true, "config_visible": true,
"groups": { "groups": {
"53a4f647a89ea57992571187d8025f830625192a": { "53a4f647a89ea57992571187d8025f830625192a": {
@ -313,6 +314,7 @@ The entries in the map are sorted by project name.
], ],
"can_upload": true, "can_upload": true,
"can_add": true, "can_add": true,
"can_add_tags": true,
"config_visible": true "config_visible": true
} }
} }
@ -399,6 +401,8 @@ Whether the calling user owns this project.
Whether the calling user can upload to any ref. Whether the calling user can upload to any ref.
|`can_add` |not set if `false`| |`can_add` |not set if `false`|
Whether the calling user can add any ref. Whether the calling user can add any ref.
|`can_add_tags` |not set if `false`|
Whether the calling user can add any tag ref.
|`config_visible` |not set if `false`| |`config_visible` |not set if `false`|
Whether the calling user can see the `refs/meta/config` branch of the Whether the calling user can see the `refs/meta/config` branch of the
project. project.

View File

@ -418,7 +418,10 @@ If the account is active the string `ok` is returned.
.Response .Response
---- ----
HTTP/1.1 200 OK HTTP/1.1 200 OK
Content-Disposition: attachment
Content-Type: application/json; charset=UTF-8
)]}'
ok ok
---- ----
@ -1095,7 +1098,10 @@ If the user has the global capability the string `ok` is returned.
.Response .Response
---- ----
HTTP/1.1 200 OK HTTP/1.1 200 OK
Content-Disposition: attachment
Content-Type: application/json; charset=UTF-8
)]}'
ok ok
---- ----

View File

@ -1141,6 +1141,7 @@ entity is returned.
], ],
"can_upload": true, "can_upload": true,
"can_add": true, "can_add": true,
"can_add_tags": true,
"config_visible": true, "config_visible": true,
"groups": { "groups": {
"c2ce4749a32ceb82cd6adcce65b8216e12afb41c": { "c2ce4749a32ceb82cd6adcce65b8216e12afb41c": {
@ -1242,6 +1243,7 @@ entity is returned.
], ],
"can_upload": true, "can_upload": true,
"can_add": true, "can_add": true,
"can_add_tags": true,
"config_visible": true, "config_visible": true,
"groups": { "groups": {
"global:Anonymous-Users": { "global:Anonymous-Users": {
@ -3442,10 +3444,10 @@ The max object size limit that is configured on the project as a
formatted string. + formatted string. +
Not set if there is no limit for the object size configured on project Not set if there is no limit for the object size configured on project
level. level.
|`inherited_value` |optional| |`summary` |optional|
The max object size limit that is inherited from the global config as a A string describing whether the value was inherited or overridden from
formatted string. + the parent project or global config. +
Not set if there is no global limit for the object size. Not set if not inherited or overridden.
|=============================== |===============================
[[project-access-input]] [[project-access-input]]

View File

@ -1038,8 +1038,8 @@ maven_jar(
maven_jar( maven_jar(
name = "elasticsearch-rest-client", name = "elasticsearch-rest-client",
artifact = "org.elasticsearch.client:elasticsearch-rest-client:6.3.2", artifact = "org.elasticsearch.client:elasticsearch-rest-client:6.4.0",
sha1 = "2077ea5f00fdd2d6af85223b730ba8047303297f", sha1 = "0eaa13decb9796eb671c5841d0770ae68b348da5",
) )
JACKSON_VERSION = "2.8.9" JACKSON_VERSION = "2.8.9"

View File

@ -19,6 +19,8 @@ import com.google.gwt.core.client.JavaScriptObject;
public class ProjectAccessInfo extends JavaScriptObject { public class ProjectAccessInfo extends JavaScriptObject {
public final native boolean canAddRefs() /*-{ return this.can_add ? true : false; }-*/; public final native boolean canAddRefs() /*-{ return this.can_add ? true : false; }-*/;
public final native boolean canAddTagRefs() /*-{ return this.can_add_tags ? true : false; }-*/;
public final native boolean isOwner() /*-{ return this.is_owner ? true : false; }-*/; public final native boolean isOwner() /*-{ return this.is_owner ? true : false; }-*/;
public final native boolean configVisible() /*-{ return this.config_visible ? true : false; }-*/; public final native boolean configVisible() /*-{ return this.config_visible ? true : false; }-*/;

View File

@ -41,7 +41,7 @@ class UsernameField extends Composite {
// corresponding regular expressions in the // corresponding regular expressions in the
// com.google.gerrit.server.account.externalids.ExternalId class. // com.google.gerrit.server.account.externalids.ExternalId class.
private static final String USER_NAME_PATTERN_FIRST_REGEX = "[a-zA-Z0-9]"; private static final String USER_NAME_PATTERN_FIRST_REGEX = "[a-zA-Z0-9]";
private static final String USER_NAME_PATTERN_REST_REGEX = "[a-zA-Z0-9._@-]"; private static final String USER_NAME_PATTERN_REST_REGEX = "[a-zA-Z0-9.!#$%&*+=?^_`\\{|\\}~@-]";
private CopyableLabel userNameLbl; private CopyableLabel userNameLbl;
private NpTextBox userNameTxt; private NpTextBox userNameTxt;

View File

@ -36,8 +36,6 @@ public interface AdminMessages extends Messages {
String effectiveMaxObjectSizeLimit(String effectiveMaxObjectSizeLimit); String effectiveMaxObjectSizeLimit(String effectiveMaxObjectSizeLimit);
String globalMaxObjectSizeLimit(String globalMaxObjectSizeLimit);
String noMaxObjectSizeLimit(); String noMaxObjectSizeLimit();
String pluginProjectOptionsTitle(String pluginName); String pluginProjectOptionsTitle(String pluginName);

View File

@ -6,7 +6,6 @@ deletedGroup = Deleted Group {0}
deletedReference = Reference {0} was deleted deletedReference = Reference {0} was deleted
deletedSection = Section {0} was deleted deletedSection = Section {0} was deleted
effectiveMaxObjectSizeLimit = effective: {0} bytes effectiveMaxObjectSizeLimit = effective: {0} bytes
globalMaxObjectSizeLimit = The global max object size limit is set to {0}. The limit cannot be increased on project level.
noMaxObjectSizeLimit = No max object size limit is set. noMaxObjectSizeLimit = No max object size limit is set.
pluginProjectOptionsTitle = {0} Plugin Options pluginProjectOptionsTitle = {0} Plugin Options
pluginProjectOptionsTitle = {0} Plugin pluginProjectOptionsTitle = {0} Plugin

View File

@ -442,9 +442,8 @@ public class ProjectInfoScreen extends ProjectScreen {
if (result.maxObjectSizeLimit().value() != null) { if (result.maxObjectSizeLimit().value() != null) {
effectiveMaxObjectSizeLimit.setText( effectiveMaxObjectSizeLimit.setText(
AdminMessages.I.effectiveMaxObjectSizeLimit(result.maxObjectSizeLimit().value())); AdminMessages.I.effectiveMaxObjectSizeLimit(result.maxObjectSizeLimit().value()));
if (result.maxObjectSizeLimit().inheritedValue() != null) { if (result.maxObjectSizeLimit().summary() != null) {
effectiveMaxObjectSizeLimit.setTitle( effectiveMaxObjectSizeLimit.setTitle(result.maxObjectSizeLimit().summary());
AdminMessages.I.globalMaxObjectSizeLimit(result.maxObjectSizeLimit().inheritedValue()));
} }
} else { } else {
effectiveMaxObjectSizeLimit.setText(AdminMessages.I.noMaxObjectSizeLimit()); effectiveMaxObjectSizeLimit.setText(AdminMessages.I.noMaxObjectSizeLimit());

View File

@ -94,7 +94,7 @@ public class ProjectTagsScreen extends PaginatedProjectScreen {
new GerritCallback<ProjectAccessInfo>() { new GerritCallback<ProjectAccessInfo>() {
@Override @Override
public void onSuccess(ProjectAccessInfo result) { public void onSuccess(ProjectAccessInfo result) {
addPanel.setVisible(result.canAddRefs()); addPanel.setVisible(result.canAddTagRefs());
} }
}); });
query = new Query(match).start(start).run(); query = new Query(match).start(start).run();

View File

@ -175,10 +175,10 @@ public class ConfigInfo extends JavaScriptObject {
public static class MaxObjectSizeLimitInfo extends JavaScriptObject { public static class MaxObjectSizeLimitInfo extends JavaScriptObject {
public final native String value() /*-{ return this.value; }-*/; public final native String value() /*-{ return this.value; }-*/;
public final native String inheritedValue() /*-{ return this.inherited_value; }-*/;
public final native String configuredValue() /*-{ return this.configured_value }-*/; public final native String configuredValue() /*-{ return this.configured_value }-*/;
public final native String summary() /*-{ return this.summary; }-*/;
protected MaxObjectSizeLimitInfo() {} protected MaxObjectSizeLimitInfo() {}
} }

View File

@ -71,6 +71,7 @@ import org.apache.http.StatusLine;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
import org.apache.http.nio.entity.NStringEntity; import org.apache.http.nio.entity.NStringEntity;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response; import org.elasticsearch.client.Response;
abstract class AbstractElasticIndex<K, V> implements Index<K, V> { abstract class AbstractElasticIndex<K, V> implements Index<K, V> {
@ -171,10 +172,10 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> {
public void deleteAll() throws IOException { public void deleteAll() throws IOException {
// Delete the index, if it exists. // Delete the index, if it exists.
String endpoint = indexName + client.adapter().indicesExistParam(); String endpoint = indexName + client.adapter().indicesExistParam();
Response response = client.get().performRequest("HEAD", endpoint); Response response = client.get().performRequest(new Request("HEAD", endpoint));
int statusCode = response.getStatusLine().getStatusCode(); int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) { if (statusCode == HttpStatus.SC_OK) {
response = client.get().performRequest("DELETE", indexName); response = client.get().performRequest(new Request("DELETE", indexName));
statusCode = response.getStatusLine().getStatusCode(); statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) { if (statusCode != HttpStatus.SC_OK) {
throw new IOException( throw new IOException(
@ -307,9 +308,13 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> {
private Response performRequest( private Response performRequest(
String method, Object payload, String uri, Map<String, String> params) throws IOException { String method, Object payload, String uri, Map<String, String> params) throws IOException {
Request request = new Request(method, uri);
String payloadStr = payload instanceof String ? (String) payload : payload.toString(); String payloadStr = payload instanceof String ? (String) payload : payload.toString();
HttpEntity entity = new NStringEntity(payloadStr, ContentType.APPLICATION_JSON); request.setEntity(new NStringEntity(payloadStr, ContentType.APPLICATION_JSON));
return client.get().performRequest(method, uri, params, entity); for (Map.Entry<String, String> entry : params.entrySet()) {
request.addParameter(entry.getKey(), entry.getValue());
}
return client.get().performRequest(request);
} }
protected class ElasticQuerySource implements DataSource<V> { protected class ElasticQuerySource implements DataSource<V> {

View File

@ -24,7 +24,7 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.StatusLine; import org.apache.http.StatusLine;
import org.apache.http.client.methods.HttpGet; import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response; import org.elasticsearch.client.Response;
@Singleton @Singleton
@ -40,10 +40,8 @@ class ElasticIndexVersionDiscovery {
List<String> discover(String prefix, String indexName) throws IOException { List<String> discover(String prefix, String indexName) throws IOException {
String name = prefix + indexName + "_"; String name = prefix + indexName + "_";
Response response = Request request = new Request("GET", client.adapter().getVersionDiscoveryUrl(name));
client Response response = client.get().performRequest(request);
.get()
.performRequest(HttpGet.METHOD_NAME, client.adapter().getVersionDiscoveryUrl(name));
StatusLine statusLine = response.getStatusLine(); StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() != HttpStatus.SC_OK) { if (statusLine.getStatusCode() != HttpStatus.SC_OK) {

View File

@ -32,13 +32,14 @@ public class ElasticQueryAdapter {
ElasticQueryAdapter(ElasticVersion version) { ElasticQueryAdapter(ElasticVersion version) {
this.ignoreUnmapped = version == ElasticVersion.V2_4; this.ignoreUnmapped = version == ElasticVersion.V2_4;
this.usePostV5Type = isV6(version); this.usePostV5Type = version.isV6();
this.versionDiscoveryUrl = isV6(version) ? "%s*" : "%s*/_aliases"; this.versionDiscoveryUrl = version.isV6() ? "%s*" : "%s*/_aliases";
switch (version) { switch (version) {
case V5_6: case V5_6:
case V6_2: case V6_2:
case V6_3: case V6_3:
case V6_4:
this.searchFilteringName = "_source"; this.searchFilteringName = "_source";
this.indicesExistParam = "?allow_no_indices=false"; this.indicesExistParam = "?allow_no_indices=false";
this.exactFieldType = "keyword"; this.exactFieldType = "keyword";
@ -58,10 +59,6 @@ public class ElasticQueryAdapter {
} }
} }
private boolean isV6(ElasticVersion version) {
return version == ElasticVersion.V6_2 || version == ElasticVersion.V6_3;
}
void setIgnoreUnmapped(JsonObject properties) { void setIgnoreUnmapped(JsonObject properties) {
if (ignoreUnmapped) { if (ignoreUnmapped) {
properties.addProperty("ignore_unmapped", true); properties.addProperty("ignore_unmapped", true);

View File

@ -29,6 +29,7 @@ import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider; import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response; import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestClientBuilder;
@ -105,7 +106,7 @@ class ElasticRestClientProvider implements Provider<RestClient>, LifecycleListen
private ElasticVersion getVersion() throws ElasticException { private ElasticVersion getVersion() throws ElasticException {
try { try {
Response response = client.performRequest("GET", ""); Response response = client.performRequest(new Request("GET", ""));
StatusLine statusLine = response.getStatusLine(); StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() != HttpStatus.SC_OK) { if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
throw new FailedToGetVersion(statusLine); throw new FailedToGetVersion(statusLine);

View File

@ -21,7 +21,8 @@ public enum ElasticVersion {
V2_4("2.4.*"), V2_4("2.4.*"),
V5_6("5.6.*"), V5_6("5.6.*"),
V6_2("6.2.*"), V6_2("6.2.*"),
V6_3("6.3.*"); V6_3("6.3.*"),
V6_4("6.4.*");
private final String version; private final String version;
private final Pattern pattern; private final Pattern pattern;
@ -31,29 +32,33 @@ public enum ElasticVersion {
this.pattern = Pattern.compile(version); this.pattern = Pattern.compile(version);
} }
public static class InvalidVersion extends ElasticException { public static class UnsupportedVersion extends ElasticException {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
InvalidVersion(String version) { UnsupportedVersion(String version) {
super( super(
String.format( String.format(
"Invalid version: [%s]. Supported versions: %s", version, supportedVersions())); "Unsupported version: [%s]. Supported versions: %s", version, supportedVersions()));
} }
} }
public static ElasticVersion forVersion(String version) throws InvalidVersion { public static ElasticVersion forVersion(String version) throws UnsupportedVersion {
for (ElasticVersion value : ElasticVersion.values()) { for (ElasticVersion value : ElasticVersion.values()) {
if (value.pattern.matcher(version).matches()) { if (value.pattern.matcher(version).matches()) {
return value; return value;
} }
} }
throw new InvalidVersion(version); throw new UnsupportedVersion(version);
} }
public static String supportedVersions() { public static String supportedVersions() {
return Joiner.on(", ").join(ElasticVersion.values()); return Joiner.on(", ").join(ElasticVersion.values());
} }
public boolean isV6() {
return version.startsWith("6.");
}
@Override @Override
public String toString() { public String toString() {
return version; return version;

View File

@ -29,6 +29,7 @@ public class ProjectAccessInfo {
public Set<String> ownerOf; public Set<String> ownerOf;
public Boolean canUpload; public Boolean canUpload;
public Boolean canAdd; public Boolean canAdd;
public Boolean canAddTags;
public Boolean configVisible; public Boolean configVisible;
public Map<String, GroupInfo> groups; public Map<String, GroupInfo> groups;
public List<WebLinkInfo> configWebLinks; public List<WebLinkInfo> configWebLinks;

View File

@ -59,14 +59,17 @@ public class ConfigInfo {
} }
public static class MaxObjectSizeLimitInfo { public static class MaxObjectSizeLimitInfo {
/* The effective value. Null if not set. */ /** The effective value in bytes. Null if not set. */
@Nullable public String value; @Nullable public String value;
/* The value configured on the project. Null if not set. */ /** The value configured explicitly on the project as a formatted string. Null if not set. */
@Nullable public String configuredValue; @Nullable public String configuredValue;
/* The value configured globally. Null if not set. */ /**
@Nullable public String inheritedValue; * Whether the value was inherited or overridden from the project's parent hierarchy or global
* config. Null if not inherited or overridden.
*/
@Nullable public String summary;
} }
public static class ConfigParameterInfo { public static class ConfigParameterInfo {

View File

@ -1392,10 +1392,15 @@ public class RestApiServlet extends HttpServlet {
private void checkRequiresCapability(ViewData d) private void checkRequiresCapability(ViewData d)
throws AuthException, PermissionBackendException { throws AuthException, PermissionBackendException {
globals try {
.permissionBackend globals.permissionBackend.currentUser().check(GlobalPermission.ADMINISTRATE_SERVER);
.currentUser() } catch (AuthException e) {
.checkAny(GlobalPermission.fromAnnotation(d.pluginName, d.view.getClass())); // Skiping
globals
.permissionBackend
.currentUser()
.checkAny(GlobalPermission.fromAnnotation(d.pluginName, d.view.getClass()));
}
} }
private static long handleException( private static long handleException(

View File

@ -47,14 +47,12 @@ public abstract class ExternalId implements Serializable {
// corresponding regular expressions in the // corresponding regular expressions in the
// com.google.gerrit.client.account.UsernameField class. // com.google.gerrit.client.account.UsernameField class.
private static final String USER_NAME_PATTERN_FIRST_REGEX = "[a-zA-Z0-9]"; private static final String USER_NAME_PATTERN_FIRST_REGEX = "[a-zA-Z0-9]";
private static final String USER_NAME_PATTERN_REST_REGEX = "[a-zA-Z0-9._@-]"; private static final String USER_NAME_PATTERN_REST_REGEX = "[a-zA-Z0-9.!#$%&*+=?^_`\\{|\\}~@-]";
private static final String USER_NAME_PATTERN_LAST_REGEX = "[a-zA-Z0-9]"; private static final String USER_NAME_PATTERN_LAST_REGEX = "[a-zA-Z0-9]";
/** Regular expression that a username must match. */ /** Regular expression that a username must match. */
private static final String USER_NAME_PATTERN_REGEX = private static final String USER_NAME_PATTERN_REGEX =
"^" "^("
+ //
"("
+ // + //
USER_NAME_PATTERN_FIRST_REGEX USER_NAME_PATTERN_FIRST_REGEX
+ // + //
@ -67,9 +65,7 @@ public abstract class ExternalId implements Serializable {
+ // + //
USER_NAME_PATTERN_FIRST_REGEX USER_NAME_PATTERN_FIRST_REGEX
+ // + //
")" ")$";
+ //
"$";
private static final Pattern USER_NAME_PATTERN = Pattern.compile(USER_NAME_PATTERN_REGEX); private static final Pattern USER_NAME_PATTERN = Pattern.compile(USER_NAME_PATTERN_REGEX);

View File

@ -28,6 +28,7 @@ public class TransferConfig {
private final PackConfig packConfig; private final PackConfig packConfig;
private final long maxObjectSizeLimit; private final long maxObjectSizeLimit;
private final String maxObjectSizeLimitFormatted; private final String maxObjectSizeLimitFormatted;
private final boolean inheritProjectMaxObjectSizeLimit;
@Inject @Inject
TransferConfig(@GerritServerConfig Config cfg) { TransferConfig(@GerritServerConfig Config cfg) {
@ -42,6 +43,8 @@ public class TransferConfig {
TimeUnit.SECONDS); TimeUnit.SECONDS);
maxObjectSizeLimit = cfg.getLong("receive", "maxObjectSizeLimit", 0); maxObjectSizeLimit = cfg.getLong("receive", "maxObjectSizeLimit", 0);
maxObjectSizeLimitFormatted = cfg.getString("receive", null, "maxObjectSizeLimit"); maxObjectSizeLimitFormatted = cfg.getString("receive", null, "maxObjectSizeLimit");
inheritProjectMaxObjectSizeLimit =
cfg.getBoolean("receive", "inheritProjectMaxObjectSizeLimit", false);
packConfig = new PackConfig(); packConfig = new PackConfig();
packConfig.setDeltaCompress(false); packConfig.setDeltaCompress(false);
@ -65,4 +68,8 @@ public class TransferConfig {
public String getFormattedMaxObjectSizeLimit() { public String getFormattedMaxObjectSizeLimit() {
return maxObjectSizeLimitFormatted; return maxObjectSizeLimitFormatted;
} }
public boolean getInheritProjectMaxObjectSizeLimit() {
return inheritProjectMaxObjectSizeLimit;
}
} }

View File

@ -224,7 +224,7 @@ public class AsyncReceiveCommits implements PreReceiveHook {
receivePack.setAllowNonFastForwards(true); receivePack.setAllowNonFastForwards(true);
receivePack.setRefLogIdent(user.newRefLogIdent()); receivePack.setRefLogIdent(user.newRefLogIdent());
receivePack.setTimeout(transferConfig.getTimeout()); receivePack.setTimeout(transferConfig.getTimeout());
receivePack.setMaxObjectSizeLimit(projectState.getEffectiveMaxObjectSizeLimit()); receivePack.setMaxObjectSizeLimit(projectState.getEffectiveMaxObjectSizeLimit().value);
receivePack.setCheckReceivedObjects(projectState.getConfig().getCheckReceivedObjects()); receivePack.setCheckReceivedObjects(projectState.getConfig().getCheckReceivedObjects());
receivePack.setRefFilter(new ReceiveRefFilter()); receivePack.setRefFilter(new ReceiveRefFilter());
receivePack.setAllowPushOptions(true); receivePack.setAllowPushOptions(true);

View File

@ -53,7 +53,8 @@ public class ListMailFilter implements MailFilter {
} }
boolean match = mailPattern.matcher(message.from().getEmail()).find(); boolean match = mailPattern.matcher(message.from().getEmail()).find();
if (mode == ListFilterMode.WHITELIST && !match || mode == ListFilterMode.BLACKLIST && match) { if ((mode == ListFilterMode.WHITELIST && !match)
|| (mode == ListFilterMode.BLACKLIST && match)) {
logger.atInfo().log("Mail message from %s rejected by list filter", message.from()); logger.atInfo().log("Mail message from %s rejected by list filter", message.from());
return false; return false;
} }

View File

@ -395,7 +395,7 @@ public class ChangeBundle {
excludeOrigSubj = true; excludeOrigSubj = true;
String aTopic = trimOrNull(a.getTopic()); String aTopic = trimOrNull(a.getTopic());
excludeTopic = excludeTopic =
Objects.equals(aTopic, b.getTopic()) || "".equals(aTopic) && b.getTopic() == null; Objects.equals(aTopic, b.getTopic()) || ("".equals(aTopic) && b.getTopic() == null);
aUpdated = bundleA.getLatestTimestamp(); aUpdated = bundleA.getLatestTimestamp();
} else if (bundleA.source == NOTE_DB && bundleB.source == REVIEW_DB) { } else if (bundleA.source == NOTE_DB && bundleB.source == REVIEW_DB) {
boolean createdOnMatchesFirstPs = boolean createdOnMatchesFirstPs =
@ -413,7 +413,7 @@ public class ChangeBundle {
excludeOrigSubj = true; excludeOrigSubj = true;
String bTopic = trimOrNull(b.getTopic()); String bTopic = trimOrNull(b.getTopic());
excludeTopic = excludeTopic =
Objects.equals(bTopic, a.getTopic()) || a.getTopic() == null && "".equals(bTopic); Objects.equals(bTopic, a.getTopic()) || (a.getTopic() == null && "".equals(bTopic));
bUpdated = bundleB.getLatestTimestamp(); bUpdated = bundleB.getLatestTimestamp();
} }
@ -718,7 +718,8 @@ public class ChangeBundle {
excludePostSubmit = a.getValue() == 0 && b.isPostSubmit(); excludePostSubmit = a.getValue() == 0 && b.isPostSubmit();
} else if (bundleA.source == NOTE_DB && bundleB.source == REVIEW_DB) { } else if (bundleA.source == NOTE_DB && bundleB.source == REVIEW_DB) {
excludeGranted = excludeGranted =
tb.before(psb.getCreatedOn()) && ta.equals(psa.getCreatedOn()) || tb.compareTo(ta) < 0; (tb.before(psb.getCreatedOn()) && ta.equals(psa.getCreatedOn()))
|| (tb.compareTo(ta) < 0);
excludePostSubmit = b.getValue() == 0 && a.isPostSubmit(); excludePostSubmit = b.getValue() == 0 && a.isPostSubmit();
} }

View File

@ -15,6 +15,7 @@
package com.google.gerrit.server.permissions; package com.google.gerrit.server.permissions;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.gerrit.reviewdb.client.RefNames.REFS_TAGS;
import com.google.gerrit.common.data.AccessSection; import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.Permission; import com.google.gerrit.common.data.Permission;
@ -212,6 +213,10 @@ class ProjectControl {
return (canPerformOnAnyRef(Permission.CREATE) || isAdmin()); return (canPerformOnAnyRef(Permission.CREATE) || isAdmin());
} }
private boolean canAddTagRefs() {
return (canPerformOnTagRef(Permission.CREATE) || isAdmin());
}
private boolean canCreateChanges() { private boolean canCreateChanges() {
for (SectionMatcher matcher : access()) { for (SectionMatcher matcher : access()) {
AccessSection section = matcher.getSection(); AccessSection section = matcher.getSection();
@ -233,6 +238,26 @@ class ProjectControl {
return declaredOwner; return declaredOwner;
} }
private boolean canPerformOnTagRef(String permissionName) {
for (SectionMatcher matcher : access()) {
AccessSection section = matcher.getSection();
if (section.getName().startsWith(REFS_TAGS)) {
Permission permission = section.getPermission(permissionName);
if (permission == null) {
continue;
}
Boolean can = canPerform(permissionName, section, permission);
if (can != null) {
return can;
}
}
}
return false;
}
private boolean canPerformOnAnyRef(String permissionName) { private boolean canPerformOnAnyRef(String permissionName) {
for (SectionMatcher matcher : access()) { for (SectionMatcher matcher : access()) {
AccessSection section = matcher.getSection(); AccessSection section = matcher.getSection();
@ -241,25 +266,33 @@ class ProjectControl {
continue; continue;
} }
for (PermissionRule rule : permission.getRules()) { Boolean can = canPerform(permissionName, section, permission);
if (rule.isBlock() || rule.isDeny() || !match(rule)) { if (can != null) {
continue; return can;
}
// Being in a group that was granted this permission is only an
// approximation. There might be overrides and doNotInherit
// that would render this to be false.
//
if (controlForRef(section.getName()).canPerform(permissionName)) {
return true;
}
break;
} }
} }
return false; return false;
} }
private Boolean canPerform(String permissionName, AccessSection section, Permission permission) {
for (PermissionRule rule : permission.getRules()) {
if (rule.isBlock() || rule.isDeny() || !match(rule)) {
continue;
}
// Being in a group that was granted this permission is only an
// approximation. There might be overrides and doNotInherit
// that would render this to be false.
//
if (controlForRef(section.getName()).canPerform(permissionName)) {
return true;
}
break;
}
return null;
}
private boolean canPerformOnAllRefs(String permission, Set<String> ignore) { private boolean canPerformOnAllRefs(String permission, Set<String> ignore) {
boolean canPerform = false; boolean canPerform = false;
Set<String> patterns = allRefPatterns(permission); Set<String> patterns = allRefPatterns(permission);
@ -403,6 +436,8 @@ class ProjectControl {
case CREATE_REF: case CREATE_REF:
return canAddRefs(); return canAddRefs();
case CREATE_TAG_REF:
return canAddTagRefs();
case CREATE_CHANGE: case CREATE_CHANGE:
return canCreateChanges(); return canCreateChanges();

View File

@ -50,6 +50,21 @@ public enum ProjectPermission implements GerritPermission {
*/ */
CREATE_REF, CREATE_REF,
/**
* Can create at least one tag reference in the project.
*
* <p>This project level permission only validates the user may create some tag reference within
* the project. The exact reference name must be checked at creation:
*
* <pre>permissionBackend
* .user(user)
* .project(proj)
* .ref(ref)
* .check(RefPermission.CREATE);
* </pre>
*/
CREATE_TAG_REF,
/** /**
* Can create at least one change in the project. * Can create at least one change in the project.
* *

View File

@ -17,6 +17,7 @@ package com.google.gerrit.server.project;
import static com.google.gerrit.common.data.PermissionRule.Action.ALLOW; import static com.google.gerrit.common.data.PermissionRule.Action.ALLOW;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.FluentIterable; import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -89,6 +90,7 @@ public class ProjectState {
private final Map<String, ProjectLevelConfig> configs; private final Map<String, ProjectLevelConfig> configs;
private final Set<AccountGroup.UUID> localOwners; private final Set<AccountGroup.UUID> localOwners;
private final long globalMaxObjectSizeLimit; private final long globalMaxObjectSizeLimit;
private final boolean inheritProjectMaxObjectSizeLimit;
/** Last system time the configuration's revision was examined. */ /** Last system time the configuration's revision was examined. */
private volatile long lastCheckGeneration; private volatile long lastCheckGeneration;
@ -132,6 +134,7 @@ public class ProjectState {
? limitsFactory.create(config.getAccessSection(AccessSection.GLOBAL_CAPABILITIES)) ? limitsFactory.create(config.getAccessSection(AccessSection.GLOBAL_CAPABILITIES))
: null; : null;
this.globalMaxObjectSizeLimit = transferConfig.getMaxObjectSizeLimit(); this.globalMaxObjectSizeLimit = transferConfig.getMaxObjectSizeLimit();
this.inheritProjectMaxObjectSizeLimit = transferConfig.getInheritProjectMaxObjectSizeLimit();
if (isAllProjects && !Permission.canBeOnAllProjects(AccessSection.ALL, Permission.OWNER)) { if (isAllProjects && !Permission.canBeOnAllProjects(AccessSection.ALL, Permission.OWNER)) {
localOwners = Collections.emptySet(); localOwners = Collections.emptySet();
@ -264,13 +267,58 @@ public class ProjectState {
} }
} }
public long getEffectiveMaxObjectSizeLimit() { public static class EffectiveMaxObjectSizeLimit {
long local = config.getMaxObjectSizeLimit(); public long value;
if (globalMaxObjectSizeLimit > 0 && local > 0) { public String summary;
return Math.min(globalMaxObjectSizeLimit, local); }
private static final String MAY_NOT_SET = "This project may not set a higher limit.";
@VisibleForTesting
public static final String INHERITED_FROM_PARENT = "Inherited from parent project '%s'.";
@VisibleForTesting
public static final String OVERRIDDEN_BY_PARENT =
"Overridden by parent project '%s'. " + MAY_NOT_SET;
@VisibleForTesting
public static final String INHERITED_FROM_GLOBAL = "Inherited from the global config.";
@VisibleForTesting
public static final String OVERRIDDEN_BY_GLOBAL =
"Overridden by the global config. " + MAY_NOT_SET;
public EffectiveMaxObjectSizeLimit getEffectiveMaxObjectSizeLimit() {
EffectiveMaxObjectSizeLimit result = new EffectiveMaxObjectSizeLimit();
result.value = config.getMaxObjectSizeLimit();
if (inheritProjectMaxObjectSizeLimit) {
for (ProjectState parent : parents()) {
long parentValue = parent.config.getMaxObjectSizeLimit();
if (parentValue > 0 && result.value > 0) {
if (parentValue < result.value) {
result.value = parentValue;
result.summary = String.format(OVERRIDDEN_BY_PARENT, parent.config.getName());
}
} else if (parentValue > 0) {
result.value = parentValue;
result.summary = String.format(INHERITED_FROM_PARENT, parent.config.getName());
}
}
} }
// zero means "no limit", in this case the max is more limiting
return Math.max(globalMaxObjectSizeLimit, local); if (globalMaxObjectSizeLimit > 0 && result.value > 0) {
if (globalMaxObjectSizeLimit < result.value) {
result.value = globalMaxObjectSizeLimit;
result.summary = OVERRIDDEN_BY_GLOBAL;
}
} else if (globalMaxObjectSizeLimit > result.value) {
// zero means "no limit", in this case the max is more limiting
result.value = globalMaxObjectSizeLimit;
result.summary = INHERITED_FROM_GLOBAL;
}
return result;
} }
/** Get the sections that pertain only to this project. */ /** Get the sections that pertain only to this project. */

View File

@ -115,8 +115,7 @@ public class CreateAccount
throw new BadRequestException("username must match URL"); throw new BadRequestException("username must match URL");
} }
if (!ExternalId.isValidUsername(username)) { if (!ExternalId.isValidUsername(username)) {
throw new BadRequestException( throw new BadRequestException("Invalid username '" + username + "'");
"Username '" + username + "' must contain only letters, numbers, _, - or .");
} }
Set<AccountGroup.UUID> groups = parseGroups(input.groups); Set<AccountGroup.UUID> groups = parseGroups(input.groups);

View File

@ -26,8 +26,8 @@ import com.google.gerrit.extensions.api.access.GlobalOrPluginPermission;
import com.google.gerrit.extensions.api.access.PluginPermission; import com.google.gerrit.extensions.api.access.PluginPermission;
import com.google.gerrit.extensions.config.CapabilityDefinition; import com.google.gerrit.extensions.config.CapabilityDefinition;
import com.google.gerrit.extensions.registration.DynamicMap; import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestReadView; import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
@ -172,9 +172,9 @@ public class GetCapabilities implements RestReadView<AccountResource> {
} }
@Override @Override
public BinaryResult apply(Capability resource) throws ResourceNotFoundException { public Response<String> apply(Capability resource) throws ResourceNotFoundException {
permissionBackend.checkUsesDefaultCapabilities(); permissionBackend.checkUsesDefaultCapabilities();
return BinaryResult.create("ok\n"); return Response.ok("ok");
} }
} }
} }

View File

@ -33,10 +33,10 @@ import com.google.gerrit.server.config.PluginConfig;
import com.google.gerrit.server.config.PluginConfigFactory; import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.config.ProjectConfigEntry; import com.google.gerrit.server.config.ProjectConfigEntry;
import com.google.gerrit.server.extensions.webui.UiActions; import com.google.gerrit.server.extensions.webui.UiActions;
import com.google.gerrit.server.git.TransferConfig;
import com.google.gerrit.server.project.BooleanProjectConfigTransformations; import com.google.gerrit.server.project.BooleanProjectConfigTransformations;
import com.google.gerrit.server.project.ProjectResource; import com.google.gerrit.server.project.ProjectResource;
import com.google.gerrit.server.project.ProjectState; import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.project.ProjectState.EffectiveMaxObjectSizeLimit;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
@ -48,7 +48,6 @@ public class ConfigInfoImpl extends ConfigInfo {
boolean serverEnableSignedPush, boolean serverEnableSignedPush,
ProjectState projectState, ProjectState projectState,
CurrentUser user, CurrentUser user,
TransferConfig transferConfig,
DynamicMap<ProjectConfigEntry> pluginConfigEntries, DynamicMap<ProjectConfigEntry> pluginConfigEntries,
PluginConfigFactory cfgFactory, PluginConfigFactory cfgFactory,
AllProjectsName allProjects, AllProjectsName allProjects,
@ -72,7 +71,7 @@ public class ConfigInfoImpl extends ConfigInfo {
this.requireSignedPush = null; this.requireSignedPush = null;
} }
this.maxObjectSizeLimit = getMaxObjectSizeLimit(projectState, transferConfig, p); this.maxObjectSizeLimit = getMaxObjectSizeLimit(projectState, p);
this.defaultSubmitType = new SubmitTypeInfo(); this.defaultSubmitType = new SubmitTypeInfo();
this.defaultSubmitType.value = projectState.getSubmitType(); this.defaultSubmitType.value = projectState.getSubmitType();
@ -107,13 +106,13 @@ public class ConfigInfoImpl extends ConfigInfo {
this.extensionPanelNames = projectState.getConfig().getExtensionPanelSections(); this.extensionPanelNames = projectState.getConfig().getExtensionPanelSections();
} }
private MaxObjectSizeLimitInfo getMaxObjectSizeLimit( private MaxObjectSizeLimitInfo getMaxObjectSizeLimit(ProjectState projectState, Project p) {
ProjectState projectState, TransferConfig transferConfig, Project p) {
MaxObjectSizeLimitInfo info = new MaxObjectSizeLimitInfo(); MaxObjectSizeLimitInfo info = new MaxObjectSizeLimitInfo();
long value = projectState.getEffectiveMaxObjectSizeLimit(); EffectiveMaxObjectSizeLimit limit = projectState.getEffectiveMaxObjectSizeLimit();
long value = limit.value;
info.value = value == 0 ? null : String.valueOf(value); info.value = value == 0 ? null : String.valueOf(value);
info.configuredValue = p.getMaxObjectSizeLimit(); info.configuredValue = p.getMaxObjectSizeLimit();
info.inheritedValue = transferConfig.getFormattedMaxObjectSizeLimit(); info.summary = limit.summary;
return info; return info;
} }

View File

@ -16,6 +16,7 @@ package com.google.gerrit.server.restapi.project;
import static com.google.gerrit.server.permissions.GlobalPermission.ADMINISTRATE_SERVER; import static com.google.gerrit.server.permissions.GlobalPermission.ADMINISTRATE_SERVER;
import static com.google.gerrit.server.permissions.ProjectPermission.CREATE_REF; import static com.google.gerrit.server.permissions.ProjectPermission.CREATE_REF;
import static com.google.gerrit.server.permissions.ProjectPermission.CREATE_TAG_REF;
import static com.google.gerrit.server.permissions.RefPermission.CREATE_CHANGE; import static com.google.gerrit.server.permissions.RefPermission.CREATE_CHANGE;
import static com.google.gerrit.server.permissions.RefPermission.READ; import static com.google.gerrit.server.permissions.RefPermission.READ;
import static com.google.gerrit.server.permissions.RefPermission.WRITE_CONFIG; import static com.google.gerrit.server.permissions.RefPermission.WRITE_CONFIG;
@ -270,6 +271,7 @@ public class GetAccess implements RestReadView<ProjectResource> {
|| (canReadConfig || (canReadConfig
&& perm.ref(RefNames.REFS_CONFIG).testOrFalse(CREATE_CHANGE)))); && perm.ref(RefNames.REFS_CONFIG).testOrFalse(CREATE_CHANGE))));
info.canAdd = toBoolean(perm.testOrFalse(CREATE_REF)); info.canAdd = toBoolean(perm.testOrFalse(CREATE_REF));
info.canAddTags = toBoolean(perm.testOrFalse(CREATE_TAG_REF));
info.configVisible = canReadConfig || canWriteConfig; info.configVisible = canReadConfig || canWriteConfig;
info.groups = info.groups =

View File

@ -23,7 +23,6 @@ import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.PluginConfigFactory; import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.config.ProjectConfigEntry; import com.google.gerrit.server.config.ProjectConfigEntry;
import com.google.gerrit.server.extensions.webui.UiActions; import com.google.gerrit.server.extensions.webui.UiActions;
import com.google.gerrit.server.git.TransferConfig;
import com.google.gerrit.server.project.ProjectResource; import com.google.gerrit.server.project.ProjectResource;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
@ -31,7 +30,6 @@ import com.google.inject.Singleton;
@Singleton @Singleton
public class GetConfig implements RestReadView<ProjectResource> { public class GetConfig implements RestReadView<ProjectResource> {
private final boolean serverEnableSignedPush; private final boolean serverEnableSignedPush;
private final TransferConfig transferConfig;
private final DynamicMap<ProjectConfigEntry> pluginConfigEntries; private final DynamicMap<ProjectConfigEntry> pluginConfigEntries;
private final PluginConfigFactory cfgFactory; private final PluginConfigFactory cfgFactory;
private final AllProjectsName allProjects; private final AllProjectsName allProjects;
@ -41,14 +39,12 @@ public class GetConfig implements RestReadView<ProjectResource> {
@Inject @Inject
public GetConfig( public GetConfig(
@EnableSignedPush boolean serverEnableSignedPush, @EnableSignedPush boolean serverEnableSignedPush,
TransferConfig transferConfig,
DynamicMap<ProjectConfigEntry> pluginConfigEntries, DynamicMap<ProjectConfigEntry> pluginConfigEntries,
PluginConfigFactory cfgFactory, PluginConfigFactory cfgFactory,
AllProjectsName allProjects, AllProjectsName allProjects,
UiActions uiActions, UiActions uiActions,
DynamicMap<RestView<ProjectResource>> views) { DynamicMap<RestView<ProjectResource>> views) {
this.serverEnableSignedPush = serverEnableSignedPush; this.serverEnableSignedPush = serverEnableSignedPush;
this.transferConfig = transferConfig;
this.pluginConfigEntries = pluginConfigEntries; this.pluginConfigEntries = pluginConfigEntries;
this.allProjects = allProjects; this.allProjects = allProjects;
this.cfgFactory = cfgFactory; this.cfgFactory = cfgFactory;
@ -62,7 +58,6 @@ public class GetConfig implements RestReadView<ProjectResource> {
serverEnableSignedPush, serverEnableSignedPush,
resource.getProjectState(), resource.getProjectState(),
resource.getUser(), resource.getUser(),
transferConfig,
pluginConfigEntries, pluginConfigEntries,
cfgFactory, cfgFactory,
allProjects, allProjects,

View File

@ -38,7 +38,6 @@ import com.google.gerrit.server.config.PluginConfig;
import com.google.gerrit.server.config.PluginConfigFactory; import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.config.ProjectConfigEntry; import com.google.gerrit.server.config.ProjectConfigEntry;
import com.google.gerrit.server.extensions.webui.UiActions; import com.google.gerrit.server.extensions.webui.UiActions;
import com.google.gerrit.server.git.TransferConfig;
import com.google.gerrit.server.git.meta.MetaDataUpdate; import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.permissions.PermissionBackend; import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException; import com.google.gerrit.server.permissions.PermissionBackendException;
@ -71,7 +70,6 @@ public class PutConfig implements RestModifyView<ProjectResource, ConfigInput> {
private final Provider<MetaDataUpdate.User> metaDataUpdateFactory; private final Provider<MetaDataUpdate.User> metaDataUpdateFactory;
private final ProjectCache projectCache; private final ProjectCache projectCache;
private final ProjectState.Factory projectStateFactory; private final ProjectState.Factory projectStateFactory;
private final TransferConfig transferConfig;
private final DynamicMap<ProjectConfigEntry> pluginConfigEntries; private final DynamicMap<ProjectConfigEntry> pluginConfigEntries;
private final PluginConfigFactory cfgFactory; private final PluginConfigFactory cfgFactory;
private final AllProjectsName allProjects; private final AllProjectsName allProjects;
@ -86,7 +84,6 @@ public class PutConfig implements RestModifyView<ProjectResource, ConfigInput> {
Provider<MetaDataUpdate.User> metaDataUpdateFactory, Provider<MetaDataUpdate.User> metaDataUpdateFactory,
ProjectCache projectCache, ProjectCache projectCache,
ProjectState.Factory projectStateFactory, ProjectState.Factory projectStateFactory,
TransferConfig transferConfig,
DynamicMap<ProjectConfigEntry> pluginConfigEntries, DynamicMap<ProjectConfigEntry> pluginConfigEntries,
PluginConfigFactory cfgFactory, PluginConfigFactory cfgFactory,
AllProjectsName allProjects, AllProjectsName allProjects,
@ -98,7 +95,6 @@ public class PutConfig implements RestModifyView<ProjectResource, ConfigInput> {
this.metaDataUpdateFactory = metaDataUpdateFactory; this.metaDataUpdateFactory = metaDataUpdateFactory;
this.projectCache = projectCache; this.projectCache = projectCache;
this.projectStateFactory = projectStateFactory; this.projectStateFactory = projectStateFactory;
this.transferConfig = transferConfig;
this.pluginConfigEntries = pluginConfigEntries; this.pluginConfigEntries = pluginConfigEntries;
this.cfgFactory = cfgFactory; this.cfgFactory = cfgFactory;
this.allProjects = allProjects; this.allProjects = allProjects;
@ -173,7 +169,6 @@ public class PutConfig implements RestModifyView<ProjectResource, ConfigInput> {
serverEnableSignedPush, serverEnableSignedPush,
state, state,
user.get(), user.get(),
transferConfig,
pluginConfigEntries, pluginConfigEntries,
cfgFactory, cfgFactory,
allProjects, allProjects,

View File

@ -159,7 +159,7 @@ public class ConfigSuite extends Suite {
@Override @Override
public Object createTest() throws Exception { public Object createTest() throws Exception {
Object test = getTestClass().getJavaClass().newInstance(); Object test = getTestClass().getJavaClass().getDeclaredConstructor().newInstance();
parameterField.set(test, new org.eclipse.jgit.lib.Config(cfg)); parameterField.set(test, new org.eclipse.jgit.lib.Config(cfg));
if (nameField != null) { if (nameField != null) {
nameField.set(test, name); nameField.set(test, name);

View File

@ -2163,6 +2163,38 @@ public class AccountIT extends AbstractDaemonTest {
.containsExactly("Anonymous Users", "Registered Users", "Administrators"); .containsExactly("Anonymous Users", "Registered Users", "Administrators");
} }
@Test
public void createUserWithValidUsername() throws Exception {
ImmutableList<String> names =
ImmutableList.of(
"user@domain",
"user-name",
"user_name",
"1234",
"user1234",
"1234@domain",
"user!+alias{*}#$%&^=~|@domain");
for (String name : names) {
gApi.accounts().create(name);
}
}
@Test
public void createUserWithInvalidUsername() throws Exception {
ImmutableList<String> invalidNames =
ImmutableList.of(
"@", "@foo", "-", "-foo", "_", "_foo", "!", "+", "{", "}", "*", "%", "#", "$", "&", "",
"^", "=", "~");
for (String name : invalidNames) {
try {
gApi.accounts().create(name);
fail(String.format("Expected BadRequestException for username [%s]", name));
} catch (BadRequestException e) {
assertThat(e).hasMessageThat().isEqualTo(String.format("Invalid username '%s'", name));
}
}
}
@Test @Test
public void allGroupsForAUserAccountCanBeRetrieved() throws Exception { public void allGroupsForAUserAccountCanBeRetrieved() throws Exception {
String username = name("user1"); String username = name("user1");

View File

@ -16,6 +16,10 @@ package com.google.gerrit.acceptance.api.project;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.server.git.QueueProvider.QueueType.BATCH; import static com.google.gerrit.server.git.QueueProvider.QueueType.BATCH;
import static com.google.gerrit.server.project.ProjectState.INHERITED_FROM_GLOBAL;
import static com.google.gerrit.server.project.ProjectState.INHERITED_FROM_PARENT;
import static com.google.gerrit.server.project.ProjectState.OVERRIDDEN_BY_GLOBAL;
import static com.google.gerrit.server.project.ProjectState.OVERRIDDEN_BY_PARENT;
import static java.util.stream.Collectors.toSet; import static java.util.stream.Collectors.toSet;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -416,7 +420,7 @@ public class ProjectIT extends AbstractDaemonTest {
ConfigInfo info = getConfig(); ConfigInfo info = getConfig();
assertThat(info.maxObjectSizeLimit.value).isNull(); assertThat(info.maxObjectSizeLimit.value).isNull();
assertThat(info.maxObjectSizeLimit.configuredValue).isNull(); assertThat(info.maxObjectSizeLimit.configuredValue).isNull();
assertThat(info.maxObjectSizeLimit.inheritedValue).isNull(); assertThat(info.maxObjectSizeLimit.summary).isNull();
} }
@Test @Test
@ -425,13 +429,30 @@ public class ProjectIT extends AbstractDaemonTest {
ConfigInfo info = setMaxObjectSize("100k"); ConfigInfo info = setMaxObjectSize("100k");
assertThat(info.maxObjectSizeLimit.value).isEqualTo("102400"); assertThat(info.maxObjectSizeLimit.value).isEqualTo("102400");
assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("100k"); assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("100k");
assertThat(info.maxObjectSizeLimit.inheritedValue).isNull(); assertThat(info.maxObjectSizeLimit.summary).isNull();
// Clear the value // Clear the value
info = setMaxObjectSize("0"); info = setMaxObjectSize("0");
assertThat(info.maxObjectSizeLimit.value).isNull(); assertThat(info.maxObjectSizeLimit.value).isNull();
assertThat(info.maxObjectSizeLimit.configuredValue).isNull(); assertThat(info.maxObjectSizeLimit.configuredValue).isNull();
assertThat(info.maxObjectSizeLimit.inheritedValue).isNull(); assertThat(info.maxObjectSizeLimit.summary).isNull();
}
@Test
@GerritConfig(name = "receive.inheritProjectMaxObjectSizeLimit", value = "true")
public void maxObjectSizeIsInheritedFromParentProject() throws Exception {
Project.NameKey child = createProject(name("child"), project);
ConfigInfo info = setMaxObjectSize("100k");
assertThat(info.maxObjectSizeLimit.value).isEqualTo("102400");
assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("100k");
assertThat(info.maxObjectSizeLimit.summary).isNull();
info = getConfig(child);
assertThat(info.maxObjectSizeLimit.value).isEqualTo("102400");
assertThat(info.maxObjectSizeLimit.configuredValue).isNull();
assertThat(info.maxObjectSizeLimit.summary)
.isEqualTo(String.format(INHERITED_FROM_PARENT, project));
} }
@Test @Test
@ -441,21 +462,75 @@ public class ProjectIT extends AbstractDaemonTest {
ConfigInfo info = setMaxObjectSize("100k"); ConfigInfo info = setMaxObjectSize("100k");
assertThat(info.maxObjectSizeLimit.value).isEqualTo("102400"); assertThat(info.maxObjectSizeLimit.value).isEqualTo("102400");
assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("100k"); assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("100k");
assertThat(info.maxObjectSizeLimit.inheritedValue).isNull(); assertThat(info.maxObjectSizeLimit.summary).isNull();
info = getConfig(child); info = getConfig(child);
assertThat(info.maxObjectSizeLimit.value).isNull(); assertThat(info.maxObjectSizeLimit.value).isNull();
assertThat(info.maxObjectSizeLimit.configuredValue).isNull(); assertThat(info.maxObjectSizeLimit.configuredValue).isNull();
assertThat(info.maxObjectSizeLimit.inheritedValue).isNull(); assertThat(info.maxObjectSizeLimit.summary).isNull();
}
@Test
public void maxObjectSizeOverridesParentProjectWhenNotSetOnParent() throws Exception {
Project.NameKey child = createProject(name("child"), project);
ConfigInfo info = setMaxObjectSize("0");
assertThat(info.maxObjectSizeLimit.value).isNull();
assertThat(info.maxObjectSizeLimit.configuredValue).isNull();
assertThat(info.maxObjectSizeLimit.summary).isNull();
info = setMaxObjectSize(child, "100k");
assertThat(info.maxObjectSizeLimit.value).isEqualTo("102400");
assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("100k");
assertThat(info.maxObjectSizeLimit.summary).isNull();
}
@Test
public void maxObjectSizeOverridesParentProjectWhenLower() throws Exception {
Project.NameKey child = createProject(name("child"), project);
ConfigInfo info = setMaxObjectSize("200k");
assertThat(info.maxObjectSizeLimit.value).isEqualTo("204800");
assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("200k");
assertThat(info.maxObjectSizeLimit.summary).isNull();
info = setMaxObjectSize(child, "100k");
assertThat(info.maxObjectSizeLimit.value).isEqualTo("102400");
assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("100k");
assertThat(info.maxObjectSizeLimit.summary).isNull();
}
@Test
@GerritConfig(name = "receive.inheritProjectMaxObjectSizeLimit", value = "true")
public void maxObjectSizeDoesNotOverrideParentProjectWhenHigher() throws Exception {
Project.NameKey child = createProject(name("child"), project);
ConfigInfo info = setMaxObjectSize("100k");
assertThat(info.maxObjectSizeLimit.value).isEqualTo("102400");
assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("100k");
assertThat(info.maxObjectSizeLimit.summary).isNull();
info = setMaxObjectSize(child, "200k");
assertThat(info.maxObjectSizeLimit.value).isEqualTo("102400");
assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("200k");
assertThat(info.maxObjectSizeLimit.summary)
.isEqualTo(String.format(OVERRIDDEN_BY_PARENT, project));
} }
@Test @Test
@GerritConfig(name = "receive.maxObjectSizeLimit", value = "200k") @GerritConfig(name = "receive.maxObjectSizeLimit", value = "200k")
public void maxObjectSizeIsInheritedFromGlobalConfig() throws Exception { public void maxObjectSizeIsInheritedFromGlobalConfig() throws Exception {
Project.NameKey child = createProject(name("child"), project);
ConfigInfo info = getConfig(); ConfigInfo info = getConfig();
assertThat(info.maxObjectSizeLimit.value).isEqualTo("204800"); assertThat(info.maxObjectSizeLimit.value).isEqualTo("204800");
assertThat(info.maxObjectSizeLimit.configuredValue).isNull(); assertThat(info.maxObjectSizeLimit.configuredValue).isNull();
assertThat(info.maxObjectSizeLimit.inheritedValue).isEqualTo("200k"); assertThat(info.maxObjectSizeLimit.summary).isEqualTo(INHERITED_FROM_GLOBAL);
info = getConfig(child);
assertThat(info.maxObjectSizeLimit.value).isEqualTo("204800");
assertThat(info.maxObjectSizeLimit.configuredValue).isNull();
assertThat(info.maxObjectSizeLimit.summary).isEqualTo(INHERITED_FROM_GLOBAL);
} }
@Test @Test
@ -464,16 +539,40 @@ public class ProjectIT extends AbstractDaemonTest {
ConfigInfo info = setMaxObjectSize("100k"); ConfigInfo info = setMaxObjectSize("100k");
assertThat(info.maxObjectSizeLimit.value).isEqualTo("102400"); assertThat(info.maxObjectSizeLimit.value).isEqualTo("102400");
assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("100k"); assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("100k");
assertThat(info.maxObjectSizeLimit.inheritedValue).isEqualTo("200k"); assertThat(info.maxObjectSizeLimit.summary).isNull();
}
@Test
@GerritConfig(name = "receive.maxObjectSizeLimit", value = "300k")
public void inheritedMaxObjectSizeOverridesGlobalConfigWhenLower() throws Exception {
Project.NameKey child = createProject(name("child"), project);
ConfigInfo info = setMaxObjectSize("200k");
assertThat(info.maxObjectSizeLimit.value).isEqualTo("204800");
assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("200k");
assertThat(info.maxObjectSizeLimit.summary).isNull();
info = setMaxObjectSize(child, "100k");
assertThat(info.maxObjectSizeLimit.value).isEqualTo("102400");
assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("100k");
assertThat(info.maxObjectSizeLimit.summary).isNull();
} }
@Test @Test
@GerritConfig(name = "receive.maxObjectSizeLimit", value = "200k") @GerritConfig(name = "receive.maxObjectSizeLimit", value = "200k")
@GerritConfig(name = "receive.inheritProjectMaxObjectSizeLimit", value = "true")
public void maxObjectSizeDoesNotOverrideGlobalConfigWhenHigher() throws Exception { public void maxObjectSizeDoesNotOverrideGlobalConfigWhenHigher() throws Exception {
Project.NameKey child = createProject(name("child"), project);
ConfigInfo info = setMaxObjectSize("300k"); ConfigInfo info = setMaxObjectSize("300k");
assertThat(info.maxObjectSizeLimit.value).isEqualTo("204800"); assertThat(info.maxObjectSizeLimit.value).isEqualTo("204800");
assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("300k"); assertThat(info.maxObjectSizeLimit.configuredValue).isEqualTo("300k");
assertThat(info.maxObjectSizeLimit.inheritedValue).isEqualTo("200k"); assertThat(info.maxObjectSizeLimit.summary).isEqualTo(OVERRIDDEN_BY_GLOBAL);
info = getConfig(child);
assertThat(info.maxObjectSizeLimit.value).isEqualTo("204800");
assertThat(info.maxObjectSizeLimit.configuredValue).isNull();
assertThat(info.maxObjectSizeLimit.summary).isEqualTo(OVERRIDDEN_BY_GLOBAL);
} }
@Test @Test
@ -487,10 +586,6 @@ public class ProjectIT extends AbstractDaemonTest {
return gApi.projects().name(name.get()).config(input); return gApi.projects().name(name.get()).config(input);
} }
private ConfigInfo setConfig(ConfigInput input) throws Exception {
return setConfig(project, input);
}
private ConfigInfo getConfig(Project.NameKey name) throws Exception { private ConfigInfo getConfig(Project.NameKey name) throws Exception {
return gApi.projects().name(name.get()).config(); return gApi.projects().name(name.get()).config();
} }
@ -517,9 +612,13 @@ public class ProjectIT extends AbstractDaemonTest {
} }
private ConfigInfo setMaxObjectSize(String value) throws Exception { private ConfigInfo setMaxObjectSize(String value) throws Exception {
return setMaxObjectSize(project, value);
}
private ConfigInfo setMaxObjectSize(Project.NameKey name, String value) throws Exception {
ConfigInput input = new ConfigInput(); ConfigInput input = new ConfigInput();
input.maxObjectSizeLimit = value; input.maxObjectSizeLimit = value;
return setConfig(input); return setConfig(name, input);
} }
private static class ProjectIndexedCounter implements ProjectIndexedListener { private static class ProjectIndexedCounter implements ProjectIndexedListener {

View File

@ -47,13 +47,8 @@ public class ElasticReindexIT extends AbstractReindexTests {
} }
@ConfigSuite.Config @ConfigSuite.Config
public static Config elasticsearchV6_2() { public static Config elasticsearchV6() {
return getConfig(ElasticVersion.V6_2); return getConfig(ElasticVersion.V6_4);
}
@ConfigSuite.Config
public static Config elasticsearchV6_3() {
return getConfig(ElasticVersion.V6_3);
} }
@Override @Override

View File

@ -46,13 +46,8 @@ public class ElasticIndexIT extends AbstractIndexTests {
} }
@ConfigSuite.Config @ConfigSuite.Config
public static Config elasticsearchV6_2() { public static Config elasticsearchV6() {
return getConfig(ElasticVersion.V6_2); return getConfig(ElasticVersion.V6_4);
}
@ConfigSuite.Config
public static Config elasticsearchV6_3() {
return getConfig(ElasticVersion.V6_3);
} }
@Override @Override

View File

@ -45,11 +45,13 @@ public class ElasticContainer<SELF extends ElasticContainer<SELF>> extends Gener
case V2_4: case V2_4:
return "elasticsearch:2.4.6-alpine"; return "elasticsearch:2.4.6-alpine";
case V5_6: case V5_6:
return "docker.elastic.co/elasticsearch/elasticsearch:5.6.10"; return "docker.elastic.co/elasticsearch/elasticsearch:5.6.11";
case V6_2: case V6_2:
return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.4"; return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.4";
case V6_3: case V6_3:
return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.3.2"; return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.3.2";
case V6_4:
return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.4.0";
} }
throw new IllegalStateException("No tests for version: " + version.name()); throw new IllegalStateException("No tests for version: " + version.name());
} }

View File

@ -41,7 +41,7 @@ public class ElasticV6QueryAccountsTest extends AbstractQueryAccountsTest {
return; return;
} }
container = ElasticContainer.createAndStart(ElasticVersion.V6_3); container = ElasticContainer.createAndStart(ElasticVersion.V6_4);
nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort()); nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort());
} }

View File

@ -41,7 +41,7 @@ public class ElasticV6QueryChangesTest extends AbstractQueryChangesTest {
return; return;
} }
container = ElasticContainer.createAndStart(ElasticVersion.V6_3); container = ElasticContainer.createAndStart(ElasticVersion.V6_4);
nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort()); nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort());
} }

View File

@ -41,7 +41,7 @@ public class ElasticV6QueryGroupsTest extends AbstractQueryGroupsTest {
return; return;
} }
container = ElasticContainer.createAndStart(ElasticVersion.V6_3); container = ElasticContainer.createAndStart(ElasticVersion.V6_4);
nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort()); nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort());
} }

View File

@ -29,21 +29,31 @@ public class ElasticVersionTest {
assertThat(ElasticVersion.forVersion("2.4.6")).isEqualTo(ElasticVersion.V2_4); assertThat(ElasticVersion.forVersion("2.4.6")).isEqualTo(ElasticVersion.V2_4);
assertThat(ElasticVersion.forVersion("5.6.0")).isEqualTo(ElasticVersion.V5_6); assertThat(ElasticVersion.forVersion("5.6.0")).isEqualTo(ElasticVersion.V5_6);
assertThat(ElasticVersion.forVersion("5.6.9")).isEqualTo(ElasticVersion.V5_6); assertThat(ElasticVersion.forVersion("5.6.11")).isEqualTo(ElasticVersion.V5_6);
assertThat(ElasticVersion.forVersion("5.6.10")).isEqualTo(ElasticVersion.V5_6);
assertThat(ElasticVersion.forVersion("6.2.0")).isEqualTo(ElasticVersion.V6_2); assertThat(ElasticVersion.forVersion("6.2.0")).isEqualTo(ElasticVersion.V6_2);
assertThat(ElasticVersion.forVersion("6.2.4")).isEqualTo(ElasticVersion.V6_2); assertThat(ElasticVersion.forVersion("6.2.4")).isEqualTo(ElasticVersion.V6_2);
assertThat(ElasticVersion.forVersion("6.3.0")).isEqualTo(ElasticVersion.V6_3); assertThat(ElasticVersion.forVersion("6.3.0")).isEqualTo(ElasticVersion.V6_3);
assertThat(ElasticVersion.forVersion("6.3.1")).isEqualTo(ElasticVersion.V6_3); assertThat(ElasticVersion.forVersion("6.3.2")).isEqualTo(ElasticVersion.V6_3);
assertThat(ElasticVersion.forVersion("6.4.0")).isEqualTo(ElasticVersion.V6_4);
assertThat(ElasticVersion.forVersion("6.4.1")).isEqualTo(ElasticVersion.V6_4);
} }
@Test @Test
public void unsupportedVersion() throws Exception { public void unsupportedVersion() throws Exception {
exception.expect(ElasticVersion.InvalidVersion.class); exception.expect(ElasticVersion.UnsupportedVersion.class);
exception.expectMessage( exception.expectMessage(
"Invalid version: [4.0.0]. Supported versions: " + ElasticVersion.supportedVersions()); "Unsupported version: [4.0.0]. Supported versions: " + ElasticVersion.supportedVersions());
ElasticVersion.forVersion("4.0.0"); ElasticVersion.forVersion("4.0.0");
} }
@Test
public void version6() throws Exception {
assertThat(ElasticVersion.V6_2.isV6()).isTrue();
assertThat(ElasticVersion.V6_3.isV6()).isTrue();
assertThat(ElasticVersion.V6_4.isV6()).isTrue();
assertThat(ElasticVersion.V5_6.isV6()).isFalse();
}
} }

@ -1 +1 @@
Subproject commit e4024e9d8d8139fc4c658c3af1a5e11e19b2d476 Subproject commit cc636d7e36afb62455a9f045b125d246fd84afd0