InlineEdit: Add POST /changes/<id>/edit REST endpoint

Add post REST endpoint to create new change edit without content or
restore deleted file from change edit. When change doesn't exist yet
for this change it is created.

Change-Id: I7ff308b1e875b5591bf8492273048ae61cba3cff
This commit is contained in:
David Ostrovsky
2014-08-15 21:31:43 +02:00
parent a5ab829a4c
commit 138edb474a
3 changed files with 137 additions and 2 deletions

View File

@@ -1217,6 +1217,36 @@ content isn't provided, it is wiped out for that file. As response
HTTP/1.1 204 No Content
----
[[post-edit]]
=== Restore file content in Change Edit
--
'POST /changes/link:#change-id[\{change-id\}]/edit
--
Creates empty change edit or restores file content in change edit. The
request body needs to include a link:#change-edit-input[ChangeEditInput]
entity when a file within change edit should be restored.
.Request
----
POST /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/edit HTTP/1.0
Content-Type: application/json;charset=UTF-8
{
"path": "foo",
"restore": true
}
----
When change edit doesn't exist for this change yet it is created. When path
and restore flag are provided in request body, this file is restored. As
response "`204 No Content`" is returned.
.Response
----
HTTP/1.1 204 No Content
----
[[reviewer-endpoints]]
== Reviewer Endpoints
@@ -3677,6 +3707,17 @@ The `EditInfo` entity contains information about a change edit.
link:#commit-info[CommitInfo] entity.
|===========================
[[restore-path-input]]
=== RestorePathInput
The `RestorePathInput` entity contains information for restoring a
path within change edit.
[options="header",width="50%",cols="1,^1,5"]
|===========================
|Field Name ||Description
|`restore_path`|optional|Path to file to restore.
|===========================
GERRIT
------
Part of link:index.html[Gerrit Code Review]

View File

@@ -40,6 +40,7 @@ import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.change.ChangeEdits.Put;
import com.google.gerrit.server.change.ChangeEdits.Post;
import com.google.gerrit.server.change.FileContentUtil;
import com.google.gerrit.server.edit.ChangeEdit;
import com.google.gerrit.server.edit.ChangeEditModifier;
@@ -315,6 +316,18 @@ public class ChangeEditIT extends AbstractDaemonTest {
edit.get().getRevision().get(), FILE_NAME)));
}
@Test
public void restoreDeletedFileInPatchSetRest() throws Exception {
Post.Input in = new Post.Input();
in.restorePath = FILE_NAME;
assertEquals(SC_NO_CONTENT, session.post(urlEdit2(),
in).getStatusCode());
Optional<ChangeEdit> edit = editUtil.byChange(change2);
assertArrayEquals(CONTENT_OLD,
toBytes(fileUtil.getContent(edit.get().getChange().getProject(),
edit.get().getRevision().get(), FILE_NAME)));
}
@Test
public void amendExistingFile() throws Exception {
assertEquals(RefUpdate.Result.NEW,
@@ -390,6 +403,15 @@ public class ChangeEditIT extends AbstractDaemonTest {
edit.get().getRevision().get(), FILE_NAME)));
}
@Test
public void createEmptyEditRest() throws Exception {
assertEquals(SC_NO_CONTENT, session.post(urlEdit()).getStatusCode());
Optional<ChangeEdit> edit = editUtil.byChange(change);
assertArrayEquals(CONTENT_OLD,
toBytes(fileUtil.getContent(edit.get().getChange().getProject(),
edit.get().getRevision().get(), FILE_NAME)));
}
@Test
public void addNewFile() throws Exception {
assertEquals(RefUpdate.Result.NEW,
@@ -495,6 +517,12 @@ public class ChangeEditIT extends AbstractDaemonTest {
+ "/edit";
}
private String urlEdit2() {
return "/changes/"
+ change2.getChangeId()
+ "/edit/";
}
private String urlEditFile() {
return urlEdit()
+ "/"

View File

@@ -21,7 +21,9 @@ import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.common.EditInfo;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AcceptsCreate;
import com.google.gerrit.extensions.restapi.AcceptsPost;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ChildCollection;
import com.google.gerrit.extensions.restapi.DefaultInput;
import com.google.gerrit.extensions.restapi.IdString;
@@ -52,21 +54,25 @@ import java.io.IOException;
@Singleton
public class ChangeEdits implements
ChildCollection<ChangeResource, ChangeEditResource>,
AcceptsCreate<ChangeResource> {
AcceptsCreate<ChangeResource>,
AcceptsPost<ChangeResource> {
private final DynamicMap<RestView<ChangeEditResource>> views;
private final Create.Factory createFactory;
private final Detail detail;
private final ChangeEditUtil editUtil;
private final Post post;
@Inject
ChangeEdits(DynamicMap<RestView<ChangeEditResource>> views,
Create.Factory createFactory,
Detail detail,
ChangeEditUtil editUtil) {
ChangeEditUtil editUtil,
Post post) {
this.views = views;
this.createFactory = createFactory;
this.detail = detail;
this.editUtil = editUtil;
this.post = post;
}
@Override
@@ -97,6 +103,13 @@ public class ChangeEdits implements
return createFactory.create(parent.getChange(), id.get());
}
@SuppressWarnings("unchecked")
@Override
public Post post(ChangeResource parent) throws RestApiException {
return post;
}
/**
* Create handler that is activated when collection element is accessed
* but doesn't exist, e. g. PUT request with a path was called but
@@ -183,6 +196,59 @@ public class ChangeEdits implements
}
}
/**
* Post to edit collection resource. Two different operations are
* supported:
* <ul>
* <li>Create non existing change edit</li>
* <li>Restore path in existing change edit</li>
* </ul>
* The combination of two operations in one request is supported.
*/
@Singleton
public static class Post implements
RestModifyView<ChangeResource, Post.Input> {
public static class Input {
public String restorePath;
}
private final Provider<ReviewDb> db;
private final ChangeEditUtil editUtil;
private final ChangeEditModifier editModifier;
@Inject
Post(Provider<ReviewDb> db,
ChangeEditUtil editUtil,
ChangeEditModifier editModifier) {
this.db = db;
this.editUtil = editUtil;
this.editModifier = editModifier;
}
@Override
public Response<?> apply(ChangeResource resource, Post.Input input)
throws AuthException, InvalidChangeOperationException, IOException,
ResourceConflictException, OrmException {
Optional<ChangeEdit> edit = editUtil.byChange(resource.getChange());
if (!edit.isPresent()) {
edit = createEdit(resource.getChange());
}
if (input != null && !Strings.isNullOrEmpty(input.restorePath)) {
editModifier.restoreFile(edit.get(), input.restorePath);
}
return Response.none();
}
private Optional<ChangeEdit> createEdit(Change change)
throws AuthException, IOException, ResourceConflictException,
OrmException, InvalidChangeOperationException {
editModifier.createEdit(change,
db.get().patchSets().get(change.currentPatchSetId()));
return editUtil.byChange(change);
}
}
/**
* Put handler that is activated when PUT request is called on
* collection element.