aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJukka Jokiniva <jukka.jokiniva@qt.io>2019-01-03 12:04:39 +0200
committerFrederik Gladhorn <frederik.gladhorn@qt.io>2019-04-09 12:30:16 +0000
commit061d5338055456655d64dd8f4ee2cc434a501bf7 (patch)
treed6a9122c19f025e17e5fa0c285b3e2a73fa9f01a
parentbe31ec0d9673eaf040e78b80faeef3c942fde9fa (diff)
Add new build ssh command
Fixes: QTBI-1545 Change-Id: I2da62e83eda43fe9127cef238a3c82cf46171202 Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
-rw-r--r--qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html7
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuild.java175
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtSshModule.java3
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java126
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCodeReviewIT.java12
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuildIT.java231
6 files changed, 552 insertions, 2 deletions
diff --git a/qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html b/qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html
index 9dc76e8..784011b 100644
--- a/qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html
+++ b/qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html
@@ -86,12 +86,17 @@
link_elem.href = '/q/status:staged';
ul_elem.insertBefore(li_elem, ul_elem.children[2]);
+ li_elem = htmlToElement(ul_elem.children[1].outerHTML);
+ link_elem = li_elem.children[0].children[1];
+ link_elem.text = 'Integrating';
+ link_elem.href = '/q/status:integrating';
+ ul_elem.insertBefore(li_elem, ul_elem.children[3]);
li_elem = htmlToElement(ul_elem.children[1].outerHTML);
link_elem = li_elem.children[0].children[1];
link_elem.text = 'Deferred';
link_elem.href = '/q/status:deferred';
- ul_elem.insertBefore(li_elem, ul_elem.children[4]);
+ ul_elem.insertBefore(li_elem, ul_elem.children[5]);
});
// Customize change view
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuild.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuild.java
new file mode 100644
index 0000000..d6cba28
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuild.java
@@ -0,0 +1,175 @@
+//
+// Copyright (C) 2019 The Qt Company
+//
+
+package com.googlesource.gerrit.plugins.qtcodereview;
+
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.InternalUser;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.permissions.ProjectPermission;
+import com.google.gerrit.server.permissions.RefPermission;
+import com.google.gerrit.server.project.NoSuchProjectException;
+import com.google.gerrit.server.project.NoSuchRefException;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gerrit.server.update.BatchUpdate;
+import com.google.gerrit.server.update.UpdateException;
+import com.google.gerrit.server.util.time.TimeUtil;
+import com.google.gerrit.sshd.SshCommand;
+import com.google.gerrit.sshd.CommandMetaData;
+
+import com.google.gwtorm.server.OrmException;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.RefUpdate.Result;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.kohsuke.args4j.Option;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map.Entry;
+
+@CommandMetaData(name="staging-new-build", description="Create unique build branch of the current staging branch and change the gerrit status of the changes to INTEGRATING.")
+class QtCommandNewBuild extends SshCommand {
+
+ @Inject
+ private PermissionBackend permissionBackend;
+
+ @Inject
+ private GitRepositoryManager gitManager;
+
+ @Inject
+ private Provider<ReviewDb> dbProvider;
+
+ @Inject
+ private BatchUpdate.Factory updateFactory;
+
+ @Inject
+ private QtUtil qtUtil;
+
+ @Inject
+ private QtChangeUpdateOp.Factory qtUpdateFactory;
+
+ @Option(name = "--project", aliases = {"-p"},
+ required = true, usage = "project name")
+ private String project;
+
+ @Option(name = "--staging-branch", aliases = {"-s"},
+ required = true, usage = "branch name, e.g. refs/staging/master or just master")
+ private String stagingBranch;
+
+ @Option(name = "--build-id", aliases = {"-i"},
+ required = true, usage = "build id, e.g. refs/builds/my_build or just my_build")
+ private String build;
+
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ private Repository git;
+
+
+ @Override
+ protected void run() throws UnloggedFailure {
+
+ logger.atInfo().log("qtcodereview: staging-new-build -p %s -s %s -i %s", project, stagingBranch, build);
+
+ try {
+ Project.NameKey projectKey = new Project.NameKey(project);
+ git = gitManager.openRepository(projectKey);
+
+ Branch.NameKey buildBranchKey = QtUtil.getNameKeyLong(project, QtUtil.R_BUILDS, build);
+ Branch.NameKey stagingBranchKey = QtUtil.getNameKeyLong(project, QtUtil.R_STAGING, stagingBranch);
+ Branch.NameKey destBranchShortKey = QtUtil.getNameKeyShort(project, QtUtil.R_STAGING, stagingBranch);
+ Branch.NameKey destinationKey = QtUtil.getNameKeyLong(project, QtUtil.R_HEADS, stagingBranch);
+
+ // Check required permissions
+ permissionBackend.user(user).project(projectKey).ref(destinationKey.get()).check(RefPermission.UPDATE);
+ permissionBackend.user(user).project(projectKey).ref(buildBranchKey.get()).check(RefPermission.CREATE);
+
+ if (QtUtil.branchExists(git, buildBranchKey) == true) {
+ logger.atSevere().log("qtcodereview: staging-new-build Target build %s already exists", buildBranchKey);
+ throw die("Target build already exists!");
+ }
+
+ if (QtUtil.branchExists(git, stagingBranchKey) == false) {
+ logger.atSevere().log("qtcodereview: staging-new-build staging ref %s not found", stagingBranchKey);
+ throw die("Staging ref not found!");
+ }
+
+ // Create build reference.
+ Result result = qtUtil.createBuildRef(git, user.asIdentifiedUser(),
+ projectKey, stagingBranchKey, buildBranchKey);
+ String message = String.format("Added to build %s for %s", build, destinationKey);
+
+ if (result != Result.NEW && result != Result.FAST_FORWARD) {
+ logger.atSevere().log("qtcodereview: staging-new-build failed to create new build ref %s result %s",
+ buildBranchKey, result);
+ throw new UnloggedFailure(1, "fatal: failed to create new build ref: " + result);
+ } else {
+ // list the changes in staging branch but missing from the destination branch
+ List<Entry<ChangeData, RevCommit>> openChanges = qtUtil.listChangesNotMerged(git, buildBranchKey, destBranchShortKey);
+
+ // Make sure that there are changes in the staging branch.
+ if (openChanges.isEmpty()) {
+ logger.atSevere().log("qtcodereview: staging-new-build No changes in staging branch %s.", stagingBranchKey);
+ throw die("No changes in staging branch. Not creating a build reference");
+ }
+
+ QtChangeUpdateOp op = qtUpdateFactory.create(Change.Status.INTEGRATING, message, null, null, null);
+ try (BatchUpdate u = updateFactory.create(dbProvider.get(), projectKey, user, TimeUtil.nowTs())) {
+ for (Entry<ChangeData, RevCommit> item: openChanges) {
+ Change change = item.getKey().change();
+ logger.atInfo().log("qtcodereview: staging-new-build inserted change %s (%s) into build %s for %s",
+ change, item.getValue().toString(), build, destinationKey);
+ u.addOp(change.getId(), op);
+ }
+ u.execute();
+ }
+ }
+
+ logger.atInfo().log("qtcodereview: staging-new-build build %s for %s created", build, destBranchShortKey);
+
+ } catch (AuthException e) {
+ logger.atSevere().log("qtcodereview: staging-new-build Authentication failed to access repository: %s", e);
+ throw die("Authentication failed to access repository");
+ } catch (PermissionBackendException e) {
+ logger.atSevere().log("qtcodereview: staging-new-build Not enough permissions to access repository %s", e);
+ throw die("Not enough permissions to access repository");
+ } catch (RepositoryNotFoundException e) {
+ throw die("project not found");
+ } catch (IOException e) {
+ logger.atSevere().log("qtcodereview: staging-new-build Failed to access repository %s", e);
+ throw die("Failed to access repository");
+ } catch (OrmException e) {
+ logger.atSevere().log("qtcodereview: staging-new-build Failed to access database %s", e);
+ throw die("Failed to access database");
+ } catch (QtUtil.BranchNotFoundException e) {
+ logger.atSevere().log("qtcodereview: staging-new-build Failed to access build or staging ref %s", e);
+ throw die("Failed to access build or staging ref");
+ } catch (NoSuchRefException e) {
+ logger.atSevere().log("qtcodereview: staging-new-build Invalid branch name %s", e);
+ throw die("Invalid branch name");
+ } catch (UpdateException | RestApiException e) {
+ logger.atSevere().log("qtcodereview: staging-new-build failed to update change status %s", e);
+ throw die("Failed to update change status");
+ } finally {
+ if (git != null) {
+ git.close();
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtSshModule.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtSshModule.java
index ca7c940..306d032 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtSshModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtSshModule.java
@@ -1,5 +1,5 @@
//
-// Copyright (C) 2018 The Qt Company
+// Copyright (C) 2019 The Qt Company
//
package com.googlesource.gerrit.plugins.qtcodereview;
@@ -11,5 +11,6 @@ class QtSshModule extends PluginCommandModule {
@Override
protected void configureCommands() {
command(QtCommandPing.class);
+ command(QtCommandNewBuild.class);
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java
index bf14223..8033d80 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java
@@ -48,10 +48,14 @@ import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.merge.ThreeWayMerger;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
import java.io.IOException;
+import java.util.AbstractMap;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
/**
@@ -64,6 +68,7 @@ public class QtUtil {
public static final String R_HEADS = "refs/heads/";
public static final String R_STAGING = "refs/staging/";
+ public static final String R_BUILDS = "refs/builds/";
private final Provider<InternalChangeQuery> queryProvider;
private final GitReferenceUpdated referenceUpdated;
@@ -85,6 +90,13 @@ public class QtUtil {
}
}
+ public static class BranchNotFoundException extends Exception {
+ private static final long serialVersionUID = 1L;
+ public BranchNotFoundException(final String message) {
+ super(message);
+ }
+ }
+
public static Project.NameKey getProjectKey(final String project) {
String projectName = project;
if (project.endsWith(Constants.DOT_GIT_EXT)) {
@@ -94,6 +106,24 @@ public class QtUtil {
}
/**
+ * Creates a branch key including ref prefix.
+ * @param project Project for the branch key.
+ * @param prefix Expected prefix.
+ * @param branch Branch name with or without prefix.
+ * @return Branch name key with prefix.
+ */
+ public static Branch.NameKey getNameKeyLong(final String project,
+ final String prefix,
+ final String branch) {
+ final Project.NameKey projectKey = getProjectKey(project);
+ if (branch.startsWith(prefix)) {
+ return new Branch.NameKey(projectKey, branch);
+ } else {
+ return new Branch.NameKey(projectKey, prefix + branch);
+ }
+ }
+
+ /**
* Creates a branch key without any prefix.
* @param project Project for the branch key.
* @param prefix Prefix to remove.
@@ -111,6 +141,11 @@ public class QtUtil {
}
}
+ public static boolean branchExists(Repository git, final Branch.NameKey branch)
+ throws IOException {
+ return git.getRefDatabase().getRef(branch.get()) != null;
+ }
+
/**
* Gets a staging branch for a branch.
* @param branch Branch under refs/heads. E.g. refs/heads/master. Can be short
@@ -152,6 +187,51 @@ public class QtUtil {
}
}
+ /**
+ * Creates a build ref. Build refs are stored under refs/builds.
+ *
+ * @param git Git repository.
+ * @param stagingBranch Staging branch to create the build ref from. Can be
+ * short name.
+ * @param newBranch Build ref name, under refs/builds. Can be short name.
+ * @return
+ * @throws IOException
+ * @throws NoSuchRefException
+ */
+ public Result createBuildRef(Repository git,
+ IdentifiedUser user,
+ final Project.NameKey projectKey,
+ final Branch.NameKey stagingBranch,
+ final Branch.NameKey newBranch)
+ throws IOException, NoSuchRefException {
+ final String stagingBranchName;
+ if (stagingBranch.get().startsWith(R_STAGING)) {
+ stagingBranchName = stagingBranch.get();
+ } else {
+ stagingBranchName = R_STAGING + stagingBranch.get();
+ }
+
+ final String buildBranchName;
+ if (newBranch.get().startsWith(R_BUILDS)) {
+ buildBranchName = newBranch.get();
+ } else {
+ buildBranchName = R_BUILDS + newBranch.get();
+ }
+
+ Ref sourceRef = git.getRefDatabase().getRef(stagingBranchName);
+ if (sourceRef == null) { throw new NoSuchRefException(stagingBranchName); }
+
+ RefUpdate refUpdate = git.updateRef(buildBranchName);
+ refUpdate.setNewObjectId(sourceRef.getObjectId());
+ refUpdate.setForceUpdate(false);
+ RefUpdate.Result result = refUpdate.update();
+
+ // send ref created event
+ referenceUpdated.fire(projectKey, refUpdate, ReceiveCommand.Type.CREATE, user.state());
+
+ return result;
+ }
+
private static Result updateRef(Repository git,
final String ref,
final String newValue,
@@ -305,6 +385,52 @@ public class QtUtil {
}
}
+ /**
+ * Lists not merged changes between branches.
+ * @param git jGit Repository. Must be open.
+ * @param db ReviewDb of a Gerrit site.
+ * @param branch Branch to search for the changes.
+ * @param destination Destination branch for changes.
+ * @return List of not merged changes.
+ * @throws IOException Thrown by Repository or RevWalk if repository is not
+ * accessible.
+ * @throws OrmException Thrown if ReviewDb is not accessible.
+ */
+ public List<Map.Entry<ChangeData,RevCommit>> listChangesNotMerged(Repository git,
+ final Branch.NameKey branch,
+ final Branch.NameKey destination)
+ throws IOException, OrmException,
+ BranchNotFoundException {
+
+ List<Map.Entry<ChangeData, RevCommit>> result = new ArrayList<Map.Entry<ChangeData, RevCommit>>();
+ RevWalk revWalk = new RevWalk(git);
+
+ try {
+ Ref ref = git.getRefDatabase().getRef(branch.get());
+ if (ref == null) throw new BranchNotFoundException("No such branch: " + branch);
+ Ref refDest = git.getRefDatabase().getRef(destination.get());
+ if (refDest == null) throw new BranchNotFoundException("No such branch: " + destination);
+ RevCommit firstCommit = revWalk.parseCommit(ref.getObjectId());
+ revWalk.markStart(firstCommit);
+ // Destination is the walker end point
+ revWalk.markUninteresting(revWalk.parseCommit(refDest.getObjectId()));
+
+ Iterator<RevCommit> i = revWalk.iterator();
+ while (i.hasNext()) {
+ RevCommit commit = i.next();
+ List<ChangeData> changes = queryProvider.get().byBranchCommit(destination, commit.name());
+ if (changes != null && !changes.isEmpty()) {
+ if (changes.size() > 1) logger.atWarning().log("qtcodereview: commit belongs to multiple changes: %s", commit.name());
+ ChangeData cd = changes.get(0);
+ result.add(new AbstractMap.SimpleEntry<ChangeData,RevCommit>(cd, commit));
+ }
+ }
+ } finally {
+ revWalk.dispose();
+ }
+ return result;
+ }
+
public static RevCommit merge(PersonIdent committerIdent,
Repository git,
ObjectInserter objInserter,
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCodeReviewIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCodeReviewIT.java
index 28a9d73..5fbb78d 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCodeReviewIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCodeReviewIT.java
@@ -45,6 +45,7 @@ public class QtCodeReviewIT extends LightweightPluginDaemonTest {
protected static final String R_HEADS = "refs/heads/";
protected static final String R_STAGING = "refs/staging/";
+ protected static final String R_BUILDS = "refs/builds/";
protected static final String R_PUSH = "refs/for/";
protected static final String CONTENT_DATA = "hereisjustsomecontentforthecommits";
@@ -116,6 +117,17 @@ public class QtCodeReviewIT extends LightweightPluginDaemonTest {
return response;
}
+ protected void QtNewBuild(String branch, String buildId) throws Exception {
+ String commandStr;
+ commandStr ="gerrit-plugin-qt-workflow staging-new-build";
+ commandStr += " --project " + project.get();
+ commandStr += " --staging-branch " + branch;
+ commandStr += " --build-id " + buildId;
+ String resultStr = adminSshSession.exec(commandStr);
+ assertThat(adminSshSession.getError()).isNull();
+ resetEvents();
+ }
+
protected PushOneCommit.Result pushCommit(String branch,
String message,
String file,
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuildIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuildIT.java
new file mode 100644
index 0000000..f029046
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuildIT.java
@@ -0,0 +1,231 @@
+// Copyright (C) 2019 The Qt Company
+
+package com.googlesource.gerrit.plugins.qtcodereview;
+
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.TestPlugin;
+import com.google.gerrit.acceptance.UseSsh;
+
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+
+import org.eclipse.jgit.revwalk.RevCommit;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@TestPlugin(
+ name = "gerrit-plugin-qt-workflow",
+ sysModule = "com.googlesource.gerrit.plugins.qtcodereview.QtModule",
+ sshModule = "com.googlesource.gerrit.plugins.qtcodereview.QtSshModule"
+)
+
+@UseSsh
+public class QtCommandNewBuildIT extends QtCodeReviewIT {
+
+ private final String BUILDING_MSG = "Added to build ";
+
+ @Before
+ public void SetDefaultPermissions() throws Exception {
+ grant(project, "refs/heads/master", Permission.QT_STAGE, false, REGISTERED_USERS);
+ grant(project, "refs/staging/*", Permission.PUSH, false, adminGroupUuid());
+ grant(project, "refs/builds/*", Permission.CREATE, false, adminGroupUuid());
+ }
+
+ @Test
+ public void singleChange_New_Staged_Integrating() throws Exception {
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c.getChangeId());
+ QtStage(c);
+
+ RevCommit buildHead = qtNewBuild("master", "test-build-100", c, null);
+ }
+
+ @Test
+ public void multiChange_New_Staged_Integrating() throws Exception {
+ // Push 3 independent commits
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "file1", "content1");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c2 = pushCommit("master", "commitmsg2", "file2", "content2");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c3 = pushCommit("master", "commitmsg3", "file3", "content3");
+ approve(c1.getChangeId());
+ approve(c2.getChangeId());
+ approve(c3.getChangeId());
+ QtStage(c1);
+ QtStage(c2);
+ QtStage(c3);
+
+ RevCommit buildHead = qtNewBuild("master", "test-build-101", c3, null);
+ Change change = c1.getChange().change();
+ assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
+ change = c2.getChange().change();
+ assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
+ }
+
+
+ @Test
+ public void errorNewBuild_NoPermission() throws Exception {
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c.getChangeId());
+ QtStage(c);
+
+ String commandStr;
+ commandStr ="gerrit-plugin-qt-workflow staging-new-build";
+ commandStr += " --project " + project.get();
+ commandStr += " --staging-branch master";
+ commandStr += " --build-id test-build-500";
+ String resultStr = userSshSession.exec(commandStr);
+ assertThat(userSshSession.getError()).contains("Authentication failed to access repository");
+ }
+
+ @Test
+ public void errorNewBuild_RepoNotFound() throws Exception {
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c.getChangeId());
+ QtStage(c);
+
+ String commandStr;
+ commandStr ="gerrit-plugin-qt-workflow staging-new-build";
+ commandStr += " --project notarepo";
+ commandStr += " --staging-branch master";
+ commandStr += " --build-id test-build-500";
+ String resultStr = adminSshSession.exec(commandStr);
+ assertThat(adminSshSession.getError()).contains("project not found");
+ }
+
+ @Test
+ public void errorNewBuild_BuildAlreadyExists() throws Exception {
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c.getChangeId());
+ QtStage(c);
+
+ RevCommit buildHead = qtNewBuild("master", "test-build-501", c, null);
+ String resultStr = qtNewBuildExpectFail("master", "test-build-501");
+ assertThat(resultStr).contains("Target build already exists!");
+ }
+
+ @Test
+ public void errorNewBuild_NoChanges() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c.getChangeId());
+ QtStage(c);
+ QtUnStage(c);
+
+ String resultStr = qtNewBuildExpectFail("master", "test-build-502");
+ assertThat(resultStr).contains("No changes in staging branch. Not creating a build reference");
+ }
+
+ @Test
+ public void errorNewBuild_NoStagingRef() throws Exception {
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+
+ String resultStr = qtNewBuildExpectFail("master", "test-build-503");
+ assertThat(resultStr).contains("Staging ref not found!");
+ }
+
+ @Test
+ public void errorNewBuild_NonExistingBranch() throws Exception {
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c.getChangeId());
+ QtStage(c);
+
+ String resultStr = qtNewBuildExpectFail("invalidbranchname", "test-build-504");
+ assertThat(resultStr).contains("Staging ref not found!");
+ }
+
+ @Test
+ public void errorAmend_Status_Integrating() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c1.getChangeId());
+ QtStage(c1);
+ RevCommit buildHead = qtNewBuild("master", "test-build-150", c1, null);
+
+ PushOneCommit.Result c2 = amendCommit(c1.getChangeId());
+ c2.assertErrorStatus(" closed");
+
+ RevCommit updatedHead = getRemoteHead(project, "master");
+ assertThat(updatedHead.getId()).isEqualTo(initialHead.getId()); // not updated
+ }
+
+ private RevCommit qtNewBuild(String branch,
+ String buildId,
+ PushOneCommit.Result c,
+ RevCommit expectedHead)
+ throws Exception {
+ String stagingRef = R_STAGING + branch;
+ String branchRef = R_HEADS + branch;
+ String buildRef = R_BUILDS + buildId;
+ String commandStr;
+ RevCommit initialHead = getRemoteHead(project, branchRef);
+
+ commandStr ="gerrit-plugin-qt-workflow staging-new-build";
+ commandStr += " --project " + project.get();
+ commandStr += " --staging-branch " + branch;
+ commandStr += " --build-id " + buildId;
+ String resultStr = adminSshSession.exec(commandStr);
+ assertThat(adminSshSession.getError()).isNull();
+
+ RevCommit updatedHead = getRemoteHead(project, branchRef);
+ assertThat(updatedHead.getId()).isEqualTo(initialHead.getId()); // master is not updated
+
+ RevCommit stagingHead = getRemoteHead(project, stagingRef);
+ assertThat(stagingHead.getId()).isNotEqualTo(initialHead.getId()); // staging is not master
+
+ if (expectedHead == null) {
+ assertCherryPick(stagingHead, c.getCommit(), getCurrentPatchSHA(c));
+ expectedHead = stagingHead;
+ }
+
+ RevCommit buildHead = getRemoteHead(project, buildRef);
+ assertThat(buildHead).isEqualTo(expectedHead); // build ref is updated
+ assertRefUpdatedEvents(buildRef, null, expectedHead);
+
+ resetEvents();
+
+ Change change = c.getChange().change();
+ assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
+
+ ArrayList<ChangeMessage> messages = new ArrayList(c.getChange().messages());
+ assertThat(messages.get(messages.size() - 1).getMessage()).contains(BUILDING_MSG + buildId); // check last message
+
+ return buildHead;
+ }
+
+ private String qtNewBuildExpectFail(String branch,
+ String buildId)
+ throws Exception {
+ String stagingRef = R_STAGING + branch;
+ String branchRef = R_HEADS + branch;
+ String commandStr;
+ RevCommit initialHead = getRemoteHead(project, branchRef);
+ RevCommit stagingHeadOld = getRemoteHead(project, stagingRef);
+
+ commandStr ="gerrit-plugin-qt-workflow staging-new-build";
+ commandStr += " --project " + project.get();
+ commandStr += " --staging-branch " + branch;
+ commandStr += " --build-id " + buildId;
+ String resultStr = adminSshSession.exec(commandStr);
+
+ RevCommit updatedHead = getRemoteHead(project, branchRef);
+ if (updatedHead != null) assertThat(updatedHead.getId()).isEqualTo(initialHead.getId()); // master is not updated
+
+ RevCommit stagingHead = getRemoteHead(project, stagingRef);
+ if (stagingHeadOld != null && stagingHead != null) assertThat(stagingHead.getId()).isEqualTo(stagingHeadOld.getId()); // staging is not updated
+
+ return adminSshSession.getError();
+ }
+
+
+}