Implement new /changes/{id}/action style REST API
All existing JSON APIs are converted to this new style.
/changes/{id} parses the id field from a JSON response from a prior
response and uses that to uniquely identify a change and verify the
caller can see it. If the user requests only /changes/{id}/ then the
data is returned as a single JSON object.
This commit also gives full remote control of plugins using the
/plugins/ namespace:
PUT /plugins/{name} (JAR as request body)
POST /plugins/{name} (JSON object {url:"https://..."})
DELETE /plugins/{name}
GET /plugins/{name}/gerrit~status
POST /plugins/{name}/gerrit~reload
POST /plugins/{name}/gerrit~enable
POST /plugins/{name}/gerrit~disable
The commit provides some project admin commands:
GET /projects/{name}/description
PUT /projects/{name}/description
GET /projects/{name}/parent
PUT /projects/{name}/parent
Project dashboards have moved:
GET /projects/{name}/dashboards
GET /projects/{name}/dashboards/{id}
GET /projects/{name}/dashboards/default
To access project names containing /, the name must be encoded with
URL encoding, translating / to %2F.
Change-Id: I6a38902ee473003ec637758b7c911f926a2e948a
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
// Copyright (C) 2012 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.change;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||
import com.google.gerrit.extensions.restapi.TopLevelResource;
|
||||
import com.google.gerrit.extensions.restapi.RestCollection;
|
||||
import com.google.gerrit.extensions.restapi.RestView;
|
||||
import com.google.gerrit.reviewdb.client.Branch;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
import com.google.gerrit.server.query.change.QueryChanges;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ChangesCollection implements
|
||||
RestCollection<TopLevelResource, ChangeResource> {
|
||||
private final Provider<ReviewDb> db;
|
||||
private final ChangeControl.Factory changeControlFactory;
|
||||
private final Provider<QueryChanges> queryFactory;
|
||||
private final DynamicMap<RestView<ChangeResource>> views;
|
||||
|
||||
@Inject
|
||||
ChangesCollection(
|
||||
Provider<ReviewDb> dbProvider,
|
||||
ChangeControl.Factory changeControlFactory,
|
||||
Provider<QueryChanges> queryFactory,
|
||||
DynamicMap<RestView<ChangeResource>> views) {
|
||||
this.db = dbProvider;
|
||||
this.changeControlFactory = changeControlFactory;
|
||||
this.queryFactory = queryFactory;
|
||||
this.views = views;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestView<TopLevelResource> list() {
|
||||
return queryFactory.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicMap<RestView<ChangeResource>> views() {
|
||||
return views;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChangeResource parse(TopLevelResource root, String id)
|
||||
throws ResourceNotFoundException, OrmException,
|
||||
UnsupportedEncodingException {
|
||||
ParsedId p = new ParsedId(id);
|
||||
List<Change> changes = findChanges(p);
|
||||
if (changes.size() != 1) {
|
||||
throw new ResourceNotFoundException(id);
|
||||
}
|
||||
|
||||
ChangeControl control;
|
||||
try {
|
||||
control = changeControlFactory.validateFor(changes.get(0));
|
||||
} catch (NoSuchChangeException e) {
|
||||
throw new ResourceNotFoundException(id);
|
||||
}
|
||||
return new ChangeResource(control);
|
||||
}
|
||||
|
||||
private List<Change> findChanges(ParsedId k) throws OrmException {
|
||||
if (k.legacyId != null) {
|
||||
Change c = db.get().changes().get(k.legacyId);
|
||||
if (c != null) {
|
||||
return ImmutableList.of(c);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
} else if (k.project == null && k.branch == null && k.changeId != null) {
|
||||
return db.get().changes().byKey(new Change.Key(k.changeId)).toList();
|
||||
}
|
||||
return db.get().changes().byBranchKey(
|
||||
k.branch(),
|
||||
new Change.Key(k.changeId)).toList();
|
||||
}
|
||||
|
||||
private static class ParsedId {
|
||||
Change.Id legacyId;
|
||||
String project;
|
||||
String branch;
|
||||
String changeId;
|
||||
|
||||
ParsedId(String id) throws ResourceNotFoundException,
|
||||
UnsupportedEncodingException {
|
||||
if (id.matches("^[0-9]+$")) {
|
||||
legacyId = Change.Id.parse(id);
|
||||
return;
|
||||
}
|
||||
|
||||
int t2 = id.lastIndexOf('~');
|
||||
int t1 = id.lastIndexOf('~', t2 - 1);
|
||||
if (t1 < 0 || t2 < 0) {
|
||||
if (!id.matches("^I[0-9a-z]{40}$")) {
|
||||
throw new ResourceNotFoundException(id);
|
||||
}
|
||||
changeId = id;
|
||||
return;
|
||||
}
|
||||
|
||||
project = URLDecoder.decode(id.substring(0, t1), "UTF-8");
|
||||
branch = URLDecoder.decode(id.substring(t1 + 1, t2), "UTF-8");
|
||||
changeId = URLDecoder.decode(id.substring(t2 + 1), "UTF-8");
|
||||
|
||||
if (!branch.startsWith(Constants.R_REFS)) {
|
||||
branch = Constants.R_HEADS + branch;
|
||||
}
|
||||
}
|
||||
|
||||
Branch.NameKey branch() {
|
||||
return new Branch.NameKey(new Project.NameKey(project), branch);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user