Fix reading /default for inherited dashboards

When loading the default dashboard for a project the default REST
approach is to load only the default defined locally in this project.
If no such default is defined, the caller may supply an optional
?inherited query parameter to search up the inheritance tree.

Change-Id: I5ed3d63f734fa9734c7ccd05c940fbdcf9dcab1d
This commit is contained in:
Shawn O. Pearce
2012-11-17 21:29:39 -08:00
parent a7d9c9b7ac
commit 8e6ccbcb68
5 changed files with 91 additions and 21 deletions

View File

@@ -31,7 +31,9 @@ public class DashboardList extends NativeList<DashboardInfo> {
public static void defaultDashboard(Project.NameKey project,
AsyncCallback<DashboardInfo> callback) {
new RestApi(base(project) + "default").get(callback);
new RestApi(base(project) + "default")
.addParameterTrue("inherited")
.get(callback);
}
public static void get(Project.NameKey project, String dashboardId,

View File

@@ -19,29 +19,29 @@ import com.google.gerrit.extensions.restapi.RestView;
import com.google.inject.TypeLiteral;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
public class DashboardResource implements RestResource {
public static final TypeLiteral<RestView<DashboardResource>> DASHBOARD_KIND =
new TypeLiteral<RestView<DashboardResource>>() {};
static DashboardResource projectDefault(ProjectControl ctl) {
return new DashboardResource(ctl, null, null, null, true);
}
private final ProjectControl control;
private final String refName;
private final String pathName;
private final ObjectId objId;
private final Config config;
private final boolean projectDefault;
DashboardResource(ProjectControl control,
String refName,
String pathName,
ObjectId objId,
Config config,
boolean projectDefault) {
this.control = control;
this.refName = refName;
this.pathName = pathName;
this.objId = objId;
this.config = config;
this.projectDefault = projectDefault;
}
@@ -58,10 +58,6 @@ public class DashboardResource implements RestResource {
return pathName;
}
public ObjectId getObjectId() {
return objId;
}
public Config getConfig() {
return config;
}

View File

@@ -36,6 +36,7 @@ import com.google.inject.Inject;
import com.google.inject.Provider;
import org.eclipse.jgit.errors.AmbiguousObjectException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.BlobBasedConfig;
@@ -43,6 +44,7 @@ import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
@@ -84,12 +86,10 @@ class DashboardsCollection implements
@Override
public DashboardResource parse(ProjectResource parent, String id)
throws ResourceNotFoundException, Exception {
throws ResourceNotFoundException, IOException, ConfigInvalidException {
ProjectControl ctl = parent.getControl();
boolean def = false;
if ("default".equals(id)) {
id = defaultOf(ctl.getProject());
def = true;
return DashboardResource.projectDefault(ctl);
}
List<String> parts = Lists.newArrayList(
@@ -117,7 +117,7 @@ class DashboardsCollection implements
try {
ObjectId objId;
try {
objId = git.resolve(Joiner.on(':').join(ref, path));
objId = git.resolve(ref + ':' + path);
} catch (AmbiguousObjectException e) {
throw new ResourceNotFoundException(id);
} catch (IncorrectObjectTypeException e) {
@@ -127,7 +127,7 @@ class DashboardsCollection implements
throw new ResourceNotFoundException();
}
BlobBasedConfig cfg = new BlobBasedConfig(null, git, objId);
return new DashboardResource(ctl, ref, path, objId, cfg, def);
return new DashboardResource(ctl, ref, path, cfg, false);
} finally {
git.close();
}

View File

@@ -16,19 +16,78 @@ package com.google.gerrit.server.project;
import static com.google.gerrit.server.git.GitRepositoryManager.REFS_DASHBOARDS;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.project.DashboardsCollection.DashboardInfo;
import com.google.inject.Inject;
import java.io.UnsupportedEncodingException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.kohsuke.args4j.Option;
import java.io.IOException;
import java.util.Set;
class GetDashboard implements RestReadView<DashboardResource> {
private final DashboardsCollection dashboards;
@Option(name = "--inherited", usage = "include inherited dashboards")
private boolean inherited;
@Inject
GetDashboard(DashboardsCollection dashboards) {
this.dashboards = dashboards;
}
@Override
public DashboardInfo apply(DashboardResource resource)
throws UnsupportedEncodingException {
throws ResourceNotFoundException, IOException, ConfigInvalidException {
if (inherited && !resource.isProjectDefault()) {
// inherited flag can only be used with default.
throw new ResourceNotFoundException("inherited");
}
if (resource.isProjectDefault()) {
// The default is not resolved to a definition yet.
resource = defaultOf(resource.getControl());
}
return DashboardsCollection.parse(
resource.getControl().getProject(),
resource.getRefName().substring(REFS_DASHBOARDS.length()),
resource.getPathName(),
resource.getConfig());
}
private DashboardResource defaultOf(ProjectControl ctl)
throws ResourceNotFoundException, IOException, ConfigInvalidException {
String id = ctl.getProject().getLocalDefaultDashboard();
if (Strings.isNullOrEmpty(id)) {
id = ctl.getProject().getDefaultDashboard();
}
if ("default".equals(id)) {
throw new ResourceNotFoundException();
} else if (!Strings.isNullOrEmpty(id)) {
return dashboards.parse(new ProjectResource(ctl), id);
} else if (!inherited) {
throw new ResourceNotFoundException();
}
Set<Project.NameKey> seen = Sets.newHashSet();
seen.add(ctl.getProject().getNameKey());
ProjectState ps = ctl.getProjectState().getParentState();
while (ps != null && seen.add(ps.getProject().getNameKey())) {
id = ps.getProject().getDefaultDashboard();
if ("default".equals(id)) {
throw new ResourceNotFoundException();
} else if (!Strings.isNullOrEmpty(id)) {
ctl = ps.controlFor(ctl.getCurrentUser());
return dashboards.parse(new ProjectResource(ctl), id);
}
ps = ps.getParentState();
}
throw new ResourceNotFoundException();
}
}

View File

@@ -32,6 +32,7 @@ import com.google.inject.Provider;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.kohsuke.args4j.Option;
class SetDefaultDashboard implements RestModifyView<DashboardResource, Input> {
private final ProjectCache cache;
@@ -39,6 +40,9 @@ class SetDefaultDashboard implements RestModifyView<DashboardResource, Input> {
private final DashboardsCollection dashboards;
private final Provider<GetDashboard> get;
@Option(name = "--inherited", usage = "set dashboard inherited by children")
private boolean inherited;
@Inject
SetDefaultDashboard(ProjectCache cache,
MetaDataUpdate.Server updateFactory,
@@ -84,7 +88,11 @@ class SetDefaultDashboard implements RestModifyView<DashboardResource, Input> {
try {
ProjectConfig config = ProjectConfig.read(md);
Project project = config.getProject();
if (inherited) {
project.setDefaultDashboard(input.id);
} else {
project.setLocalDefaultDashboard(input.id);
}
String msg = Objects.firstNonNull(
Strings.emptyToNull(input.commitMessage),
@@ -120,6 +128,9 @@ class SetDefaultDashboard implements RestModifyView<DashboardResource, Input> {
RestModifyView<ProjectResource, SetDashboard.Input> {
private final Provider<SetDefaultDashboard> setDefault;
@Option(name = "--inherited", usage = "set dashboard inherited by children")
private boolean inherited;
@Inject
CreateDefault(Provider<SetDefaultDashboard> setDefault) {
this.setDefault = setDefault;
@@ -134,9 +145,11 @@ class SetDefaultDashboard implements RestModifyView<DashboardResource, Input> {
public Object apply(ProjectResource resource, Input input)
throws AuthException, BadRequestException, ResourceConflictException,
Exception {
ProjectControl ctl = resource.getControl();
return setDefault.get().apply(
new DashboardResource(ctl, null, null, null, null, true), input);
SetDefaultDashboard set = setDefault.get();
set.inherited = inherited;
return set.apply(
DashboardResource.projectDefault(resource.getControl()),
input);
}
}
}