Merge branch 'stable-3.3' into master

* stable-3.3: (33 commits)
  Update git submodules
  Update git submodules
  Add z-index to gr-main-header
  Compact the REST-API output JSON unconditionally
  Remove requesting DETAILED_LABELS for the dashboard
  Update git submodules
  Honor toogleWipState permission for %ready %wip push options
  Update JGit to 9a1065afe
  Update JGit to 8f422e9a9
  Update JGit to c9d871f15
  Update JGit to 5.3.9.202012012026-r
  Update JGit to 5.1.15.202012011955-r
  Set version to 3.3.1-SNAPSHOT
  Set version to 3.3.0
  Auto-enable git wire protocol v2 in jgit
  Fix NPE with StoredCommentLinkInfoSerializer when enabled is null
  Auto-disable auto gc in jgit
  Bump up jetty version to 9.4.33.v20201020
  Update zero-downtime documentation in config-gerrit.txt
  Improve message if submit fails due to non-fulfilled submit requirements
  Upgrade JGit to d1801402
  Upgrade JGit to ad902087
  Upgrade JGit to 5cd485e5
  Upgrade JGit to 5.3.8.202011260953-r
  Include repo config into CommitReceivedEvent
  MergeValidationListener: Also provide RevWalk to the onPreMerge method
  Add fatal to consistency and validation error enums
  Upgrade JGit to 5.1.14.202011251942-r
  Fix flaky test for group renaming in ProjectConfig
  ProjectConfig: Write resolved groups to file
  Fix bazel run_shell usage for newer versions
  Use strict equality
  Add a warning if submitting a change with an open change edit

Change-Id: I87c8a326f41fd9622034206fa512548380dc666a
This commit is contained in:
Sven Selberg
2020-12-08 15:00:55 +01:00
committed by Sven Selberg
13 changed files with 237 additions and 37 deletions

View File

