Rename 'Non-Interactive Users' to 'Service Users'

The term 'Service Users' is more in-line with other
products while 'Non-Interactive Users' is a quite
unique and arcane name. Hence, this commit renames
the existing group.

This was discussued in this mailing list thread.

Change-Id: I5e62b0fe4cab455461920801486b0cc4abd377e7
This commit is contained in:
Patrick Hiesel
2020-08-07 16:11:29 +02:00
parent 443f7314cb
commit e587c40aaa
32 changed files with 295 additions and 86 deletions

View File

@@ -100,7 +100,7 @@ to those groups. These UUIDs are different on different Gerrit sites.
Gerrit comes with two predefined groups:
* Administrators
* Non-Interactive Users
* Service Users
[[administrators]]
@@ -117,7 +117,7 @@ renamed.
[[non-interactive_users]]
=== Non-Interactive Users
=== Service Users
This is the Gerrit "batch" identity. The capabilities
link:access-control.html#capability_priority['Priority BATCH'] and
@@ -131,7 +131,7 @@ However, sometimes such a user may need a separate thread pool in
order to prevent it from grabbing threads from the interactive users.
These users live in a second thread pool, which separates operations
made by the non-interactive users from the ones made by the interactive
made by the service users from the ones made by the interactive
users. This ensures that the interactive users can keep working when
resources are tight.
@@ -1323,7 +1323,7 @@ Allow link:cmd-create-account.html[account creation over the ssh prompt].
This capability allows the granted group members to create non-interactive
service accounts. These service accounts are generally used for automation
and made to be members of the
link:access-control.html#non-interactive_users['Non-Interactive users'] group.
link:access-control.html#service_users['Service users'] group.
[[capability_createGroup]]
@@ -1402,7 +1402,7 @@ of other accounts.
This capability allows users to use
link:config-gerrit.html#sshd.batchThreads[the thread pool reserved] for
link:access-control.html#non-interactive_users['Non-Interactive Users'].
link:access-control.html#service_users['Service Users'].
It's a binary value in that granted users either have access to the thread
pool, or they don't.
@@ -1414,7 +1414,7 @@ The user isn't a member of a group with any priority capability granted. By
default the user is then in the 'INTERACTIVE' thread pool.
'BATCH'::
If there's a thread pool configured for 'Non-Interactive Users' and a user is
If there's a thread pool configured for 'Service Users' and a user is
granted the priority capability with the 'BATCH' mode selected, the user ends
up in the separate batch user thread pool. This is true unless the user is
also granted the below 'INTERACTIVE' option.

View File

@@ -23,7 +23,7 @@ used for batch/role access, such as from an automated build system
or event monitoring over link:cmd-stream-events.html[gerrit stream-events].
Note, however, that in this case the account is not implicitly added
to the 'Non-Interactive Users' group. The account must be explicitly
to the 'Service Users' group. The account must be explicitly
added to the group with the `--group` option.
If LDAP authentication is being used, the user account is created
@@ -66,10 +66,10 @@ This most likely requires double quoting the value, for example
== EXAMPLES
Create a new batch/role access user account called `watcher` in
the 'Non-Interactive Users' group.
the 'Service Users' group.
----
$ cat ~/.ssh/id_watcher.pub | ssh -p 29418 review.example.com gerrit create-account --group "'Non-Interactive Users'" --ssh-key - watcher
$ cat ~/.ssh/id_watcher.pub | ssh -p 29418 review.example.com gerrit create-account --group "'Service Users'" --ssh-key - watcher
----
GERRIT

View File

@@ -4763,16 +4763,16 @@ concurrent Git requests for interactive users over SSH and HTTP together.
[[sshd.batchThreads]]sshd.batchThreads::
+
Number of threads to allocate for SSH command requests from
link:access-control.html#non-interactive_users[non-interactive users].
link:access-control.html#service_users[service users].
If equals to 0, then all non-interactive requests are executed in the same
queue as interactive requests.
+
Any other value will remove the number of threads from the queue
allocated to interactive users, and create a separate thread pool
of the requested size, which will be used to run commands from
non-interactive users.
service users.
+
If the number of threads requested for non-interactive users is larger
If the number of threads requested for service users is larger
than the total number of threads allocated in sshd.threads, then the
value of sshd.threads is increased to accommodate the requested value.
+

View File

