diff --git a/Documentation/cmd-index.txt b/Documentation/cmd-index.txt index edb54b5ccb..c991a2ab45 100644 --- a/Documentation/cmd-index.txt +++ b/Documentation/cmd-index.txt @@ -178,6 +178,9 @@ link:cmd-reload-config.html[gerrit reload-config]:: link:cmd-set-account.html[gerrit set-account]:: Change an account's settings. +link:cmd-sequence-show.html[gerrit sequence show]:: + Display current sequence value. + link:cmd-set-members.html[gerrit set-members]:: Set group members. diff --git a/Documentation/cmd-sequence-show.txt b/Documentation/cmd-sequence-show.txt new file mode 100644 index 0000000000..a3ec02e4aa --- /dev/null +++ b/Documentation/cmd-sequence-show.txt @@ -0,0 +1,48 @@ += gerrit sequence show + +== NAME +gerrit sequence show - Display current sequence value. + +== SYNOPSIS +[verse] +-- +_ssh_ -p _gerrit sequence show_ +-- + +== DESCRIPTION +Gerrit maintains the generation of the next available sequence numbers for +account, group and change entities. The sequences are stored as UTF-8 text in +a blob pointed to by the `refs/sequences/accounts`, `refs/sequences/groups` +and `refs/sequences/changes` refs. Those refs are stored in `All-Users` and +`All-Projects` git repositories correspondingly. + +This command allows to display the current sequence value for those sequences. + +== ACCESS +Caller must be a member of the privileged 'Administrators' group. + +== SCRIPTING +This command is intended to be used in scripts. + +== OPTIONS +:: + Sequence name to show the current value for. + Currently supported values: + * accounts + * groups + * changes + +== EXAMPLES +Display the current value for the 'changes' sequence: + +---- +$ ssh -p 29418 review.example.com gerrit sequence show changes +42 +---- + +GERRIT +------ +Part of link:index.html[Gerrit Code Review] + +SEARCHBOX +--------- diff --git a/java/com/google/gerrit/httpd/init/WebAppInitializer.java b/java/com/google/gerrit/httpd/init/WebAppInitializer.java index 952c509878..9b39a2deab 100644 --- a/java/com/google/gerrit/httpd/init/WebAppInitializer.java +++ b/java/com/google/gerrit/httpd/init/WebAppInitializer.java @@ -99,6 +99,7 @@ import com.google.gerrit.sshd.SshKeyCacheImpl; import com.google.gerrit.sshd.SshModule; import com.google.gerrit.sshd.commands.DefaultCommandModule; import com.google.gerrit.sshd.commands.IndexCommandsModule; +import com.google.gerrit.sshd.commands.SequenceCommandsModule; import com.google.gerrit.sshd.plugin.LfsPluginAuthCommand; import com.google.inject.AbstractModule; import com.google.inject.CreationException; @@ -372,6 +373,7 @@ public class WebAppInitializer extends GuiceServletContextListener implements Fi sysInjector.getInstance(DownloadConfig.class), sysInjector.getInstance(LfsPluginAuthCommand.Module.class))); modules.add(new IndexCommandsModule(sysInjector)); + modules.add(new SequenceCommandsModule()); return sysInjector.createChildInjector(modules); } diff --git a/java/com/google/gerrit/pgm/Daemon.java b/java/com/google/gerrit/pgm/Daemon.java index e6860c2cd5..568fb6084e 100644 --- a/java/com/google/gerrit/pgm/Daemon.java +++ b/java/com/google/gerrit/pgm/Daemon.java @@ -109,6 +109,7 @@ import com.google.gerrit.sshd.SshKeyCacheImpl; import com.google.gerrit.sshd.SshModule; import com.google.gerrit.sshd.commands.DefaultCommandModule; import com.google.gerrit.sshd.commands.IndexCommandsModule; +import com.google.gerrit.sshd.commands.SequenceCommandsModule; import com.google.gerrit.sshd.plugin.LfsPluginAuthCommand; import com.google.inject.AbstractModule; import com.google.inject.Guice; @@ -517,6 +518,7 @@ public class Daemon extends SiteProgram { sysInjector.getInstance(LfsPluginAuthCommand.Module.class))); if (!replica) { modules.add(new IndexCommandsModule(sysInjector)); + modules.add(new SequenceCommandsModule()); } return sysInjector.createChildInjector(modules); } diff --git a/java/com/google/gerrit/server/notedb/RepoSequence.java b/java/com/google/gerrit/server/notedb/RepoSequence.java index 8096f89431..27aefb998d 100644 --- a/java/com/google/gerrit/server/notedb/RepoSequence.java +++ b/java/com/google/gerrit/server/notedb/RepoSequence.java @@ -291,4 +291,23 @@ public class RepoSequence { ObjectId newId = ins.insert(OBJ_BLOB, Integer.toString(val).getBytes(UTF_8)); return new ReceiveCommand(ObjectId.zeroId(), newId, RefNames.REFS_SEQUENCES + name); } + + public int current() { + counterLock.lock(); + try (Repository repo = repoManager.openRepository(projectName); + RevWalk rw = new RevWalk(repo)) { + Optional blob = IntBlob.parse(repo, refName, rw); + int current; + if (!blob.isPresent()) { + current = seed.get(); + } else { + current = blob.get().value(); + } + return current; + } catch (IOException e) { + throw new StorageException(e); + } finally { + counterLock.unlock(); + } + } } diff --git a/java/com/google/gerrit/server/notedb/Sequences.java b/java/com/google/gerrit/server/notedb/Sequences.java index 73cc600311..b89064d0b7 100644 --- a/java/com/google/gerrit/server/notedb/Sequences.java +++ b/java/com/google/gerrit/server/notedb/Sequences.java @@ -128,4 +128,16 @@ public class Sequences { return groupSeq.next(); } } + + public int currentChangeId() { + return changeSeq.current(); + } + + public int currentAccountId() { + return accountSeq.current(); + } + + public int currentGroupId() { + return groupSeq.current(); + } } diff --git a/java/com/google/gerrit/sshd/commands/SequenceCommandsModule.java b/java/com/google/gerrit/sshd/commands/SequenceCommandsModule.java new file mode 100644 index 0000000000..7f78f4aa5f --- /dev/null +++ b/java/com/google/gerrit/sshd/commands/SequenceCommandsModule.java @@ -0,0 +1,31 @@ +// Copyright (C) 2019 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.sshd.commands; + +import com.google.gerrit.sshd.CommandModule; +import com.google.gerrit.sshd.CommandName; +import com.google.gerrit.sshd.Commands; +import com.google.gerrit.sshd.DispatchCommandProvider; + +public class SequenceCommandsModule extends CommandModule { + + @Override + protected void configure() { + CommandName gerrit = Commands.named("gerrit"); + CommandName sequence = Commands.named(gerrit, "sequence"); + command(sequence).toProvider(new DispatchCommandProvider(sequence)); + command(sequence, SequenceShowCommand.class); + } +} diff --git a/java/com/google/gerrit/sshd/commands/SequenceShowCommand.java b/java/com/google/gerrit/sshd/commands/SequenceShowCommand.java new file mode 100644 index 0000000000..490c7ca8ff --- /dev/null +++ b/java/com/google/gerrit/sshd/commands/SequenceShowCommand.java @@ -0,0 +1,54 @@ +// Copyright (C) 2019 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.sshd.commands; + +import com.google.gerrit.common.data.GlobalCapability; +import com.google.gerrit.extensions.annotations.RequiresCapability; +import com.google.gerrit.server.notedb.Sequences; +import com.google.gerrit.sshd.CommandMetaData; +import com.google.gerrit.sshd.SshCommand; +import com.google.inject.Inject; +import org.kohsuke.args4j.Argument; + +/** Display sequence value. */ +@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER) +@CommandMetaData(name = "show", description = "Display the sequence value") +final class SequenceShowCommand extends SshCommand { + @Argument(index = 0, metaVar = "NAME", required = true, usage = "sequence name") + private String name; + + @Inject Sequences sequences; + + @Override + public void run() throws Exception { + int current; + switch (name) { + case "changes": + current = sequences.currentChangeId(); + break; + case "accounts": + current = sequences.currentAccountId(); + break; + case "groups": + current = sequences.currentGroupId(); + break; + default: + throw die("Unknown sequence name: " + name); + } + stdout.print(current); + stdout.print('\n'); + stdout.flush(); + } +} diff --git a/javatests/com/google/gerrit/acceptance/ssh/SshCommandsIT.java b/javatests/com/google/gerrit/acceptance/ssh/SshCommandsIT.java index 4e9c4a49e9..f43b5bf2e3 100644 --- a/javatests/com/google/gerrit/acceptance/ssh/SshCommandsIT.java +++ b/javatests/com/google/gerrit/acceptance/ssh/SshCommandsIT.java @@ -67,6 +67,7 @@ public class SshCommandsIT extends AbstractDaemonTest { "receive-pack", "rename-group", "review", + "sequence", "set-account", "set-head", "set-members", @@ -96,6 +97,7 @@ public class SshCommandsIT extends AbstractDaemonTest { "gerrit plugin", ImmutableList.of("add", "enable", "install", "ls", "reload", "remove", "rm")) .put("gerrit test-submit", ImmutableList.of("rule", "type")) + .put("gerrit sequence", ImmutableList.of("show")) .build(); private static final ImmutableMap> SLAVE_COMMANDS =