Add REST endpoint to get one change message

Change-Id: I816623bc2e610e377280c2f705f3258f56f4e890
This commit is contained in:
Changcheng Xiao
2018-04-30 10:59:14 +02:00
parent 7fb73298e7
commit d61590ffbd
9 changed files with 195 additions and 2 deletions

View File

@@ -2453,6 +2453,38 @@ As response a list of link:#change-message-info[ChangeMessageInfo] entities is r
] ]
---- ----
[[get-change-message]]
=== Get Change Message
Retrieves a change message including link:#detailed-accounts[detailed account information].
--
'GET /changes/link:#change-id[\{change-id\}]/message/link:#change-message-id[\{change-message-id\}'
--
As response a link:#change-message-info[ChangeMessageInfo] entity is returned.
.Response
----
HTTP/1.1 200 OK
Content-Disposition: attachment
Content-Type: application/json; charset=UTF-8
)]}'
{
"id": "aaee04dcb46bafc8be24d8aa70b3b1beb7df5780",
"author": {
"_account_id": 1000096,
"name": "John Doe",
"email": "john.doe@example.com",
"username": "jdoe"
},
"date": "2013-03-23 21:34:02.419000000",
"message": "Change message removed by: Administrator; Reason: spam",
"_revision_number": 1
}
----
[[edit-endpoints]] [[edit-endpoints]]
== Change Edit Endpoints == Change Edit Endpoints
@@ -5415,6 +5447,10 @@ If you need more time to migrate off of old change IDs, please see
link:config-gerrit.html#change.api.allowedIdentifier[change.api.allowedIdentifier] link:config-gerrit.html#change.api.allowedIdentifier[change.api.allowedIdentifier]
for more information on how to enable the use of deprecated identifiers. for more information on how to enable the use of deprecated identifiers.
[[change-message-id]]
=== \{change-message-id\}
ID of a change message returned in a link:#change-message-info[ChangeMessageInfo].
[[comment-id]] [[comment-id]]
=== \{comment-id\} === \{comment-id\}
UUID of a published comment. UUID of a published comment.

View File

