diff --git a/Documentation/rest-api-groups.txt b/Documentation/rest-api-groups.txt index a99c3bb772..5086e190ab 100644 --- a/Documentation/rest-api-groups.txt +++ b/Documentation/rest-api-groups.txt @@ -503,8 +503,9 @@ describes the created group. } ---- -If the group creation fails because the name is already in use the -response is "`409 Conflict`". +If the group creation fails because the name is already in use, or the +UUID was specified and the UUID is already in use, the response is +"`409 Conflict`". [[get-group-detail]] === Get Group Detail @@ -1591,6 +1592,7 @@ a new internal group. |Field Name ||Description |`name` |optional|The name of the group (not encoded). + If set, must match the group name in the URL. +|`uuid` |optional|The UUID of the group. |`description` |optional|The description of the group. |`visible_to_all`|optional| Whether the group is visible to all registered users. + diff --git a/java/com/google/gerrit/extensions/api/groups/GroupInput.java b/java/com/google/gerrit/extensions/api/groups/GroupInput.java index ab38434168..30af08fb5a 100644 --- a/java/com/google/gerrit/extensions/api/groups/GroupInput.java +++ b/java/com/google/gerrit/extensions/api/groups/GroupInput.java @@ -18,6 +18,7 @@ import java.util.List; public class GroupInput { public String name; + public String uuid; public String description; public Boolean visibleToAll; public String ownerId; diff --git a/java/com/google/gerrit/server/account/CreateGroupArgs.java b/java/com/google/gerrit/server/account/CreateGroupArgs.java index 2c59a08350..2a764ccd6d 100644 --- a/java/com/google/gerrit/server/account/CreateGroupArgs.java +++ b/java/com/google/gerrit/server/account/CreateGroupArgs.java @@ -20,6 +20,7 @@ import java.util.Collection; public class CreateGroupArgs { private AccountGroup.NameKey groupName; + public AccountGroup.UUID uuid; public String groupDescription; public boolean visibleToAll; public AccountGroup.UUID ownerGroupUuid; diff --git a/java/com/google/gerrit/server/restapi/group/CreateGroup.java b/java/com/google/gerrit/server/restapi/group/CreateGroup.java index 531d350713..e5a1478b51 100644 --- a/java/com/google/gerrit/server/restapi/group/CreateGroup.java +++ b/java/com/google/gerrit/server/restapi/group/CreateGroup.java @@ -138,6 +138,16 @@ public class CreateGroup AccountGroup.UUID ownerUuid = owner(input); CreateGroupArgs args = new CreateGroupArgs(); args.setGroupName(name); + args.uuid = Strings.isNullOrEmpty(input.uuid) ? null : AccountGroup.UUID.parse(input.uuid); + if (args.uuid != null) { + if (!args.uuid.isInternalGroup()) { + throw new BadRequestException(String.format("invalid group UUID '%s'", args.uuid.get())); + } + if (groupCache.get(args.uuid).isPresent()) { + throw new ResourceConflictException( + String.format("group with UUID '%s' already exists", args.uuid.get())); + } + } args.groupDescription = Strings.emptyToNull(input.description); args.visibleToAll = MoreObjects.firstNonNull(input.visibleToAll, defaultVisibleToAll); args.ownerGroupUuid = ownerUuid; @@ -196,9 +206,11 @@ public class CreateGroup AccountGroup.Id groupId = AccountGroup.id(sequences.nextGroupId()); AccountGroup.UUID uuid = - GroupUuid.make( - createGroupArgs.getGroupName(), - self.get().newCommitterIdent(serverIdent.getWhen(), serverIdent.getTimeZone())); + MoreObjects.firstNonNull( + createGroupArgs.uuid, + GroupUuid.make( + createGroupArgs.getGroupName(), + self.get().newCommitterIdent(serverIdent.getWhen(), serverIdent.getTimeZone()))); InternalGroupCreation groupCreation = InternalGroupCreation.builder() .setGroupUUID(uuid) diff --git a/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java b/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java index 988580e399..17a0ea61b0 100644 --- a/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java +++ b/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java @@ -414,6 +414,43 @@ public class GroupsIT extends AbstractDaemonTest { assertThat(thrown).hasMessageThat().contains("group name 'Anonymous Users' is reserved"); } + @Test + public void createGroupWithUuid() throws Exception { + AccountGroup.UUID uuid = AccountGroup.UUID.parse("4eb25d1cca562f53b9356117f33840706a36a349"); + GroupInput input = new GroupInput(); + input.uuid = uuid.get(); + input.name = name("new-group"); + GroupInfo info = gApi.groups().create(input).get(); + assertThat(info.name).isEqualTo(input.name); + assertThat(info.id).isEqualTo(input.uuid); + } + + @Test + public void createGroupWithExistingUuid_Conflict() throws Exception { + GroupInfo existingGroup = gApi.groups().create(name("new-group")).get(); + GroupInput input = new GroupInput(); + input.uuid = existingGroup.id; + input.name = name("another-new-group"); + ResourceConflictException thrown = + assertThrows(ResourceConflictException.class, () -> gApi.groups().create(input).get()); + assertThat(thrown) + .hasMessageThat() + .isEqualTo(String.format("group with UUID '%s' already exists", input.uuid)); + } + + @Test + public void createGroupWithInvalidUuid_BadRequest() throws Exception { + AccountGroup.UUID uuid = AccountGroup.UUID.parse("foo:bar"); + GroupInput input = new GroupInput(); + input.uuid = uuid.get(); + input.name = name("new-group"); + BadRequestException thrown = + assertThrows(BadRequestException.class, () -> gApi.groups().create(input).get()); + assertThat(thrown) + .hasMessageThat() + .isEqualTo(String.format("invalid group UUID '%s'", input.uuid)); + } + @Test public void createGroupWithProperties() throws Exception { GroupInput in = new GroupInput();