diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/BUCK new file mode 100644 index 0000000000..94e6f6a5e3 --- /dev/null +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/BUCK @@ -0,0 +1,6 @@ +include_defs('//gerrit-acceptance-tests/tests.defs') + +acceptance_tests( + srcs = glob(['*IT.java']), + deps = ['//gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git:util'], +) diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java new file mode 100644 index 0000000000..dc6547057c --- /dev/null +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java @@ -0,0 +1,145 @@ +// Copyright (C) 2013 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.acceptance.api.change; + +import static com.google.gerrit.acceptance.git.GitUtil.cloneProject; +import static com.google.gerrit.acceptance.git.GitUtil.createProject; +import static com.google.gerrit.acceptance.git.GitUtil.initSsh; + +import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.acceptance.AcceptanceTestRequestScope; +import com.google.gerrit.acceptance.AccountCreator; +import com.google.gerrit.acceptance.SshSession; +import com.google.gerrit.acceptance.TestAccount; +import com.google.gerrit.acceptance.git.PushOneCommit; +import com.google.gerrit.extensions.api.GerritApi; +import com.google.gerrit.extensions.api.changes.ReviewInput; +import com.google.gerrit.extensions.restapi.ResourceConflictException; +import com.google.gerrit.extensions.restapi.RestApiException; +import com.google.gerrit.reviewdb.client.Project; +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.IdentifiedUser; +import com.google.gwtorm.server.SchemaFactory; +import com.google.inject.Inject; +import com.google.inject.util.Providers; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; + +public class ChangeIT extends AbstractDaemonTest { + + @Inject + private AccountCreator accounts; + + @Inject + private SchemaFactory reviewDbProvider; + + @Inject + private GerritApi gApi; + + @Inject + private AcceptanceTestRequestScope atrScope; + + @Inject + private IdentifiedUser.GenericFactory identifiedUserFactory; + + private TestAccount admin; + private Git git; + private ReviewDb db; + + @Before + public void setUp() throws Exception { + admin = accounts.admin(); + initSsh(admin); + Project.NameKey project = new Project.NameKey("p"); + SshSession sshSession = new SshSession(server, admin); + createProject(sshSession, project.get()); + git = cloneProject(sshSession.getUrl() + "/" + project.get()); + db = reviewDbProvider.open(); + atrScope.set(atrScope.newContext(reviewDbProvider, sshSession, + identifiedUserFactory.create(Providers.of(db), admin.getId()))); + } + + @After + public void cleanup() { + db.close(); + } + + @Test + public void abandon() throws GitAPIException, + IOException, RestApiException { + PushOneCommit.Result r = createChange(); + gApi.changes() + .id("p~master~" + r.getChangeId()) + .abandon(); + } + + @Test + public void restore() throws GitAPIException, + IOException, RestApiException { + PushOneCommit.Result r = createChange(); + gApi.changes() + .id("p~master~" + r.getChangeId()) + .abandon(); + gApi.changes() + .id("p~master~" + r.getChangeId()) + .restore(); + } + + @Test + public void revert() throws GitAPIException, + IOException, RestApiException { + PushOneCommit.Result r = createChange(); + gApi.changes() + .id("p~master~" + r.getChangeId()) + .revision(r.getCommit().name()) + .review(approve()); + gApi.changes() + .id("p~master~" + r.getChangeId()) + .revision(r.getCommit().name()) + .submit(); + gApi.changes() + .id("p~master~" + r.getChangeId()) + .revert(); + } + + // Change is already up to date + @Test(expected = ResourceConflictException.class) + public void rebase() throws GitAPIException, + IOException, RestApiException { + PushOneCommit.Result r = createChange(); + gApi.changes() + .id("p~master~" + r.getChangeId()) + .revision(r.getCommit().name()) + .rebase(); + } + + private PushOneCommit.Result createChange() throws GitAPIException, + IOException { + PushOneCommit push = new PushOneCommit(db, admin.getIdent()); + return push.to(git, "refs/for/master"); + } + + private static ReviewInput approve() { + return new ReviewInput() + .message("Looks good!") + .label("Code-Review", 2); + } +} diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/BUCK index 6875aad541..94e6f6a5e3 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/BUCK +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/BUCK @@ -1,6 +1,6 @@ include_defs('//gerrit-acceptance-tests/tests.defs') acceptance_tests( - srcs = ['ReviewIT.java'], + srcs = glob(['*IT.java']), deps = ['//gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git:util'], ) diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/ReviewIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java similarity index 73% rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/ReviewIT.java rename to gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java index 28b9fafcce..d60a9044cb 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/ReviewIT.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java @@ -18,7 +18,6 @@ import static com.google.gerrit.acceptance.git.GitUtil.cloneProject; import static com.google.gerrit.acceptance.git.GitUtil.createProject; import static com.google.gerrit.acceptance.git.GitUtil.initSsh; -import com.google.common.collect.Maps; import com.google.gerrit.acceptance.AbstractDaemonTest; import com.google.gerrit.acceptance.AcceptanceTestRequestScope; import com.google.gerrit.acceptance.AccountCreator; @@ -27,12 +26,14 @@ import com.google.gerrit.acceptance.TestAccount; import com.google.gerrit.acceptance.git.PushOneCommit; import com.google.gerrit.extensions.api.GerritApi; import com.google.gerrit.extensions.api.changes.ReviewInput; +import com.google.gerrit.extensions.api.changes.RevisionApi; import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.IdentifiedUser; import com.google.gwtorm.server.SchemaFactory; import com.google.inject.Inject; +import com.google.inject.util.Providers; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; @@ -42,7 +43,7 @@ import org.junit.Test; import java.io.IOException; -public class ReviewIT extends AbstractDaemonTest { +public class RevisionIT extends AbstractDaemonTest { @Inject private AccountCreator accounts; @@ -54,7 +55,7 @@ public class ReviewIT extends AbstractDaemonTest { private GerritApi gApi; @Inject - AcceptanceTestRequestScope atrScope; + private AcceptanceTestRequestScope atrScope; @Inject private IdentifiedUser.GenericFactory identifiedUserFactory; @@ -71,9 +72,9 @@ public class ReviewIT extends AbstractDaemonTest { SshSession sshSession = new SshSession(server, admin); createProject(sshSession, project.get()); git = cloneProject(sshSession.getUrl() + "/" + project.get()); - atrScope.set(atrScope.newContext(reviewDbProvider, sshSession, - identifiedUserFactory.create(admin.getId()))); db = reviewDbProvider.open(); + atrScope.set(atrScope.newContext(reviewDbProvider, sshSession, + identifiedUserFactory.create(Providers.of(db), admin.getId()))); } @After @@ -88,17 +89,38 @@ public class ReviewIT extends AbstractDaemonTest { gApi.changes() .id("p~master~" + r.getChangeId()) .revision(r.getCommit().name()) - .review(makeReview()); + .review(approve()); } @Test public void reviewId() throws GitAPIException, IOException, RestApiException { PushOneCommit.Result r = createChange(); + gApi.changes() + .id(r.getChangeId()) + .current() + .review(approve()); + } + + @Test + public void submit() throws GitAPIException, + IOException, RestApiException { + PushOneCommit.Result r = createChange(); + RevisionApi rApi = gApi.changes() + .id("p~master~" + r.getChangeId()) + .current(); + rApi.review(approve()); + rApi.submit(); + } + + @Test + public void deleteDraft() throws GitAPIException, + IOException, RestApiException { + PushOneCommit.Result r = createDraft(); gApi.changes() .id(r.getChangeId()) .revision(r.getCommit().name()) - .review(makeReview()); + .delete(); } private PushOneCommit.Result createChange() throws GitAPIException, @@ -107,11 +129,15 @@ public class ReviewIT extends AbstractDaemonTest { return push.to(git, "refs/for/master"); } - private static ReviewInput makeReview() { - ReviewInput in = new ReviewInput(); - in.message = "Looks good!"; - in.labels = Maps.newHashMap(); - in.labels.put("Code-Review", (short) 2); - return in; + private PushOneCommit.Result createDraft() throws GitAPIException, + IOException { + PushOneCommit push = new PushOneCommit(db, admin.getIdent()); + return push.to(git, "refs/drafts/master"); + } + + private static ReviewInput approve() { + return new ReviewInput() + .message("Looks good!") + .label("Code-Review", 2); } } diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java index fc2fccd5b3..5e2c0d80f6 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java @@ -28,6 +28,7 @@ import com.google.gerrit.acceptance.SshSession; import com.google.gerrit.acceptance.TestAccount; import com.google.gerrit.acceptance.git.GitUtil; import com.google.gerrit.acceptance.git.PushOneCommit; +import com.google.gerrit.extensions.api.changes.ReviewInput; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project.InheritableBoolean; @@ -171,9 +172,9 @@ public abstract class AbstractSubmit extends AbstractDaemonTest { } private void approve(String changeId) throws IOException { - RestResponse r = - session.post("/changes/" + changeId + "/revisions/current/review", - ReviewInput.approve()); + RestResponse r = session.post( + "/changes/" + changeId + "/revisions/current/review", + new ReviewInput().label("Code-Review", 2)); assertEquals(HttpStatus.SC_OK, r.getStatusCode()); r.consume(); } diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/BUCK index 20b1033f36..754d6a1a88 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/BUCK +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/BUCK @@ -32,8 +32,8 @@ java_library( java_library( name = 'util', srcs = ['AccountInfo.java', 'ChangeInfo.java', 'ChangeMessageInfo.java', - 'GroupInfo.java', 'ProjectConfigInput.java', 'ReviewInput.java', - 'SubmitInput.java', 'SuggestReviewerInfo.java'], + 'GroupInfo.java', 'ProjectConfigInput.java', 'SubmitInput.java', + 'SuggestReviewerInfo.java'], deps = [ '//lib:guava', '//gerrit-reviewdb:server', diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/AbandonInput.java similarity index 64% rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java rename to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/AbandonInput.java index a5371d2912..04a7bc7b1c 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/AbandonInput.java @@ -12,19 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.google.gerrit.acceptance.rest.change; +package com.google.gerrit.extensions.api.changes; -import com.google.common.collect.Maps; +import com.google.gerrit.extensions.restapi.DefaultInput; -import java.util.Map; - -public class ReviewInput { - Map labels; - - public static ReviewInput approve() { - ReviewInput in = new ReviewInput(); - in.labels = Maps.newHashMap(); - in.labels.put("Code-Review", 2); - return in; - } +public class AbandonInput { + @DefaultInput + public String message; } + diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java index 68507d1abe..a264009a77 100644 --- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java @@ -17,6 +17,18 @@ package com.google.gerrit.extensions.api.changes; import com.google.gerrit.extensions.restapi.RestApiException; public interface ChangeApi { + String id(); + + RevisionApi current() throws RestApiException; RevisionApi revision(int id) throws RestApiException; RevisionApi revision(String id) throws RestApiException; + + void abandon() throws RestApiException; + void abandon(AbandonInput in) throws RestApiException; + + void restore() throws RestApiException; + void restore(RestoreInput in) throws RestApiException; + + ChangeApi revert() throws RestApiException; + ChangeApi revert(RevertInput in) throws RestApiException; } diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RestoreInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RestoreInput.java new file mode 100644 index 0000000000..a116dde542 --- /dev/null +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RestoreInput.java @@ -0,0 +1,23 @@ +// Copyright (C) 2013 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.api.changes; + +import com.google.gerrit.extensions.restapi.DefaultInput; + +public class RestoreInput { + @DefaultInput + public String message; +} + diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevertInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevertInput.java new file mode 100644 index 0000000000..2c1c6887a4 --- /dev/null +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevertInput.java @@ -0,0 +1,22 @@ +// Copyright (C) 2013 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.api.changes; + +import com.google.gerrit.extensions.restapi.DefaultInput; + +public class RevertInput { + @DefaultInput + public String message; +} diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java index 5ba31b4f26..969c23d1b9 100644 --- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java @@ -16,6 +16,7 @@ package com.google.gerrit.extensions.api.changes; import com.google.gerrit.extensions.restapi.DefaultInput; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -85,4 +86,31 @@ public class ReviewInput { public int endCharacter; } } + + public ReviewInput message(String msg) { + message = msg != null && !msg.isEmpty() ? msg : null; + return this; + } + + public ReviewInput label(String name, short value) { + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException(); + } + if (labels == null) { + labels = new LinkedHashMap(4); + } + labels.put(name, value); + return this; + } + + public ReviewInput label(String name, int value) { + if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { + throw new IllegalArgumentException(); + } + return label(name, (short) value); + } + + public ReviewInput label(String name) { + return label(name, (short) 1); + } } diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java index 2a0fc9be6e..ff4a94e501 100644 --- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java @@ -17,5 +17,11 @@ package com.google.gerrit.extensions.api.changes; import com.google.gerrit.extensions.restapi.RestApiException; public interface RevisionApi { + void delete() throws RestApiException; + void rebase() throws RestApiException; void review(ReviewInput in) throws RestApiException; + + /** {@code submit} with {@link SubmitInput#waitForMerge} set to true. */ + void submit() throws RestApiException; + void submit(SubmitInput in) throws RestApiException; } diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/SubmitInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/SubmitInput.java new file mode 100644 index 0000000000..91e3c70eb1 --- /dev/null +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/SubmitInput.java @@ -0,0 +1,19 @@ +// Copyright (C) 2013 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.api.changes; + +public class SubmitInput { + public boolean waitForMerge; +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java index 47572dea69..bbc147fe36 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java @@ -14,34 +14,68 @@ package com.google.gerrit.server.api.changes; +import com.google.gerrit.common.errors.EmailException; +import com.google.gerrit.extensions.api.changes.AbandonInput; import com.google.gerrit.extensions.api.changes.ChangeApi; +import com.google.gerrit.extensions.api.changes.Changes; +import com.google.gerrit.extensions.api.changes.RestoreInput; +import com.google.gerrit.extensions.api.changes.RevertInput; import com.google.gerrit.extensions.api.changes.RevisionApi; import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.RestApiException; +import com.google.gerrit.server.change.Abandon; import com.google.gerrit.server.change.ChangeResource; +import com.google.gerrit.server.change.Restore; +import com.google.gerrit.server.change.Revert; import com.google.gerrit.server.change.Revisions; +import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.assistedinject.Assisted; +import java.io.IOException; + class ChangeApiImpl implements ChangeApi { interface Factory { ChangeApiImpl create(ChangeResource change); } + private final Changes changeApi; private final Revisions revisions; private final RevisionApiImpl.Factory revisionApi; private final ChangeResource change; + private final Provider abandon; + private final Provider revert; + private final Provider restore; @Inject - ChangeApiImpl(Revisions revisions, - RevisionApiImpl.Factory api, + ChangeApiImpl(Changes changeApi, + Revisions revisions, + RevisionApiImpl.Factory revisionApi, + Provider abandon, + Provider revert, + Provider restore, @Assisted ChangeResource change) { + this.changeApi = changeApi; + this.revert = revert; this.revisions = revisions; - this.revisionApi = api; + this.revisionApi = revisionApi; + this.abandon = abandon; + this.restore = restore; this.change = change; } + @Override + public String id() { + return Integer.toString(change.getChange().getId().get()); + } + + @Override + public RevisionApi current() throws RestApiException { + return revision("current"); + } + @Override public RevisionApi revision(int id) throws RestApiException { return revision(String.valueOf(id)); @@ -56,4 +90,56 @@ class ChangeApiImpl implements ChangeApi { throw new RestApiException("Cannot parse revision", e); } } + + @Override + public void abandon() throws RestApiException { + abandon(new AbandonInput()); + } + + @Override + public void abandon(AbandonInput in) throws RestApiException { + try { + abandon.get().apply(change, in); + } catch (OrmException e) { + throw new RestApiException("Cannot abandon change", e); + } catch (IOException e) { + throw new RestApiException("Cannot abandon change", e); + } + } + + @Override + public void restore() throws RestApiException { + restore(new RestoreInput()); + } + + @Override + public void restore(RestoreInput in) throws RestApiException { + try { + restore.get().apply(change, in); + } catch (OrmException e) { + throw new RestApiException("Cannot restore change", e); + } catch (IOException e) { + throw new RestApiException("Cannot restore change", e); + } + } + + @Override + public ChangeApi revert() throws RestApiException { + return revert(new RevertInput()); + } + + @Override + public ChangeApi revert(RevertInput in) throws RestApiException { + try { + return changeApi.id(revert.get().apply(change, in)._number); + } catch (OrmException e) { + throw new RestApiException("Cannot revert change", e); + } catch (EmailException e) { + throw new RestApiException("Cannot revert change", e); + } catch (IOException e) { + throw new RestApiException("Cannot revert change", e); + } catch (NoSuchChangeException e) { + throw new RestApiException("Cannot revert change", e); + } + } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java index 48ca9f9a03..4e401c0d77 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java @@ -14,11 +14,16 @@ package com.google.gerrit.server.api.changes; +import com.google.gerrit.common.errors.EmailException; import com.google.gerrit.extensions.api.changes.ReviewInput; import com.google.gerrit.extensions.api.changes.RevisionApi; +import com.google.gerrit.extensions.api.changes.SubmitInput; import com.google.gerrit.extensions.restapi.RestApiException; +import com.google.gerrit.server.change.DeleteDraftPatchSet; import com.google.gerrit.server.change.PostReview; +import com.google.gerrit.server.change.Rebase; import com.google.gerrit.server.change.RevisionResource; +import com.google.gerrit.server.change.Submit; import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; import com.google.inject.Provider; @@ -31,13 +36,22 @@ class RevisionApiImpl implements RevisionApi { RevisionApiImpl create(RevisionResource r); } + private final Provider deleteDraft; + private final Provider rebase; private final Provider review; + private final Provider submit; private final RevisionResource revision; @Inject - RevisionApiImpl(Provider review, + RevisionApiImpl(Provider deleteDraft, + Provider rebase, + Provider review, + Provider submit, @Assisted RevisionResource r) { + this.deleteDraft = deleteDraft; + this.rebase = rebase; this.review = review; + this.submit = submit; this.revision = r; } @@ -51,4 +65,44 @@ class RevisionApiImpl implements RevisionApi { throw new RestApiException("Cannot post review", e); } } + + @Override + public void submit() throws RestApiException { + SubmitInput in = new SubmitInput(); + in.waitForMerge = true; + submit(in); + } + + @Override + public void submit(SubmitInput in) throws RestApiException { + try { + submit.get().apply(revision, in); + } catch (OrmException e) { + throw new RestApiException("Cannot submit change", e); + } catch (IOException e) { + throw new RestApiException("Cannot submit change", e); + } + } + + @Override + public void delete() throws RestApiException { + try { + deleteDraft.get().apply(revision, null); + } catch (OrmException e) { + throw new RestApiException("Cannot delete draft ps", e); + } catch (IOException e) { + throw new RestApiException("Cannot delete draft ps", e); + } + } + + @Override + public void rebase() throws RestApiException { + try { + rebase.get().apply(revision, null); + } catch (OrmException e) { + throw new RestApiException("Cannot rebase ps", e); + } catch (EmailException e) { + throw new RestApiException("Cannot rebase ps", e); + } + } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java index 4959cfb0e3..1218de8dfc 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java @@ -17,9 +17,9 @@ package com.google.gerrit.server.change; import com.google.common.base.Strings; import com.google.common.util.concurrent.CheckedFuture; import com.google.gerrit.common.ChangeHooks; +import com.google.gerrit.extensions.api.changes.AbandonInput; import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.BadRequestException; -import com.google.gerrit.extensions.restapi.DefaultInput; import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.webui.UiAction; @@ -29,7 +29,6 @@ import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.ApprovalsUtil; import com.google.gerrit.server.ChangeUtil; import com.google.gerrit.server.IdentifiedUser; -import com.google.gerrit.server.change.Abandon.Input; import com.google.gerrit.server.change.ChangeJson.ChangeInfo; import com.google.gerrit.server.index.ChangeIndexer; import com.google.gerrit.server.mail.AbandonedSender; @@ -46,7 +45,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Collections; -public class Abandon implements RestModifyView, +public class Abandon implements RestModifyView, UiAction { private static final Logger log = LoggerFactory.getLogger(Abandon.class); @@ -56,11 +55,6 @@ public class Abandon implements RestModifyView, private final ChangeJson json; private final ChangeIndexer indexer; - public static class Input { - @DefaultInput - public String message; - } - @Inject Abandon(ChangeHooks hooks, AbandonedSender.Factory abandonedSenderFactory, @@ -75,9 +69,9 @@ public class Abandon implements RestModifyView, } @Override - public Object apply(ChangeResource req, Input input) + public Object apply(ChangeResource req, AbandonInput input) throws BadRequestException, AuthException, - ResourceConflictException, Exception { + ResourceConflictException, OrmException, IOException { ChangeControl control = req.getControl(); IdentifiedUser caller = (IdentifiedUser) control.getCurrentUser(); Change change = req.getChange(); @@ -144,7 +138,7 @@ public class Abandon implements RestModifyView, && resource.getControl().canAbandon()); } - private ChangeMessage newMessage(Input input, IdentifiedUser caller, + private ChangeMessage newMessage(AbandonInput input, IdentifiedUser caller, Change change) throws OrmException { StringBuilder msg = new StringBuilder(); msg.append("Abandoned"); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java index d31d1f0498..a05599302a 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java @@ -17,8 +17,8 @@ package com.google.gerrit.server.change; import com.google.common.base.Strings; import com.google.common.util.concurrent.CheckedFuture; import com.google.gerrit.common.ChangeHooks; +import com.google.gerrit.extensions.api.changes.RestoreInput; import com.google.gerrit.extensions.restapi.AuthException; -import com.google.gerrit.extensions.restapi.DefaultInput; import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.webui.UiAction; @@ -30,7 +30,6 @@ import com.google.gerrit.server.ApprovalsUtil; import com.google.gerrit.server.ChangeUtil; import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.change.ChangeJson.ChangeInfo; -import com.google.gerrit.server.change.Restore.Input; import com.google.gerrit.server.index.ChangeIndexer; import com.google.gerrit.server.mail.ReplyToChangeSender; import com.google.gerrit.server.mail.RestoredSender; @@ -46,7 +45,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Collections; -public class Restore implements RestModifyView, +public class Restore implements RestModifyView, UiAction { private static final Logger log = LoggerFactory.getLogger(Restore.class); @@ -56,11 +55,6 @@ public class Restore implements RestModifyView, private final ChangeJson json; private final ChangeIndexer indexer; - public static class Input { - @DefaultInput - public String message; - } - @Inject Restore(ChangeHooks hooks, RestoredSender.Factory restoredSenderFactory, @@ -75,8 +69,9 @@ public class Restore implements RestModifyView, } @Override - public Object apply(ChangeResource req, Input input) - throws Exception { + public Object apply(ChangeResource req, RestoreInput input) + throws OrmException, IOException, AuthException, + ResourceConflictException { ChangeControl control = req.getControl(); IdentifiedUser caller = (IdentifiedUser) control.getCurrentUser(); Change change = req.getChange(); @@ -143,7 +138,7 @@ public class Restore implements RestModifyView, && resource.getControl().canRestore()); } - private ChangeMessage newMessage(Input input, IdentifiedUser caller, + private ChangeMessage newMessage(RestoreInput input, IdentifiedUser caller, Change change) throws OrmException { StringBuilder msg = new StringBuilder(); msg.append("Restored"); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Revert.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Revert.java index 73a6b03539..74bc68f906 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Revert.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Revert.java @@ -16,6 +16,8 @@ package com.google.gerrit.server.change; import com.google.common.base.Strings; import com.google.gerrit.common.ChangeHooks; +import com.google.gerrit.common.errors.EmailException; +import com.google.gerrit.extensions.api.changes.RevertInput; import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.BadRequestException; import com.google.gerrit.extensions.restapi.ResourceConflictException; @@ -27,21 +29,25 @@ import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.ChangeUtil; import com.google.gerrit.server.GerritPersonIdent; import com.google.gerrit.server.IdentifiedUser; -import com.google.gerrit.server.change.Revert.Input; +import com.google.gerrit.server.change.ChangeJson.ChangeInfo; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.validators.CommitValidators; import com.google.gerrit.server.mail.RevertedSender; import com.google.gerrit.server.patch.PatchSetInfoFactory; import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.InvalidChangeOperationException; +import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gerrit.server.ssh.NoSshInfo; +import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; import com.google.inject.Provider; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Repository; -public class Revert implements RestModifyView, +import java.io.IOException; + +public class Revert implements RestModifyView, UiAction { private final ChangeHooks hooks; private final RevertedSender.Factory revertedSenderFactory; @@ -53,10 +59,6 @@ public class Revert implements RestModifyView, private final PatchSetInfoFactory patchSetInfoFactory; private final ChangeInserter.Factory changeInserterFactory; - public static class Input { - public String message; - } - @Inject Revert(ChangeHooks hooks, RevertedSender.Factory revertedSenderFactory, @@ -79,7 +81,9 @@ public class Revert implements RestModifyView, } @Override - public Object apply(ChangeResource req, Input input) throws Exception { + public ChangeInfo apply(ChangeResource req, RevertInput input) + throws AuthException, ResourceConflictException, IOException, + NoSuchChangeException, EmailException, OrmException, BadRequestException { ChangeControl control = req.getControl(); Change change = req.getChange(); if (!control.canAddPatchSet()) { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java index a5070964d5..22b6562fb1 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java @@ -21,6 +21,7 @@ import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.gerrit.common.data.SubmitRecord; +import com.google.gerrit.extensions.api.changes.SubmitInput; import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.RestModifyView; @@ -34,7 +35,6 @@ import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.ChangeUtil; import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.ProjectUtil; -import com.google.gerrit.server.change.Submit.Input; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.MergeQueue; import com.google.gerrit.server.index.ChangeIndexer; @@ -53,7 +53,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -public class Submit implements RestModifyView, +public class Submit implements RestModifyView, UiAction { public static class Input { public boolean waitForMerge; @@ -90,9 +90,9 @@ public class Submit implements RestModifyView, } @Override - public Output apply(RevisionResource rsrc, Input input) throws AuthException, - ResourceConflictException, RepositoryNotFoundException, IOException, - OrmException { + public Output apply(RevisionResource rsrc, SubmitInput input) + throws AuthException, ResourceConflictException, + RepositoryNotFoundException, IOException, OrmException { ChangeControl control = rsrc.getControl(); IdentifiedUser caller = (IdentifiedUser) control.getCurrentUser(); Change change = rsrc.getChange(); @@ -317,7 +317,7 @@ public class Submit implements RestModifyView, } public static class CurrentRevision implements - RestModifyView { + RestModifyView { private final Provider dbProvider; private final Submit submit; private final ChangeJson json; @@ -332,9 +332,9 @@ public class Submit implements RestModifyView, } @Override - public Object apply(ChangeResource rsrc, Input input) throws AuthException, - ResourceConflictException, RepositoryNotFoundException, IOException, - OrmException { + public Object apply(ChangeResource rsrc, SubmitInput input) + throws AuthException, ResourceConflictException, + RepositoryNotFoundException, IOException, OrmException { PatchSet ps = dbProvider.get().patchSets() .get(rsrc.getChange().currentPatchSetId()); if (ps == null) { diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java index 5f0081827a..6665a25668 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java @@ -23,23 +23,19 @@ import com.google.gerrit.common.data.LabelValue; import com.google.gerrit.common.data.ReviewResult; import com.google.gerrit.common.data.ReviewResult.Error.Type; import com.google.gerrit.extensions.api.GerritApi; +import com.google.gerrit.extensions.api.changes.AbandonInput; +import com.google.gerrit.extensions.api.changes.RestoreInput; import com.google.gerrit.extensions.api.changes.ReviewInput; import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.BadRequestException; import com.google.gerrit.extensions.restapi.ResourceConflictException; +import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.RevId; import com.google.gerrit.reviewdb.server.ReviewDb; -import com.google.gerrit.server.change.Abandon; -import com.google.gerrit.server.change.ChangeResource; -import com.google.gerrit.server.change.DeleteDraftPatchSet; -import com.google.gerrit.server.change.Restore; -import com.google.gerrit.server.change.RevisionResource; -import com.google.gerrit.server.change.Submit; import com.google.gerrit.server.changedetail.PublishDraft; import com.google.gerrit.server.config.AllProjectsName; -import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.InvalidChangeOperationException; import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gerrit.server.project.NoSuchProjectException; @@ -131,9 +127,6 @@ public class ReviewCommand extends SshCommand { @Inject private ReviewDb db; - @Inject - private DeleteDraftPatchSet deleteDraftPatchSetImpl; - @Inject private ProjectControl.Factory projectControlFactory; @@ -141,23 +134,11 @@ public class ReviewCommand extends SshCommand { private AllProjectsName allProjects; @Inject - private ChangeControl.Factory changeControlFactory; - - @Inject - private Provider abandonProvider; - - @Inject - private Provider api; + private Provider gApi; @Inject private PublishDraft.Factory publishDraftFactory; - @Inject - private Provider restoreProvider; - - @Inject - private Provider submitProvider; - private List optionList; private Map customLabels; @@ -213,10 +194,10 @@ public class ReviewCommand extends SshCommand { } } - private void applyReview(final ChangeControl ctl, final PatchSet patchSet, + private void applyReview(PatchSet patchSet, final ReviewInput review) throws Exception { - api.get().changes() - .id(ctl.getChange().getChangeId()) + gApi.get().changes() + .id(patchSet.getId().getParentKey().get()) .revision(patchSet.getRevision().get()) .review(review); } @@ -248,44 +229,41 @@ public class ReviewCommand extends SshCommand { } try { - ChangeControl ctl = - changeControlFactory.controlFor(patchSet.getId().getParentKey()); - if (abandonChange) { - final Abandon abandon = abandonProvider.get(); - final Abandon.Input input = new Abandon.Input(); + AbandonInput input = new AbandonInput(); input.message = changeComment; - applyReview(ctl, patchSet, review); + applyReview(patchSet, review); try { - abandon.apply(new ChangeResource(ctl), input); + gApi.get().changes() + .id(patchSet.getId().getParentKey().get()) + .abandon(input); } catch (AuthException e) { writeError("error: " + parseError(Type.ABANDON_NOT_PERMITTED) + "\n"); } catch (ResourceConflictException e) { writeError("error: " + parseError(Type.CHANGE_IS_CLOSED) + "\n"); } } else if (restoreChange) { - final Restore restore = restoreProvider.get(); - final Restore.Input input = new Restore.Input(); + RestoreInput input = new RestoreInput(); input.message = changeComment; try { - restore.apply(new ChangeResource(ctl), input); - applyReview(ctl, patchSet, review); + gApi.get().changes() + .id(patchSet.getId().getParentKey().get()) + .restore(input); + applyReview(patchSet, review); } catch (AuthException e) { writeError("error: " + parseError(Type.RESTORE_NOT_PERMITTED) + "\n"); } catch (ResourceConflictException e) { writeError("error: " + parseError(Type.CHANGE_NOT_ABANDONED) + "\n"); } } else { - applyReview(ctl, patchSet, review); + applyReview(patchSet, review); } if (submitChange) { - Submit submit = submitProvider.get(); - Submit.Input input = new Submit.Input(); - input.waitForMerge = true; - submit.apply(new RevisionResource( - new ChangeResource(ctl), patchSet), - input); + gApi.get().changes() + .id(patchSet.getId().getParentKey().get()) + .revision(patchSet.getRevision().get()) + .submit(); } if (publishPatchSet) { @@ -293,9 +271,10 @@ public class ReviewCommand extends SshCommand { publishDraftFactory.create(patchSet.getId()).call(); handleReviewResultErrors(result); } else if (deleteDraftPatchSet) { - deleteDraftPatchSetImpl.apply(new RevisionResource( - new ChangeResource(ctl), patchSet), - new DeleteDraftPatchSet.Input()); + gApi.get().changes() + .id(patchSet.getId().getParentKey().get()) + .revision(patchSet.getRevision().get()) + .delete(); } } catch (InvalidChangeOperationException e) { throw error(e.getMessage()); @@ -307,6 +286,8 @@ public class ReviewCommand extends SshCommand { throw error(e.getMessage()); } catch (ResourceConflictException e) { throw error(e.getMessage()); + } catch (RestApiException e) { + throw error(e.getMessage()); } }