diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java index cc19c15829..32705ba727 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java @@ -56,7 +56,7 @@ import java.util.Set; public class PushOneCommit { public static final String SUBJECT = "test commit"; - static final String FILE_NAME = "a.txt"; + public static final String FILE_NAME = "a.txt"; private static final String FILE_CONTENT = "some content"; public interface Factory { diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java index 78b9a545d4..d77f11f093 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java @@ -14,9 +14,11 @@ package com.google.gerrit.acceptance.api.revision; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import com.google.common.collect.Iterables; import com.google.gerrit.acceptance.AbstractDaemonTest; import com.google.gerrit.acceptance.NoHttpd; import com.google.gerrit.acceptance.PushOneCommit; @@ -169,6 +171,36 @@ public class RevisionIT extends AbstractDaemonTest { .canRebase()); } + @Test + public void setUnsetReviewedFlag() throws Exception { + PushOneCommit push = pushFactory.create(db, admin.getIdent()); + PushOneCommit.Result r = push.to(git, "refs/for/master"); + + gApi.changes() + .id(r.getChangeId()) + .current() + .setReviewed(PushOneCommit.FILE_NAME, true); + + assertEquals(PushOneCommit.FILE_NAME, + Iterables.getOnlyElement( + gApi.changes() + .id(r.getChangeId()) + .current() + .reviewed())); + + gApi.changes() + .id(r.getChangeId()) + .current() + .setReviewed(PushOneCommit.FILE_NAME, false); + + assertTrue( + gApi.changes() + .id(r.getChangeId()) + .current() + .reviewed() + .isEmpty()); + } + protected RevisionApi revision(PushOneCommit.Result r) throws Exception { return gApi.changes() .id(r.getChangeId()) 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 a2a96f9359..20bcea9bb8 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,6 +17,8 @@ package com.google.gerrit.extensions.api.changes; import com.google.gerrit.extensions.restapi.NotImplementedException; import com.google.gerrit.extensions.restapi.RestApiException; +import java.util.Set; + public interface RevisionApi { void delete() throws RestApiException; void review(ReviewInput in) throws RestApiException; @@ -29,6 +31,9 @@ public interface RevisionApi { ChangeApi rebase() throws RestApiException; boolean canRebase(); + void setReviewed(String path, boolean reviewed) throws RestApiException; + Set reviewed() throws RestApiException; + /** * A default implementation which allows source compatibility * when adding new methods to the interface. @@ -73,5 +78,15 @@ public interface RevisionApi { public boolean canRebase() { throw new NotImplementedException(); } + + @Override + public void setReviewed(String path, boolean reviewed) throws RestApiException { + throw new NotImplementedException(); + } + + @Override + public Set reviewed() throws RestApiException { + throw new NotImplementedException(); + } } } 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 4b84cabd20..c709b3488b 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,6 +14,7 @@ package com.google.gerrit.server.api.changes; +import com.google.common.collect.ImmutableSet; import com.google.gerrit.common.errors.EmailException; import com.google.gerrit.extensions.api.changes.ChangeApi; import com.google.gerrit.extensions.api.changes.Changes; @@ -21,12 +22,17 @@ import com.google.gerrit.extensions.api.changes.CherryPickInput; 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.IdString; import com.google.gerrit.extensions.restapi.RestApiException; +import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.server.change.CherryPick; import com.google.gerrit.server.change.DeleteDraftPatchSet; +import com.google.gerrit.server.change.FileResource; +import com.google.gerrit.server.change.Files; import com.google.gerrit.server.change.PostReview; import com.google.gerrit.server.change.Publish; import com.google.gerrit.server.change.Rebase; +import com.google.gerrit.server.change.Reviewed; import com.google.gerrit.server.change.RevisionResource; import com.google.gerrit.server.change.Submit; import com.google.gerrit.server.changedetail.RebaseChange; @@ -36,6 +42,7 @@ import com.google.inject.Provider; import com.google.inject.assistedinject.Assisted; import java.io.IOException; +import java.util.Set; class RevisionApiImpl extends RevisionApi.NotImplemented implements RevisionApi { interface Factory { @@ -49,7 +56,11 @@ class RevisionApiImpl extends RevisionApi.NotImplemented implements RevisionApi private final RebaseChange rebaseChange; private final Submit submit; private final Publish publish; + private final Reviewed.PutReviewed putReviewed; + private final Reviewed.DeleteReviewed deleteReviewed; private final RevisionResource revision; + private final Provider files; + private final Provider listFiles; private final Provider review; @Inject @@ -60,6 +71,10 @@ class RevisionApiImpl extends RevisionApi.NotImplemented implements RevisionApi RebaseChange rebaseChange, Submit submit, Publish publish, + Reviewed.PutReviewed putReviewed, + Reviewed.DeleteReviewed deleteReviewed, + Provider files, + Provider listFiles, Provider review, @Assisted RevisionResource r) { this.changes = changes; @@ -70,6 +85,10 @@ class RevisionApiImpl extends RevisionApi.NotImplemented implements RevisionApi this.review = review; this.submit = submit; this.publish = publish; + this.files = files; + this.putReviewed = putReviewed; + this.deleteReviewed = deleteReviewed; + this.listFiles = listFiles; this.revision = r; } @@ -138,4 +157,33 @@ class RevisionApiImpl extends RevisionApi.NotImplemented implements RevisionApi throw new RestApiException("Cannot cherry pick", e); } } + + @Override + public void setReviewed(String path, boolean reviewed) throws RestApiException { + try { + RestModifyView view; + if (reviewed) { + view = putReviewed; + } else { + view = deleteReviewed; + } + view.apply( + files.get().parse(revision, IdString.fromDecoded(path)), + new Reviewed.Input()); + } catch (Exception e) { + throw new RestApiException("Cannot update reviewed flag", e); + } + } + + @SuppressWarnings("unchecked") + @Override + public Set reviewed() throws RestApiException { + try { + return ImmutableSet.copyOf((Iterable) listFiles + .get().setReviewed(true) + .apply(revision).value()); + } catch (OrmException e) { + throw new RestApiException("Cannot list reviewed files", e); + } + } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java index 75b99012c5..712c19643d 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java @@ -59,7 +59,7 @@ import java.util.Set; import java.util.SortedSet; import java.util.concurrent.TimeUnit; -class Files implements ChildCollection { +public class Files implements ChildCollection { private final DynamicMap> views; private final Provider list; @@ -85,7 +85,7 @@ class Files implements ChildCollection { return new FileResource(rev, id.get()); } - private static final class ListFiles implements RestReadView { + public static final class ListFiles implements RestReadView { private static final Logger log = LoggerFactory.getLogger(ListFiles.class); @Option(name = "--base", metaVar = "revision-id") @@ -116,6 +116,11 @@ class Files implements ChildCollection { this.patchListCache = patchListCache; } + public ListFiles setReviewed(boolean r) { + this.reviewed = r; + return this; + } + @Override public Response apply(RevisionResource resource) throws AuthException, BadRequestException, ResourceNotFoundException, OrmException { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewed.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewed.java index c138a600ac..120a414fcc 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewed.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewed.java @@ -26,12 +26,12 @@ import com.google.inject.Singleton; import java.util.Collections; -class Reviewed { - static class Input { +public class Reviewed { + public static class Input { } @Singleton - static class PutReviewed implements RestModifyView { + public static class PutReviewed implements RestModifyView { private final Provider dbProvider; @Inject @@ -60,7 +60,7 @@ class Reviewed { } @Singleton - static class DeleteReviewed implements RestModifyView { + public static class DeleteReviewed implements RestModifyView { private final Provider dbProvider; @Inject