Add support for branching operation
Change-Id: Ic129697f86646c6e965d019eaee1423cc8136d71
diff --git a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/BranchManifest.java b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/BranchManifest.java
new file mode 100644
index 0000000..68e772d
--- /dev/null
+++ b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/BranchManifest.java
@@ -0,0 +1,92 @@
+// Copyright (C) 2015 Advanced Micro Devices, Inc. All rights reserved.
+//
+// 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.amd.gerrit.plugins.manifestsubscription;
+
+import com.amd.gerrit.plugins.manifestsubscription.manifest.Manifest;
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.extensions.annotations.RequiresCapability;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.sshd.CommandMetaData;
+import com.google.gerrit.sshd.SshCommand;
+import com.google.inject.Inject;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.kohsuke.args4j.Option;
+
+import javax.xml.bind.JAXBException;
+import java.io.IOException;
+
+@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
+@CommandMetaData(name = "branch", description = "branch all projects described in a manifest on the server")
+public class BranchManifest extends SshCommand {
+
+ @Inject
+ private GitRepositoryManager gitRepoManager;
+
+ @Option(name = "-r", aliases = {"--manifest-repo"},
+ usage = "", required = true)
+ private String manifestRepo;
+
+ @Option(name = "-c", aliases = {"--manifest-commit-ish"},
+ usage = "", required = true)
+ private String manifestCommitish;
+
+ @Option(name = "-p", aliases = {"--manifest-path"},
+ usage = "", required = true)
+ private String manifestPath;
+
+ @Option(name = "-b", aliases = {"--new-branch"},
+ usage = "", required = true)
+ private String newBranch;
+
+ @Override
+ protected void run() {
+ stdout.println("Branching manifest:");
+ stdout.println(manifestRepo);
+ stdout.println(manifestCommitish);
+ stdout.println(manifestPath);
+
+
+ Project.NameKey p = new Project.NameKey(manifestRepo);
+ try {
+ Repository repo = gitRepoManager.openRepository(p);
+ ObjectId commitId = repo.resolve(manifestCommitish);
+ VersionedManifests vManifests = new VersionedManifests(manifestCommitish);
+ vManifests.load(repo, commitId);
+ CanonicalManifest manifests = new CanonicalManifest(vManifests);
+
+ Manifest manifest = manifests.getCanonicalManifest(manifestPath);
+
+ stdout.println("");
+ stdout.println("Branch '" + newBranch +
+ "' will be created for the following projects:");
+ for (com.amd.gerrit.plugins.manifestsubscription.manifest.Project proj :
+ manifest.getProject()) {
+ stdout.print(proj.getRevision());
+ stdout.print("\t");
+ stdout.println(proj.getName());
+ }
+
+ VersionedManifests.branchManifest(gitRepoManager, manifest, newBranch);
+
+ } catch (IOException | ConfigInvalidException | ManifestReadException |
+ JAXBException | GitAPIException e) {
+ e.printStackTrace(stderr);
+ }
+ }
+}
diff --git a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/ManifestOp.java b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/ManifestOp.java
index d6fbe5d..dd3ba05 100644
--- a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/ManifestOp.java
+++ b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/ManifestOp.java
@@ -2,8 +2,16 @@
import com.amd.gerrit.plugins.manifestsubscription.manifest.Project;
import com.google.gerrit.server.git.GitRepositoryManager;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.InvalidRefNameException;
+import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
+import org.eclipse.jgit.api.errors.RefNotFoundException;
+
+import java.io.IOException;
public interface ManifestOp {
boolean apply(Project project, String hash, String name,
- GitRepositoryManager gitRepoManager);
+ GitRepositoryManager gitRepoManager) throws
+ RefAlreadyExistsException, InvalidRefNameException,
+ RefNotFoundException, GitAPIException, IOException;
}
diff --git a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/ManifestSubscription.java b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/ManifestSubscription.java
index 1dbf190..9899c9c 100644
--- a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/ManifestSubscription.java
+++ b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/ManifestSubscription.java
@@ -22,12 +22,12 @@
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.project.ProjectCache;
import com.google.inject.Inject;
+import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
@@ -281,7 +281,7 @@
updateManifest(store, STORE_BRANCH_PREFIX + bp,
manifest, projectName);
- } catch (ManifestReadException e) {
+ } catch (ManifestReadException | GitAPIException e) {
e.printStackTrace();
}
diff --git a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/SshModule.java b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/SshModule.java
index b0940eb..c3363cb 100644
--- a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/SshModule.java
+++ b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/SshModule.java
@@ -20,5 +20,6 @@
@Override
protected void configureCommands() {
command(ShowSubscription.class);
+ command(BranchManifest.class);
}
}
diff --git a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/VersionedManifests.java b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/VersionedManifests.java
index d8e571d..91ffa7c 100644
--- a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/VersionedManifests.java
+++ b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/VersionedManifests.java
@@ -21,6 +21,11 @@
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.VersionedMetaData;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.InvalidRefNameException;
+import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
+import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.PersonIdent;
@@ -202,6 +207,40 @@
saveFile(path, output.toByteArray());
}
+ static void branchManifest(GitRepositoryManager gitRepoManager,
+ Manifest manifest,
+ final String branch)
+ throws GitAPIException, IOException {
+ Table<String, String, String> lookup = HashBasedTable.create();
+ String defaultRef = null;
+
+ if (manifest.getDefault() != null) {
+ defaultRef = manifest.getDefault().getRevision();
+ }
+
+ ManifestOp op = new ManifestOp() {
+ @Override
+ public boolean apply(com.amd.gerrit.plugins.manifestsubscription.manifest.Project project,
+ String hash, String name,
+ GitRepositoryManager gitRepoManager) throws
+ RefAlreadyExistsException,
+ InvalidRefNameException, RefNotFoundException,
+ GitAPIException, IOException {
+ Project.NameKey p = new Project.NameKey(project.getName());
+ Repository db = gitRepoManager.openRepository(p);
+ Git git = new Git(db);
+
+ git.branchCreate().setName(branch).setStartPoint(hash).call();
+
+ git.close();
+ //db.close(); //closed by git.close()
+ return true;
+ }
+ };
+
+ traverseManifestAndApplyOp(gitRepoManager, manifest.getProject(), defaultRef, op, lookup);
+ }
+
/**
* Pass in a {@link com.google.common.collect.Table} if you want to reuse
* the lookup cache
@@ -211,7 +250,9 @@
* @param lookup
*/
static void affixManifest(GitRepositoryManager gitRepoManager,
- Manifest manifest, Table<String, String, String> lookup) {
+ Manifest manifest,
+ Table<String, String, String> lookup)
+ throws GitAPIException, IOException {
if (lookup == null) {
// project, branch, hash
lookup = HashBasedTable.create();
@@ -242,7 +283,7 @@
List<com.amd.gerrit.plugins.manifestsubscription.manifest.Project> projects,
String defaultRef,
ManifestOp op,
- Table<String, String, String> lookup) {
+ Table<String, String, String> lookup) throws GitAPIException, IOException {
String ref;
String hash;
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index a5adbd3..22bd289 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -55,6 +55,7 @@
Manifest represent raw XML
CanonicalManifest resolve <include> and <remove-project>
+* TODO: possibly separate out manifest op into a separate plugin and make VesionedManifest as a libary (manifest-base or something)
* TODO: generate snapshot manifest for all commit (Currently only generated on a per push/ref-updated basis)
* Make it configurable, possibly per project, using plugin config or via special tag in manifest
* TODO: monitor all manifest branch if no branch is specified
diff --git a/src/main/resources/Documentation/cmd-branch.md b/src/main/resources/Documentation/cmd-branch.md
new file mode 100644
index 0000000..8cd65a3
--- /dev/null
+++ b/src/main/resources/Documentation/cmd-branch.md
@@ -0,0 +1,47 @@
+@PLUGIN@ branch
+==============
+
+NAME
+----
+@PLUGIN@ branch - Branch all projects on the server described by a manifest
+on the server.
+
+SYNOPSIS
+--------
+```
+ssh -p @SSH_PORT@ @SSH_HOST@ @PLUGIN@ branch
+ {-r/--manifest-repo <manifest repo>}
+ {-c/--manifest-commit-ish <manifest commit-ish>}
+ {-p/--manifest-path <manifest path>}
+ {-b/--new-branch <new branch name>}
+ [--help]
+```
+
+ACCESS
+------
+Caller must be a member of the privileged 'Administrators' group
+
+OPTIONS
+-------
+
+`-r/--manifest-repo <manifest repo>`
+`-c/--manifest-commit-ish <manifest commit-ish>`
+`-p/--manifest-path <manifest path>`
+: The manifest the branching operation is based on
+
+`-b/--new-branch <new branch name>`
+: The name of the branch that will be created on all projects in the manifest specified above
+
+EXAMPLES
+--------
+Branch all projects on the server described in the `default.xml` manifest in commit 5f51acb585b6a of repo `demo/build_manifest` to branch `releases/1.0.0`
+```
+ssh -p @SSH_PORT@ @SSH_HOST@ @PLUGIN@ branch -r demo/build_manifest -c 5f51acb585b6a -p default.xml -b releases/1.0.0
+
+```
+
+Branch all projects on the server described in the `default.xml` manifest in commit v0.9-15-g5f51acb of repo `demo/build_manifest` to branch `releases/1.0.0`
+```
+ssh -p @SSH_PORT@ @SSH_HOST@ @PLUGIN@ branch -r demo/build_manifest -c v0.9-15-g5f51acb -p default.xml -b releases/1.0.0
+
+```