@@ -292,6 +292,17 @@ public interface ChangeApi {
*/ */
List<ChangeMessageInfo> messages() throws RestApiException; List<ChangeMessageInfo> messages() throws RestApiException;
/**
* Look up a change message of a change by its id.
*
* @param id the id of the change message. Note that in NoteDb, this id is the {@code ObjectId} of
* a commit on the change meta branch. In ReviewDb, it's a UUID generated randomly. That means
* a change message id could be different between NoteDb and ReviewDb.
* @return API for accessing a change message.
* @throws RestApiException if the id is invalid.
*/
ChangeMessageApi message(String id) throws RestApiException;
abstract class SuggestedReviewersRequest { abstract class SuggestedReviewersRequest {
private String query; private String query;
private int limit; private int limit;
@@ -604,5 +615,10 @@ public interface ChangeApi {
public List<ChangeMessageInfo> messages() throws RestApiException { public List<ChangeMessageInfo> messages() throws RestApiException {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@Override
public ChangeMessageApi message(String id) throws RestApiException {
throw new NotImplementedException();
}
} }
} }

View File

@@ -0,0 +1,36 @@
// Copyright (C) 2018 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.api.changes;
import com.google.gerrit.extensions.common.ChangeMessageInfo;
import com.google.gerrit.extensions.restapi.NotImplementedException;
import com.google.gerrit.extensions.restapi.RestApiException;
/** Interface for change message APIs. */
public interface ChangeMessageApi {
/** Gets one change message. */
ChangeMessageInfo get() throws RestApiException;
/**
* A default implementation which allows source compatibility when adding new methods to the
* interface.
*/
class NotImplemented implements ChangeMessageApi {
@Override
public ChangeMessageInfo get() throws RestApiException {
throw new NotImplementedException();
}
}
}

View File

@@ -23,6 +23,7 @@ import com.google.gerrit.extensions.api.changes.AddReviewerResult;
import com.google.gerrit.extensions.api.changes.AssigneeInput; import com.google.gerrit.extensions.api.changes.AssigneeInput;
import com.google.gerrit.extensions.api.changes.ChangeApi; import com.google.gerrit.extensions.api.changes.ChangeApi;
import com.google.gerrit.extensions.api.changes.ChangeEditApi; import com.google.gerrit.extensions.api.changes.ChangeEditApi;
import com.google.gerrit.extensions.api.changes.ChangeMessageApi;
import com.google.gerrit.extensions.api.changes.Changes; import com.google.gerrit.extensions.api.changes.Changes;
import com.google.gerrit.extensions.api.changes.FixInput; import com.google.gerrit.extensions.api.changes.FixInput;
import com.google.gerrit.extensions.api.changes.HashtagsInput; import com.google.gerrit.extensions.api.changes.HashtagsInput;
@@ -54,6 +55,7 @@ import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.server.StarredChangesUtil; import com.google.gerrit.server.StarredChangesUtil;
import com.google.gerrit.server.StarredChangesUtil.IllegalLabelException; import com.google.gerrit.server.StarredChangesUtil.IllegalLabelException;
import com.google.gerrit.server.change.ChangeJson; import com.google.gerrit.server.change.ChangeJson;
import com.google.gerrit.server.change.ChangeMessageResource;
import com.google.gerrit.server.change.ChangeResource; import com.google.gerrit.server.change.ChangeResource;
import com.google.gerrit.server.change.PureRevert; import com.google.gerrit.server.change.PureRevert;
import com.google.gerrit.server.change.WorkInProgressOp; import com.google.gerrit.server.change.WorkInProgressOp;
@@ -113,6 +115,7 @@ class ChangeApiImpl implements ChangeApi {
private final Revisions revisions; private final Revisions revisions;
private final ReviewerApiImpl.Factory reviewerApi; private final ReviewerApiImpl.Factory reviewerApi;
private final RevisionApiImpl.Factory revisionApi; private final RevisionApiImpl.Factory revisionApi;
private final ChangeMessageApiImpl.Factory changeMessageApi;
private final ChangeMessages changeMessages; private final ChangeMessages changeMessages;
private final SuggestChangeReviewers suggestReviewers; private final SuggestChangeReviewers suggestReviewers;
private final ChangeResource change; private final ChangeResource change;
@@ -160,6 +163,7 @@ class ChangeApiImpl implements ChangeApi {
Revisions revisions, Revisions revisions,
ReviewerApiImpl.Factory reviewerApi, ReviewerApiImpl.Factory reviewerApi,
RevisionApiImpl.Factory revisionApi, RevisionApiImpl.Factory revisionApi,
ChangeMessageApiImpl.Factory changeMessageApi,
ChangeMessages changeMessages, ChangeMessages changeMessages,
SuggestChangeReviewers suggestReviewers, SuggestChangeReviewers suggestReviewers,
Abandon abandon, Abandon abandon,
@@ -205,6 +209,7 @@ class ChangeApiImpl implements ChangeApi {
this.revisions = revisions; this.revisions = revisions;
this.reviewerApi = reviewerApi; this.reviewerApi = reviewerApi;
this.revisionApi = revisionApi; this.revisionApi = revisionApi;
this.changeMessageApi = changeMessageApi;
this.changeMessages = changeMessages; this.changeMessages = changeMessages;
this.suggestReviewers = suggestReviewers; this.suggestReviewers = suggestReviewers;
this.abandon = abandon; this.abandon = abandon;
@@ -723,4 +728,14 @@ class ChangeApiImpl implements ChangeApi {
throw asRestApiException("Cannot list change messages", e); throw asRestApiException("Cannot list change messages", e);
} }
} }
@Override
public ChangeMessageApi message(String id) throws RestApiException {
try {
ChangeMessageResource resource = changeMessages.parse(change, IdString.fromDecoded(id));
return changeMessageApi.create(resource);
} catch (Exception e) {
throw asRestApiException("Cannot parse change message " + id, e);
}
}
} }

