diff options
author | Luca Milanesio <luca.milanesio@gmail.com> | 2021-09-24 01:05:44 +0100 |
---|---|---|
committer | Luca Milanesio <luca.milanesio@gmail.com> | 2021-09-24 01:05:44 +0100 |
commit | 72d88d3db230179c389c369eba7cc3d8822d7d71 (patch) | |
tree | 1386ac9a24e8e49111f7f0caeabe1e20d03b498d | |
parent | 91bea9c579170a95ec58f9e5cfdf055f07d7bc17 (diff) | |
parent | 130c4f7cf28fcd06dd9c6cbaa7aef01994777f5c (diff) |
Merge branch 'stable-3.2' into stable-3.3
* stable-3.2:
Unify getRefs() and getRefsByPrefix() in permission-aware refdb
rest-api-projects: Fix typo referring to /groups/
Log the result of git-upload-pack command in httpd_log
Fix serialization of AllUsersName and AllProjectsName
Update git submodules
Update jgit to 84707715108a65a366ef35f2ae04aabecd0b35f6
Add PluginServletContext#getVirtualServerName
Allow moving of merge commits
Change-Id: Ie2633fca8ee097171738fd871ef7fec3c44c8cc0
14 files changed, 124 insertions, 42 deletions
diff --git a/Documentation/intro-user.txt b/Documentation/intro-user.txt index eb2025c980..9909aac0ed 100644 --- a/Documentation/intro-user.txt +++ b/Documentation/intro-user.txt @@ -459,7 +459,7 @@ abandon permission] on the change and link:access-control.html#category_push[ push permission] on the destination branch. The move operation will not update the change's parent and users will have -to link:#rebase[rebase] the change. Also, merge commits cannot be moved. +to link:#rebase[rebase] the change. [[abandon]] [[restore]] diff --git a/Documentation/logs.txt b/Documentation/logs.txt index 6624366044..f072984036 100644 --- a/Documentation/logs.txt +++ b/Documentation/logs.txt @@ -51,6 +51,11 @@ if a log field is not present, a "-" is substituted: * `referer`: the `Referer` HTTP request header. This gives the site that the client reports having been referred from. * `client agent`: the client agent which sent the request. +* `command status`: the overall result of the git command over HTTP. Currently + populated only for the transfer phase of `git-upload-pack` commands. + Possible values: +** `-1`: The `git-upload-pack` transfer was ultimately not successful +** `0`: The `git-upload-pack` transfer was ultimately successful Example: ``` diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt index d53bd9c256..84da169b92 100644 --- a/Documentation/rest-api-projects.txt +++ b/Documentation/rest-api-projects.txt @@ -421,11 +421,11 @@ Query the first 25 projects in project list. ---- The `/projects/` URL also accepts a start integer in the `start` -parameter. The results will skip `start` groups from project list. +parameter. The results will skip `start` projects from project list. Query 25 projects starting from index 50. ---- - GET /groups/?query=<query>&limit=25&start=50 HTTP/1.0 + GET /projects/?query=<query>&limit=25&start=50 HTTP/1.0 ---- [[project-query-options]] diff --git a/java/com/google/gerrit/httpd/GitOverHttpServlet.java b/java/com/google/gerrit/httpd/GitOverHttpServlet.java index 6e22704534..3e2d3efb07 100644 --- a/java/com/google/gerrit/httpd/GitOverHttpServlet.java +++ b/java/com/google/gerrit/httpd/GitOverHttpServlet.java @@ -14,11 +14,15 @@ package com.google.gerrit.httpd; +import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; +import static org.eclipse.jgit.http.server.GitSmartHttpTools.sendError; + import com.google.common.annotations.VisibleForTesting; import com.google.common.cache.Cache; import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Lists; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.common.data.Capable; import com.google.gerrit.entities.Project; import com.google.gerrit.extensions.registration.DynamicSet; @@ -54,6 +58,7 @@ import com.google.inject.Singleton; import com.google.inject.TypeLiteral; import com.google.inject.name.Named; import java.io.IOException; +import java.text.MessageFormat; import java.time.Duration; import java.util.Arrays; import java.util.Collections; @@ -70,10 +75,13 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; +import org.eclipse.jgit.errors.PackProtocolException; import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.http.server.GitServlet; import org.eclipse.jgit.http.server.GitSmartHttpTools; +import org.eclipse.jgit.http.server.HttpServerText; import org.eclipse.jgit.http.server.ServletUtils; +import org.eclipse.jgit.http.server.UploadPackErrorHandler; import org.eclipse.jgit.http.server.resolver.AsIsFileService; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; @@ -100,6 +108,23 @@ public class GitOverHttpServlet extends GitServlet { private static final String ID_CACHE = "adv_bases"; public static final String URL_REGEX; + public static final String GIT_COMMAND_STATUS_HEADER = "X-git-command-status"; + + private enum GIT_COMMAND_STATUS { + OK(0), + FAIL(-1); + + private final int exitStatus; + + GIT_COMMAND_STATUS(int exitStatus) { + this.exitStatus = exitStatus; + } + + @Override + public String toString() { + return Integer.toString(exitStatus); + } + } static { StringBuilder url = new StringBuilder(); @@ -212,12 +237,14 @@ public class GitOverHttpServlet extends GitServlet { Resolver resolver, UploadFactory upload, UploadFilter uploadFilter, + GerritUploadPackErrorHandler uploadPackErrorHandler, ReceivePackFactory<HttpServletRequest> receive, ReceiveFilter receiveFilter) { setRepositoryResolver(resolver); setAsIsFileService(AsIsFileService.DISABLED); setUploadPackFactory(upload); + setUploadPackErrorHandler(uploadPackErrorHandler); addUploadPackFilter(uploadFilter); setReceivePackFactory(receive); @@ -456,6 +483,35 @@ public class GitOverHttpServlet extends GitServlet { public void destroy() {} } + static class GerritUploadPackErrorHandler implements UploadPackErrorHandler { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + + @Override + public void upload(HttpServletRequest req, HttpServletResponse rsp, UploadPackRunnable r) + throws IOException { + rsp.setHeader(GIT_COMMAND_STATUS_HEADER, GIT_COMMAND_STATUS.FAIL.toString()); + try { + r.upload(); + rsp.setHeader(GIT_COMMAND_STATUS_HEADER, GIT_COMMAND_STATUS.OK.toString()); + } catch (ServiceMayNotContinueException e) { + if (!e.isOutput() && !rsp.isCommitted()) { + rsp.reset(); + sendError(req, rsp, e.getStatusCode(), e.getMessage()); + } + } catch (Throwable e) { + logger.atSevere().withCause(e).log( + MessageFormat.format( + HttpServerText.get().internalErrorDuringUploadPack, + ServletUtils.getRepository(req))); + if (!rsp.isCommitted()) { + rsp.reset(); + String msg = e instanceof PackProtocolException ? e.getMessage() : null; + sendError(req, rsp, SC_INTERNAL_SERVER_ERROR, msg); + } + } + } + } + static class ReceiveFactory implements ReceivePackFactory<HttpServletRequest> { private final AsyncReceiveCommits.Factory factory; private final Provider<CurrentUser> userProvider; diff --git a/java/com/google/gerrit/httpd/plugins/PluginServletContext.java b/java/com/google/gerrit/httpd/plugins/PluginServletContext.java index 40083e441e..5a8fa31c25 100644 --- a/java/com/google/gerrit/httpd/plugins/PluginServletContext.java +++ b/java/com/google/gerrit/httpd/plugins/PluginServletContext.java @@ -199,6 +199,11 @@ class PluginServletContext { String v = Version.getVersion(); return "Gerrit Code Review/" + (v != null ? v : "dev"); } + + @Override + public String getVirtualServerName() { + return null; + } } interface API { @@ -255,5 +260,7 @@ class PluginServletContext { int getMinorVersion(); String getServerInfo(); + + String getVirtualServerName(); } } diff --git a/java/com/google/gerrit/pgm/http/jetty/HttpLog.java b/java/com/google/gerrit/pgm/http/jetty/HttpLog.java index 4e4c93b57b..27a53c2052 100644 --- a/java/com/google/gerrit/pgm/http/jetty/HttpLog.java +++ b/java/com/google/gerrit/pgm/http/jetty/HttpLog.java @@ -14,6 +14,8 @@ package com.google.gerrit.pgm.http.jetty; +import static com.google.gerrit.httpd.GitOverHttpServlet.GIT_COMMAND_STATUS_HEADER; + import com.google.common.base.Strings; import com.google.gerrit.httpd.GetUserFilter; import com.google.gerrit.httpd.restapi.LogRedactUtil; @@ -51,6 +53,7 @@ class HttpLog extends AbstractLifeCycle implements RequestLog { protected static final String P_LATENCY = "Latency"; protected static final String P_REFERER = "Referer"; protected static final String P_USER_AGENT = "User-Agent"; + protected static final String P_COMMAND_STATUS = "Command-Status"; private final AsyncAppender async; @@ -113,6 +116,7 @@ class HttpLog extends AbstractLifeCycle implements RequestLog { set(event, P_LATENCY, System.currentTimeMillis() - req.getTimeStamp()); set(event, P_REFERER, req.getHeader("Referer")); set(event, P_USER_AGENT, req.getHeader("User-Agent")); + set(event, P_COMMAND_STATUS, rsp.getHeader(GIT_COMMAND_STATUS_HEADER)); async.append(event); } diff --git a/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java b/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java index 95a5b07689..807b311745 100644 --- a/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java +++ b/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java @@ -14,6 +14,7 @@ package com.google.gerrit.pgm.http.jetty; +import static com.google.gerrit.pgm.http.jetty.HttpLog.P_COMMAND_STATUS; import static com.google.gerrit.pgm.http.jetty.HttpLog.P_CONTENT_LENGTH; import static com.google.gerrit.pgm.http.jetty.HttpLog.P_HOST; import static com.google.gerrit.pgm.http.jetty.HttpLog.P_LATENCY; @@ -50,6 +51,7 @@ public class HttpLogJsonLayout extends JsonLayout { public String latency; public String referer; public String userAgent; + public String commandStatus; public HttpJsonLogEntry(LoggingEvent event) { this.host = getMdcString(event, P_HOST); @@ -64,6 +66,7 @@ public class HttpLogJsonLayout extends JsonLayout { this.latency = getMdcString(event, P_LATENCY); this.referer = getMdcString(event, P_REFERER); this.userAgent = getMdcString(event, P_USER_AGENT); + this.commandStatus = getMdcString(event, P_COMMAND_STATUS); } } } diff --git a/java/com/google/gerrit/pgm/http/jetty/HttpLogLayout.java b/java/com/google/gerrit/pgm/http/jetty/HttpLogLayout.java index 268f59fdbe..b83fcc55b0 100644 --- a/java/com/google/gerrit/pgm/http/jetty/HttpLogLayout.java +++ b/java/com/google/gerrit/pgm/http/jetty/HttpLogLayout.java @@ -71,6 +71,9 @@ public final class HttpLogLayout extends Layout { buf.append(' '); dq_opt(buf, event, HttpLog.P_USER_AGENT); + buf.append(' '); + dq_opt(buf, event, HttpLog.P_COMMAND_STATUS); + buf.append('\n'); return buf.toString(); } diff --git a/java/com/google/gerrit/server/events/EventGsonProvider.java b/java/com/google/gerrit/server/events/EventGsonProvider.java index 688507bfe3..ab51518e01 100644 --- a/java/com/google/gerrit/server/events/EventGsonProvider.java +++ b/java/com/google/gerrit/server/events/EventGsonProvider.java @@ -30,7 +30,7 @@ public class EventGsonProvider implements Provider<Gson> { .registerTypeAdapter(Supplier.class, new SupplierSerializer()) .registerTypeAdapter(Supplier.class, new SupplierDeserializer()) .registerTypeAdapter(Change.Key.class, new ChangeKeyAdapter()) - .registerTypeAdapter(Project.NameKey.class, new ProjectNameKeyAdapter()) + .registerTypeHierarchyAdapter(Project.NameKey.class, new ProjectNameKeyAdapter()) .create(); } } diff --git a/java/com/google/gerrit/server/git/PermissionAwareReadOnlyRefDatabase.java b/java/com/google/gerrit/server/git/PermissionAwareReadOnlyRefDatabase.java index b7dc2b3258..7950dc6edf 100644 --- a/java/com/google/gerrit/server/git/PermissionAwareReadOnlyRefDatabase.java +++ b/java/com/google/gerrit/server/git/PermissionAwareReadOnlyRefDatabase.java @@ -14,7 +14,6 @@ package com.google.gerrit.server.git; -import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; import com.google.common.base.Preconditions; @@ -95,20 +94,11 @@ public class PermissionAwareReadOnlyRefDatabase extends DelegateRefDatabase { return Iterables.getOnlyElement(result); } + // WARNING: This method is deprecated in JGit's RefDatabase and it will be removed on master. + // Do not add any logic here but rather enrich the getRefsByPrefix method below. @Override public Map<String, Ref> getRefs(String prefix) throws IOException { - List<Ref> refs = getDelegate().getRefDatabase().getRefsByPrefix(prefix); - if (refs.isEmpty()) { - return Collections.emptyMap(); - } - - Collection<Ref> result; - try { - result = forProject.filter(refs, getDelegate(), RefFilterOptions.defaults()); - } catch (PermissionBackendException e) { - throw new IOException("", e); - } - return buildPrefixRefMap(prefix, result); + return buildPrefixRefMap(prefix, getRefsByPrefix(prefix)); } private Map<String, Ref> buildPrefixRefMap(String prefix, Collection<Ref> refs) { @@ -125,26 +115,18 @@ public class PermissionAwareReadOnlyRefDatabase extends DelegateRefDatabase { @Override public List<Ref> getRefsByPrefix(String prefix) throws IOException { - Map<String, Ref> coarseRefs; - int lastSlash = prefix.lastIndexOf('/'); - if (lastSlash == -1) { - coarseRefs = getRefs(ALL); - } else { - coarseRefs = getRefs(prefix.substring(0, lastSlash + 1)); + List<Ref> refs = getDelegate().getRefDatabase().getRefsByPrefix(prefix); + if (refs.isEmpty()) { + return Collections.emptyList(); } - List<Ref> result; - if (lastSlash + 1 == prefix.length()) { - result = coarseRefs.values().stream().collect(toList()); - } else { - String p = prefix.substring(lastSlash + 1); - result = - coarseRefs.entrySet().stream() - .filter(e -> e.getKey().startsWith(p)) - .map(e -> e.getValue()) - .collect(toList()); + Collection<Ref> result; + try { + result = forProject.filter(refs, getDelegate(), RefFilterOptions.defaults()); + } catch (PermissionBackendException e) { + throw new IOException("", e); } - return Collections.unmodifiableList(result); + return result.stream().collect(Collectors.toList()); } @Override diff --git a/java/com/google/gerrit/server/restapi/change/Move.java b/java/com/google/gerrit/server/restapi/change/Move.java index 577174f184..ecfb96d2bc 100644 --- a/java/com/google/gerrit/server/restapi/change/Move.java +++ b/java/com/google/gerrit/server/restapi/change/Move.java @@ -191,9 +191,6 @@ public class Move implements RestModifyView<ChangeResource, MoveInput>, UiAction RevWalk revWalk = new RevWalk(repo)) { RevCommit currPatchsetRevCommit = revWalk.parseCommit(psUtil.current(ctx.getNotes()).commitId()); - if (currPatchsetRevCommit.getParentCount() > 1) { - throw new ResourceConflictException("Merge commit cannot be moved"); - } ObjectId refId = repo.resolve(input.destinationBranch); // Check if destination ref exists in project repo diff --git a/javatests/com/google/gerrit/acceptance/rest/change/MoveChangeIT.java b/javatests/com/google/gerrit/acceptance/rest/change/MoveChangeIT.java index d5881ea7a2..987d646711 100644 --- a/javatests/com/google/gerrit/acceptance/rest/change/MoveChangeIT.java +++ b/javatests/com/google/gerrit/acceptance/rest/change/MoveChangeIT.java @@ -169,11 +169,9 @@ public class MoveChangeIT extends AbstractDaemonTest { BranchNameKey newBranch = BranchNameKey.create(r1.getChange().change().getProject(), "moveTest"); createBranch(newBranch); - ResourceConflictException thrown = - assertThrows( - ResourceConflictException.class, - () -> move(GitUtil.getChangeId(testRepo, c).get(), newBranch.branch())); - assertThat(thrown).hasMessageThat().contains("Merge commit cannot be moved"); + String changeId = GitUtil.getChangeId(testRepo, c).get(); + move(changeId, newBranch.branch()); + assertThat(gApi.changes().id(changeId).get().branch).isEqualTo("moveTest"); } @Test diff --git a/javatests/com/google/gerrit/server/events/EventDeserializerTest.java b/javatests/com/google/gerrit/server/events/EventDeserializerTest.java index e0223e4885..97f6e4e64a 100644 --- a/javatests/com/google/gerrit/server/events/EventDeserializerTest.java +++ b/javatests/com/google/gerrit/server/events/EventDeserializerTest.java @@ -22,6 +22,8 @@ import com.google.gerrit.entities.Account; import com.google.gerrit.entities.BranchNameKey; import com.google.gerrit.entities.Change; import com.google.gerrit.entities.Project; +import com.google.gerrit.server.config.AllProjectsName; +import com.google.gerrit.server.config.AllUsersName; import com.google.gerrit.server.data.AccountAttribute; import com.google.gerrit.server.data.ChangeAttribute; import com.google.gerrit.server.data.RefUpdateAttribute; @@ -240,6 +242,31 @@ public class EventDeserializerTest { assertSameChangeEvent(e, orig); } + @Test + public void shouldSerializeAllProjectsToString() { + String allProjectsString = "foobar"; + AllProjectsName allProjectsNameKey = new AllProjectsName(allProjectsString); + + assertThat(gson.toJson(allProjectsNameKey)) + .isEqualTo(String.format("\"%s\"", allProjectsString)); + } + + @Test + public void shouldSerializeAllUsersToString() { + String allUsersString = "foobar"; + AllUsersName allUsersNameKey = new AllUsersName(allUsersString); + + assertThat(gson.toJson(allUsersNameKey)).isEqualTo(String.format("\"%s\"", allUsersString)); + } + + @Test + public void shouldSerializeProjectNameKeyToString() { + String projectString = "foobar"; + Project.NameKey projectNameKey = Project.nameKey(projectString); + + assertThat(gson.toJson(projectNameKey)).isEqualTo(String.format("\"%s\"", projectString)); + } + private <T> Supplier<T> createSupplier(T value) { return Suppliers.memoize(() -> value); } diff --git a/modules/jgit b/modules/jgit -Subproject 24d6d605388c82201092cf1699b51095299380a +Subproject 84707715108a65a366ef35f2ae04aabecd0b35f |