Add REST endpoint to get an arbitrary commit from a project
Bug: issue 2604 Change-Id: I138e60c5291d61c379e947ea26b0fd9d5555c743 Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:

committed by
Edwin Kempin

parent
990662d0b8
commit
1b99360cc7
@@ -972,6 +972,59 @@ describes the child project.
|
||||
}
|
||||
----
|
||||
|
||||
[[commit-endpoints]]
|
||||
== Commit Endpoints
|
||||
|
||||
[[get-commit]]
|
||||
=== Get Commit
|
||||
--
|
||||
'GET /projects/link:#project-name[\{project-name\}]/commits/link:#commit-id[\{commit-id\}]'
|
||||
--
|
||||
|
||||
Retrieves a commit of a project.
|
||||
|
||||
The commit must be visible to the caller.
|
||||
|
||||
.Request
|
||||
----
|
||||
GET /projects/work%2Fmy-project/commits/a8a477efffbbf3b44169bb9a1d3a334cbbd9aa96 HTTP/1.0
|
||||
----
|
||||
|
||||
As response a link:rest-api-changes.html#commit-info[CommitInfo] entity
|
||||
is returned that describes the commit.
|
||||
|
||||
.Response
|
||||
----
|
||||
HTTP/1.1 200 OK
|
||||
Content-Disposition: attachment
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
|
||||
)]}'
|
||||
{
|
||||
"commit": "184ebe53805e102605d11f6b143486d15c23a09c",
|
||||
"parents": [
|
||||
{
|
||||
"commit": "1eee2c9d8f352483781e772f35dc586a69ff5646",
|
||||
"subject": "Migrate contributor agreements to All-Projects."
|
||||
}
|
||||
],
|
||||
"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 ..."
|
||||
}
|
||||
----
|
||||
|
||||
[[dashboard-endpoints]]
|
||||
== Dashboard Endpoints
|
||||
|
||||
@@ -1199,6 +1252,10 @@ requests.
|
||||
The name of a branch or `HEAD`. The prefix `refs/heads/` can be
|
||||
omitted.
|
||||
|
||||
[[commit-id]]
|
||||
=== \{commit-id\}
|
||||
Commit ID.
|
||||
|
||||
[[dashboard-id]]
|
||||
=== \{dashboard-id\}
|
||||
The ID of a dashboard in the format '<ref>:<path>'.
|
||||
|
@@ -0,0 +1,111 @@
|
||||
// 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.acceptance.rest.project;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||
import com.google.gerrit.acceptance.RestResponse;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.extensions.common.CommitInfo;
|
||||
import com.google.gerrit.extensions.restapi.IdString;
|
||||
import com.google.gerrit.reviewdb.client.RefNames;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.project.ListBranches.BranchInfo;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class GetCommitIT extends AbstractDaemonTest {
|
||||
|
||||
@Inject
|
||||
private ProjectCache projectCache;
|
||||
|
||||
@Inject
|
||||
private AllProjectsName allProjects;
|
||||
|
||||
@Inject
|
||||
private MetaDataUpdate.Server metaDataUpdateFactory;
|
||||
|
||||
@Test
|
||||
public void getCommit() throws IOException {
|
||||
RestResponse r =
|
||||
adminSession.get("/projects/" + project.get() + "/branches/"
|
||||
+ IdString.fromDecoded(RefNames.REFS_CONFIG).encoded());
|
||||
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
|
||||
BranchInfo branchInfo =
|
||||
newGson().fromJson(r.getReader(), BranchInfo.class);
|
||||
r.consume();
|
||||
|
||||
r = adminSession.get("/projects/" + project.get() + "/commits/"
|
||||
+ branchInfo.revision);
|
||||
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
|
||||
CommitInfo commitInfo =
|
||||
newGson().fromJson(r.getReader(), CommitInfo.class);
|
||||
assertEquals(branchInfo.revision, commitInfo.commit);
|
||||
assertEquals("Created project", commitInfo.subject);
|
||||
assertEquals("Created project\n", commitInfo.message);
|
||||
assertNotNull(commitInfo.author);
|
||||
assertEquals("Administrator", commitInfo.author.name);
|
||||
assertNotNull(commitInfo.committer);
|
||||
assertEquals("Gerrit Code Review", commitInfo.committer.name);
|
||||
assertTrue(commitInfo.parents.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNonExistingCommit_NotFound() throws IOException {
|
||||
RestResponse r = adminSession.get("/projects/" + project.get() + "/commits/"
|
||||
+ ObjectId.zeroId().name());
|
||||
assertEquals(HttpStatus.SC_NOT_FOUND, r.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNonVisibleCommit_NotFound() throws IOException {
|
||||
RestResponse r =
|
||||
adminSession.get("/projects/" + project.get() + "/branches/"
|
||||
+ IdString.fromDecoded(RefNames.REFS_CONFIG).encoded());
|
||||
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
|
||||
BranchInfo branchInfo =
|
||||
newGson().fromJson(r.getReader(), BranchInfo.class);
|
||||
r.consume();
|
||||
|
||||
ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
|
||||
cfg.getAccessSection("refs/*", false).removePermission(Permission.READ);
|
||||
saveProjectConfig(cfg);
|
||||
projectCache.evict(cfg.getProject());
|
||||
|
||||
r = adminSession.get("/projects/" + project.get() + "/commits/"
|
||||
+ branchInfo.revision);
|
||||
assertEquals(HttpStatus.SC_NOT_FOUND, r.getStatusCode());
|
||||
}
|
||||
|
||||
private void saveProjectConfig(ProjectConfig cfg) throws IOException {
|
||||
MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
|
||||
try {
|
||||
cfg.commit(md);
|
||||
} finally {
|
||||
md.close();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
// 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.project;
|
||||
|
||||
import com.google.gerrit.extensions.restapi.RestView;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
|
||||
public class CommitResource extends ProjectResource {
|
||||
public static final TypeLiteral<RestView<CommitResource>> COMMIT_KIND =
|
||||
new TypeLiteral<RestView<CommitResource>>() {};
|
||||
|
||||
private final RevCommit commit;
|
||||
|
||||
public CommitResource(ProjectControl control, RevCommit commit) {
|
||||
super(control);
|
||||
this.commit = commit;
|
||||
}
|
||||
|
||||
public RevCommit getCommit() {
|
||||
return commit;
|
||||
}
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
// 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.project;
|
||||
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
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.RestView;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
||||
import org.eclipse.jgit.errors.MissingObjectException;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Singleton
|
||||
public class CommitsCollection implements
|
||||
ChildCollection<ProjectResource, CommitResource> {
|
||||
private final DynamicMap<RestView<CommitResource>> views;
|
||||
private final GitRepositoryManager repoManager;
|
||||
|
||||
@Inject
|
||||
public CommitsCollection(DynamicMap<RestView<CommitResource>> views,
|
||||
GitRepositoryManager repoManager) {
|
||||
this.views = views;
|
||||
this.repoManager = repoManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestView<ProjectResource> list() throws ResourceNotFoundException {
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommitResource parse(ProjectResource parent, IdString id)
|
||||
throws ResourceNotFoundException, IOException {
|
||||
ObjectId objectId;
|
||||
try {
|
||||
objectId = ObjectId.fromString(id.get());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ResourceNotFoundException(id);
|
||||
}
|
||||
|
||||
Repository repo = repoManager.openRepository(parent.getNameKey());
|
||||
try {
|
||||
RevWalk rw = new RevWalk(repo);
|
||||
try {
|
||||
RevCommit commit = rw.parseCommit(objectId);
|
||||
if (!parent.getControl().canReadCommit(rw, commit)) {
|
||||
throw new ResourceNotFoundException(id);
|
||||
}
|
||||
for (int i = 0; i < commit.getParentCount(); i++) {
|
||||
rw.parseCommit(commit.getParent(i));
|
||||
}
|
||||
return new CommitResource(parent.getControl(), commit);
|
||||
} catch (MissingObjectException | IncorrectObjectTypeException e) {
|
||||
throw new ResourceNotFoundException(id);
|
||||
} finally {
|
||||
rw.release();
|
||||
}
|
||||
} finally {
|
||||
repo.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicMap<RestView<CommitResource>> views() {
|
||||
return views;
|
||||
}
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
// 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.project;
|
||||
|
||||
import com.google.gerrit.extensions.common.CommitInfo;
|
||||
import com.google.gerrit.extensions.common.GitPerson;
|
||||
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Singleton
|
||||
public class GetCommit implements RestReadView<CommitResource> {
|
||||
|
||||
@Override
|
||||
public CommitInfo apply(CommitResource rsrc) {
|
||||
RevCommit c = rsrc.getCommit();
|
||||
CommitInfo info = toCommitInfo(c);
|
||||
return info;
|
||||
}
|
||||
|
||||
private static CommitInfo toCommitInfo(RevCommit commit) {
|
||||
CommitInfo info = new CommitInfo();
|
||||
info.commit = commit.getName();
|
||||
info.author = toGitPerson(commit.getAuthorIdent());
|
||||
info.committer = toGitPerson(commit.getCommitterIdent());
|
||||
info.subject = commit.getShortMessage();
|
||||
info.message = commit.getFullMessage();
|
||||
info.parents = new ArrayList<>(commit.getParentCount());
|
||||
for (int i = 0; i < commit.getParentCount(); i++) {
|
||||
RevCommit p = commit.getParent(i);
|
||||
CommitInfo parentInfo = new CommitInfo();
|
||||
parentInfo.commit = p.getName();
|
||||
parentInfo.subject = p.getShortMessage();
|
||||
info.parents.add(parentInfo);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
private static GitPerson toGitPerson(PersonIdent ident) {
|
||||
GitPerson gp = new GitPerson();
|
||||
gp.name = ident.getName();
|
||||
gp.email = ident.getEmailAddress();
|
||||
gp.date = new Timestamp(ident.getWhen().getTime());
|
||||
gp.tz = ident.getTimeZoneOffset();
|
||||
return gp;
|
||||
}
|
||||
}
|
@@ -16,9 +16,10 @@ package com.google.gerrit.server.project;
|
||||
|
||||
import static com.google.gerrit.server.project.BranchResource.BRANCH_KIND;
|
||||
import static com.google.gerrit.server.project.ChildProjectResource.CHILD_PROJECT_KIND;
|
||||
import static com.google.gerrit.server.project.CommitResource.COMMIT_KIND;
|
||||
import static com.google.gerrit.server.project.DashboardResource.DASHBOARD_KIND;
|
||||
import static com.google.gerrit.server.project.ProjectResource.PROJECT_KIND;
|
||||
import static com.google.gerrit.server.project.FileResource.FILE_KIND;
|
||||
import static com.google.gerrit.server.project.ProjectResource.PROJECT_KIND;
|
||||
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
import com.google.gerrit.extensions.restapi.RestApiModule;
|
||||
@@ -35,6 +36,7 @@ public class Module extends RestApiModule {
|
||||
DynamicMap.mapOf(binder(), BRANCH_KIND);
|
||||
DynamicMap.mapOf(binder(), DASHBOARD_KIND);
|
||||
DynamicMap.mapOf(binder(), FILE_KIND);
|
||||
DynamicMap.mapOf(binder(), COMMIT_KIND);
|
||||
|
||||
put(PROJECT_KIND).to(PutProject.class);
|
||||
get(PROJECT_KIND).to(GetProject.class);
|
||||
@@ -63,6 +65,9 @@ public class Module extends RestApiModule {
|
||||
child(BRANCH_KIND, "files").to(FilesCollection.class);
|
||||
get(FILE_KIND, "content").to(GetContent.class);
|
||||
|
||||
child(PROJECT_KIND, "commits").to(CommitsCollection.class);
|
||||
get(COMMIT_KIND).to(GetCommit.class);
|
||||
|
||||
child(PROJECT_KIND, "dashboards").to(DashboardsCollection.class);
|
||||
get(DASHBOARD_KIND).to(GetDashboard.class);
|
||||
put(DASHBOARD_KIND).to(SetDashboard.class);
|
||||
|
Reference in New Issue
Block a user