Skip to content

Commit 869952d

Browse files
committed
Add ssh command to rebuild a staging ref
Fixes: QTBI-1547 Change-Id: Ia571f64af3f297790b759483eaf56a0782603045 Reviewed-by: Frederik Gladhorn <[email protected]>
1 parent cf648c9 commit 869952d

File tree

3 files changed

+281
-0
lines changed

3 files changed

+281
-0
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//
2+
// Copyright (C) 2019 The Qt Company
3+
//
4+
5+
package com.googlesource.gerrit.plugins.qtcodereview;
6+
7+
import com.google.common.flogger.FluentLogger;
8+
import com.google.gerrit.extensions.restapi.AuthException;
9+
import com.google.gerrit.reviewdb.client.Branch;
10+
import com.google.gerrit.reviewdb.client.Change;
11+
import com.google.gerrit.reviewdb.client.Project;
12+
import com.google.gerrit.reviewdb.server.ReviewDb;
13+
import com.google.gerrit.server.git.GitRepositoryManager;
14+
import com.google.gerrit.server.permissions.PermissionBackend;
15+
import com.google.gerrit.server.permissions.PermissionBackendException;
16+
import com.google.gerrit.server.permissions.RefPermission;
17+
import com.google.gerrit.server.update.BatchUpdate;
18+
import com.google.gerrit.sshd.SshCommand;
19+
import com.google.gerrit.sshd.CommandMetaData;
20+
21+
import com.google.inject.Inject;
22+
import com.google.inject.Provider;
23+
24+
import org.eclipse.jgit.errors.RepositoryNotFoundException;
25+
import org.eclipse.jgit.lib.Repository;
26+
import org.kohsuke.args4j.Option;
27+
28+
import java.io.IOException;
29+
30+
31+
@CommandMetaData(name="staging-rebuild", description="Rebuild a staging branch.")
32+
class QtCommandRebuildStaging extends SshCommand {
33+
34+
@Inject
35+
private PermissionBackend permissionBackend;
36+
37+
@Inject
38+
private GitRepositoryManager gitManager;
39+
40+
@Inject
41+
private ReviewDb db;
42+
43+
@Inject
44+
private BatchUpdate.Factory updateFactory;
45+
46+
@Inject
47+
private QtUtil qtUtil;
48+
49+
@Option(name = "--project", aliases = {"-p"},
50+
required = true, usage = "project name")
51+
private String project;
52+
53+
@Option(name = "--branch", aliases = {"-b"},
54+
required = true, usage = "branch name, e.g. refs/heads/master or just master")
55+
private String branch;
56+
57+
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
58+
59+
private Repository git;
60+
61+
62+
@Override
63+
protected void run() throws UnloggedFailure {
64+
logger.atInfo().log("qtcodereview: staging-rebuild -p %s -b %s", project, branch);
65+
66+
Branch.NameKey stagingBranchKey = QtUtil.getNameKeyLong(project, QtUtil.R_STAGING, branch);
67+
Branch.NameKey destBranchShortKey = QtUtil.getNameKeyShort(project, QtUtil.R_HEADS, branch);
68+
69+
try {
70+
Project.NameKey projectKey = new Project.NameKey(project);
71+
git = gitManager.openRepository(projectKey);
72+
73+
permissionBackend.user(user).project(projectKey).ref(destBranchShortKey.get()).check(RefPermission.UPDATE);
74+
75+
if (git.resolve(stagingBranchKey.get()) == null) throw die("branch staging ref not found");
76+
77+
qtUtil.rebuildStagingBranch(git, user.asIdentifiedUser(), projectKey, stagingBranchKey, destBranchShortKey);
78+
79+
logger.atInfo().log("qtcodereview: staging-rebuild done for %s", stagingBranchKey);
80+
} catch (AuthException e) {
81+
logger.atSevere().log("qtcodereview: staging-rebuild Authentication failed to access repository: %s", e);
82+
throw die("not authorized");
83+
} catch (PermissionBackendException e) {
84+
logger.atSevere().log("qtcodereview: staging-rebuild permission error %s", e);
85+
} catch (RepositoryNotFoundException e) {
86+
logger.atSevere().log("qtcodereview: staging-rebuild repository not found: %s", e);
87+
throw die("project not found");
88+
} catch (IOException e) {
89+
logger.atSevere().log("qtcodereview: staging-rebuild IOException %s", e);
90+
throw die(e.getMessage());
91+
} catch (QtUtil.MergeConflictException e) {
92+
logger.atSevere().log("qtcodereview: staging-rebuild error %s", e);
93+
throw die("staging rebuild failed, merge conflict");
94+
} finally {
95+
if (git != null) {
96+
git.close();
97+
}
98+
}
99+
100+
}
101+
}

