Merge branch 'stable-2.16'

* stable-2.16:
  ssh: Allow GIT_PROTOCOL to contain multiple parameters
  Fix running Gerrit on Tomcat
  Fix too-aggressive shortcut
  Filter MERGE_LIST magic file from Prolog facts
  Allow to enable git protocol version 2 for upload pack
  Remove irrelevant styles
  Remove unneeded AuditServiceImpl
  Fix some reviewers emails showing as undefined
  Add shift+m shortcut to diff view
  Delete system config table
  Don't use List in GerritConfigListener API
  Revert "Revert "Show author and committer when relevant""
  Reload repo and group list after creating a repo or group
  Hide "private" check box if private changes are disabled
  Set version to 2.15.7
  Trigger audit for GIT over Http commands

Change-Id: Idf8aed46f7a4fc1cd9b2630f79c73b86eefd970f
This commit is contained in:
David Pursehouse
2018-11-14 18:12:04 -08:00
48 changed files with 468 additions and 439 deletions

View File

@@ -27,15 +27,14 @@ If the `gerrit.site_path` system property is defined then the init is
run for that site. The database connectivity, in that case, is defined
in the `etc/gerrit.config`.
If `gerrit.site_path` is not defined then Gerrit will try to find the
`gerrit.init_path` system property. If defined this property will be
used to determine the site path. The database connectivity, also for
this case, is defined by the `jdbc/ReviewDb` JNDI property.
`gerrit.site_path` system property must be defined to run the init for
that site.
[WARNING]
Defining the `jdbc/ReviewDb` JNDI property for an H2 database under the
path defined by either `gerrit.site_path` or `gerrit.init_path` will
cause an incomplete auto initialization and Gerrit will fail to start.
path defined by `gerrit.site_path` will cause an incomplete auto
initialization and Gerrit will fail to start.
Opening a connection to such a database will create a subfolder under the
site path folder (in order to create the H2 database) and Gerrit will
no longer consider that site path to be new and, because of that,

View File

@@ -3798,6 +3798,20 @@ link:https://www.gnupg.org/documentation/manuals/gnupg/OpenPGP-Key-Management.ht
If no keys are specified, web-of-trust checks are disabled. This is the
default behavior.
[[receive.enableProtocolV2]]receive.enableProtocolV2::
+
Enable support for git protocol version 2.
+
When this option is enabled, clients may send upload pack using git
protocol version 2.
+
The repository must also be configured on the server side to use protocol
version 2 by setting `protocol.version = 2` either in the gerrit user's
`~/.gitconfig` file (which will enable it for all repositories) or on
a per repository basis by setting the option in the `.git/config` file
of the repository.
+
Defaults to false, git protocol version 2 is not enabled.
[[repository]]
=== Section repository
@@ -5081,16 +5095,9 @@ command.
The format is one Base-64 encoded public key per line.
== Configuring the Polygerrit UI
== Database system_config
Several columns in the `system_config` table within the metadata
database may be set to control how Gerrit behaves.
[NOTE]
The contents of the `system_config` table are cached at startup
by Gerrit. If you modify any columns in this table, Gerrit needs
to be restarted before it will use the new values.
Please see link:dev-polygerrit.html[UI] on configuring the Polygerrit UI.
=== Configurable Parameters

View File

@@ -105,9 +105,8 @@ script and modify it for your configuration:
----
[TIP]
Under Jetty, restarting the web application (e.g. after modifying
`system_config`) is as simple as touching the context config file:
`'$JETTY_HOME'/contexts/gerrit.xml`
Under Jetty, restarting the web application is as simple as
touching the context config file: `'$JETTY_HOME'/contexts/gerrit.xml`
[[tomcat]]
== Tomcat 7.x

View File

@@ -126,6 +126,7 @@ import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.testing.ConfigSuite;
import com.google.gerrit.testing.FakeEmailSender;
import com.google.gerrit.testing.FakeEmailSender.Message;
import com.google.gerrit.testing.FakeGroupAuditService;
import com.google.gerrit.testing.NoteDbMode;
import com.google.gerrit.testing.SshMode;
import com.google.gerrit.testing.TempFileUtil;
@@ -242,6 +243,7 @@ public abstract class AbstractDaemonTest {
@Inject protected ChangeNoteUtil changeNoteUtil;
@Inject protected ChangeResource.Factory changeResourceFactory;
@Inject protected FakeEmailSender sender;
@Inject protected FakeGroupAuditService auditService;
@Inject protected GerritApi gApi;
@Inject protected GitRepositoryManager repoManager;
@Inject protected GroupBackend groupBackend;

View File

@@ -43,6 +43,7 @@ import com.google.gerrit.server.util.OneOffRequestContext;
import com.google.gerrit.server.util.SocketUtil;
import com.google.gerrit.server.util.SystemLog;
import com.google.gerrit.testing.FakeEmailSender;
import com.google.gerrit.testing.FakeGroupAuditService;
import com.google.gerrit.testing.InMemoryDatabase;
import com.google.gerrit.testing.InMemoryRepositoryManager;
import com.google.gerrit.testing.NoteDbChecker;
@@ -355,6 +356,7 @@ public class GerritServer implements AutoCloseable {
},
site);
daemon.setEmailModuleForTesting(new FakeEmailSender.Module());
daemon.setAuditEventModuleForTesting(new FakeGroupAuditService.Module());
daemon.setAdditionalSysModuleForTesting(testSysModule);
daemon.setEnableSshd(desc.useSsh());
daemon.setSlave(isSlave(baseConfig));

View File

@@ -23,7 +23,7 @@ import java.lang.annotation.Target;
* Audit annotation for JSON/RPC interfaces.
*
* <p>Flag with @Audit all the JSON/RPC methods to be traced in audit-trail and submitted to the
* AuditService.
* GroupAuditService.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})

View File