View File

@@ -0,0 +1,50 @@
// Copyright (C) 2018 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.api.changes;
import static com.google.gerrit.server.api.ApiUtil.asRestApiException;
import com.google.gerrit.extensions.api.changes.ChangeMessageApi;
import com.google.gerrit.extensions.common.ChangeMessageInfo;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.server.change.ChangeMessageResource;
import com.google.gerrit.server.restapi.change.GetChangeMessage;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
class ChangeMessageApiImpl implements ChangeMessageApi {
interface Factory {
ChangeMessageApiImpl create(ChangeMessageResource changeMessageResource);
}
private final GetChangeMessage getChangeMessage;
private final ChangeMessageResource changeMessageResource;
@Inject
ChangeMessageApiImpl(
GetChangeMessage getChangeMessage, @Assisted ChangeMessageResource changeMessageResource) {
this.getChangeMessage = getChangeMessage;
this.changeMessageResource = changeMessageResource;
}
@Override
public ChangeMessageInfo get() throws RestApiException {
try {
return getChangeMessage.apply(changeMessageResource);
} catch (Exception e) {
throw asRestApiException("Cannot retrieve change message", e);
}
}
}

View File

@@ -31,5 +31,6 @@ public class Module extends FactoryModule {
factory(ReviewerApiImpl.Factory.class); factory(ReviewerApiImpl.Factory.class);
factory(RevisionReviewerApiImpl.Factory.class); factory(RevisionReviewerApiImpl.Factory.class);
factory(ChangeEditApiImpl.Factory.class); factory(ChangeEditApiImpl.Factory.class);
factory(ChangeMessageApiImpl.Factory.class);
} }
} }

View File

@@ -0,0 +1,29 @@
// Copyright (C) 2018 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.restapi.change;
import com.google.gerrit.extensions.common.ChangeMessageInfo;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.change.ChangeMessageResource;
import com.google.inject.Singleton;
/** Gets one change message. */
@Singleton
public class GetChangeMessage implements RestReadView<ChangeMessageResource> {
@Override
public ChangeMessageInfo apply(ChangeMessageResource resource) {
return resource.getChangeMessage();
}
}

View File

@@ -177,6 +177,7 @@ public class Module extends RestApiModule {
post(COMMIT_KIND, "cherrypick").to(CherryPickCommit.class); post(COMMIT_KIND, "cherrypick").to(CherryPickCommit.class);
child(CHANGE_KIND, "messages").to(ChangeMessages.class); child(CHANGE_KIND, "messages").to(ChangeMessages.class);
get(CHANGE_MESSAGE_KIND).to(GetChangeMessage.class);
factory(AccountLoader.Factory.class); factory(AccountLoader.Factory.class);
factory(ChangeEdits.Create.Factory.class); factory(ChangeEdits.Create.Factory.class);

View File

@@ -110,9 +110,18 @@ public class ChangeMessagesIT extends AbstractDaemonTest {
assertThat(messages1).containsExactlyElementsIn(messages2).inOrder(); assertThat(messages1).containsExactlyElementsIn(messages2).inOrder();
} }
private int createOneChangeWithMultipleChangeMessagesInHistory() throws Exception { @Test
// Creates the following commit history on the meta branch of the test change. public void getOneChangeMessage() throws Exception {
int changeNum = createOneChangeWithMultipleChangeMessagesInHistory();
List<ChangeMessageInfo> messages = new ArrayList<>(gApi.changes().id(changeNum).get().messages);
for (ChangeMessageInfo messageInfo : messages) {
String id = messageInfo.id;
assertThat(gApi.changes().id(changeNum).message(id).get()).isEqualTo(messageInfo);
}
}
private int createOneChangeWithMultipleChangeMessagesInHistory() throws Exception {
setApiUser(user); setApiUser(user);
// Commit 1: create a change. // Commit 1: create a change.
PushOneCommit.Result result = createChange(); PushOneCommit.Result result = createChange();