src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtSshModule.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ protected void configureCommands() {
1313
command(QtCommandPing.class);
1414
command(QtCommandNewBuild.class);
1515
command(QtCommandListStaging.class);
16+
command(QtCommandRebuildStaging.class);
1617
}
1718
}
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// Copyright (C) 2019 The Qt Company
2+
3+
package com.googlesource.gerrit.plugins.qtcodereview;
4+
5+
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
6+
7+
import static com.google.common.truth.Truth.assertThat;
8+
9+
import com.google.gerrit.acceptance.PushOneCommit;
10+
import com.google.gerrit.acceptance.RestResponse;
11+
import com.google.gerrit.acceptance.TestPlugin;
12+
import com.google.gerrit.acceptance.UseSsh;
13+
14+
import com.google.gerrit.common.data.Permission;
15+
16+
import org.eclipse.jgit.revwalk.RevCommit;
17+
18+
import java.util.ArrayList;
19+
20+
import org.junit.Before;
21+
import org.junit.Test;
22+
23+
@TestPlugin(
24+
name = "gerrit-plugin-qt-workflow",
25+
sysModule = "com.googlesource.gerrit.plugins.qtcodereview.QtModule",
26+
sshModule = "com.googlesource.gerrit.plugins.qtcodereview.QtSshModule"
27+
)
28+
29+
@UseSsh
30+
public class QtCommandRebuildStagingIT extends QtCodeReviewIT {
31+
32+
@Before
33+
public void SetDefaultPermissions() throws Exception {
34+
grant(project, "refs/heads/master", Permission.QT_STAGE, false, REGISTERED_USERS);
35+
grant(project, "refs/staging/*", Permission.PUSH, false, adminGroupUuid());
36+
grant(project, "refs/builds/*", Permission.CREATE, false, adminGroupUuid());
37+
}
38+
39+
@Test
40+
public void multiChange_RebuildStaging() throws Exception {
41+
// Push 3 independent commits
42+
RevCommit initialHead = getRemoteHead();
43+
PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "file1", "content1");
44+
testRepo.reset(initialHead);
45+
PushOneCommit.Result c2 = pushCommit("master", "commitmsg2", "file2", "content2");
46+
testRepo.reset(initialHead);
47+
PushOneCommit.Result c3 = pushCommit("master", "commitmsg3", "file3", "content3");
48+
approve(c1.getChangeId());
49+
approve(c2.getChangeId());
50+
approve(c3.getChangeId());
51+
QtStage(c1);
52+
QtStage(c2);
53+
QtStage(c3);
54+
55+
RevCommit stagingHead = qtRebuildStaging("master", c3, null);
56+
}
57+
58+
@Test
59+
public void multiChange_RebuildStaging_WhileBuilding() throws Exception {
60+
// Push 3 independent commits
61+
RevCommit initialHead = getRemoteHead();
62+
PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "file1", "content1");
63+
testRepo.reset(initialHead);
64+
PushOneCommit.Result c2 = pushCommit("master", "commitmsg2", "file2", "content2");
65+
testRepo.reset(initialHead);
66+
PushOneCommit.Result c3 = pushCommit("master", "commitmsg3", "file3", "content3");
67+
approve(c1.getChangeId());
68+
approve(c2.getChangeId());
69+
approve(c3.getChangeId());
70+
QtStage(c1);
71+
QtStage(c2);
72+
QtNewBuild("master", "test-build-250");
73+
QtStage(c3);
74+
75+
RevCommit stagingHead = qtRebuildStaging("master", c3, null);
76+
}
77+
78+
@Test
79+
public void errorRebuildStaging_NoPermission() throws Exception {
80+
PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
81+
approve(c.getChangeId());
82+
QtStage(c);
83+
84+
deny(project, "refs/heads/master", Permission.SUBMIT, REGISTERED_USERS);
85+
86+
String commandStr;
87+
commandStr ="gerrit-plugin-qt-workflow staging-rebuild";
88+
commandStr += " --project " + project.get();
89+
commandStr += " --branch master";
90+
String resultStr = userSshSession.exec(commandStr);
91+
assertThat(userSshSession.getError()).contains("not authorized");
92+
93+
grant(project, "refs/heads/master", Permission.SUBMIT, false, REGISTERED_USERS);
94+
}
95+
96+
@Test
97+
public void errorRebuildStaging_RepoNotFound() throws Exception {
98+
PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
99+
approve(c.getChangeId());
100+
QtStage(c);
101+
102+
String commandStr ="gerrit-plugin-qt-workflow staging-rebuild";
103+
commandStr += " --project notarepo --branch master";
104+
String resultStr = adminSshSession.exec(commandStr);
105+
assertThat(adminSshSession.getError()).contains("project not found");
106+
}
107+
108+
@Test
109+
public void errorRebuildStaging_InvalidBranch() throws Exception {
110+
PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
111+
approve(c.getChangeId());
112+
QtStage(c);
113+
114+
String resultStr = qtRebuildStagingExpectFail("invalidbranch");
115+
assertThat(resultStr).contains("branch staging ref not found");
116+
}
117+
118+
private RevCommit qtRebuildStaging(String branch,
119+
PushOneCommit.Result expectedContent,
120+
RevCommit expectedStagingHead)
121+
throws Exception {
122+
String stagingRef = R_STAGING + branch;
123+
String branchRef = R_HEADS + branch;
124+
RevCommit initialHead = getRemoteHead(project, branchRef);
125+
RevCommit oldStagingHead = getRemoteHead(project, stagingRef);
126+
127+
String commandStr;
128+
commandStr ="gerrit-plugin-qt-workflow staging-rebuild";
129+
commandStr += " --project " + project.get();
130+
commandStr += " --branch " + branch;
131+
String resultStr = adminSshSession.exec(commandStr);
132+
assertThat(adminSshSession.getError()).isNull();
133+
134+
RevCommit updatedHead = getRemoteHead(project, branchRef);
135+
assertThat(updatedHead.getId()).isEqualTo(initialHead.getId()); // master is not updated
136+
137+
RevCommit stagingHead = getRemoteHead(project, stagingRef);
138+
139+
if (expectedStagingHead==null && expectedContent != null) {
140+
assertCherryPick(stagingHead, expectedContent.getCommit(), getCurrentPatchSHA(expectedContent));
141+
expectedStagingHead = stagingHead;
142+
} else {
143+
assertThat(stagingHead).isEqualTo(expectedStagingHead); // staging is updated
144+
}
145+
146+
if (expectedStagingHead.equals(oldStagingHead)) {
147+
assertRefUpdatedEvents(stagingRef); // no events
148+
} else {
149+
assertRefUpdatedEvents(stagingRef, oldStagingHead, expectedStagingHead);
150+
resetEvents();
151+
}
152+
153+
return stagingHead;
154+
}
155+
156+
private String qtRebuildStagingExpectFail(String branch)
157+
throws Exception {
158+
String stagingRef = R_STAGING + branch;
159+
String branchRef = R_HEADS + branch;
160+
RevCommit initialHead = getRemoteHead(project, branchRef);
161+
RevCommit oldStagingHead = getRemoteHead(project, stagingRef);
162+
163+
String commandStr;
164+
commandStr ="gerrit-plugin-qt-workflow staging-rebuild";
165+
commandStr += " --project " + project.get();
166+
commandStr += " --branch " + branch;
167+
String resultStr = adminSshSession.exec(commandStr);
168+
assertThat(adminSshSession.getError()).isNotNull();
169+
170+
RevCommit updatedHead = getRemoteHead(project, branchRef);
171+
if (updatedHead != null) assertThat(updatedHead.getId()).isEqualTo(initialHead.getId()); // master is not updated
172+
173+
RevCommit stagingHead = getRemoteHead(project, stagingRef);
174+
if (stagingHead != null) assertThat(stagingHead.getId()).isEqualTo(oldStagingHead.getId()); // staging is not updated
175+
176+
return adminSshSession.getError();
177+
}
178+
179+
}

0 commit comments

Comments
 (0)