Add new extension point for clone commands

The clone commands can be retrieved via REST from the
/config/server/info endpoint.

Bug: Issue 2208
Change-Id: I1a6bcc8eeea38ca30061bb380266e3b5cf7d3515
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
Edwin Kempin 2015-05-11 15:40:44 +02:00
parent 2d099cc046
commit eafde882be
5 changed files with 84 additions and 12 deletions

View File

@ -1767,15 +1767,17 @@ discover and bind the implementation.
[[download-commands]]
== Download Commands
Gerrit offers commands for downloading changes using different
download schemes (e.g. for downloading via different network
protocols). Plugins can contribute download schemes and download
commands by implementing
`com.google.gerrit.extensions.config.DownloadScheme` and
`com.google.gerrit.extensions.config.DownloadCommand`.
Gerrit offers commands for downloading changes and cloning projects
using different download schemes (e.g. for downloading via different
network protocols). Plugins can contribute download schemes, download
commands and clone commands by implementing
`com.google.gerrit.extensions.config.DownloadScheme`,
`com.google.gerrit.extensions.config.DownloadCommand` and
`com.google.gerrit.extensions.config.CloneCommand`.
The download schemes and download commands which are used most often
are provided by the Gerrit core plugin `download-commands`.
The download schemes, download commands and clone commands which are
used most often are provided by the Gerrit core plugin
`download-commands`.
[[included-in]]
== Included In

View File

@ -68,6 +68,10 @@ As result a link:#server-info[ServerInfo] entity is returned.
"Format Patch": "git fetch http://gerrithost:8080/${project} ${ref} \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD",
"Pull": "git pull http://gerrithost:8080/${project} ${ref}",
"Cherry Pick": "git fetch http://gerrithost:8080/${project} ${ref} \u0026\u0026 git cherry-pick FETCH_HEAD"
},
"clone_commands": {
"Clone": "git clone http://gerrithost:8080/${project}"
"Clone with commit-msg hook": "git clone http://gerrithost:8080/${project} \u0026\u0026 scp -p -P 29418 jdoe@gerrithost:hooks/commit-msg ${project}/.git/hooks/"
}
},
"http": {
@ -79,6 +83,10 @@ As result a link:#server-info[ServerInfo] entity is returned.
"Format Patch": "git fetch http://jdoe@gerrithost:8080/${project} ${ref} \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD",
"Pull": "git pull http://jdoe@gerrithost:8080/${project} ${ref}",
"Cherry Pick": "git fetch http://jdoe@gerrithost:8080/${project} ${ref} \u0026\u0026 git cherry-pick FETCH_HEAD"
},
"clone_commands": {
"Clone": "git clone http://jdoe@gerrithost:8080/${project}",
"Clone with commit-msg hook": "git clone http://jdoe@gerrithost:8080/${project} \u0026\u0026 scp -p -P 29418 jdoe@gerrithost:hooks/commit-msg ${project}/.git/hooks/"
}
},
"ssh": {
@ -90,6 +98,10 @@ As result a link:#server-info[ServerInfo] entity is returned.
"Format Patch": "git fetch ssh://jdoe@gerrithost:29418/${project} ${ref} \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD",
"Pull": "git pull ssh://jdoe@gerrithost:29418/${project} ${ref}",
"Cherry Pick": "git fetch ssh://jdoe@gerrithost:29418/${project} ${ref} \u0026\u0026 git cherry-pick FETCH_HEAD"
},
"clone_commands": {
"Clone": "git clone ssh://jdoe@gerrithost:29418/${project}",
"Clone with commit-msg hook": "git clone ssh://jdoe@gerrithost:29418/${project} \u0026\u0026 scp -p -P 29418 jdoe@gerrithost:hooks/commit-msg ${project}/.git/hooks/"
}
}
],
@ -1090,6 +1102,13 @@ command. In the download command '${project}' is used as
placeholder for the project name, and '${ref}' is used as
placeholder for the (change) ref.
Empty, if accessed anonymously and the download scheme requires
authentication.
|`clone_commands` ||
Clone commands as a map which maps the command name to the clone
command. In the clone command '${project}' is used as
placeholder for the project name.
Empty, if accessed anonymously and the download scheme requires
authentication.
|=================================

View File

@ -0,0 +1,30 @@
// Copyright (C) 2015 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.extensions.config;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
@ExtensionPoint
public abstract class CloneCommand {
/**
* Returns the clone command for the given download scheme and project.
*
* @param scheme the download scheme for which the command should be returned
* @param project the name of the project for which the clone command
* should be returned
* @return the clone command
*/
public abstract String getCommand(DownloadScheme scheme, String project);
}

View File

