Merge topic 'inline-3'
* changes: InlineEdit: Add POST /changes/<id>/edit REST endpoint InlineEdit: Add PUT /changes/<id>/edit/path%2fto%2ffile REST endpoint InlineEdit: Add GET /changes/<id>/edit REST endpoint
This commit is contained in:
@@ -23,16 +23,27 @@ import com.google.gerrit.server.edit.ChangeEdit;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
* Represents change edit resource, that is actualy two kinds of resources:
|
||||
* <ul>
|
||||
* <li>the change edit itself</li>
|
||||
* <li>a path within the edit</li>
|
||||
* </ul>
|
||||
* distinguished by whether path is null or not.
|
||||
*/
|
||||
public class ChangeEditResource implements RestResource {
|
||||
public static final TypeLiteral<RestView<ChangeEditResource>> CHANGE_EDIT_KIND =
|
||||
new TypeLiteral<RestView<ChangeEditResource>>() {};
|
||||
|
||||
private final ChangeResource change;
|
||||
private final ChangeEdit edit;
|
||||
private final String path;
|
||||
|
||||
public ChangeEditResource(ChangeResource change, ChangeEdit edit) {
|
||||
public ChangeEditResource(ChangeResource change, ChangeEdit edit,
|
||||
String path) {
|
||||
this.change = change;
|
||||
this.edit = edit;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
// TODO(davido): Make this cacheable.
|
||||
@@ -57,6 +68,10 @@ public class ChangeEditResource implements RestResource {
|
||||
return edit;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
Account.Id getAccountId() {
|
||||
return getUser().getAccountId();
|
||||
}
|
||||
|
||||
@@ -14,21 +14,65 @@
|
||||
|
||||
package com.google.gerrit.server.change;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.io.ByteStreams;
|
||||
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;
|
||||
import com.google.gerrit.extensions.restapi.RawInput;
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||
import com.google.gerrit.extensions.restapi.Response;
|
||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||
import com.google.gerrit.extensions.restapi.RestView;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.edit.ChangeEdit;
|
||||
import com.google.gerrit.server.edit.ChangeEditJson;
|
||||
import com.google.gerrit.server.edit.ChangeEditModifier;
|
||||
import com.google.gerrit.server.edit.ChangeEditUtil;
|
||||
import com.google.gerrit.server.project.InvalidChangeOperationException;
|
||||
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.Singleton;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Singleton
|
||||
class ChangeEdits implements
|
||||
ChildCollection<ChangeResource, ChangeEditResource> {
|
||||
public class ChangeEdits implements
|
||||
ChildCollection<ChangeResource, ChangeEditResource>,
|
||||
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) {
|
||||
ChangeEdits(DynamicMap<RestView<ChangeEditResource>> views,
|
||||
Create.Factory createFactory,
|
||||
Detail detail,
|
||||
ChangeEditUtil editUtil,
|
||||
Post post) {
|
||||
this.views = views;
|
||||
this.createFactory = createFactory;
|
||||
this.detail = detail;
|
||||
this.editUtil = editUtil;
|
||||
this.post = post;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -38,11 +82,202 @@ class ChangeEdits implements
|
||||
|
||||
@Override
|
||||
public RestView<ChangeResource> list() {
|
||||
throw new IllegalStateException("not yet implemented");
|
||||
return detail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChangeEditResource parse(ChangeResource change, IdString id) {
|
||||
throw new IllegalStateException("not yet implemented");
|
||||
public ChangeEditResource parse(ChangeResource rsrc, IdString id)
|
||||
throws ResourceNotFoundException, AuthException, IOException,
|
||||
InvalidChangeOperationException {
|
||||
Optional<ChangeEdit> edit = editUtil.byChange(rsrc.getChange());
|
||||
if (!edit.isPresent()) {
|
||||
throw new ResourceNotFoundException(id);
|
||||
}
|
||||
return new ChangeEditResource(rsrc, edit.get(), id.get());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Create create(ChangeResource parent, IdString id)
|
||||
throws RestApiException {
|
||||
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
|
||||
* change edit wasn't created yet. Change edit is created and PUT
|
||||
* handler is called.
|
||||
*/
|
||||
static class Create implements
|
||||
RestModifyView<ChangeResource, Put.Input> {
|
||||
|
||||
interface Factory {
|
||||
Create create(Change change, String path);
|
||||
}
|
||||
|
||||
private final Provider<ReviewDb> db;
|
||||
private final ChangeEditUtil editUtil;
|
||||
private final ChangeEditModifier editModifier;
|
||||
private final Put putEdit;
|
||||
private final Change change;
|
||||
private final String path;
|
||||
|
||||
@Inject
|
||||
Create(Provider<ReviewDb> db,
|
||||
ChangeEditUtil editUtil,
|
||||
ChangeEditModifier editModifier,
|
||||
Put putEdit,
|
||||
@Assisted Change change,
|
||||
@Assisted @Nullable String path) {
|
||||
this.db = db;
|
||||
this.editUtil = editUtil;
|
||||
this.editModifier = editModifier;
|
||||
this.putEdit = putEdit;
|
||||
this.change = change;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<?> apply(ChangeResource resource, Put.Input input)
|
||||
throws AuthException, IOException, ResourceConflictException,
|
||||
OrmException, InvalidChangeOperationException {
|
||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||
if (edit.isPresent()) {
|
||||
throw new ResourceConflictException(String.format(
|
||||
"edit already exists for the change %s",
|
||||
resource.getChange().getChangeId()));
|
||||
}
|
||||
edit = createEdit();
|
||||
if (!Strings.isNullOrEmpty(path)) {
|
||||
putEdit.apply(new ChangeEditResource(resource, edit.get(), path),
|
||||
input);
|
||||
}
|
||||
return Response.none();
|
||||
}
|
||||
|
||||
private Optional<ChangeEdit> createEdit() throws AuthException,
|
||||
IOException, ResourceConflictException, OrmException,
|
||||
InvalidChangeOperationException {
|
||||
editModifier.createEdit(change,
|
||||
db.get().patchSets().get(change.currentPatchSetId()));
|
||||
return editUtil.byChange(change);
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Singleton
|
||||
public static class Put implements
|
||||
RestModifyView<ChangeEditResource, Put.Input> {
|
||||
public static class Input {
|
||||
@DefaultInput
|
||||
public RawInput content;
|
||||
}
|
||||
|
||||
private final ChangeEditModifier editModifier;
|
||||
|
||||
@Inject
|
||||
Put(ChangeEditModifier editModifier) {
|
||||
this.editModifier = editModifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<?> apply(ChangeEditResource rsrc, Input input)
|
||||
throws AuthException, ResourceConflictException, IOException {
|
||||
try {
|
||||
editModifier.modifyFile(rsrc.getChangeEdit(), rsrc.getPath(),
|
||||
ByteStreams.toByteArray(input.content.getInputStream()));
|
||||
} catch(InvalidChangeOperationException | IOException e) {
|
||||
throw new ResourceConflictException(e.getMessage());
|
||||
}
|
||||
return Response.none();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
|
||||
package com.google.gerrit.server.change;
|
||||
|
||||
import static com.google.gerrit.server.change.ChangeEditResource.CHANGE_EDIT_KIND;
|
||||
import static com.google.gerrit.server.change.ChangeResource.CHANGE_KIND;
|
||||
import static com.google.gerrit.server.change.CommentResource.COMMENT_KIND;
|
||||
import static com.google.gerrit.server.change.DraftResource.DRAFT_KIND;
|
||||
import static com.google.gerrit.server.change.FileResource.FILE_KIND;
|
||||
import static com.google.gerrit.server.change.ReviewerResource.REVIEWER_KIND;
|
||||
import static com.google.gerrit.server.change.RevisionResource.REVISION_KIND;
|
||||
import static com.google.gerrit.server.change.ChangeEditResource.CHANGE_EDIT_KIND;
|
||||
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
import com.google.gerrit.extensions.restapi.RestApiModule;
|
||||
@@ -101,6 +101,9 @@ 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);
|
||||
put(CHANGE_EDIT_KIND, "/").to(ChangeEdits.Put.class);
|
||||
|
||||
install(new FactoryModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
@@ -109,6 +112,7 @@ public class Module extends RestApiModule {
|
||||
factory(EmailReviewComments.Factory.class);
|
||||
factory(ChangeInserter.Factory.class);
|
||||
factory(PatchSetInserter.Factory.class);
|
||||
factory(ChangeEdits.Create.Factory.class);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user