@@ -15,6 +15,8 @@
package com.google.gerrit.httpd;
import com.google.common.cache.Cache;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.gerrit.common.data.Capable;
import com.google.gerrit.extensions.registration.DynamicSet;
@@ -23,6 +25,7 @@ import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.AccessPath;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.audit.HttpAuditEvent;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.git.DefaultAdvertiseRefsHook;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -30,12 +33,14 @@ import com.google.gerrit.server.git.TransferConfig;
import com.google.gerrit.server.git.UploadPackInitializer;
import com.google.gerrit.server.git.receive.AsyncReceiveCommits;
import com.google.gerrit.server.git.validators.UploadValidators;
import com.google.gerrit.server.group.GroupAuditService;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackend.RefFilterOptions;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.permissions.ProjectPermission;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.util.time.TimeUtil;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -44,6 +49,7 @@ import com.google.inject.TypeLiteral;
import com.google.inject.name.Named;
import java.io.IOException;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@@ -141,6 +147,30 @@ public class GitOverHttpServlet extends GitServlet {
addReceivePackFilter(receiveFilter);
}
private static String extractWhat(HttpServletRequest request) {
StringBuilder commandName = new StringBuilder(request.getRequestURL());
if (request.getQueryString() != null) {
commandName.append("?").append(request.getQueryString());
}
return commandName.toString();
}
private static ListMultimap<String, String> extractParameters(HttpServletRequest request) {
ListMultimap<String, String> multiMap = ArrayListMultimap.create();
if (request.getQueryString() != null) {
request
.getParameterMap()
.forEach(
(k, v) -> {
for (int i = 0; i < v.length; i++) {
multiMap.put(k, v[i]);
}
});
}
return multiMap;
}
static class Resolver implements RepositoryResolver<HttpServletRequest> {
private final GitRepositoryManager manager;
private final PermissionBackend permissionBackend;
@@ -229,6 +259,13 @@ public class GitOverHttpServlet extends GitServlet {
up.setTimeout(config.getTimeout());
up.setPreUploadHook(PreUploadHookChain.newChain(Lists.newArrayList(preUploadHooks)));
up.setPostUploadHook(PostUploadHookChain.newChain(Lists.newArrayList(postUploadHooks)));
if (config.enableProtocolV2()) {
String header = req.getHeader("Git-Protocol");
if (header != null) {
String[] params = header.split(":");
up.setExtraParameters(Arrays.asList(params));
}
}
ProjectState state = (ProjectState) req.getAttribute(ATT_STATE);
for (UploadPackInitializer initializer : uploadPackInitializers) {
initializer.init(state.getNameKey(), up);
@@ -240,12 +277,19 @@ public class GitOverHttpServlet extends GitServlet {
static class UploadFilter implements Filter {
private final UploadValidators.Factory uploadValidatorsFactory;
private final PermissionBackend permissionBackend;
private final Provider<CurrentUser> userProvider;
private final GroupAuditService groupAuditService;
@Inject
UploadFilter(
UploadValidators.Factory uploadValidatorsFactory, PermissionBackend permissionBackend) {
UploadValidators.Factory uploadValidatorsFactory,
PermissionBackend permissionBackend,
Provider<CurrentUser> userProvider,
GroupAuditService groupAuditService) {
this.uploadValidatorsFactory = uploadValidatorsFactory;
this.permissionBackend = permissionBackend;
this.userProvider = userProvider;
this.groupAuditService = groupAuditService;
}
@Override
@@ -268,7 +312,22 @@ public class GitOverHttpServlet extends GitServlet {
return;
} catch (PermissionBackendException e) {
throw new ServletException(e);
} finally {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
groupAuditService.dispatch(
new HttpAuditEvent(
httpRequest.getSession().getId(),
userProvider.get(),
extractWhat(httpRequest),
TimeUtil.nowMs(),
extractParameters(httpRequest),
httpRequest.getMethod(),
httpRequest,
httpResponse.getStatus(),
httpResponse));
}
// We use getRemoteHost() here instead of getRemoteAddr() because REMOTE_ADDR
// may have been overridden by a proxy server -- we'll try to avoid this.
UploadValidators uploadValidators =
@@ -326,15 +385,18 @@ public class GitOverHttpServlet extends GitServlet {
private final Cache<AdvertisedObjectsCacheKey, Set<ObjectId>> cache;
private final PermissionBackend permissionBackend;
private final Provider<CurrentUser> userProvider;
private final GroupAuditService groupAuditService;
@Inject
ReceiveFilter(
@Named(ID_CACHE) Cache<AdvertisedObjectsCacheKey, Set<ObjectId>> cache,
PermissionBackend permissionBackend,
Provider<CurrentUser> userProvider) {
Provider<CurrentUser> userProvider,
GroupAuditService groupAuditService) {
this.cache = cache;
this.permissionBackend = permissionBackend;
this.userProvider = userProvider;
this.groupAuditService = groupAuditService;
}
@Override
@@ -365,6 +427,20 @@ public class GitOverHttpServlet extends GitServlet {
return;
} catch (PermissionBackendException e) {
throw new RuntimeException(e);
} finally {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
groupAuditService.dispatch(
new HttpAuditEvent(
httpRequest.getSession().getId(),
userProvider.get(),
extractWhat(httpRequest),
TimeUtil.nowMs(),
extractParameters(httpRequest),
httpRequest.getMethod(),
httpRequest,
httpResponse.getStatus(),
httpResponse));
}
if (canUpload != Capable.OK) {

View File

@@ -17,8 +17,8 @@ package com.google.gerrit.httpd;
import com.google.common.base.Strings;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.server.AuditEvent;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.audit.AuditEvent;
import com.google.gerrit.server.audit.AuditService;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.config.CanonicalWebUrl;

View File

@@ -14,19 +14,17 @@
package com.google.gerrit.httpd.init;
import com.google.common.base.Strings;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.pgm.init.BaseInit;
import com.google.gerrit.pgm.init.PluginsDistribution;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
public final class SiteInitializer {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final String GERRIT_SITE_PATH = "gerrit.site_path";
private final String sitePath;
private final String initPath;
@@ -53,8 +51,12 @@ public final class SiteInitializer {
return;
}
try (Connection conn = connectToDb()) {
Path site = getSiteFromReviewDb(conn);
String path = System.getProperty(GERRIT_SITE_PATH);
Path site = null;
if (!Strings.isNullOrEmpty(path)) {
site = Paths.get(path);
}
if (site == null && initPath != null) {
site = Paths.get(initPath);
}
@@ -69,26 +71,9 @@ public final class SiteInitializer {
pluginsToInstall)
.run();
}
}
} catch (Exception e) {
logger.atSevere().withCause(e).log("Site init failed");
throw new RuntimeException(e);
}
}
private Connection connectToDb() throws SQLException {
return new ReviewDbDataSourceProvider().get().getConnection();
}
private Path getSiteFromReviewDb(Connection conn) {
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT site_path FROM system_config")) {
if (rs.next()) {
return Paths.get(rs.getString(1));
}
} catch (SQLException e) {
return null;
}
return null;
}
}

View File

@@ -1,58 +0,0 @@
// Copyright (C) 2009 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.httpd.init;
import com.google.gerrit.reviewdb.client.SystemConfig;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.schema.ReviewDbFactory;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
/** Provides {@link Path} annotated with {@link SitePath}. */
class SitePathFromSystemConfigProvider implements Provider<Path> {
private final Path path;
@Inject
SitePathFromSystemConfigProvider(@ReviewDbFactory SchemaFactory<ReviewDb> schemaFactory)
throws OrmException {
path = read(schemaFactory);
}
@Override
public Path get() {
return path;
}
private static Path read(SchemaFactory<ReviewDb> schemaFactory) throws OrmException {
try (ReviewDb db = schemaFactory.open()) {
List<SystemConfig> all = db.systemConfig().all().toList();
switch (all.size()) {
case 1:
return Paths.get(all.get(0).sitePath);
case 0:
throw new OrmException("system_config table is empty");
default:
throw new OrmException(
"system_config must have exactly 1 row; found " + all.size() + " rows instead");
}
}
}
}

View File

@@ -48,6 +48,7 @@ import com.google.gerrit.server.StartupChecks;
import com.google.gerrit.server.account.AccountDeactivator;
import com.google.gerrit.server.account.InternalAccountDirectory;
import com.google.gerrit.server.api.GerritApiModule;
import com.google.gerrit.server.api.PluginApiModule;
import com.google.gerrit.server.audit.AuditModule;
import com.google.gerrit.server.cache.h2.H2CacheModule;
import com.google.gerrit.server.cache.mem.DefaultMemoryCacheModule;
@@ -60,6 +61,7 @@ import com.google.gerrit.server.config.DownloadConfig;
import com.google.gerrit.server.config.GerritGlobalModule;
import com.google.gerrit.server.config.GerritInstanceNameModule;
import com.google.gerrit.server.config.GerritOptions;
import com.google.gerrit.server.config.GerritRuntime;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.GerritServerConfigModule;
import com.google.gerrit.server.config.SitePath;
@@ -107,6 +109,7 @@ import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
import com.google.inject.name.Names;
import com.google.inject.servlet.GuiceFilter;
import com.google.inject.servlet.GuiceServletContextListener;
@@ -134,6 +137,8 @@ import org.eclipse.jgit.lib.Config;
public class WebAppInitializer extends GuiceServletContextListener implements Filter {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final String GERRIT_SITE_PATH = "gerrit.site_path";
private Path sitePath;
private Injector dbInjector;
private Injector cfgInjector;
@@ -155,9 +160,11 @@ public class WebAppInitializer extends GuiceServletContextListener implements Fi
private synchronized void init() {
if (manager == null) {
final String path = System.getProperty("gerrit.site_path");
String path = System.getProperty(GERRIT_SITE_PATH);
if (path != null) {
sitePath = Paths.get(path);
} else {
throw new ProvisionException(GERRIT_SITE_PATH + " must be defined");
}
if (System.getProperty("gerrit.init") != null) {
@@ -171,7 +178,7 @@ public class WebAppInitializer extends GuiceServletContextListener implements Fi
}
new SiteInitializer(
path,
System.getProperty("gerrit.init_path"),
System.getProperty(GERRIT_SITE_PATH),
new UnzippedDistribution(servletContext),
pluginsToInstall)
.init();
@@ -292,21 +299,6 @@ public class WebAppInitializer extends GuiceServletContextListener implements Fi
listener().to(ReviewDbDataSourceProvider.class);
}
});
// If we didn't get the site path from the system property
// we need to get it from the database, as that's our old
// method of locating the site path on disk.
//
modules.add(
new AbstractModule() {
@Override
protected void configure() {
bind(Path.class)
.annotatedWith(SitePath.class)
.toProvider(SitePathFromSystemConfigProvider.class)
.in(SINGLETON);
}
});
modules.add(new GerritServerConfigModule());
}
modules.add(new DatabaseModule());
@@ -336,6 +328,7 @@ public class WebAppInitializer extends GuiceServletContextListener implements Fi
modules.add(new MimeUtil2Module());
modules.add(cfgInjector.getInstance(GerritGlobalModule.class));
modules.add(new GerritApiModule());
modules.add(new PluginApiModule());
modules.add(new SearchingChangeCacheImpl.Module());
modules.add(new InternalAccountDirectory.Module());
modules.add(new DefaultPermissionBackendModule());
@@ -385,6 +378,7 @@ public class WebAppInitializer extends GuiceServletContextListener implements Fi
@Override
protected void configure() {
bind(GerritOptions.class).toInstance(new GerritOptions(false, false, false));
bind(GerritRuntime.class).toInstance(GerritRuntime.DAEMON);
}
});
modules.add(new GarbageCollectionModule());

