Skip to content

Commit 6b6abb7

Browse files
committed
Add ssh command api for staging
Fixes: QTQAINFRA-2989 Change-Id: I204153146a5c321fcc87dbabcf8b180264b897e4 Reviewed-by: Frederik Gladhorn <[email protected]>
1 parent ef970bc commit 6b6abb7

File tree

3 files changed

+245
-0
lines changed

3 files changed

+245
-0
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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+
9+
import com.google.gerrit.extensions.api.changes.SubmitInput;
10+
import com.google.gerrit.extensions.restapi.IdString;
11+
import com.google.gerrit.server.change.ChangeResource;
12+
import com.google.gerrit.server.change.RevisionResource;
13+
import com.google.gerrit.server.restapi.change.ChangesCollection;
14+
import com.google.gerrit.server.restapi.change.Revisions;
15+
import com.google.gerrit.reviewdb.client.PatchSet;
16+
import com.google.gerrit.sshd.SshCommand;
17+
import com.google.gerrit.sshd.CommandMetaData;
18+
import com.google.gerrit.sshd.commands.PatchSetParser;
19+
import com.google.gwtorm.server.OrmException;
20+
import com.google.inject.Inject;
21+
import java.util.HashSet;
22+
import java.util.Set;
23+
import org.kohsuke.args4j.Argument;
24+
25+
@CommandMetaData(name="stage", description="Stage a change.")
26+
class QtCommandStage extends SshCommand {
27+
28+
@Inject private QtStage qtStage;
29+
@Inject private ChangesCollection changes;
30+
@Inject private PatchSetParser psParser;
31+
@Inject private Revisions revisions;
32+
33+
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
34+
35+
private final Set<PatchSet> patchSets = new HashSet<>();
36+
37+
@Argument(
38+
index = 0,
39+
required = true,
40+
multiValued = true,
41+
metaVar = "{COMMIT | CHANGE,PATCHSET}",
42+
usage = "list of commits or patch sets to stage")
43+
void addPatchSetId(String token) {
44+
try {
45+
PatchSet ps = psParser.parsePatchSet(token, null, null);
46+
patchSets.add(ps);
47+
} catch (UnloggedFailure e) {
48+
throw new IllegalArgumentException(e.getMessage(), e);
49+
} catch (OrmException e) {
50+
throw new IllegalArgumentException("database error", e);
51+
}
52+
}
53+
54+
@Override
55+
protected void run() throws UnloggedFailure {
56+
boolean ok = true;
57+
58+
for (PatchSet patchSet : patchSets) {
59+
try {
60+
logger.atInfo().log("qtcodereview: ssh command stage %s", patchSet.getId());
61+
ChangeResource c = changes.parse(patchSet.getId().getParentKey());
62+
IdString id = IdString.fromDecoded(patchSet.getRevision().get());
63+
RevisionResource r = revisions.parse(c, id);
64+
qtStage.apply(r, new SubmitInput());
65+
} catch (Exception e) {
66+
ok = false;
67+
writeError("error", e.getMessage() + "\n");
68+
}
69+
}
70+
71+
if (!ok) {
72+
throw die("one or more stages failed; review output above");
73+
}
74+
}
75+
76+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ protected void configureCommands() {
1616
command(QtCommandNewBuild.class);
1717
command(QtCommandListStaging.class);
1818
command(QtCommandRebuildStaging.class);
19+
command(QtCommandStage.class);
1920
}
2021
}
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
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+
import static com.google.common.truth.Truth.assertThat;
7+
8+
import com.google.gerrit.acceptance.PushOneCommit;
9+
import com.google.gerrit.acceptance.TestPlugin;
10+
import com.google.gerrit.acceptance.UseSsh;
11+
import com.google.gerrit.common.data.Permission;
12+
import com.google.gerrit.reviewdb.client.Change;
13+
import com.google.gerrit.reviewdb.client.ChangeMessage;
14+
import org.eclipse.jgit.revwalk.RevCommit;
15+
import org.junit.Before;
16+
import org.junit.Test;
17+
18+
@TestPlugin(
19+
name = "gerrit-plugin-qt-workflow",
20+
sysModule = "com.googlesource.gerrit.plugins.qtcodereview.QtModule",
21+
sshModule = "com.googlesource.gerrit.plugins.qtcodereview.QtSshModule"
22+
)
23+
24+
@UseSsh
25+
public class QtCommandStageIT extends QtCodeReviewIT {
26+
27+
@Before
28+
public void SetDefaultPermissions() throws Exception {
29+
grant(project, "refs/heads/master", Permission.QT_STAGE, false, REGISTERED_USERS);
30+
}
31+
32+
@Test
33+
public void single_Change_Stage() throws Exception {
34+
PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
35+
approve(c.getChangeId());
36+
qtSshStage(c);
37+
}
38+
39+
@Test
40+
public void multi_Change_Stage() 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+
49+
approve(c1.getChangeId());
50+
approve(c2.getChangeId());
51+
approve(c3.getChangeId());
52+
53+
String changes;
54+
changes = String.valueOf(c1.getPatchSetId().getParentKey().get()) + "," + c1.getPatchSetId().getId();
55+
changes += " " + String.valueOf(c2.getPatchSetId().getParentKey().get()) + "," + c2.getPatchSetId().getId();
56+
changes += " " + String.valueOf(c3.getPatchSetId().getParentKey().get()) + "," + c3.getPatchSetId().getId();
57+
String result = qtSshStageCommon(c1, changes, false);
58+
assertThat(result).isNull();
59+
}
60+
61+
@Test
62+
public void error_InvalidPatch() throws Exception {
63+
PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
64+
approve(c.getChangeId());
65+
66+
String changes = "invalid";
67+
String result = qtSshStageCommon(c, changes, true);
68+
assertThat(result).contains("is not a valid patch set");
69+
}
70+
71+
@Test
72+
public void error_ChangeNotFound() throws Exception {
73+
PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
74+
approve(c.getChangeId());
75+
76+
String changes = "9999,1";
77+
String result = qtSshStageCommon(c, changes, true);
78+
assertThat(result).contains("no such change");
79+
}
80+
81+
@Test
82+
public void error_PatchNotFound() throws Exception {
83+
PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
84+
approve(c.getChangeId());
85+
String changes = String.valueOf(c.getPatchSetId().getParentKey().get()) +",9999";
86+
String result = qtSshStageCommon(c, changes, true);
87+
assertThat(result).contains("no such patch set");
88+
}
89+
90+
@Test
91+
public void error_PatchNotCurrent() throws Exception {
92+
PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "file1", "content1");
93+
PushOneCommit.Result c2 = amendCommit(c1.getChangeId());
94+
approve(c2.getChangeId());
95+
96+
String changes = String.valueOf(c2.getPatchSetId().getParentKey().get()) +",1";
97+
String result = qtSshStageCommon(c2, changes, true);
98+
assertThat(result).contains("is not current");
99+
}
100+
101+
@Test
102+
public void error_Wrong_Status() throws Exception {
103+
PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
104+
approve(c.getChangeId());
105+
106+
grant(project, "refs/heads/master", Permission.ABANDON, false, REGISTERED_USERS);
107+
QtDefer(c);
108+
deny(project, "refs/heads/master", Permission.ABANDON, REGISTERED_USERS);
109+
110+
String result = qtSshStageExpectFail(c);
111+
assertThat(result).contains("Change is DEFERRED");
112+
}
113+
114+
@Test
115+
public void error_NoPermission() throws Exception {
116+
deny(project, "refs/heads/master", Permission.QT_STAGE, REGISTERED_USERS);
117+
PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
118+
approve(c.getChangeId());
119+
120+
String result = qtSshStageExpectFail(c);
121+
assertThat(result).contains("not permitted");
122+
grant(project, "refs/heads/master", Permission.QT_STAGE, false, REGISTERED_USERS);
123+
}
124+
125+
@Test
126+
public void error_notReviewed() throws Exception {
127+
PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
128+
129+
String result = qtSshStageExpectFail(c);
130+
assertThat(result).contains("needs Code-Review");
131+
}
132+
133+
private void qtSshStage(PushOneCommit.Result c) throws Exception {
134+
qtSshStageCommon(c, false);
135+
}
136+
137+
private String qtSshStageExpectFail(PushOneCommit.Result c) throws Exception {
138+
return qtSshStageCommon(c, true);
139+
}
140+
141+
private String qtSshStageCommon(PushOneCommit.Result c,
142+
Boolean expectFail)
143+
throws Exception {
144+
String changes;
145+
changes = String.valueOf(c.getPatchSetId().getParentKey().get()) + ",";
146+
changes += c.getPatchSetId().getId();
147+
148+
return qtSshStageCommon(c, changes, expectFail);
149+
}
150+
151+
private String qtSshStageCommon(PushOneCommit.Result c,
152+
String changes,
153+
Boolean expectFail)
154+
throws Exception {
155+
String commandStr ="gerrit-plugin-qt-workflow stage " + changes;
156+
157+
String resultStr = adminSshSession.exec(commandStr);
158+
if (expectFail) assertThat(adminSshSession.getError()).isNotNull();
159+
else assertThat(adminSshSession.getError()).isNull();
160+
161+
Change change = c.getChange().change();
162+
if (expectFail) assertThat(change.getStatus()).isNotEqualTo(Change.Status.STAGED);
163+
else assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
164+
165+
return adminSshSession.getError();
166+
}
167+
168+
}

0 commit comments

Comments
 (0)