@@ -2336,8 +2336,8 @@ Defaults to the full hostname of the Gerrit server.
[[gerrit.experimentalRollingUpgrade]]gerrit.experimentalRollingUpgrade::
+
Enable Gerrit rolling upgrade to the next version.
For example if Gerrit v3.1 is version N (All-Projects:refs/meta/version=181)
then its next version N+1 is v3.2 (All-Projects:refs/meta/version=183).
For example if Gerrit v3.2 is version N (All-Projects:refs/meta/version=183)
then its next version N+1 is v3.3 (All-Projects:refs/meta/version=184).
Allow Gerrit to start even if the underlying schema version has been bumped to
the next Gerrit version.
+
@@ -2354,7 +2354,7 @@ of the following steps:
1. Set gerrit.experimentalRollingUpgrade to true on all Gerrit masters
2. Set the first master unhealthy
3. Shutdown the first master and [upgrade](install.html#init) to the next version
4. Startup the first master, wait for the online reindex to complete
4. Startup the first master, wait for the online reindex to complete (where applicable)
5. Verify the the first master upgrade is successful and online reindex is complete
6. Set the first master healthy
7. Repeat steps 2. to 6. for all the other Gerrit nodes
@@ -5625,10 +5625,12 @@ Supported versions:
[[receive.autogc]]receive.autogc::
+
By default, `git-receive-pack` will run auto gc after receiving data from git-push and updating refs.
By default, up to Gerrit 3.2 `git-receive-pack` will run auto gc after receiving data from git-push and updating refs.
You can stop it by setting this variable to `false`. This is recommended in gerrit to avoid the
additional load this creates. Instead schedule gc using link:cmd-gc.html#gc.startTime[gc.startTime]
and link:cmd-gc.html#gc.interval[gc.interval] or e.g. in a cron job that runs gc in a separate process.
Since Gerrit 3.3 the init command will auto-configure `git-receive-pack = false` in `etc/jgit.config` if
it wasn't set manually and show a warning if it was set to `true` manually.
GERRIT
------

View File

@@ -899,48 +899,48 @@ maven_jar(
sha1 = "7e060dd5b19431e6d198e91ff670644372f60fbd",
)
JETTY_VERS = "9.4.32.v20200930"
JETTY_VERS = "9.4.33.v20201020"
maven_jar(
name = "jetty-servlet",
artifact = "org.eclipse.jetty:jetty-servlet:" + JETTY_VERS,
sha1 = "4253dd46c099e0bca4dd763fc1e10774e10de00a",
sha1 = "101609e8e5365c4406e4448099459eb605ac551f",
)
maven_jar(
name = "jetty-security",
artifact = "org.eclipse.jetty:jetty-security:" + JETTY_VERS,
sha1 = "16a6110fa40e49050146de5f597ab3a3a3fa83b5",
sha1 = "c150bf2aca6cb1636e7195f844a2bb156546e50e",
)
maven_jar(
name = "jetty-server",
artifact = "org.eclipse.jetty:jetty-server:" + JETTY_VERS,
sha1 = "d2d89099be5237cf68254bc943a7d800d3ee1945",
sha1 = "f586ff2ee048ad2575866c1833d854288f402307",
)
maven_jar(
name = "jetty-jmx",
artifact = "org.eclipse.jetty:jetty-jmx:" + JETTY_VERS,
sha1 = "5e8e87a6f89b8eabf5b5b1765e3d758209001570",
sha1 = "56b723070eeafc51b943cd9bf1a064a037e806a7",
)
maven_jar(
name = "jetty-http",
artifact = "org.eclipse.jetty:jetty-http:" + JETTY_VERS,
sha1 = "5fdcefd82178d11f895690f4fe6e843be69394b3",
sha1 = "ad28940f89ffde6ec1bd1656fe3f8493b01ba3c2",
)
maven_jar(
name = "jetty-io",
artifact = "org.eclipse.jetty:jetty-io:" + JETTY_VERS,
sha1 = "0d0f32c3b511d6b3a542787f95ed229731588810",
sha1 = "9e4b0048285b71f4769908780f957a470eca11da",
)
maven_jar(
name = "jetty-util",
artifact = "org.eclipse.jetty:jetty-util:" + JETTY_VERS,
sha1 = "efefd29006dcc9c9960a679263504287ce4e6896",
sha1 = "c88807f210ab216aa831b48569ef50bd797384bc",
)
maven_jar(

View File

@@ -1348,7 +1348,7 @@ public class RestApiServlet extends HttpServlet {
TemporaryBuffer.Heap buf = heap(HEAP_EST_SIZE, Integer.MAX_VALUE);
buf.write(JSON_MAGIC);
Writer w = new BufferedWriter(new OutputStreamWriter(buf, UTF_8));
Gson gson = newGson(config, req);
Gson gson = newGson(config);
if (result instanceof JsonElement) {
gson.toJson((JsonElement) result, w);
} else {
@@ -1375,25 +1375,18 @@ public class RestApiServlet extends HttpServlet {
req, res, asBinaryResult(buf).setContentType(JSON_TYPE).setCharacterEncoding(UTF_8));
}
private static Gson newGson(
ListMultimap<String, String> config, @Nullable HttpServletRequest req) {
private static Gson newGson(ListMultimap<String, String> config) {
GsonBuilder gb = OutputFormat.JSON_COMPACT.newGsonBuilder();
enablePrettyPrint(gb, config, req);
enablePrettyPrint(gb, config);
enablePartialGetFields(gb, config);
return gb.create();
}
private static void enablePrettyPrint(
GsonBuilder gb, ListMultimap<String, String> config, @Nullable HttpServletRequest req) {
String pp = Iterables.getFirst(config.get("pp"), null);
if (pp == null) {
pp = Iterables.getFirst(config.get("prettyPrint"), null);
if (pp == null && req != null) {
pp = acceptsJson(req) ? "0" : "1";
}
}
private static void enablePrettyPrint(GsonBuilder gb, ListMultimap<String, String> config) {
String pp =
Iterables.getFirst(config.get("pp"), Iterables.getFirst(config.get("prettyPrint"), "0"));
if ("1".equals(pp) || "true".equals(pp)) {
gb.setPrettyPrinting();
}
@@ -1903,10 +1896,6 @@ public class RestApiServlet extends HttpServlet {
return CharMatcher.anyOf("<&").matchesAnyOf(text);
}
private static boolean acceptsJson(HttpServletRequest req) {
return req != null && isType(JSON_TYPE, req.getHeader(HttpHeaders.ACCEPT));
}
private static boolean acceptsGzip(HttpServletRequest req) {
if (req != null) {
String accepts = req.getHeader(HttpHeaders.ACCEPT_ENCODING);

View File

@@ -0,0 +1,102 @@
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.pgm.init;
import static com.google.gerrit.pgm.init.api.InitUtil.die;
import com.google.gerrit.pgm.init.api.ConsoleUI;
import com.google.gerrit.pgm.init.api.InitStep;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.transport.TransferConfig;
import org.eclipse.jgit.util.FS;
/** Initialize the JGit configuration. */
@Singleton
class InitJGitConfig implements InitStep {
private final ConsoleUI ui;
private final SitePaths sitePaths;
@Inject
InitJGitConfig(ConsoleUI ui, SitePaths sitePaths) {
this.ui = ui;
this.sitePaths = sitePaths;
}
@Override
public void run() {
ui.header("JGit Configuration");
FileBasedConfig jgitConfig = new FileBasedConfig(sitePaths.jgit_config.toFile(), FS.DETECTED);
try {
jgitConfig.load();
if (!jgitConfig
.getNames(ConfigConstants.CONFIG_RECEIVE_SECTION)
.contains(ConfigConstants.CONFIG_KEY_AUTOGC)) {
jgitConfig.setBoolean(
ConfigConstants.CONFIG_RECEIVE_SECTION, null, ConfigConstants.CONFIG_KEY_AUTOGC, false);
jgitConfig.save();
ui.error(
"Auto-configured \"receive.autogc = false\" to disable auto-gc after git-receive-pack.");
} else if (jgitConfig.getBoolean(
ConfigConstants.CONFIG_RECEIVE_SECTION, ConfigConstants.CONFIG_KEY_AUTOGC, true)) {
ui.error(
"WARNING: JGit option \"receive.autogc = true\". This is not recommended in Gerrit.\n"
+ "git-receive-pack will run auto gc after receiving data from "
+ "git-push and updating refs.\n"
+ "Disable this behavior to avoid the additional load it creates: "
+ "gc should be configured in gc config section or run as a separate process.");
}
if (!jgitConfig
.getNames(ConfigConstants.CONFIG_PROTOCOL_SECTION)
.contains(ConfigConstants.CONFIG_KEY_VERSION)) {
jgitConfig.setString(
ConfigConstants.CONFIG_PROTOCOL_SECTION,
null,
ConfigConstants.CONFIG_KEY_VERSION,
TransferConfig.ProtocolVersion.V2.version());
jgitConfig.save();
ui.error(
String.format(
"Auto-configured \"%s.%s = %s\" to activate git wire protocol version 2.",
ConfigConstants.CONFIG_PROTOCOL_SECTION,
ConfigConstants.CONFIG_KEY_VERSION,
TransferConfig.ProtocolVersion.V2.version()));
} else {
String version =
jgitConfig.getString(
ConfigConstants.CONFIG_PROTOCOL_SECTION, null, ConfigConstants.CONFIG_KEY_VERSION);
if (!TransferConfig.ProtocolVersion.V2.version().equals(version)) {
ui.error(
String.format(
"HINT: JGit option \"%s.%s = %s\". It's recommended to activate git\n"
+ "wire protocol version 2 to improve git fetch performance.",
ConfigConstants.CONFIG_PROTOCOL_SECTION,
ConfigConstants.CONFIG_KEY_VERSION,
version));
}
}
} catch (IOException e) {
throw die(String.format("Handling JGit configuration %s failed", sitePaths.jgit_config), e);
} catch (ConfigInvalidException e) {
throw die(String.format("Invalid JGit configuration %s", sitePaths.jgit_config), e);
}
}
}

View File

@@ -40,6 +40,7 @@ public class InitModule extends FactoryModule {
// Steps are executed in the order listed here.
//
step().to(InitGitManager.class);
step().to(InitJGitConfig.class);
step().to(InitLogging.class);
step().to(InitIndex.class);
step().to(InitAuth.class);

View File

@@ -19,6 +19,7 @@ import static com.google.common.base.Strings.nullToEmpty;
import com.google.gerrit.entities.StoredCommentLinkInfo;
import com.google.gerrit.server.cache.proto.Cache;
import java.util.Optional;
/** Helper to (de)serialize values for caches. */
public class StoredCommentLinkInfoSerializer {
@@ -38,7 +39,7 @@ public class StoredCommentLinkInfoSerializer {
.setMatch(nullToEmpty(autoValue.getMatch()))
.setLink(nullToEmpty(autoValue.getLink()))
.setHtml(nullToEmpty(autoValue.getHtml()))
.setEnabled(autoValue.getEnabled())
.setEnabled(Optional.ofNullable(autoValue.getEnabled()).orElse(true))
.setOverrideOnly(autoValue.getOverrideOnly())
.build();
}

View File

@@ -25,7 +25,7 @@ import static com.google.gerrit.git.ObjectIds.abbreviateName;
import static com.google.gerrit.server.change.HashtagsUtil.cleanupHashtag;
import static com.google.gerrit.server.git.MultiProgressMonitor.UNKNOWN;
import static com.google.gerrit.server.git.receive.ReceiveConstants.COMMAND_REJECTION_MESSAGE_FOOTER;
import static com.google.gerrit.server.git.receive.ReceiveConstants.ONLY_CHANGE_OWNER_OR_PROJECT_OWNER_CAN_MODIFY_WIP;
import static com.google.gerrit.server.git.receive.ReceiveConstants.ONLY_USERS_WITH_TOGGLE_WIP_STATE_PERM_CAN_MODIFY_WIP;
import static com.google.gerrit.server.git.receive.ReceiveConstants.PUSH_OPTION_SKIP_VALIDATION;
import static com.google.gerrit.server.git.receive.ReceiveConstants.SAME_CHANGE_ID_IN_MULTIPLE_CHANGES;
import static com.google.gerrit.server.git.validators.CommitValidators.NEW_PATCHSET_PATTERN;
@@ -2883,9 +2883,9 @@ class ReceiveCommits {
if (!hasWriteConfigPermission) {
try {
permissionBackend.user(user).check(GlobalPermission.ADMINISTRATE_SERVER);
permissions.change(notes).check(ChangePermission.TOGGLE_WORK_IN_PROGRESS_STATE);
} catch (AuthException e1) {
reject(inputCommand, ONLY_CHANGE_OWNER_OR_PROJECT_OWNER_CAN_MODIFY_WIP);
reject(inputCommand, ONLY_USERS_WITH_TOGGLE_WIP_STATE_PERM_CAN_MODIFY_WIP);
}
}
}

View File

@@ -20,8 +20,8 @@ public final class ReceiveConstants {
public static final String PUSH_OPTION_SKIP_VALIDATION = "skip-validation";
@VisibleForTesting
public static final String ONLY_CHANGE_OWNER_OR_PROJECT_OWNER_CAN_MODIFY_WIP =
"only change owner or project owner can modify Work-in-Progress";
public static final String ONLY_USERS_WITH_TOGGLE_WIP_STATE_PERM_CAN_MODIFY_WIP =
"only users with Toogle-Wip-State permission can modify Work-in-Progress";
static final String COMMAND_REJECTION_MESSAGE_FOOTER =
"Contact an administrator to fix the permissions";

View File

@@ -899,7 +899,19 @@ public abstract class AbstractPushForReview extends AbstractDaemonTest {
GitUtil.fetch(user2Repo, r.getPatchSet().refName() + ":ps");
user2Repo.reset("ps");
r = amendChange(r.getChangeId(), "refs/for/master%ready", user2, user2Repo);
r.assertErrorStatus(ReceiveConstants.ONLY_CHANGE_OWNER_OR_PROJECT_OWNER_CAN_MODIFY_WIP);
r.assertErrorStatus(ReceiveConstants.ONLY_USERS_WITH_TOGGLE_WIP_STATE_PERM_CAN_MODIFY_WIP);
// Non owner, non admin and non project owner with toggleWipState should succeed.
projectOperations
.project(project)
.forUpdate()
.add(
allow(Permission.TOGGLE_WORK_IN_PROGRESS_STATE)
.ref(RefNames.REFS_HEADS + "*")
.group(REGISTERED_USERS))
.update();
r = amendChange(r.getChangeId(), "refs/for/master%ready", user2, user2Repo);
r.assertOkStatus();
// Project owner trying to move from WIP to ready should succeed.
projectOperations

View File

@@ -0,0 +1,76 @@
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.acceptance.rest;
import static com.google.common.truth.Truth.assertThat;
import static org.apache.http.HttpStatus.SC_OK;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.httpd.restapi.RestApiServlet;
import java.io.IOException;
import java.util.regex.Pattern;
import org.apache.http.message.BasicHeader;
import org.junit.Test;
public class RestApiServletIT extends AbstractDaemonTest {
private static String ANY_REST_API = "/accounts/self/capabilities";
private static BasicHeader ACCEPT_STAR_HEADER = new BasicHeader("Accept", "*/*");
private static Pattern ANY_SPACE = Pattern.compile("\\s");
@Test
public void restResponseBodyShouldBeCompactWithoutSpaces() throws Exception {
RestResponse response = adminRestSession.getWithHeader(ANY_REST_API, ACCEPT_STAR_HEADER);
assertThat(response.getStatusCode()).isEqualTo(SC_OK);
assertThat(contentWithoutMagicJson(response)).doesNotContainMatch(ANY_SPACE);
}
@Test
public void restResponseBodyShouldBeCompactWithoutSpacesWhenPPIsZero() throws Exception {
assertThat(contentWithoutMagicJson(prettyJsonRestResponse("prettyPrint", 0)))
.doesNotContainMatch(ANY_SPACE);
}
@Test
public void restResponseBodyShouldBeCompactWithoutSpacesWhenPrerryPrintIsZero() throws Exception {
assertThat(contentWithoutMagicJson(prettyJsonRestResponse("pp", 0)))
.doesNotContainMatch(ANY_SPACE);
}
@Test
public void restResponseBodyShouldBePrettyfiedWhenPPIsOne() throws Exception {
assertThat(contentWithoutMagicJson(prettyJsonRestResponse("pp", 1))).containsMatch(ANY_SPACE);
}
@Test
public void restResponseBodyShouldBePrettyfiedWhenPrettyPrintIsOne() throws Exception {
assertThat(contentWithoutMagicJson(prettyJsonRestResponse("prettyPrint", 1)))
.containsMatch(ANY_SPACE);
}
private RestResponse prettyJsonRestResponse(String ppArgument, int ppValue) throws Exception {
RestResponse response =
adminRestSession.getWithHeader(
ANY_REST_API + "?" + ppArgument + "=" + ppValue, ACCEPT_STAR_HEADER);
assertThat(response.getStatusCode()).isEqualTo(SC_OK);
return response;
}
private String contentWithoutMagicJson(RestResponse response) throws IOException {
return response.getEntityContent().substring(RestApiServlet.JSON_MAGIC.length);
}
}

View File

@@ -56,4 +56,19 @@ public class StoredCommentLinkInfoSerializerTest {
.build();
assertThat(deserialize(serialize(autoValue))).isEqualTo(autoValue);
}
@Test
public void nullEnabled_roundTrip() {
StoredCommentLinkInfo sourceAutoValue =
StoredCommentLinkInfo.builder("name").setLink("<p>html").setMatch("*").build();
StoredCommentLinkInfo storedAutoValue =
StoredCommentLinkInfo.builder("name")
.setLink("<p>html")
.setMatch("*")
.setEnabled(true)
.build();
assertThat(deserialize(serialize(sourceAutoValue))).isEqualTo(storedAutoValue);
}
}

View File

@@ -40,6 +40,8 @@ export const htmlTemplate = html`
border-left: 0;
border-top: 0;
box-shadow: var(--header-box-shadow);
/* Make sure the header is above the main content, to preserve box-shadow visibility */
z-index: 1;
}
footer {
background: var(