View File

@@ -199,6 +199,7 @@ public class Daemon extends SiteProgram {
private AbstractModule luceneModule;
private Module emailModule;
private Module testSysModule;
private Module auditEventModule;
private Runnable serverStarted;
private IndexType indexType;
@@ -319,6 +320,11 @@ public class Daemon extends SiteProgram {
emailModule = module;
}
@VisibleForTesting
public void setAuditEventModuleForTesting(Module module) {
auditEventModule = module;
}
@VisibleForTesting
public void setLuceneModule(LuceneIndexModule m) {
luceneModule = m;
@@ -425,7 +431,6 @@ public class Daemon extends SiteProgram {
modules.add(cfgInjector.getInstance(GerritGlobalModule.class));
modules.add(new GerritApiModule());
modules.add(new PluginApiModule());
modules.add(new AuditModule());
modules.add(new SearchingChangeCacheImpl.Module(slave));
modules.add(new InternalAccountDirectory.Module());
@@ -438,6 +443,11 @@ public class Daemon extends SiteProgram {
} else {
modules.add(new SmtpEmailSender.Module());
}
if (auditEventModule != null) {
modules.add(auditEventModule);
} else {
modules.add(new AuditModule());
}
modules.add(new SignedTokenEmailTokenVerifier.Module());
modules.add(new RestApiModule());
modules.add(new GpgModule(config));

View File

@@ -1,89 +0,0 @@
// Copyright (C) 2008 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.reviewdb.client;
import com.google.gwtorm.client.Column;
import com.google.gwtorm.client.StringKey;
/** Global configuration needed to serve web requests. */
public final class SystemConfig {
public static final class Key extends StringKey<com.google.gwtorm.client.Key<?>> {
private static final long serialVersionUID = 1L;
private static final String VALUE = "X";
@Column(id = 1, length = 1)
protected String one = VALUE;
public Key() {}
@Override
public String get() {
return VALUE;
}
@Override
protected void set(String newValue) {
assert get().equals(newValue);
}
}
/** Construct a new, unconfigured instance. */
public static SystemConfig create() {
final SystemConfig r = new SystemConfig();
r.singleton = new SystemConfig.Key();
return r;
}
@Column(id = 1)
protected Key singleton;
/** Local filesystem location of header/footer/CSS configuration files */
@Column(id = 3, notNull = false, length = Integer.MAX_VALUE)
public transient String sitePath;
// DO NOT LOOK BELOW THIS LINE. These fields have all been deleted,
// but survive to support schema upgrade code.
/** DEPRECATED DO NOT USE */
@Column(id = 2, length = 36, notNull = false)
public transient String registerEmailPrivateKey;
/** DEPRECATED DO NOT USE */
@Column(id = 4, notNull = false)
public AccountGroup.Id adminGroupId;
/** DEPRECATED DO NOT USE */
@Column(id = 10, notNull = false)
public AccountGroup.UUID adminGroupUUID;
/** DEPRECATED DO NOT USE */
@Column(id = 5, notNull = false)
public AccountGroup.Id anonymousGroupId;
/** DEPRECATED DO NOT USE */
@Column(id = 6, notNull = false)
public AccountGroup.Id registeredGroupId;
/** DEPRECATED DO NOT USE */
@Column(id = 7, notNull = false)
public Project.NameKey wildProjectName;
/** DEPRECATED DO NOT USE */
@Column(id = 9, notNull = false)
public AccountGroup.Id ownerGroupId;
/** DEPRECATED DO NOT USE */
@Column(id = 8, notNull = false)
public AccountGroup.Id batchUsersGroupId;
/** DEPRECATED DO NOT USE */
@Column(id = 11, notNull = false)
public AccountGroup.UUID batchUsersGroupUUID;
protected SystemConfig() {}
}

View File

@@ -17,7 +17,6 @@ package com.google.gerrit.reviewdb.server;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.SystemConfig;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.Relation;
import com.google.gwtorm.server.Schema;
@@ -31,7 +30,6 @@ import com.google.gwtorm.server.Sequence;
* <ul>
* <li>{@link Account}: Per-user account registration, preferences, identity.
* <li>{@link Change}: All review information about a single proposed change.
* <li>{@link SystemConfig}: Server-wide settings, managed by administrator.
* </ul>
*/
public interface ReviewDb extends Schema {
@@ -40,8 +38,7 @@ public interface ReviewDb extends Schema {
@Relation(id = 1)
SchemaVersionAccess schemaVersion();
@Relation(id = 2)
SystemConfigAccess systemConfig();
// Deleted @Relation(id = 2)
// Deleted @Relation(id = 3)

View File

@@ -109,11 +109,6 @@ public class ReviewDbWrapper implements ReviewDb {
return delegate.schemaVersion();
}
@Override
public SystemConfigAccess systemConfig() {
return delegate.systemConfig();
}
@Override
public ChangeAccess changes() {
return delegate.changes();

View File

@@ -1,32 +0,0 @@
// Copyright (C) 2008 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.reviewdb.server;
import com.google.gerrit.reviewdb.client.SystemConfig;
import com.google.gwtorm.server.Access;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.PrimaryKey;
import com.google.gwtorm.server.Query;
import com.google.gwtorm.server.ResultSet;
/** Access interface for {@link SystemConfig}. */
public interface SystemConfigAccess extends Access<SystemConfig, SystemConfig.Key> {
@Override
@PrimaryKey("singleton")
SystemConfig get(SystemConfig.Key key) throws OrmException;
@Query
ResultSet<SystemConfig> all() throws OrmException;
}

View File

@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.audit;
package com.google.gerrit.server;
import static java.util.Objects.requireNonNull;
@@ -20,7 +20,6 @@ import com.google.auto.value.AutoValue;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.util.time.TimeUtil;
public class AuditEvent {

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.server.audit;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
import com.google.gerrit.server.AuditEvent;
@ExtensionPoint
public interface AuditListener {

View File

@@ -17,6 +17,7 @@ package com.google.gerrit.server.audit;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.AuditEvent;
import com.google.gerrit.server.audit.group.GroupAuditListener;
import com.google.gerrit.server.audit.group.GroupMemberAuditEvent;
import com.google.gerrit.server.audit.group.GroupSubgroupAuditEvent;
@@ -39,6 +40,7 @@ public class AuditService implements GroupAuditService {
this.groupAuditListeners = groupAuditListeners;
}
@Override
public void dispatch(AuditEvent action) {
auditListeners.runEach(l -> l.onAuditableAction(action));
}

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.server.audit;
import com.google.common.collect.ListMultimap;
import com.google.gerrit.server.AuditEvent;
import com.google.gerrit.server.CurrentUser;
public class HttpAuditEvent extends AuditEvent {

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.server.audit;
import com.google.common.collect.ListMultimap;
import com.google.gerrit.server.AuditEvent;
import com.google.gerrit.server.CurrentUser;
public class SshAuditEvent extends AuditEvent {

View File

@@ -13,10 +13,11 @@
// limitations under the License.
package com.google.gerrit.server.config;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
@@ -36,6 +37,8 @@ import org.eclipse.jgit.lib.Config;
* (+ various overloaded versions of these)
*/
public class ConfigUpdatedEvent {
public static final Multimap<UpdateResult, ConfigUpdateEntry> NO_UPDATES =
new ImmutableMultimap.Builder<UpdateResult, ConfigUpdateEntry>().build();
private final Config oldConfig;
private final Config newConfig;
@@ -52,25 +55,29 @@ public class ConfigUpdatedEvent {
return this.newConfig;
}
public Update accept(ConfigKey entry) {
private String getString(ConfigKey key, Config config) {
return config.getString(key.section(), key.subsection(), key.name());
}
public Multimap<UpdateResult, ConfigUpdateEntry> accept(ConfigKey entry) {
return accept(Collections.singleton(entry));
}
public Update accept(Set<ConfigKey> entries) {
public Multimap<UpdateResult, ConfigUpdateEntry> accept(Set<ConfigKey> entries) {
return createUpdate(entries, UpdateResult.APPLIED);
}
public Update accept(String section) {
public Multimap<UpdateResult, ConfigUpdateEntry> accept(String section) {
Set<ConfigKey> entries = getEntriesFromSection(oldConfig, section);
entries.addAll(getEntriesFromSection(newConfig, section));
return createUpdate(entries, UpdateResult.APPLIED);
}
public Update reject(ConfigKey entry) {
public Multimap<UpdateResult, ConfigUpdateEntry> reject(ConfigKey entry) {
return reject(Collections.singleton(entry));
}
public Update reject(Set<ConfigKey> entries) {
public Multimap<UpdateResult, ConfigUpdateEntry> reject(Set<ConfigKey> entries) {
return createUpdate(entries, UpdateResult.REJECTED);
}
@@ -87,20 +94,15 @@ public class ConfigUpdatedEvent {
return res;
}
private Update createUpdate(Set<ConfigKey> entries, UpdateResult updateResult) {
Update update = new Update(updateResult);
private Multimap<UpdateResult, ConfigUpdateEntry> createUpdate(
Set<ConfigKey> entries, UpdateResult updateResult) {
Multimap<UpdateResult, ConfigUpdateEntry> updates = ArrayListMultimap.create();
entries
.stream()
.filter(this::isValueUpdated)
.forEach(
key -> {
update.addConfigUpdate(
new ConfigUpdateEntry(
key,
oldConfig.getString(key.section(), key.subsection(), key.name()),
newConfig.getString(key.section(), key.subsection(), key.name())));
});
return update;
.map(e -> new ConfigUpdateEntry(e, getString(e, oldConfig), getString(e, newConfig)))
.forEach(e -> updates.put(updateResult, e));
return updates;
}
public boolean isSectionUpdated(String section) {
@@ -142,31 +144,6 @@ public class ConfigUpdatedEvent {
}
}
/**
* One Accepted/Rejected Update have one or more config updates (ConfigUpdateEntry) tied to it.
*/
public static class Update {
private UpdateResult result;
private final Set<ConfigUpdateEntry> configUpdates;
public Update(UpdateResult result) {
this.configUpdates = new LinkedHashSet<>();
this.result = result;
}
public UpdateResult getResult() {
return result;
}
public List<ConfigUpdateEntry> getConfigUpdates() {
return ImmutableList.copyOf(configUpdates);
}
public void addConfigUpdate(ConfigUpdateEntry entry) {
this.configUpdates.add(entry);
}
}
public enum ConfigEntryType {
ADDED,
REMOVED,

View File

@@ -14,9 +14,11 @@
package com.google.gerrit.server.config;
import com.google.common.collect.Multimap;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
import com.google.gerrit.server.config.ConfigUpdatedEvent.ConfigUpdateEntry;
import com.google.gerrit.server.config.ConfigUpdatedEvent.UpdateResult;
import java.util.EventListener;
import java.util.List;
/**
* Implementations of the GerritConfigListener interface expects to react GerritServerConfig
@@ -24,5 +26,5 @@ import java.util.List;
*/
@ExtensionPoint
public interface GerritConfigListener extends EventListener {
List<ConfigUpdatedEvent.Update> configUpdated(ConfigUpdatedEvent event);
Multimap<UpdateResult, ConfigUpdateEntry> configUpdated(ConfigUpdatedEvent event);
}

View File

@@ -15,13 +15,12 @@
package com.google.gerrit.server.config;
import com.google.common.collect.ImmutableSet;
import java.util.Collections;
public class GerritConfigListenerHelper {
public static GerritConfigListener acceptIfChanged(ConfigKey... keys) {
return e ->
e.isEntriesUpdated(ImmutableSet.copyOf(keys))
? Collections.singletonList(e.accept(ImmutableSet.copyOf(keys)))
: Collections.emptyList();
? e.accept(ImmutableSet.copyOf(keys))
: ConfigUpdatedEvent.NO_UPDATES;
}
}

View File

@@ -14,12 +14,14 @@
package com.google.gerrit.server.config;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.server.config.ConfigUpdatedEvent.ConfigUpdateEntry;
import com.google.gerrit.server.config.ConfigUpdatedEvent.UpdateResult;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.List;
/** Issues a configuration reload from the GerritServerConfigProvider and notify all listeners. */
@Singleton
@@ -40,18 +42,20 @@ public class GerritServerConfigReloader {
* Reloads the Gerrit Server Configuration from disk. Synchronized to ensure that one issued
* reload is fully completed before a new one starts.
*/
public List<ConfigUpdatedEvent.Update> reloadConfig() {
public Multimap<UpdateResult, ConfigUpdateEntry> reloadConfig() {
logger.atInfo().log("Starting server configuration reload");
List<ConfigUpdatedEvent.Update> updates = fireUpdatedConfigEvent(configProvider.updateConfig());
Multimap<UpdateResult, ConfigUpdateEntry> updates =
fireUpdatedConfigEvent(configProvider.updateConfig());
logger.atInfo().log("Server configuration reload completed succesfully");
return updates;
}
public List<ConfigUpdatedEvent.Update> fireUpdatedConfigEvent(ConfigUpdatedEvent event) {
ArrayList<ConfigUpdatedEvent.Update> result = new ArrayList<>();
public Multimap<UpdateResult, ConfigUpdateEntry> fireUpdatedConfigEvent(
ConfigUpdatedEvent event) {
Multimap<UpdateResult, ConfigUpdateEntry> updates = ArrayListMultimap.create();
for (GerritConfigListener configListener : configListeners) {
result.addAll(configListener.configUpdated(event));
updates.putAll(configListener.configUpdated(event));
}
return result;
return updates;
}
}

View File

@@ -29,6 +29,7 @@ public class TransferConfig {
private final long maxObjectSizeLimit;
private final String maxObjectSizeLimitFormatted;
private final boolean inheritProjectMaxObjectSizeLimit;
private final boolean enableProtocolV2;
@Inject
TransferConfig(@GerritServerConfig Config cfg) {
@@ -45,6 +46,7 @@ public class TransferConfig {
maxObjectSizeLimitFormatted = cfg.getString("receive", null, "maxObjectSizeLimit");
inheritProjectMaxObjectSizeLimit =
cfg.getBoolean("receive", "inheritProjectMaxObjectSizeLimit", false);
enableProtocolV2 = cfg.getBoolean("receive", "enableProtocolV2", false);
packConfig = new PackConfig();
packConfig.setDeltaCompress(false);
@@ -72,4 +74,8 @@ public class TransferConfig {
public boolean inheritProjectMaxObjectSizeLimit() {
return inheritProjectMaxObjectSizeLimit;
}
public boolean enableProtocolV2() {
return enableProtocolV2;
}
}

View File

@@ -18,9 +18,11 @@ import com.google.common.collect.ImmutableSet;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Account.Id;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.AuditEvent;
import java.sql.Timestamp;
public interface GroupAuditService {
void dispatch(AuditEvent action);
void dispatchAddMembers(
Account.Id actor,

View File

@@ -16,15 +16,17 @@ package com.google.gerrit.server.project;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.api.projects.CommentLinkInfo;
import com.google.gerrit.server.config.ConfigUpdatedEvent;
import com.google.gerrit.server.config.ConfigUpdatedEvent.ConfigUpdateEntry;
import com.google.gerrit.server.config.ConfigUpdatedEvent.UpdateResult;
import com.google.gerrit.server.config.GerritConfigListener;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.eclipse.jgit.lib.Config;
@@ -64,11 +66,11 @@ public class CommentLinkProvider implements Provider<List<CommentLinkInfo>>, Ger
}
@Override
public List<ConfigUpdatedEvent.Update> configUpdated(ConfigUpdatedEvent event) {
public Multimap<UpdateResult, ConfigUpdateEntry> configUpdated(ConfigUpdatedEvent event) {
if (event.isSectionUpdated(ProjectConfig.COMMENTLINK)) {
commentLinks = parseConfig(event.getNewConfig());
return Collections.singletonList(event.accept(ProjectConfig.COMMENTLINK));
return event.accept(ProjectConfig.COMMENTLINK);
}
return Collections.emptyList();
return ConfigUpdatedEvent.NO_UPDATES;
}
}

View File

@@ -16,12 +16,12 @@ package com.google.gerrit.server.restapi.config;
import static com.google.common.collect.ImmutableList.toImmutableList;
import com.google.common.collect.Multimap;
import com.google.gerrit.extensions.api.config.ConfigUpdateEntryInfo;
import com.google.gerrit.extensions.common.Input;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.config.ConfigUpdatedEvent;
import com.google.gerrit.server.config.ConfigUpdatedEvent.ConfigUpdateEntry;
import com.google.gerrit.server.config.ConfigUpdatedEvent.UpdateResult;
import com.google.gerrit.server.config.GerritServerConfigReloader;
@@ -29,10 +29,11 @@ import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class ReloadConfig implements RestModifyView<ConfigResource, Input> {
@@ -49,25 +50,22 @@ public class ReloadConfig implements RestModifyView<ConfigResource, Input> {
public Map<String, List<ConfigUpdateEntryInfo>> apply(ConfigResource resource, Input input)
throws RestApiException, PermissionBackendException {
permissions.currentUser().check(GlobalPermission.ADMINISTRATE_SERVER);
List<ConfigUpdatedEvent.Update> updates = config.reloadConfig();
Map<String, List<ConfigUpdateEntryInfo>> reply = new HashMap<>();
for (UpdateResult result : UpdateResult.values()) {
reply.put(result.name().toLowerCase(), new ArrayList<>());
}
Multimap<UpdateResult, ConfigUpdateEntry> updates = config.reloadConfig();
if (updates.isEmpty()) {
return reply;
return Collections.emptyMap();
}
updates
return updates
.asMap()
.entrySet()
.stream()
.forEach(u -> reply.get(u.getResult().name().toLowerCase()).addAll(toEntryInfos(u)));
return reply;
.collect(
Collectors.toMap(
e -> e.getKey().name().toLowerCase(), e -> toEntryInfos(e.getValue())));
}
private static List<ConfigUpdateEntryInfo> toEntryInfos(ConfigUpdatedEvent.Update update) {
return update
.getConfigUpdates()
private static List<ConfigUpdateEntryInfo> toEntryInfos(
Collection<ConfigUpdateEntry> updateEntries) {
return updateEntries
.stream()
.map(ReloadConfig::toConfigUpdateEntryInfo)
.collect(toImmutableList());

View File

@@ -19,6 +19,7 @@ import static java.util.Objects.requireNonNull;
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.gerrit.extensions.api.projects.ParentInput;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
@@ -32,6 +33,8 @@ import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.ConfigKey;
import com.google.gerrit.server.config.ConfigUpdatedEvent;
import com.google.gerrit.server.config.ConfigUpdatedEvent.ConfigUpdateEntry;
import com.google.gerrit.server.config.ConfigUpdatedEvent.UpdateResult;
import com.google.gerrit.server.config.GerritConfigListener;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
@@ -46,8 +49,6 @@ import com.google.gerrit.server.project.ProjectState;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Config;
@@ -175,18 +176,18 @@ public class SetParent
}
@Override
public List<ConfigUpdatedEvent.Update> configUpdated(ConfigUpdatedEvent event) {
public Multimap<UpdateResult, ConfigUpdateEntry> configUpdated(ConfigUpdatedEvent event) {
ConfigKey receiveSetParent = ConfigKey.create("receive", "allowProjectOwnersToChangeParent");
if (!event.isValueUpdated(receiveSetParent)) {
return Collections.emptyList();
return ConfigUpdatedEvent.NO_UPDATES;
}
try {
boolean enabled =
event.getNewConfig().getBoolean("receive", "allowProjectOwnersToChangeParent", false);
this.allowProjectOwnersToChangeParent = enabled;
return Collections.singletonList(event.accept(receiveSetParent));
} catch (IllegalArgumentException iae) {
return Collections.singletonList(event.reject(receiveSetParent));
}
return event.reject(receiveSetParent);
}
return event.accept(receiveSetParent);
}
}

View File

@@ -275,8 +275,7 @@ class GroupRebuilder {
* Distinct event types.
*
* <p>Events at the same time by the same user are batched together by type. The types should
* correspond to the possible batch operations supported by {@link
* com.google.gerrit.server.audit.AuditService}.
* correspond to the possible batch operations supported by AuditService.
*/
enum Type {
ADD_MEMBER,

View File

@@ -21,7 +21,6 @@ import com.google.gerrit.git.RefUpdateUtil;
import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
import com.google.gerrit.reviewdb.client.SystemConfig;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.Sequences;
@@ -150,7 +149,6 @@ public class ReviewDbSchemaCreator {
GroupReference admins = createGroupReference("Administrators");
GroupReference batchUsers = createGroupReference("Non-Interactive Users");
initSystemConfig(db);
allProjectsCreator.setAdministrators(admins).setBatchUsers(batchUsers).create();
// We have to create the All-Users repository before we can use it to store the groups in it.
allUsersCreator.setAdministrators(admins).create();
@@ -274,15 +272,4 @@ public class ReviewDbSchemaCreator {
.setGroupUUID(groupReference.getUUID())
.build();
}
private SystemConfig initSystemConfig(ReviewDb db) throws OrmException {
SystemConfig s = SystemConfig.create();
try {
s.sitePath = site_path.toRealPath().normalize().toString();
} catch (IOException e) {
s.sitePath = site_path.toAbsolutePath().normalize().toString();
}
db.systemConfig().insert(Collections.singleton(s));
return s;
}
}

View File

@@ -16,7 +16,6 @@ package com.google.gerrit.server.schema;
import com.google.common.annotations.VisibleForTesting;
import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
import com.google.gerrit.reviewdb.client.SystemConfig;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.reviewdb.server.ReviewDbUtil;
import com.google.gerrit.server.GerritPersonIdent;
@@ -38,7 +37,6 @@ import com.google.inject.Provider;
import com.google.inject.Stage;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Collections;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.PersonIdent;
@@ -46,18 +44,15 @@ import org.eclipse.jgit.lib.PersonIdent;
/** Creates or updates the current database schema. */
public class ReviewDbSchemaUpdater {
private final SchemaFactory<ReviewDb> schema;
private final SitePaths site;
private final ReviewDbSchemaCreator creator;
private final Provider<ReviewDbSchemaVersion> updater;
@Inject
ReviewDbSchemaUpdater(
@ReviewDbFactory SchemaFactory<ReviewDb> schema,
SitePaths site,
ReviewDbSchemaCreator creator,
Injector parent) {
this.schema = schema;
this.site = site;
this.creator = creator;
this.updater = buildInjector(parent).getProvider(ReviewDbSchemaVersion.class);
}
@@ -119,8 +114,6 @@ public class ReviewDbSchemaUpdater {
} catch (SQLException e) {
throw new OrmException("Cannot upgrade schema", e);
}
updateSystemConfig(db);
}
}
}
@@ -137,17 +130,4 @@ public class ReviewDbSchemaUpdater {
return null;
}
}
private void updateSystemConfig(ReviewDb db) throws OrmException {
final SystemConfig sc = db.systemConfig().get(new SystemConfig.Key());
if (sc == null) {
throw new OrmException("No record in system_config table");
}
try {
sc.sitePath = site.site_path.toRealPath().normalize().toString();
} catch (IOException e) {
sc.sitePath = site.site_path.toAbsolutePath().normalize().toString();
}
db.systemConfig().update(Collections.singleton(sc));
}
}

View File

@@ -36,7 +36,7 @@ import java.util.concurrent.TimeUnit;
/** A version of the database schema. */
public abstract class ReviewDbSchemaVersion {
/** The current schema version. */
public static final Class<Schema_169> C = Schema_169.class;
public static final Class<Schema_170> C = Schema_170.class;
public static int getBinaryVersion() {
return guessVersion(C);

View File

@@ -0,0 +1,25 @@
// Copyright (C) 2018 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.server.schema;
import com.google.inject.Inject;
import com.google.inject.Provider;
public class Schema_170 extends ReviewDbSchemaVersion {
@Inject
Schema_170(Provider<Schema_169> prior) {
super(prior);
}
}

View File

@@ -29,6 +29,8 @@ import org.eclipse.jgit.lib.Repository;
import org.kohsuke.args4j.Argument;
public abstract class AbstractGitCommand extends BaseCommand {
private static final String GIT_PROTOCOL = "GIT_PROTOCOL";
@Argument(index = 0, metaVar = "PROJECT.git", required = true, usage = "project name")
protected ProjectState projectState;
@@ -45,9 +47,15 @@ public abstract class AbstractGitCommand extends BaseCommand {
protected Repository repo;
protected Project.NameKey projectName;
protected Project project;
protected String[] extraParameters;
@Override
public void start(Environment env) {
String gitProtocol = env.getEnv().get(GIT_PROTOCOL);
if (gitProtocol != null) {
extraParameters = gitProtocol.split(":");
}
Context ctx = context.subContext(newSession(), context.getCommandLine());
final Context old = sshScope.set(ctx);
try {

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.sshd;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.server.CurrentUser;
@@ -24,6 +25,8 @@ import com.google.gerrit.server.audit.AuditService;
import com.google.gerrit.server.audit.SshAuditEvent;
import com.google.gerrit.server.config.ConfigKey;
import com.google.gerrit.server.config.ConfigUpdatedEvent;
import com.google.gerrit.server.config.ConfigUpdatedEvent.ConfigUpdateEntry;
import com.google.gerrit.server.config.ConfigUpdatedEvent.UpdateResult;
import com.google.gerrit.server.config.GerritConfigListener;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.ioutil.HexFormat;
@@ -33,8 +36,6 @@ import com.google.gerrit.sshd.SshScope.Context;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.util.Collections;
import java.util.List;
import org.apache.log4j.AsyncAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
@@ -318,25 +319,22 @@ class SshLog implements LifecycleListener, GerritConfigListener {
}
@Override
public List<ConfigUpdatedEvent.Update> configUpdated(ConfigUpdatedEvent event) {
public Multimap<UpdateResult, ConfigUpdateEntry> configUpdated(ConfigUpdatedEvent event) {
ConfigKey sshdRequestLog = ConfigKey.create("sshd", "requestLog");
if (!event.isValueUpdated(sshdRequestLog)) {
return Collections.emptyList();
return ConfigUpdatedEvent.NO_UPDATES;
}
boolean stateUpdated;
try {
boolean enabled = event.getNewConfig().getBoolean("sshd", "requestLog", true);
if (enabled) {
stateUpdated = enableLogging();
} else {
stateUpdated = disableLogging();
}
return stateUpdated
? Collections.singletonList(event.accept(sshdRequestLog))
: Collections.emptyList();
return stateUpdated ? event.accept(sshdRequestLog) : ConfigUpdatedEvent.NO_UPDATES;
} catch (IllegalArgumentException iae) {
return Collections.singletonList(event.reject(sshdRequestLog));
return event.reject(sshdRequestLog);
}
}
}

View File

@@ -16,16 +16,15 @@ package com.google.gerrit.sshd.commands;
import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;
import com.google.common.collect.Multimap;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.config.ConfigUpdatedEvent;
import com.google.gerrit.server.config.ConfigUpdatedEvent.ConfigUpdateEntry;
import com.google.gerrit.server.config.ConfigUpdatedEvent.UpdateResult;
import com.google.gerrit.server.config.GerritServerConfigReloader;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
import java.util.List;
import java.util.stream.Collectors;
/** Issues a reload of gerrit.config. */
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@@ -39,31 +38,16 @@ public class ReloadConfig extends SshCommand {
@Override
protected void run() throws Failure {
List<ConfigUpdatedEvent.Update> updates = gerritServerConfigReloader.reloadConfig();
Multimap<UpdateResult, ConfigUpdateEntry> updates = gerritServerConfigReloader.reloadConfig();
if (updates.isEmpty()) {
stdout.println("No config entries updated!");
return;
}
// Print out UpdateResult.{ACCEPTED|REJECTED} entries grouped by their type
for (UpdateResult updateResult : UpdateResult.values()) {
List<ConfigUpdatedEvent.Update> filteredUpdates = filterUpdates(updates, updateResult);
if (filteredUpdates.isEmpty()) {
continue;
}
stdout.println(updateResult.toString() + " configuration changes:");
filteredUpdates
.stream()
.flatMap(update -> update.getConfigUpdates().stream())
.forEach(cfgEntry -> stdout.println(cfgEntry.toString()));
for (UpdateResult result : updates.keySet()) {
stdout.println(result.toString() + " configuration changes:");
updates.get(result).forEach(cfgEntry -> stdout.println(cfgEntry.toString()));
}
}
public static List<ConfigUpdatedEvent.Update> filterUpdates(
List<ConfigUpdatedEvent.Update> updates, UpdateResult result) {
return updates
.stream()
.filter(update -> update.getResult() == result)
.collect(Collectors.toList());
}
}

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.sshd.commands;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.AuthException;
@@ -52,7 +53,6 @@ final class Upload extends AbstractGitCommand {
PermissionBackend.ForProject perm =
permissionBackend.user(user).project(projectState.getNameKey());
try {
perm.check(ProjectPermission.RUN_UPLOAD_PACK);
} catch (AuthException e) {
throw new Failure(1, "fatal: upload-pack not permitted on this server");
@@ -65,6 +65,9 @@ final class Upload extends AbstractGitCommand {
up.setPackConfig(config.getPackConfig());
up.setTimeout(config.getTimeout());
up.setPostUploadHook(PostUploadHookChain.newChain(Lists.newArrayList(postUploadHooks)));
if (config.enableProtocolV2() && extraParameters != null) {
up.setExtraParameters(ImmutableList.copyOf(extraParameters));
}
List<PreUploadHook> allPreUploadHooks = Lists.newArrayList(preUploadHooks);
allPreUploadHooks.add(

View File

@@ -21,7 +21,6 @@ import com.google.gerrit.reviewdb.server.PatchSetAccess;
import com.google.gerrit.reviewdb.server.PatchSetApprovalAccess;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.reviewdb.server.SchemaVersionAccess;
import com.google.gerrit.reviewdb.server.SystemConfigAccess;
import com.google.gwtorm.server.Access;
import com.google.gwtorm.server.StatementExecutor;
@@ -70,11 +69,6 @@ public class DisabledReviewDb implements ReviewDb {
throw new Disabled();
}
@Override
public SystemConfigAccess systemConfig() {
throw new Disabled();
}
@Override
public ChangeAccess changes() {
throw new Disabled();

View File

@@ -0,0 +1,112 @@
// Copyright (C) 2018 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.testing;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.AuditEvent;
import com.google.gerrit.server.audit.AuditListener;
import com.google.gerrit.server.audit.group.GroupAuditListener;
import com.google.gerrit.server.audit.group.GroupMemberAuditEvent;
import com.google.gerrit.server.audit.group.GroupSubgroupAuditEvent;
import com.google.gerrit.server.group.GroupAuditService;
import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
@Singleton
public class FakeGroupAuditService implements GroupAuditService {
private final PluginSetContext<GroupAuditListener> groupAuditListeners;
private final PluginSetContext<AuditListener> auditListeners;
public static class Module extends AbstractModule {
@Override
public void configure() {
DynamicSet.setOf(binder(), GroupAuditListener.class);
DynamicSet.setOf(binder(), AuditListener.class);
bind(GroupAuditService.class).to(FakeGroupAuditService.class);
}
}
@Inject
public FakeGroupAuditService(
PluginSetContext<GroupAuditListener> groupAuditListeners,
PluginSetContext<AuditListener> auditListeners) {
this.groupAuditListeners = groupAuditListeners;
this.auditListeners = auditListeners;
}
public List<AuditEvent> auditEvents = new ArrayList<>();
public void clearEvents() {
auditEvents.clear();
}
@Override
public void dispatch(AuditEvent action) {
auditEvents.add(action);
}
@Override
public void dispatchAddMembers(
Account.Id actor,
AccountGroup.UUID updatedGroup,
ImmutableSet<Account.Id> addedMembers,
Timestamp addedOn) {
GroupMemberAuditEvent event =
GroupMemberAuditEvent.create(actor, updatedGroup, addedMembers, addedOn);
groupAuditListeners.runEach(l -> l.onAddMembers(event));
}
@Override
public void dispatchDeleteMembers(
Account.Id actor,
AccountGroup.UUID updatedGroup,
ImmutableSet<Account.Id> deletedMembers,
Timestamp deletedOn) {
GroupMemberAuditEvent event =
GroupMemberAuditEvent.create(actor, updatedGroup, deletedMembers, deletedOn);
groupAuditListeners.runEach(l -> l.onDeleteMembers(event));
}
@Override
public void dispatchAddSubgroups(
Account.Id actor,
AccountGroup.UUID updatedGroup,
ImmutableSet<AccountGroup.UUID> addedSubgroups,
Timestamp addedOn) {
GroupSubgroupAuditEvent event =
GroupSubgroupAuditEvent.create(actor, updatedGroup, addedSubgroups, addedOn);
groupAuditListeners.runEach(l -> l.onAddSubgroups(event));
}
@Override
public void dispatchDeleteSubgroups(
Account.Id actor,
AccountGroup.UUID updatedGroup,
ImmutableSet<AccountGroup.UUID> deletedSubgroups,
Timestamp deletedOn) {
GroupSubgroupAuditEvent event =
GroupSubgroupAuditEvent.create(actor, updatedGroup, deletedSubgroups, deletedOn);
groupAuditListeners.runEach(l -> l.onDeleteSubgroups(event));
}
}

View File

@@ -20,7 +20,6 @@ import com.google.gerrit.lifecycle.LifecycleManager;
import com.google.gerrit.pgm.init.index.elasticsearch.ElasticIndexModuleOnInit;
import com.google.gerrit.pgm.init.index.lucene.LuceneIndexModuleOnInit;
import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
import com.google.gerrit.reviewdb.client.SystemConfig;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.index.IndexModule;
import com.google.gerrit.server.schema.ReviewDbSchemaCreator;
@@ -127,12 +126,6 @@ public class InMemoryDatabase implements SchemaFactory<ReviewDb> {
return this;
}
public SystemConfig getSystemConfig() throws OrmException {
try (ReviewDb c = open()) {
return c.systemConfig().get(new SystemConfig.Key());
}
}
public CurrentSchemaVersion getSchemaVersion() throws OrmException {
try (ReviewDb c = open()) {
return c.schemaVersion().get(new CurrentSchemaVersion.Key());

View File

@@ -102,7 +102,7 @@ public class PRED_commit_delta_4 extends Predicate.P4 {
String oldName = patch.getOldName();
Patch.ChangeType changeType = patch.getChangeType();
if (newName.equals("/COMMIT_MSG")) {
if (Patch.isMagic(newName)) {
continue;
}

View File

@@ -14,6 +14,7 @@
package gerrit;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.server.patch.PatchList;
import com.google.gerrit.server.patch.PatchListEntry;
import com.google.gerrit.server.patch.Text;
@@ -90,7 +91,7 @@ public class PRED_commit_edits_2 extends Predicate.P2 {
String newName = entry.getNewName();
String oldName = entry.getOldName();
if (newName.equals("/COMMIT_MSG")) {
if (Patch.isMagic(newName)) {
continue;
}

View File

@@ -0,0 +1,68 @@
// Copyright (C) 2018 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.git;
import static com.google.common.truth.Truth.assertThat;
import com.google.gerrit.server.AuditEvent;
import java.util.Collections;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.junit.Before;
import org.junit.Test;
public class GitOverHttpServletIT extends AbstractPushForReview {
@Before
public void beforeEach() throws Exception {
CredentialsProvider.setDefault(
new UsernamePasswordCredentialsProvider(admin.username, admin.httpPassword));
selectProtocol(AbstractPushForReview.Protocol.HTTP);
auditService.clearEvents();
}
@Test
public void receivePackAuditEventLog() throws Exception {
testRepo
.git()
.push()
.setRemote("origin")
.setRefSpecs(new RefSpec("HEAD:refs/for/master"))
.call();
// Git smart protocol makes two requests:
// https://github.com/git/git/blob/master/Documentation/technical/http-protocol.txt
assertThat(auditService.auditEvents.size()).isEqualTo(2);
AuditEvent e = auditService.auditEvents.get(1);
assertThat(e.who.getAccountId()).isEqualTo(admin.id);
assertThat(e.what).endsWith("/git-receive-pack");
assertThat(e.params).isEmpty();
}
@Test
public void uploadPackAuditEventLog() throws Exception {
testRepo.git().fetch().call();
assertThat(auditService.auditEvents.size()).isEqualTo(1);
AuditEvent e = auditService.auditEvents.get(0);
assertThat(e.who.toString()).isEqualTo("ANONYMOUS");
assertThat(e.params.get("service"))
.containsExactlyElementsIn(Collections.singletonList("git-upload-pack"));
assertThat(e.what).endsWith("service=git-upload-pack");
}
}

View File

@@ -31,7 +31,6 @@ import com.google.gwtorm.jdbc.JdbcSchema;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import java.io.File;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
@@ -63,7 +62,7 @@ public class ReviewDbSchemaCreatorTest {
}
@Test
public void getCauses_CreateSchema() throws OrmException, SQLException, IOException {
public void getCauses_CreateSchema() throws OrmException, SQLException {
// Initially the schema should be empty.
String[] types = {"TABLE", "VIEW"};
try (JdbcSchema d = (JdbcSchema) db.open();
@@ -82,7 +81,6 @@ public class ReviewDbSchemaCreatorTest {
if (sitePath.getName().equals(".")) {
sitePath = sitePath.getParentFile();
}
assertThat(db.getSystemConfig().sitePath).isEqualTo(sitePath.getCanonicalPath());
}
private LabelTypes getLabelTypes() throws Exception {

View File

@@ -20,7 +20,6 @@ import com.google.gerrit.extensions.config.FactoryModule;
import com.google.gerrit.lifecycle.LifecycleManager;
import com.google.gerrit.metrics.DisabledMetricMaker;
import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.reviewdb.client.SystemConfig;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.GerritPersonIdentProvider;
@@ -148,7 +147,5 @@ public class ReviewDbSchemaUpdaterTest {
u.update(new TestUpdateUI());
db.assertSchemaVersion();
final SystemConfig sc = db.getSystemConfig();
assertThat(sc.sitePath).isEqualTo(paths.site_path.toAbsolutePath().toString());
}
}

View File

@@ -8,7 +8,7 @@
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.gerrit.httpd.WebAppInitializer</filter-class>
<filter-class>com.google.gerrit.httpd.init.WebAppInitializer</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>