InlineEdit: Add GET /changes/<id>/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
This commit is contained in:
David Ostrovsky
2014-07-29 00:40:02 +02:00
parent 7c51481994
commit 1a49f62750
7 changed files with 230 additions and 4 deletions

View File

@@ -1139,6 +1139,61 @@ Administrate Server] capability.
HTTP/1.1 204 No Content 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]]
== Reviewer Endpoints == Reviewer Endpoints
@@ -3589,6 +3644,17 @@ The `WebLinkInfo` entity describes a link to an external site.
|`url` |The link URL. |`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 GERRIT
------ ------
Part of link:index.html[Gerrit Code Review] Part of link:index.html[Gerrit Code Review]

View File

@@ -27,9 +27,10 @@ import com.google.common.base.Optional;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest; import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.AcceptanceTestRequestScope; import com.google.gerrit.acceptance.AcceptanceTestRequestScope;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit; import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.acceptance.RestSession; 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.BinaryResult;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.reviewdb.client.Change; 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.Inject;
import com.google.inject.util.Providers; import com.google.inject.util.Providers;
import org.apache.http.HttpStatus;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.RefUpdate;
@@ -56,10 +58,10 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Date; import java.util.Date;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
@NoHttpd
public class ChangeEditIT extends AbstractDaemonTest { public class ChangeEditIT extends AbstractDaemonTest {
private final static String FILE_NAME = "foo"; private final static String FILE_NAME = "foo";
@@ -211,6 +213,32 @@ public class ChangeEditIT extends AbstractDaemonTest {
assertFalse(edit.isPresent()); 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<ChangeEdit> 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 @Test
public void deleteExistingFile() throws Exception { public void deleteExistingFile() throws Exception {
assertEquals(RefUpdate.Result.NEW, assertEquals(RefUpdate.Result.NEW,
@@ -410,4 +438,16 @@ public class ChangeEditIT extends AbstractDaemonTest {
content.writeTo(os); content.writeTo(os);
return os.toByteArray(); 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);
}
} }

View File

@@ -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;
}

View File

@@ -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 static class RevisionInfo extends JavaScriptObject {
public final native int _number() /*-{ return this._number; }-*/; public final native int _number() /*-{ return this._number; }-*/;
public final native String name() /*-{ return this.name; }-*/; public final native String name() /*-{ return this.name; }-*/;

View File

@@ -14,21 +14,37 @@
package com.google.gerrit.server.change; 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.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.ChildCollection; import com.google.gerrit.extensions.restapi.ChildCollection;
import com.google.gerrit.extensions.restapi.IdString; 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.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.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.io.IOException;
@Singleton @Singleton
class ChangeEdits implements class ChangeEdits implements
ChildCollection<ChangeResource, ChangeEditResource> { ChildCollection<ChangeResource, ChangeEditResource> {
private final DynamicMap<RestView<ChangeEditResource>> views; private final DynamicMap<RestView<ChangeEditResource>> views;
private final Detail detail;
@Inject @Inject
ChangeEdits(DynamicMap<RestView<ChangeEditResource>> views) { ChangeEdits(DynamicMap<RestView<ChangeEditResource>> views,
Detail detail) {
this.views = views; this.views = views;
this.detail = detail;
} }
@Override @Override
@@ -38,11 +54,35 @@ class ChangeEdits implements
@Override @Override
public RestView<ChangeResource> list() { public RestView<ChangeResource> list() {
throw new IllegalStateException("not yet implemented"); return detail;
} }
@Override @Override
public ChangeEditResource parse(ChangeResource change, IdString id) { public ChangeEditResource parse(ChangeResource change, IdString id) {
throw new IllegalStateException("not yet implemented"); throw new IllegalStateException("not yet implemented");
} }
@Singleton
static class Detail implements RestReadView<ChangeResource> {
private final ChangeEditUtil editUtil;
private final ChangeEditJson editJson;
@Inject
Detail(ChangeEditJson editJson,
ChangeEditUtil editUtil) {
this.editJson = editJson;
this.editUtil = editUtil;
}
@Override
public Response<EditInfo> apply(ChangeResource rsrc) throws AuthException,
IOException, NoSuchChangeException, InvalidChangeOperationException,
ResourceNotFoundException {
Optional<ChangeEdit> edit = editUtil.byChange(rsrc.getChange());
if (edit.isPresent()) {
return Response.ok(editJson.toEditInfo(edit.get()));
}
return Response.none();
}
}
} }

View File

@@ -101,6 +101,8 @@ public class Module extends RestApiModule {
get(FILE_KIND, "content").to(GetContent.class); get(FILE_KIND, "content").to(GetContent.class);
get(FILE_KIND, "diff").to(GetDiff.class); get(FILE_KIND, "diff").to(GetDiff.class);
child(CHANGE_KIND, "edit").to(ChangeEdits.class);
install(new FactoryModule() { install(new FactoryModule() {
@Override @Override
protected void configure() { protected void configure() {

View File

@@ -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;
}
}