From 1a49f627506effbe55b7e308c9e58f732443183c Mon Sep 17 00:00:00 2001 From: David Ostrovsky Date: Tue, 29 Jul 2014 00:40:02 +0200 Subject: [PATCH] InlineEdit: Add GET /changes//edit REST endpoint Add get REST endpoint to read details of change edit. Result is a EditInfo JSON response or no content when edit doesn't exist for this change. Change-Id: I72969cea48b4b1f13154bfa93d403405bec37494 --- Documentation/rest-api-changes.txt | 66 +++++++++++++++++++ .../gerrit/acceptance/edit/ChangeEditIT.java | 44 ++++++++++++- .../gerrit/extensions/common/EditInfo.java | 19 ++++++ .../gerrit/client/changes/ChangeInfo.java | 8 +++ .../gerrit/server/change/ChangeEdits.java | 44 ++++++++++++- .../google/gerrit/server/change/Module.java | 2 + .../gerrit/server/edit/ChangeEditJson.java | 51 ++++++++++++++ 7 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/EditInfo.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditJson.java diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt index 7a01b9985f..7bcd7a5690 100644 --- a/Documentation/rest-api-changes.txt +++ b/Documentation/rest-api-changes.txt @@ -1139,6 +1139,61 @@ Administrate Server] capability. HTTP/1.1 204 No Content ---- +[[edit-endpoints]] +== Change Edit Endpoints + +These endpoints are considered to be unstable and can be changed in +backwards incompatible way any time without notice. + +[[get-edit-detail]] +=== Get Change Edit Details +-- +'GET /changes/link:#change-id[\{change-id\}]/edit +-- + +Retrieves a change edit details. + +.Request +---- + GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/edit HTTP/1.0 +---- + +As response an link:#edit-info[EditInfo] entity is returned that +describes the change edit, or "`204 No Content`" when change edit doesn't +exist for this change. Change edits are stored on special branches and there +can be max one edit per user per change. Edits aren't tracked in the database. + +.Response +---- + HTTP/1.1 200 OK + Content-Disposition: attachment + Content-Type: application/json;charset=UTF-8 + + )]}' + { + "commit":{ + "parents":[ + { + "commit":"1eee2c9d8f352483781e772f35dc586a69ff5646", + } + ], + "author":{ + "name":"Shawn O. Pearce", + "email":"sop@google.com", + "date":"2012-04-24 18:08:08.000000000", + "tz":-420 + }, + "committer":{ + "name":"Shawn O. Pearce", + "email":"sop@google.com", + "date":"2012-04-24 18:08:08.000000000", + "tz":-420 + }, + "subject":"Use an EventBus to manage star icons", + "message":"Use an EventBus to manage star icons\n\nImage widgets that need to ..." + }, + } +---- [[reviewer-endpoints]] == Reviewer Endpoints @@ -3589,6 +3644,17 @@ The `WebLinkInfo` entity describes a link to an external site. |`url` |The link URL. |====================== +[[edit-info]] +=== EditInfo +The `EditInfo` entity contains information about a change edit. + +[options="header",width="50%",cols="1,^1,5"] +|=========================== +|Field Name ||Description +|`commit` ||The commit of change edit as +link:#commit-info[CommitInfo] entity. +|=========================== + GERRIT ------ Part of link:index.html[Gerrit Code Review] diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java index 45dcdc30c0..fa65acb071 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java @@ -27,9 +27,10 @@ import com.google.common.base.Optional; import com.google.common.collect.Iterables; import com.google.gerrit.acceptance.AbstractDaemonTest; import com.google.gerrit.acceptance.AcceptanceTestRequestScope; -import com.google.gerrit.acceptance.NoHttpd; import com.google.gerrit.acceptance.PushOneCommit; +import com.google.gerrit.acceptance.RestResponse; import com.google.gerrit.acceptance.RestSession; +import com.google.gerrit.extensions.common.EditInfo; import com.google.gerrit.extensions.restapi.BinaryResult; import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.reviewdb.client.Change; @@ -45,6 +46,7 @@ import com.google.gwtorm.server.SchemaFactory; import com.google.inject.Inject; import com.google.inject.util.Providers; +import org.apache.http.HttpStatus; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.RefUpdate; @@ -56,10 +58,10 @@ import org.junit.Before; import org.junit.Test; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.Date; import java.util.concurrent.atomic.AtomicLong; -@NoHttpd public class ChangeEditIT extends AbstractDaemonTest { private final static String FILE_NAME = "foo"; @@ -211,6 +213,32 @@ public class ChangeEditIT extends AbstractDaemonTest { assertFalse(edit.isPresent()); } + @Test + public void retrieveEdit() throws Exception { + RestResponse r = session.get(url()); + assertEquals(HttpStatus.SC_NO_CONTENT, r.getStatusCode()); + assertEquals(RefUpdate.Result.NEW, + modifier.createEdit( + change, + ps)); + Optional edit = editUtil.byChange(change); + assertEquals(RefUpdate.Result.FORCED, + modifier.modifyFile( + edit.get(), + FILE_NAME, + CONTENT_NEW)); + edit = editUtil.byChange(change); + EditInfo info = toEditInfo(); + assertEquals(edit.get().getRevision().get(), info.commit.commit); + assertEquals(1, info.commit.parents.size()); + + edit = editUtil.byChange(change); + editUtil.delete(edit.get()); + + r = session.get(url()); + assertEquals(HttpStatus.SC_NO_CONTENT, r.getStatusCode()); + } + @Test public void deleteExistingFile() throws Exception { assertEquals(RefUpdate.Result.NEW, @@ -410,4 +438,16 @@ public class ChangeEditIT extends AbstractDaemonTest { content.writeTo(os); return os.toByteArray(); } + + private String url() { + return "/changes/" + + change.getChangeId() + + "/edit"; + } + + private EditInfo toEditInfo() throws IOException { + RestResponse r = session.get(url()); + assertEquals(HttpStatus.SC_OK, r.getStatusCode()); + return newGson().fromJson(r.getReader(), EditInfo.class); + } } diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/EditInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/EditInfo.java new file mode 100644 index 0000000000..70cf7d604d --- /dev/null +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/EditInfo.java @@ -0,0 +1,19 @@ +// Copyright (C) 2014 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.common; + +public class EditInfo { + public CommitInfo commit; +} diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java index 4ca7ca2de2..b741dfe7bb 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java @@ -204,6 +204,14 @@ public class ChangeInfo extends JavaScriptObject { } } + public static class EditInfo extends JavaScriptObject { + public final native String name() /*-{ return this.name; }-*/; + public final native CommitInfo commit() /*-{ return this.commit; }-*/; + + protected EditInfo() { + } + } + public static class RevisionInfo extends JavaScriptObject { public final native int _number() /*-{ return this._number; }-*/; public final native String name() /*-{ return this.name; }-*/; diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java index 55834da0da..52b95e1379 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java @@ -14,21 +14,37 @@ package com.google.gerrit.server.change; +import com.google.common.base.Optional; +import com.google.gerrit.extensions.common.EditInfo; import com.google.gerrit.extensions.registration.DynamicMap; +import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.ChildCollection; import com.google.gerrit.extensions.restapi.IdString; +import com.google.gerrit.extensions.restapi.ResourceNotFoundException; +import com.google.gerrit.extensions.restapi.Response; +import com.google.gerrit.extensions.restapi.RestReadView; import com.google.gerrit.extensions.restapi.RestView; +import com.google.gerrit.server.edit.ChangeEdit; +import com.google.gerrit.server.edit.ChangeEditJson; +import com.google.gerrit.server.edit.ChangeEditUtil; +import com.google.gerrit.server.project.InvalidChangeOperationException; +import com.google.gerrit.server.project.NoSuchChangeException; import com.google.inject.Inject; import com.google.inject.Singleton; +import java.io.IOException; + @Singleton class ChangeEdits implements ChildCollection { private final DynamicMap> views; + private final Detail detail; @Inject - ChangeEdits(DynamicMap> views) { + ChangeEdits(DynamicMap> views, + Detail detail) { this.views = views; + this.detail = detail; } @Override @@ -38,11 +54,35 @@ class ChangeEdits implements @Override public RestView list() { - throw new IllegalStateException("not yet implemented"); + return detail; } @Override public ChangeEditResource parse(ChangeResource change, IdString id) { throw new IllegalStateException("not yet implemented"); } + + @Singleton + static class Detail implements RestReadView { + private final ChangeEditUtil editUtil; + private final ChangeEditJson editJson; + + @Inject + Detail(ChangeEditJson editJson, + ChangeEditUtil editUtil) { + this.editJson = editJson; + this.editUtil = editUtil; + } + + @Override + public Response apply(ChangeResource rsrc) throws AuthException, + IOException, NoSuchChangeException, InvalidChangeOperationException, + ResourceNotFoundException { + Optional edit = editUtil.byChange(rsrc.getChange()); + if (edit.isPresent()) { + return Response.ok(editJson.toEditInfo(edit.get())); + } + return Response.none(); + } + } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java index 4b8e33bf48..fb8cc1a6e2 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java @@ -101,6 +101,8 @@ public class Module extends RestApiModule { get(FILE_KIND, "content").to(GetContent.class); get(FILE_KIND, "diff").to(GetDiff.class); + child(CHANGE_KIND, "edit").to(ChangeEdits.class); + install(new FactoryModule() { @Override protected void configure() { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditJson.java new file mode 100644 index 0000000000..be88004b5a --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditJson.java @@ -0,0 +1,51 @@ +// Copyright (C) 2014 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.server.edit; + +import com.google.common.collect.Lists; +import com.google.gerrit.extensions.common.CommitInfo; +import com.google.gerrit.extensions.common.EditInfo; +import com.google.gerrit.server.CommonConverters; +import com.google.inject.Singleton; + +import org.eclipse.jgit.revwalk.RevCommit; + +import java.io.IOException; + +@Singleton +public class ChangeEditJson { + public EditInfo toEditInfo(ChangeEdit edit) throws IOException { + EditInfo out = new EditInfo(); + out.commit = fillCommit(edit.getEditCommit()); + return out; + } + + private static CommitInfo fillCommit(RevCommit editCommit) throws IOException { + CommitInfo commit = new CommitInfo(); + commit.commit = editCommit.toObjectId().getName(); + commit.parents = Lists.newArrayListWithCapacity(1); + commit.author = CommonConverters.toGitPerson(editCommit.getAuthorIdent()); + commit.committer = CommonConverters.toGitPerson( + editCommit.getCommitterIdent()); + commit.subject = editCommit.getShortMessage(); + commit.message = editCommit.getFullMessage(); + + CommitInfo i = new CommitInfo(); + i.commit = editCommit.getParent(0).toObjectId().getName(); + commit.parents.add(i); + + return commit; + } +}