diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt index b60e56d8ac..ccec37b176 100644 --- a/Documentation/rest-api-changes.txt +++ b/Documentation/rest-api-changes.txt @@ -2593,7 +2593,9 @@ provided fetch info map is also included. "subject":"Use an EventBus to manage star icons", "message":"Use an EventBus to manage star icons\n\nImage widgets that need to ..." }, - "base_revision":"c35558e0925e6985c91f3a16921537d5e572b7a3" + "base_patch_set_number":1, + "base_revision":"c35558e0925e6985c91f3a16921537d5e572b7a3", + "ref":"refs/users/01/1000001/edit-76482/1" } ---- @@ -4825,7 +4827,9 @@ resulting change edit is returned. "subject":"Implement feature X", "message":"Implement feature X\n\nWith this feature ..." }, + "base_patch_set_number":1, "base_revision":"674ac754f91e64a0efb8087e59a176484bd534d1" + "ref":"refs/users/01/1000001/edit-42622/1" } ---- @@ -6340,15 +6344,17 @@ The `EditInfo` entity contains information about a change edit. [options="header",cols="1,^1,5"] |=========================== -|Field Name ||Description -|`commit` ||The commit of change edit as +|Field Name ||Description +|`commit` ||The commit of change edit as link:#commit-info[CommitInfo] entity. -|`base_revision`||The revision of the patch set the change edit is based on. -|`fetch` |optional| +|`base_patch_set_number`||The patch set number of the patch set the change edit is based on. +|`base_revision` ||The revision of the patch set the change edit is based on. +|`ref` ||The ref of the change edit. +|`fetch` |optional| Information about how to fetch this patch set. The fetch information is provided as a map that maps the protocol name ("`git`", "`http`", "`ssh`") to link:#fetch-info[FetchInfo] entities. -|`files` |optional| +|`files` |optional| The files of the change edit as a map that maps the file names to link:#file-info[FileInfo] entities. |=========================== diff --git a/java/com/google/gerrit/acceptance/GerritServer.java b/java/com/google/gerrit/acceptance/GerritServer.java index 6f4c98ae7b..dd28d200ad 100644 --- a/java/com/google/gerrit/acceptance/GerritServer.java +++ b/java/com/google/gerrit/acceptance/GerritServer.java @@ -364,7 +364,6 @@ public class GerritServer implements AutoCloseable { daemon.setAuditEventModuleForTesting(new FakeGroupAuditService.Module()); daemon.setAdditionalSysModuleForTesting(testSysModule); daemon.setEnableSshd(desc.useSsh()); - daemon.setSlave(isSlave(baseConfig)); if (desc.memory()) { checkArgument(additionalArgs.length == 0, "cannot pass args to in-memory server"); @@ -381,6 +380,7 @@ public class GerritServer implements AutoCloseable { @Nullable InMemoryRepositoryManager inMemoryRepoManager) throws Exception { Config cfg = desc.buildConfig(baseConfig); + daemon.setSlave(isSlave(baseConfig) || cfg.getBoolean("container", "slave", false)); mergeTestConfig(cfg); // Set the log4j configuration to an invalid one to prevent system logs // from getting configured and creating log files. diff --git a/java/com/google/gerrit/extensions/common/EditInfo.java b/java/com/google/gerrit/extensions/common/EditInfo.java index 46ef8796e4..0cd5af374a 100644 --- a/java/com/google/gerrit/extensions/common/EditInfo.java +++ b/java/com/google/gerrit/extensions/common/EditInfo.java @@ -20,6 +20,7 @@ public class EditInfo { public CommitInfo commit; public int basePatchSetNumber; public String baseRevision; + public String ref; public Map fetch; public Map files; } diff --git a/java/com/google/gerrit/server/edit/ChangeEditJson.java b/java/com/google/gerrit/server/edit/ChangeEditJson.java index bf20404a0d..55e0aefbbf 100644 --- a/java/com/google/gerrit/server/edit/ChangeEditJson.java +++ b/java/com/google/gerrit/server/edit/ChangeEditJson.java @@ -53,6 +53,7 @@ public class ChangeEditJson { out.commit = fillCommit(edit.getEditCommit()); out.baseRevision = edit.getBasePatchSet().getRevision().get(); out.basePatchSetNumber = edit.getBasePatchSet().getPatchSetId(); + out.ref = edit.getRefName(); if (downloadCommands) { out.fetch = fillFetchMap(edit); } diff --git a/java/com/google/gerrit/server/permissions/DefaultRefFilter.java b/java/com/google/gerrit/server/permissions/DefaultRefFilter.java index 662ba379b8..879fddd76c 100644 --- a/java/com/google/gerrit/server/permissions/DefaultRefFilter.java +++ b/java/com/google/gerrit/server/permissions/DefaultRefFilter.java @@ -22,6 +22,7 @@ import static com.google.gerrit.reviewdb.client.RefNames.REFS_USERS_SELF; import static java.util.Objects.requireNonNull; import static java.util.stream.Collectors.toMap; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.common.flogger.FluentLogger; @@ -58,7 +59,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Stream; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Ref; @@ -365,17 +365,17 @@ class DefaultRefFilter { private Map visibleChangesByScan(Repository repo) throws PermissionBackendException { Project.NameKey p = projectState.getNameKey(); - Stream s; + ImmutableList changes; try { - s = changeNotesFactory.scan(repo, p); + changes = changeNotesFactory.scan(repo, p).collect(toImmutableList()); } catch (IOException e) { logger.atSevere().withCause(e).log( "Cannot load changes for project %s, assuming no changes are visible", p); return Collections.emptyMap(); } - Map result = Maps.newHashMapWithExpectedSize((int) s.count()); - for (ChangeNotesResult notesResult : s.collect(toImmutableList())) { + Map result = Maps.newHashMapWithExpectedSize(changes.size()); + for (ChangeNotesResult notesResult : changes) { ChangeNotes notes = toNotes(notesResult); if (notes != null) { result.put(notes.getChangeId(), notes.getChange().getDest()); diff --git a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java index e06b4062ee..e653bc419e 100644 --- a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java +++ b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java @@ -17,6 +17,7 @@ package com.google.gerrit.server.restapi.project; import com.google.common.collect.ListMultimap; import com.google.common.flogger.FluentLogger; import com.google.gerrit.common.Nullable; +import com.google.gerrit.extensions.api.GerritApi; import com.google.gerrit.extensions.registration.DynamicMap; import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.BadRequestException; @@ -26,6 +27,7 @@ import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.extensions.restapi.RestCollection; +import com.google.gerrit.extensions.restapi.RestReadView; import com.google.gerrit.extensions.restapi.RestView; import com.google.gerrit.extensions.restapi.TopLevelResource; import com.google.gerrit.extensions.restapi.UnprocessableEntityException; @@ -42,7 +44,9 @@ import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; import java.io.IOException; +import java.util.List; import org.eclipse.jgit.lib.Constants; +import org.kohsuke.args4j.Option; @Singleton public class ProjectsCollection @@ -51,23 +55,27 @@ public class ProjectsCollection private final DynamicMap> views; private final Provider list; + private final Provider gApi; private final Provider queryProjects; private final ProjectCache projectCache; private final PermissionBackend permissionBackend; private final Provider user; private boolean hasQuery; + private boolean isDisplayActiveAndReadonlyQuery; @Inject public ProjectsCollection( DynamicMap> views, Provider list, + Provider gApi, Provider queryProjects, ProjectCache projectCache, PermissionBackend permissionBackend, Provider user) { this.views = views; this.list = list; + this.gApi = gApi; this.queryProjects = queryProjects; this.projectCache = projectCache; this.permissionBackend = permissionBackend; @@ -78,11 +86,62 @@ public class ProjectsCollection public void setParams(ListMultimap params) throws BadRequestException { // The --query option is defined in QueryProjects this.hasQuery = params.containsKey("query"); + List queryParams = params.get("query"); + this.isDisplayActiveAndReadonlyQuery = + queryParams.size() == 1 + && queryParams.get(0).toLowerCase().trim().equals("state:active or state:read-only"); } @Override public RestView list() { if (hasQuery) { + // Temporary workaround for v2.16. Should be removed as soon as the Projects Lucene Index + // sorting is fixed + if (isDisplayActiveAndReadonlyQuery) { + return new RestReadView() { + private int limit; + private int start; + + @Option( + name = "--limit", + aliases = {"-n"}, + metaVar = "CNT", + usage = "maximum number of projects to list") + public void setLimit(int limit) { + this.limit = limit; + } + + @Option( + name = "--start", + aliases = {"-S"}, + metaVar = "CNT", + usage = "number of projects to skip") + public void setStart(int start) { + this.start = start; + } + + @SuppressWarnings("unused") + @Option( + name = "--query", + aliases = {"-q"}, + usage = "project query") + public void setQuery(String query) { + // Explicitly ignored because this fix is for full listing only + } + + @Override + public Object apply(TopLevelResource resource) + throws AuthException, BadRequestException, ResourceConflictException, Exception { + return gApi.get() + .projects() + .list() + .withDescription(true) + .withStart(start) + .withLimit(limit) + .get(); + } + }; + } return queryProjects.get(); } return list.get().setFormat(OutputFormat.JSON); diff --git a/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java b/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java index 1a0f256e80..f6a75440ca 100644 --- a/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java +++ b/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java @@ -338,7 +338,17 @@ public class RefAdvertisementIT extends AbstractDaemonTest { } @Test - public void uploadPackNoSearchingChangeCacheImpl() throws Exception { + public void uploadPackNoSearchingChangeCacheImplMaster() throws Exception { + uploadPackNoSearchingChangeCacheImpl(); + } + + @Test + @GerritConfig(name = "container.slave", value = "true") + public void uploadPackNoSearchingChangeCacheImplSlave() throws Exception { + uploadPackNoSearchingChangeCacheImpl(); + } + + private void uploadPackNoSearchingChangeCacheImpl() throws Exception { allow("refs/heads/*", Permission.READ, REGISTERED_USERS); setApiUser(user); diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js index 738d29e21d..a77c66d169 100644 --- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js +++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js @@ -179,11 +179,16 @@ }, _computeLinks(defaultLinks, userLinks, adminLinks, topMenus, docBaseUrl) { - const links = defaultLinks.slice(); + const links = defaultLinks.map(menu => { + return { + title: menu.title, + links: menu.links.slice(), + }; + }); if (userLinks && userLinks.length > 0) { links.push({ title: 'Your', - links: userLinks, + links: userLinks.slice(), }); } const docLinks = this._getDocLinks(docBaseUrl, DOCUMENTATION_LINKS); @@ -196,13 +201,20 @@ } links.push({ title: 'Browse', - links: adminLinks, + links: adminLinks.slice(), }); + const topMenuLinks = []; + links.forEach(link => { topMenuLinks[link.title] = link.links; }); for (const m of topMenus) { - links.push({ - title: m.name, - links: m.items.map(this._fixCustomMenuItem), - }); + const items = m.items.map(this._fixCustomMenuItem); + if (m.name in topMenuLinks) { + items.forEach(link => { topMenuLinks[m.name].push(link); }); + } else { + links.push({ + title: m.name, + links: topMenuLinks[m.name] = items, + }); + } } return links; }, diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html index b6e64ec51a..582ca61db0 100644 --- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html +++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html @@ -191,6 +191,121 @@ limitations under the License. }]); }); + test('merge top menus', () => { + const adminLinks = [{ + name: 'Repos', + url: '/repos', + }]; + const topMenus = [{ + name: 'Plugins', + items: [{ + name: 'Manage', + target: '_blank', + url: 'https://gerrit/plugins/plugin-manager/static/index.html', + }], + }, { + name: 'Plugins', + items: [{ + name: 'Create', + target: '_blank', + url: 'https://gerrit/plugins/plugin-manager/static/create.html', + }], + }]; + assert.deepEqual(element._computeLinks([], [], adminLinks, topMenus), [{ + title: 'Browse', + links: adminLinks, + }, { + title: 'Plugins', + links: [{ + name: 'Manage', + external: true, + url: 'https://gerrit/plugins/plugin-manager/static/index.html', + }, { + name: 'Create', + external: true, + url: 'https://gerrit/plugins/plugin-manager/static/create.html', + }], + }]); + }); + + test('merge top menus in default links', () => { + const defaultLinks = [{ + title: 'Faves', + links: [{ + name: 'Pinterest', + url: 'https://pinterest.com', + }], + }]; + const topMenus = [{ + name: 'Faves', + items: [{ + name: 'Manage', + target: '_blank', + url: 'https://gerrit/plugins/plugin-manager/static/index.html', + }], + }]; + assert.deepEqual(element._computeLinks(defaultLinks, [], [], topMenus), [{ + title: 'Faves', + links: defaultLinks[0].links.concat([{ + name: 'Manage', + external: true, + url: 'https://gerrit/plugins/plugin-manager/static/index.html', + }]), + }, { + title: 'Browse', + links: [], + }]); + }); + + test('merge top menus in user links', () => { + const userLinks = [{ + name: 'Facebook', + url: 'https://facebook.com', + }]; + const topMenus = [{ + name: 'Your', + items: [{ + name: 'Manage', + target: '_blank', + url: 'https://gerrit/plugins/plugin-manager/static/index.html', + }], + }]; + assert.deepEqual(element._computeLinks([], userLinks, [], topMenus), [{ + title: 'Your', + links: userLinks.concat([{ + name: 'Manage', + external: true, + url: 'https://gerrit/plugins/plugin-manager/static/index.html', + }]), + }, { + title: 'Browse', + links: [], + }]); + }); + + test('merge top menus in admin links', () => { + const adminLinks = [{ + name: 'Repos', + url: '/repos', + }]; + const topMenus = [{ + name: 'Browse', + items: [{ + name: 'Manage', + target: '_blank', + url: 'https://gerrit/plugins/plugin-manager/static/index.html', + }], + }]; + assert.deepEqual(element._computeLinks([], [], adminLinks, topMenus), [{ + title: 'Browse', + links: adminLinks.concat([{ + name: 'Manage', + external: true, + url: 'https://gerrit/plugins/plugin-manager/static/index.html', + }]), + }]); + }); + test('register URL', () => { const config = { auth: { diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.js b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.js index 30ac95dcd9..f8d9e11585 100644 --- a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.js +++ b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.js @@ -63,6 +63,7 @@ 'text/x-objectivec': 'objectivec', 'text/x-ocaml': 'ocaml', 'text/x-perl': 'perl', + 'text/x-pgsql': 'pgsql', // postgresql 'text/x-php': 'php', 'text/x-protobuf': 'protobuf', 'text/x-puppet': 'puppet', diff --git a/resources/com/google/gerrit/server/mime/mime-types.properties b/resources/com/google/gerrit/server/mime/mime-types.properties index 5f5979de6e..77d6f0f9b7 100644 --- a/resources/com/google/gerrit/server/mime/mime-types.properties +++ b/resources/com/google/gerrit/server/mime/mime-types.properties @@ -149,6 +149,7 @@ pas = text/x-pascal patch = text/x-diff pcss = text/x-pcss pgp = application/pgp +pgsql = text/x-pgsql php = text/x-php php3 = text/x-php php4 = text/x-php @@ -159,6 +160,8 @@ pig = text/x-pig pl = text/x-perl pls = text/x-plsql pm = text/x-perl +postgres = text/x-pgsql +postgresql = text/x-pgsql pp = text/x-puppet pro = text/x-idl properties = text/x-ini