@@ -287,12 +287,12 @@ The entries in the map are sorted by project name.
"15bfcd8a6de1a69c50b30cedcdcc951c15703152": {
"url": "#/admin/groups/uuid-15bfcd8a6de1a69c50b30cedcdcc951c15703152",
"options": {},
"description": "Users who perform batch actions on Gerrit",
"description": "Service accounts that interact with Gerrit",
"group_id": 2,
"owner": "Administrators",
"owner_id": "53a4f647a89ea57992571187d8025f830625192a",
"created_on": "2009-06-08 23:31:00.000000000",
"name": "Non-Interactive Users"
"name": "Service Users"
},
"global:Anonymous-Users": {
"options": {},

View File

@@ -67,12 +67,12 @@ by group name.
"owner_id": "834ec36dd5e0ed21a2ff5d7e2255da082d63bbd7",
"created_on": "2013-02-01 09:59:32.126000000"
},
"Non-Interactive Users": {
"Service Users": {
"id": "5057f3cbd3519d6ab69364429a89ffdffba50f73",
"url": "#/admin/groups/uuid-5057f3cbd3519d6ab69364429a89ffdffba50f73",
"options": {
},
"description": "Users who perform batch actions on Gerrit",
"description": "Service accounts that interact with Gerrit",
"group_id": 4,
"owner": "Administrators",
"owner_id": "6a1e70e1a88782771a91808c8af9bbb7a9871389",

View File

@@ -1153,7 +1153,7 @@ entity is returned.
"owner": "Administrators",
"owner_id": "d5b7124af4de52924ed397913e2c3b37bf186948",
"created_on": "2009-06-08 23:31:00.000000000",
"name": "Non-Interactive Users"
"name": "Service Users"
},
"global:Anonymous-Users": {
"options": {},

View File

@@ -87,7 +87,7 @@ image::images/user-attention-set-reply-select.png["reply dialog section for sele
The attention set is meant for human reviews only. Triggering bots and reacting
to their results is a different workflow and not in scope of the attenion set.
Thus members of the "Non-Interactive Users" group will never be added to the
Thus members of the "Service Users" group will never be added to the
attention set. And replies by such users will not add the change owner to the
attention set.

View File

@@ -34,8 +34,8 @@ import com.google.gerrit.server.account.CapabilityCollection;
import com.google.gerrit.server.account.FakeRealm;
import com.google.gerrit.server.account.GroupCacheImpl;
import com.google.gerrit.server.account.GroupIncludeCacheImpl;
import com.google.gerrit.server.account.NonInteractiveUserGroupRobotClassifier;
import com.google.gerrit.server.account.Realm;
import com.google.gerrit.server.account.ServiceUserClassifierImpl;
import com.google.gerrit.server.account.externalids.ExternalIdModule;
import com.google.gerrit.server.cache.CacheRemovalListener;
import com.google.gerrit.server.cache.h2.H2CacheModule;
@@ -165,7 +165,7 @@ public class BatchProgramModule extends FactoryModule {
install(SectionSortCache.module());
install(ChangeKindCacheImpl.module());
install(MergeabilityCacheImpl.module());
install(NonInteractiveUserGroupRobotClassifier.module());
install(ServiceUserClassifierImpl.module());
install(TagCache.module());
install(PureRevertCache.module());
factory(CapabilityCollection.Factory.class);

View File

@@ -16,14 +16,14 @@ package com.google.gerrit.server.account;
import com.google.gerrit.entities.Account;
public interface RobotClassifier {
/** Returns {@code true} if the given user is considered a {@code robot} user. */
boolean isRobot(Account.Id user);
public interface ServiceUserClassifier {
/** Returns {@code true} if the given user is considered a {@code Service User} user. */
boolean isServiceUser(Account.Id user);
/** An instance that can be used for testing and will consider no user to be a robot. */
class NoOp implements RobotClassifier {
/** An instance that can be used for testing and will consider no user to be a Service User. */
class NoOp implements ServiceUserClassifier {
@Override
public boolean isRobot(Account.Id user) {
public boolean isServiceUser(Account.Id user) {
return false;
}
}

View File

@@ -25,18 +25,16 @@ import java.util.Optional;
import javax.inject.Inject;
/**
* An implementation of {@link RobotClassifier} that will consider a user to be a robot if they are
* a member in the {@code Non-Interactive Users} group.
* An implementation of {@link ServiceUserClassifier} that will consider a user to be a robot if
* they are a member in the {@code Service Users} group.
*/
@Singleton
public class NonInteractiveUserGroupRobotClassifier implements RobotClassifier {
public class ServiceUserClassifierImpl implements ServiceUserClassifier {
public static Module module() {
return new AbstractModule() {
@Override
protected void configure() {
bind(RobotClassifier.class)
.to(NonInteractiveUserGroupRobotClassifier.class)
.in(Scopes.SINGLETON);
bind(ServiceUserClassifier.class).to(ServiceUserClassifierImpl.class).in(Scopes.SINGLETON);
}
};
}
@@ -44,17 +42,16 @@ public class NonInteractiveUserGroupRobotClassifier implements RobotClassifier {
private final GroupCache groupCache;
@Inject
NonInteractiveUserGroupRobotClassifier(GroupCache groupCache) {
ServiceUserClassifierImpl(GroupCache groupCache) {
this.groupCache = groupCache;
}
@Override
public boolean isRobot(Account.Id user) {
public boolean isServiceUser(Account.Id user) {
// TODO(hiesel, brohlfs, paiking): This is just an interim solution until we have figured out a
// long-term solution.
// Discussion is at: https://gerrit-review.googlesource.com/c/gerrit/+/274854
Optional<InternalGroup> maybeGroup =
groupCache.get(AccountGroup.nameKey("Non-Interactive Users"));
Optional<InternalGroup> maybeGroup = groupCache.get(AccountGroup.nameKey("Service Users"));
if (maybeGroup.isPresent()) {
return maybeGroup.get().getMembers().stream().anyMatch(member -> user.equals(member));
}

View File

@@ -95,7 +95,7 @@ import com.google.gerrit.server.account.EmailExpander;
import com.google.gerrit.server.account.GroupCacheImpl;
import com.google.gerrit.server.account.GroupControl;
import com.google.gerrit.server.account.GroupIncludeCacheImpl;
import com.google.gerrit.server.account.NonInteractiveUserGroupRobotClassifier;
import com.google.gerrit.server.account.ServiceUserClassifierImpl;
import com.google.gerrit.server.account.VersionedAuthorizedKeys;
import com.google.gerrit.server.account.externalids.ExternalIdModule;
import com.google.gerrit.server.auth.AuthBackend;
@@ -240,7 +240,7 @@ public class GerritGlobalModule extends FactoryModule {
install(GroupCacheImpl.module());
install(GroupIncludeCacheImpl.module());
install(MergeabilityCacheImpl.module());
install(NonInteractiveUserGroupRobotClassifier.module());
install(ServiceUserClassifierImpl.module());
install(PatchListCacheImpl.module());
install(ProjectCacheImpl.module());
install(SectionSortCache.module());

View File

@@ -67,7 +67,7 @@ import com.google.gerrit.entities.SubmitRecord;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.account.RobotClassifier;
import com.google.gerrit.server.account.ServiceUserClassifier;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.util.AttentionSetUtil;
import com.google.gerrit.server.util.LabelVote;
@@ -121,7 +121,7 @@ public class ChangeUpdate extends AbstractChangeUpdate {
private final ChangeDraftUpdate.Factory draftUpdateFactory;
private final RobotCommentUpdate.Factory robotCommentUpdateFactory;
private final DeleteCommentRewriter.Factory deleteCommentRewriterFactory;
private final RobotClassifier robotClassifier;
private final ServiceUserClassifier robotClassifier;
private final Table<String, Account.Id, Optional<Short>> approvals;
private final Map<Account.Id, ReviewerStateInternal> reviewers = new LinkedHashMap<>();
@@ -167,7 +167,7 @@ public class ChangeUpdate extends AbstractChangeUpdate {
RobotCommentUpdate.Factory robotCommentUpdateFactory,
DeleteCommentRewriter.Factory deleteCommentRewriterFactory,
ProjectCache projectCache,
RobotClassifier robotClassifier,
ServiceUserClassifier robotClassifier,
@Assisted ChangeNotes notes,
@Assisted CurrentUser user,
@Assisted Date when,
@@ -202,7 +202,7 @@ public class ChangeUpdate extends AbstractChangeUpdate {
ChangeDraftUpdate.Factory draftUpdateFactory,
RobotCommentUpdate.Factory robotCommentUpdateFactory,
DeleteCommentRewriter.Factory deleteCommentRewriterFactory,
RobotClassifier robotClassifier,
ServiceUserClassifier robotClassifier,
@Assisted ChangeNotes notes,
@Assisted CurrentUser user,
@Assisted Date when,
@@ -833,7 +833,7 @@ public class ChangeUpdate extends AbstractChangeUpdate {
}
if (attentionSetUpdate.operation() == AttentionSetUpdate.Operation.ADD
&& robotClassifier.isRobot(attentionSetUpdate.account())) {
&& robotClassifier.isServiceUser(attentionSetUpdate.account())) {
// Skip adding robots to the attention set.
continue;
}

View File

@@ -24,7 +24,7 @@ import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestCollectionModifyView;
import com.google.gerrit.server.account.AccountLoader;
import com.google.gerrit.server.account.AccountResolver;
import com.google.gerrit.server.account.RobotClassifier;
import com.google.gerrit.server.account.ServiceUserClassifier;
import com.google.gerrit.server.change.AddToAttentionSetOp;
import com.google.gerrit.server.change.AttentionSetEntryResource;
import com.google.gerrit.server.change.ChangeResource;
@@ -48,7 +48,7 @@ public class AddToAttentionSet
private final AccountLoader.Factory accountLoaderFactory;
private final PermissionBackend permissionBackend;
private final NotifyResolver notifyResolver;
private final RobotClassifier robotClassifier;
private final ServiceUserClassifier robotClassifier;
@Inject
AddToAttentionSet(
@@ -58,7 +58,7 @@ public class AddToAttentionSet
AccountLoader.Factory accountLoaderFactory,
PermissionBackend permissionBackend,
NotifyResolver notifyResolver,
RobotClassifier robotClassifier) {
ServiceUserClassifier robotClassifier) {
this.updateFactory = updateFactory;
this.accountResolver = accountResolver;
this.opFactory = opFactory;
@@ -74,7 +74,7 @@ public class AddToAttentionSet
AttentionSetUtil.validateInput(input);
Account.Id attentionUserId = accountResolver.resolve(input.user).asUnique().account().id();
if (robotClassifier.isRobot(attentionUserId)) {
if (robotClassifier.isServiceUser(attentionUserId)) {
throw new BadRequestException(
String.format(
"%s is a robot, and robots can't be added to the attention set.", input.user));

View File

@@ -26,7 +26,7 @@ import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.server.ApprovalsUtil;
import com.google.gerrit.server.account.AccountResolver;
import com.google.gerrit.server.account.RobotClassifier;
import com.google.gerrit.server.account.ServiceUserClassifier;
import com.google.gerrit.server.change.AddToAttentionSetOp;
import com.google.gerrit.server.change.AttentionSetUnchangedOp;
import com.google.gerrit.server.change.RemoveFromAttentionSetOp;
@@ -56,7 +56,7 @@ public class ReplyAttentionSetUpdates {
private final RemoveFromAttentionSetOp.Factory removeFromAttentionSetOpFactory;
private final ApprovalsUtil approvalsUtil;
private final AccountResolver accountResolver;
private final RobotClassifier robotClassifier;
private final ServiceUserClassifier robotClassifier;
@Inject
ReplyAttentionSetUpdates(
@@ -65,7 +65,7 @@ public class ReplyAttentionSetUpdates {
RemoveFromAttentionSetOp.Factory removeFromAttentionSetOpFactory,
ApprovalsUtil approvalsUtil,
AccountResolver accountResolver,
RobotClassifier robotClassifier) {
ServiceUserClassifier robotClassifier) {
this.permissionBackend = permissionBackend;
this.addToAttentionSetOpFactory = addToAttentionSetOpFactory;
this.removeFromAttentionSetOpFactory = removeFromAttentionSetOpFactory;
@@ -83,7 +83,7 @@ public class ReplyAttentionSetUpdates {
Account.Id currentUser)
throws IOException, ConfigInvalidException, PermissionBackendException,
UnprocessableEntityException {
if (robotClassifier.isRobot(currentUser)) {
if (robotClassifier.isServiceUser(currentUser)) {
return;
}
Set<Account.Id> potentiallyRemovedReviewerIds = new HashSet<>();
@@ -120,7 +120,7 @@ public class ReplyAttentionSetUpdates {
bu.addOp(changeNotes.getChangeId(), new AttentionSetUnchangedOp());
return;
}
if (robotClassifier.isRobot(currentUser)) {
if (robotClassifier.isServiceUser(currentUser)) {
botsWithNegativeLabelsAddOwnerAndUploader(bu, changeNotes, input);
return;
}

View File

@@ -157,7 +157,7 @@ public class AllProjectsCreator {
AccessSection.GLOBAL_CAPABILITIES,
capabilities -> {
input
.batchUsersGroup()
.serviceUsersGroup()
.ifPresent(
batchUsersGroup ->
initDefaultAclsForBatchUsers(capabilities, config, batchUsersGroup));

View File

@@ -63,7 +63,7 @@ public abstract class AllProjectsInput {
public abstract Optional<GroupReference> administratorsGroup();
/** The group which gets stream-events permission granted and appropriate properties set. */
public abstract Optional<GroupReference> batchUsersGroup();
public abstract Optional<GroupReference> serviceUsersGroup();
/** The commit message used when commit the project config change. */
public abstract Optional<String> commitMessage();
@@ -106,7 +106,7 @@ public abstract class AllProjectsInput {
public abstract static class Builder {
public abstract Builder administratorsGroup(GroupReference adminGroup);
public abstract Builder batchUsersGroup(GroupReference batchGroup);
public abstract Builder serviceUsersGroup(GroupReference serviceGroup);
public abstract Builder commitMessage(String commitMessage);

View File

@@ -19,6 +19,7 @@ import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.index.group.GroupIndexCollection;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -30,7 +31,7 @@ import org.eclipse.jgit.lib.PersonIdent;
* <p>Implementations must have a single non-private constructor with no arguments (e.g. the default
* constructor).
*/
interface NoteDbSchemaVersion {
public interface NoteDbSchemaVersion {
@Singleton
class Arguments {
final GitRepositoryManager repoManager;
@@ -39,6 +40,7 @@ interface NoteDbSchemaVersion {
final ProjectConfig.Factory projectConfigFactory;
final SystemGroupBackend systemGroupBackend;
final PersonIdent serverUser;
final GroupIndexCollection groupIndexCollection;
@Inject
Arguments(
@@ -47,13 +49,15 @@ interface NoteDbSchemaVersion {
AllUsersName allUsers,
ProjectConfig.Factory projectConfigFactory,
SystemGroupBackend systemGroupBackend,
@GerritPersonIdent PersonIdent serverUser) {
@GerritPersonIdent PersonIdent serverUser,
GroupIndexCollection groupIndexCollection) {
this.repoManager = repoManager;
this.allProjects = allProjects;
this.allUsers = allUsers;
this.projectConfigFactory = projectConfigFactory;
this.systemGroupBackend = systemGroupBackend;
this.serverUser = serverUser;
this.groupIndexCollection = groupIndexCollection;
}
}

View File

@@ -28,7 +28,12 @@ import java.util.stream.Stream;
public class NoteDbSchemaVersions {
static final ImmutableSortedMap<Integer, Class<? extends NoteDbSchemaVersion>> ALL =
// List all supported NoteDb schema versions here.
Stream.of(Schema_180.class, Schema_181.class, Schema_182.class, Schema_183.class)
Stream.of(
Schema_180.class,
Schema_181.class,
Schema_182.class,
Schema_183.class,
Schema_184.class)
.collect(toImmutableSortedMap(naturalOrder(), v -> guessVersion(v).get(), v -> v));
public static final int FIRST = ALL.firstKey();

View File

@@ -91,10 +91,13 @@ public class SchemaCreatorImpl implements SchemaCreator {
@Override
public void create() throws IOException, ConfigInvalidException {
GroupReference admins = createGroupReference("Administrators");
GroupReference batchUsers = createGroupReference("Non-Interactive Users");
GroupReference serviceUsers = createGroupReference("Service Users");
AllProjectsInput allProjectsInput =
AllProjectsInput.builder().administratorsGroup(admins).batchUsersGroup(batchUsers).build();
AllProjectsInput.builder()
.administratorsGroup(admins)
.serviceUsersGroup(serviceUsers)
.build();
allProjectsCreator.create(allProjectsInput);
// We have to create the All-Users repository before we can use it to store the groups in it.
allUsersCreator.setAdministrators(admins).create();
@@ -111,7 +114,7 @@ public class SchemaCreatorImpl implements SchemaCreator {
metricMaker);
try (Repository allUsersRepo = repoManager.openRepository(allUsersName)) {
createAdminsGroup(seqs, allUsersRepo, admins);
createBatchUsersGroup(seqs, allUsersRepo, batchUsers, admins.getUUID());
createBatchUsersGroup(seqs, allUsersRepo, serviceUsers, admins.getUUID());
}
}

View File

@@ -0,0 +1,117 @@
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.schema;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupReference;
import com.google.gerrit.git.RefUpdateUtil;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.db.AuditLogFormatter;
import com.google.gerrit.server.group.db.GroupConfig;
import com.google.gerrit.server.group.db.GroupNameNotes;
import com.google.gerrit.server.group.db.InternalGroupUpdate;
import com.google.gerrit.server.index.group.GroupIndex;
import com.google.gerrit.server.index.group.GroupIndexCollection;
import java.io.IOException;
import java.util.Optional;
import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
/**
* Schema 184 for Gerrit metadata.
*
* <p>Upgrading to this schema version will rename the {@code Non-Interactive Users} group to {@code
* Service Users}.
*/
public class Schema_184 implements NoteDbSchemaVersion {
@Override
public void upgrade(Arguments args, UpdateUI ui) throws Exception {
try (Repository allUsersRepo = args.repoManager.openRepository(args.allUsers)) {
AccountGroup.NameKey newName = AccountGroup.nameKey("Service Users");
Optional<GroupReference> nonInteractiveUsers =
GroupNameNotes.loadAllGroups(allUsersRepo).stream()
.filter(g -> g.getName().equals("Non-Interactive Users"))
.findAny();
if (!nonInteractiveUsers.isPresent()) {
return;
}
GroupNameNotes newNameNotes =
GroupNameNotes.forRename(
args.allUsers,
allUsersRepo,
nonInteractiveUsers.get().getUUID(),
AccountGroup.nameKey(nonInteractiveUsers.get().getName()),
newName);
GroupConfig groupConfig =
GroupConfig.loadForGroup(
args.allUsers, allUsersRepo, nonInteractiveUsers.get().getUUID());
groupConfig.setGroupUpdate(
InternalGroupUpdate.builder().setName(newName).build(),
AuditLogFormatter.createPartiallyWorkingFallBack());
commit(args.allUsers, args.serverUser, allUsersRepo, groupConfig, newNameNotes);
index(
args.groupIndexCollection,
groupConfig
.getLoadedGroup()
.orElseThrow(
() -> new IllegalStateException("Created group wasn't automatically loaded")));
}
}
private void commit(
AllUsersName allUsersName,
PersonIdent serverUser,
Repository allUsersRepo,
GroupConfig groupConfig,
GroupNameNotes groupNameNotes)
throws IOException {
BatchRefUpdate batchRefUpdate = allUsersRepo.getRefDatabase().newBatchUpdate();
try (MetaDataUpdate metaDataUpdate =
createMetaDataUpdate(allUsersName, serverUser, allUsersRepo, batchRefUpdate)) {
groupConfig.commit(metaDataUpdate);
}
// MetaDataUpdates unfortunately can't be reused. -> Create a new one.
try (MetaDataUpdate metaDataUpdate =
createMetaDataUpdate(allUsersName, serverUser, allUsersRepo, batchRefUpdate)) {
groupNameNotes.commit(metaDataUpdate);
}
RefUpdateUtil.executeChecked(batchRefUpdate, allUsersRepo);
}
private MetaDataUpdate createMetaDataUpdate(
AllUsersName allUsersName,
PersonIdent serverUser,
Repository allUsersRepo,
@Nullable BatchRefUpdate batchRefUpdate) {
MetaDataUpdate metaDataUpdate =
new MetaDataUpdate(
GitReferenceUpdated.DISABLED, allUsersName, allUsersRepo, batchRefUpdate);
metaDataUpdate.getCommitBuilder().setAuthor(serverUser);
metaDataUpdate.getCommitBuilder().setCommitter(serverUser);
return metaDataUpdate;
}
private void index(GroupIndexCollection indexCollection, InternalGroup group) {
for (GroupIndex groupIndex : indexCollection.getWriteIndexes()) {
groupIndex.replace(group);
}
}
}

View File

@@ -48,8 +48,8 @@ public class AllProjectsCreatorTestUtil {
ImmutableList.of(
"[capability]",
" administrateServer = group Administrators",
" priority = batch group Non-Interactive Users",
" streamEvents = group Non-Interactive Users");
" priority = batch group Service Users",
" streamEvents = group Service Users");
private static final ImmutableList<String> DEFAULT_ALL_PROJECTS_ACCESS_SECTION =
ImmutableList.of(
"[access \"refs/*\"]",

View File

@@ -916,7 +916,7 @@ public class GroupsIT extends AbstractDaemonTest {
@Test
public void defaultGroupsCreated() throws Exception {
Iterable<String> names = gApi.groups().list().getAsMap().keySet();
assertThat(names).containsAtLeast("Administrators", "Non-Interactive Users").inOrder();
assertThat(names).containsAtLeast("Administrators", "Service Users").inOrder();
}
@Test

View File

@@ -118,7 +118,7 @@ public class RefAdvertisementIT extends AbstractDaemonTest {
@Before
public void setUp() throws Exception {
admins = adminGroupUuid();
nonInteractiveUsers = groupUuid("Non-Interactive Users");
nonInteractiveUsers = groupUuid("Service Users");
setUpPermissions();
setUpChanges();
}

View File

@@ -17,6 +17,7 @@ acceptance_tests(
"//java/com/google/gerrit/index",
"//java/com/google/gerrit/index/project",
"//java/com/google/gerrit/server/schema",
"//lib/errorprone:annotations",
],
)

View File

@@ -0,0 +1,72 @@
// 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.acceptance.pgm;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.testsuite.group.GroupOperations;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.server.schema.NoteDbSchemaVersion;
import com.google.gerrit.server.schema.Schema_184;
import com.google.gerrit.testing.TestUpdateUI;
import com.google.inject.Inject;
import org.junit.Test;
public class Schema_184IT extends AbstractDaemonTest {
private static final AccountGroup.NameKey SERVICE_USERS = AccountGroup.nameKey("Service Users");
private static final AccountGroup.NameKey NON_INTERACTIVE_USERS =
AccountGroup.nameKey("Non-Interactive Users");
@Inject private GroupOperations groupOperations;
@Inject private NoteDbSchemaVersion.Arguments args;
@Test
public void groupGetsRenamed() throws Exception {
groupOperations
.group(groupCache.get(SERVICE_USERS).get().getGroupUUID())
.forUpdate()
.name(NON_INTERACTIVE_USERS.get())
.update();
assertThat(hasGroup(NON_INTERACTIVE_USERS)).isTrue();
Schema_184 upgrade = new Schema_184();
upgrade.upgrade(args, new TestUpdateUI());
assertThat(hasGroup(SERVICE_USERS)).isTrue();
assertThat(hasGroup(NON_INTERACTIVE_USERS)).isFalse();
}
@Test
public void upgradeIsIdempotent() throws Exception {
groupOperations
.group(groupCache.get(SERVICE_USERS).get().getGroupUUID())
.forUpdate()
.name(NON_INTERACTIVE_USERS.get())
.update();
Schema_184 upgrade = new Schema_184();
upgrade.upgrade(args, new TestUpdateUI());
upgrade.upgrade(args, new TestUpdateUI());
assertThat(hasGroup(SERVICE_USERS)).isTrue();
assertThat(hasGroup(NON_INTERACTIVE_USERS)).isFalse();
}
private boolean hasGroup(AccountGroup.NameKey key) {
// We have to evict here because the schema migration doesn't have the cache available.
// That's OK because that also means it won't cache an old state in production.
groupCache.evict(key);
return groupCache.get(key).isPresent();
}
}

View File

@@ -928,8 +928,7 @@ public class AttentionSetIT extends AbstractDaemonTest {
@Test
public void robotsNotAddedToAttentionSet() throws Exception {
TestAccount robot =
accountCreator.create(
"robot1", "robot1@example.com", "Ro Bot", "Ro", "Non-Interactive Users");
accountCreator.create("robot1", "robot1@example.com", "Ro Bot", "Ro", "Service Users");
PushOneCommit.Result r = createChange();
// Throw an error when adding a robot explicitly.
@@ -949,8 +948,7 @@ public class AttentionSetIT extends AbstractDaemonTest {
@Test
public void robotAddingAReviewerChangeAttentionSet() throws Exception {
TestAccount robot =
accountCreator.create(
"robot2", "robot2@example.com", "Ro Bot", "Ro", "Non-Interactive Users");
accountCreator.create("robot2", "robot2@example.com", "Ro Bot", "Ro", "Service Users");
PushOneCommit.Result r = createChange();
requestScopeOperations.setApiUser(robot.id());
change(r).addReviewer(user.id().toString());
@@ -966,8 +964,7 @@ public class AttentionSetIT extends AbstractDaemonTest {
@Test
public void robotReviewDoesNotChangeAttentionSet() throws Exception {
TestAccount robot =
accountCreator.create(
"robot2", "robot2@example.com", "Ro Bot", "Ro", "Non-Interactive Users");
accountCreator.create("robot2", "robot2@example.com", "Ro Bot", "Ro", "Service Users");
PushOneCommit.Result r = createChange();
requestScopeOperations.setApiUser(robot.id());
change(r).current().review(ReviewInput.recommend());
@@ -978,8 +975,7 @@ public class AttentionSetIT extends AbstractDaemonTest {
@Test
public void robotReviewWithNegativeLabelAddsOwner() throws Exception {
TestAccount robot =
accountCreator.create(
"robot2", "robot2@example.com", "Ro Bot", "Ro", "Non-Interactive Users");
accountCreator.create("robot2", "robot2@example.com", "Ro Bot", "Ro", "Service Users");
PushOneCommit.Result r = createChange();
requestScopeOperations.setApiUser(robot.id());
change(r).current().review(ReviewInput.dislike());
@@ -994,8 +990,7 @@ public class AttentionSetIT extends AbstractDaemonTest {
@Test
public void robotCanChangeAttentionSetExplicitly() throws Exception {
TestAccount robot =
accountCreator.create(
"robot2", "robot2@example.com", "Ro Bot", "Ro", "Non-Interactive Users");
accountCreator.create("robot2", "robot2@example.com", "Ro Bot", "Ro", "Service Users");
PushOneCommit.Result r = createChange();
requestScopeOperations.setApiUser(robot.id());
change(r).current().review(new ReviewInput().addUserToAttentionSet(admin.email(), "reason"));

View File

@@ -32,6 +32,6 @@ public class ListGroupsIT extends AbstractDaemonTest {
Map<String, GroupInfo> groupMap =
newGson()
.fromJson(response.getReader(), new TypeToken<Map<String, GroupInfo>>() {}.getType());
assertThat(groupMap.keySet()).containsExactly("Administrators", "Non-Interactive Users");
assertThat(groupMap.keySet()).containsExactly("Administrators", "Service Users");
}
}

View File

@@ -38,7 +38,7 @@ import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.FakeRealm;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.Realm;
import com.google.gerrit.server.account.RobotClassifier;
import com.google.gerrit.server.account.ServiceUserClassifier;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.gerrit.server.config.AnonymousCowardName;
@@ -166,7 +166,7 @@ public abstract class AbstractChangeNotesTest {
bind(ExecutorService.class)
.annotatedWith(FanOutExecutor.class)
.toInstance(assertableFanOutExecutor);
bind(RobotClassifier.class).to(RobotClassifier.NoOp.class);
bind(ServiceUserClassifier.class).to(ServiceUserClassifier.NoOp.class);
}
});

View File

@@ -39,7 +39,7 @@ public class GroupListTest {
private static final String TEXT =
"# UUID \tGroup Name\n"
+ "#\n"
+ "d96b998f8a66ff433af50befb975d0e2bb6e0999\tNon-Interactive Users\n"
+ "d96b998f8a66ff433af50befb975d0e2bb6e0999\tService Users\n"
+ "ebe31c01aec2c9ac3b3c03e87a47450829ff4310\tAdministrators\n";
private GroupList groupList;
@@ -57,7 +57,7 @@ public class GroupListTest {
GroupReference groupReference = groupList.byUUID(uuid);
assertEquals(uuid, groupReference.getUUID());
assertEquals("Non-Interactive Users", groupReference.getName());
assertEquals("Service Users", groupReference.getName());
}
@Test

View File

@@ -88,11 +88,11 @@ public class AllProjectsCreatorTest {
expectedConfig.fromText(getDefaultAllProjectsWithAllDefaultSections());
GroupReference adminsGroup = createGroupReference("Administrators");
GroupReference batchUsersGroup = createGroupReference("Non-Interactive Users");
GroupReference batchUsersGroup = createGroupReference("Service Users");
AllProjectsInput allProjectsInput =
AllProjectsInput.builder()
.administratorsGroup(adminsGroup)
.batchUsersGroup(batchUsersGroup)
.serviceUsersGroup(batchUsersGroup)
.build();
allProjectsCreator.create(allProjectsInput);

View File

@@ -94,7 +94,7 @@ public class NoteDbSchemaUpdaterTest {
args =
new NoteDbSchemaVersion.Arguments(
repoManager, allProjectsName, allUsersName, null, null, null);
repoManager, allProjectsName, allUsersName, null, null, null, null);
NoteDbSchemaVersionManager versionManager =
new NoteDbSchemaVersionManager(allProjectsName, repoManager);
updater =

View File

@@ -18,12 +18,15 @@ import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.entities.GroupReference;
import com.google.gerrit.entities.LabelFunction;
import com.google.gerrit.entities.LabelType;
import com.google.gerrit.entities.LabelTypes;
import com.google.gerrit.entities.LabelValue;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.group.db.GroupNameNotes;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.gerrit.testing.InMemoryModule;
import com.google.inject.Inject;
@@ -37,12 +40,11 @@ import org.junit.Test;
public class SchemaCreatorImplTest {
@Inject private AllProjectsName allProjects;
@Inject private GitRepositoryManager repoManager;
@Inject private SchemaCreator schemaCreator;
@Inject private ProjectConfig.Factory projectConfigFactory;
@Inject private GitRepositoryManager repositoryManager;
@Inject private AllUsersName allUsersName;
@Before
public void setUp() throws Exception {
@@ -78,6 +80,12 @@ public class SchemaCreatorImplTest {
assertValueRange(codeReview, -2, -1, 0, 1, 2);
}
@Test
public void groupIsCreatedWhenSchemaIsCreated() throws Exception {
assertThat(hasGroup("Service Users")).isTrue();
assertThat(hasGroup("Non-Interactive Users")).isFalse();
}
private void assertValueRange(LabelType label, Integer... range) {
List<Integer> rangeList = Arrays.asList(range);
assertThat(rangeList).isNotEmpty();
@@ -93,4 +101,11 @@ public class SchemaCreatorImplTest {
assertThat(v.getText()).isNotEmpty();
}
}
private boolean hasGroup(String name) throws Exception {
try (Repository repo = repositoryManager.openRepository(allUsersName)) {
List<GroupReference> nameNotes = GroupNameNotes.loadAllGroups(repo);
return nameNotes.stream().anyMatch(g -> g.getName().equals(name));
}
}
}