@ -20,6 +20,7 @@ import com.google.common.cache.Cache;
import com.google.gerrit.audit.AuditModule;
import com.google.gerrit.common.EventListener;
import com.google.gerrit.extensions.config.CapabilityDefinition;
import com.google.gerrit.extensions.config.CloneCommand;
import com.google.gerrit.extensions.config.DownloadCommand;
import com.google.gerrit.extensions.config.DownloadScheme;
import com.google.gerrit.extensions.config.ExternalIncludedIn;
@ -276,6 +277,7 @@ public class GerritGlobalModule extends FactoryModule {
DynamicSet.setOf(binder(), MessageOfTheDay.class);
DynamicMap.mapOf(binder(), DownloadScheme.class);
DynamicMap.mapOf(binder(), DownloadCommand.class);
DynamicMap.mapOf(binder(), CloneCommand.class);
DynamicMap.mapOf(binder(), ExternalIncludedIn.class);
DynamicMap.mapOf(binder(), ProjectConfigEntry.class);
DynamicSet.setOf(binder(), PatchSetWebLink.class);

View File

@ -19,6 +19,7 @@ import com.google.common.base.Optional;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.gerrit.common.data.GitWebType;
import com.google.gerrit.extensions.config.CloneCommand;
import com.google.gerrit.extensions.config.DownloadCommand;
import com.google.gerrit.extensions.config.DownloadScheme;
import com.google.gerrit.extensions.registration.DynamicMap;
@ -45,6 +46,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
private final Realm realm;
private final DynamicMap<DownloadScheme> downloadSchemes;
private final DynamicMap<DownloadCommand> downloadCommands;
private final DynamicMap<CloneCommand> cloneCommands;
private final GetArchive.AllowedFormats archiveFormats;
private final AllProjectsName allProjectsName;
private final AllUsersName allUsersName;
@ -58,6 +60,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
Realm realm,
DynamicMap<DownloadScheme> downloadSchemes,
DynamicMap<DownloadCommand> downloadCommands,
DynamicMap<CloneCommand> cloneCommands,
GetArchive.AllowedFormats archiveFormats,
AllProjectsName allProjectsName,
AllUsersName allUsersName,
@ -68,6 +71,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
this.realm = realm;
this.downloadSchemes = downloadSchemes;
this.downloadCommands = downloadCommands;
this.cloneCommands = cloneCommands;
this.archiveFormats = archiveFormats;
this.allProjectsName = allProjectsName;
this.allUsersName = allUsersName;
@ -82,7 +86,8 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
info.change = getChangeInfo(config);
info.contactStore = getContactStoreInfo();
info.download =
getDownloadInfo(downloadSchemes, downloadCommands, archiveFormats);
getDownloadInfo(downloadSchemes, downloadCommands, cloneCommands,
archiveFormats);
info.gerrit = getGerritInfo(config, allProjectsName, allUsersName);
info.gitWeb = getGitWebInfo(gitWebConfig);
info.suggest = getSuggestInfo(config);
@ -155,8 +160,10 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
return contactStore;
}
private DownloadInfo getDownloadInfo(DynamicMap<DownloadScheme> downloadSchemes,
private DownloadInfo getDownloadInfo(
DynamicMap<DownloadScheme> downloadSchemes,
DynamicMap<DownloadCommand> downloadCommands,
DynamicMap<CloneCommand> cloneCommands,
GetArchive.AllowedFormats archiveFormats) {
DownloadInfo info = new DownloadInfo();
info.schemes = new HashMap<>();
@ -164,7 +171,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
DownloadScheme scheme = e.getProvider().get();
if (scheme.isEnabled() && scheme.getUrl("${project}") != null) {
info.schemes.put(e.getExportName(),
getDownloadSchemeInfo(scheme, downloadCommands));
getDownloadSchemeInfo(scheme, downloadCommands, cloneCommands));
}
}
info.archives = Lists.newArrayList(Iterables.transform(
@ -179,7 +186,8 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
}
private DownloadSchemeInfo getDownloadSchemeInfo(DownloadScheme scheme,
DynamicMap<DownloadCommand> downloadCommands) {
DynamicMap<DownloadCommand> downloadCommands,
DynamicMap<CloneCommand> cloneCommands) {
DownloadSchemeInfo info = new DownloadSchemeInfo();
info.url = scheme.getUrl("${project}");
info.isAuthRequired = toBoolean(scheme.isAuthRequired());
@ -195,6 +203,16 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
}
}
info.cloneCommands = new HashMap<>();
for (DynamicMap.Entry<CloneCommand> e : cloneCommands) {
String commandName = e.getExportName();
CloneCommand command = e.getProvider().get();
String c = command.getCommand(scheme, "${project}");
if (c != null) {
info.cloneCommands.put(commandName, c);
}
}
return info;
}
@ -282,6 +300,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
public Boolean isAuthRequired;
public Boolean isAuthSupported;
public Map<String, String> commands;
public Map<String, String> cloneCommands;
}
public static class GerritInfo {