blob: 0459ef03d17853e06acc099892f4303e958e0202 [file] [log] [blame]
// Copyright (C) 2017 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.googlesource.gerrit.plugins.its.phabricator;
import java.io.IOException;
import java.net.URL;
import java.util.Set;
import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Sets;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gson.JsonElement;
import com.google.inject.Inject;
import com.googlesource.gerrit.plugins.its.base.its.ItsFacade;
import com.googlesource.gerrit.plugins.its.phabricator.conduit.Conduit;
import com.googlesource.gerrit.plugins.its.phabricator.conduit.ConduitErrorException;
import com.googlesource.gerrit.plugins.its.phabricator.conduit.ConduitException;
import com.googlesource.gerrit.plugins.its.phabricator.conduit.results.ManiphestInfo;
import com.googlesource.gerrit.plugins.its.phabricator.conduit.results.ProjectInfo;
public class PhabricatorItsFacade implements ItsFacade {
private static final Logger log = LoggerFactory.getLogger(PhabricatorItsFacade.class);
private static final String GERRIT_CONFIG_URL = "url";
private static final String GERRIT_CONFIG_TOKEN = "token";
private final Conduit conduit;
@Inject
public PhabricatorItsFacade(@PluginName String pluginName,
@GerritServerConfig Config cfg) {
String url = cfg.getString(pluginName, null, GERRIT_CONFIG_URL);
String token = cfg.getString(pluginName, null,
GERRIT_CONFIG_TOKEN);
this.conduit = new Conduit(url, token);
}
@Override
public void addComment(final String bugId, final String comment)
throws IOException {
int task_id = Integer.parseInt(bugId);
try {
conduit.maniphestEdit(task_id, comment);
} catch (ConduitException e) {
throw new IOException("Could not update message for task " + task_id, e);
}
log.debug("Added comment " + comment + " to bug " + task_id);
}
@Override
public void addRelatedLink(final String issueKey, final URL relatedUrl,
String description) throws IOException {
addComment(issueKey, "Related URL: " + createLinkForWebui(
relatedUrl.toExternalForm(), description));
}
@Override
public boolean exists(final String bugId) throws IOException {
Boolean ret = false;
int task_id = Integer.parseInt(bugId);
try {
try {
conduit.maniphestInfo(task_id);
ret = true;
} catch (ConduitErrorException e) {
// An ERR_BAD_TASK just means that the task does not exist.
// So the default value of ret would be ok
if (! ("ERR_BAD_TASK".equals(e.getErrorCode()))) {
// So we had an exception that is /not/ ERR_BAD_TASK.
// We have to relay that to the caller.
throw e;
}
}
} catch (ConduitException e) {
throw new IOException("Could not check existence of task " + task_id, e);
}
return ret;
}
@Override
public void performAction(final String taskIdString, final String actionString)
throws IOException {
int taskId = Integer.parseInt(taskIdString);
String chopped[] = actionString.split(" ");
if (chopped.length >= 1) {
String action = chopped[0];
switch (action) {
case "add-project":
assertParameters(action, chopped, 1);
maniphestEdit(chopped[1], taskId, Conduit.ACTION_PROJECT_ADD);
break;
case "remove-project":
assertParameters(action, chopped, 1);
maniphestEdit(chopped[1], taskId, Conduit.ACTION_PROJECT_REMOVE);
break;
default:
throw new IOException("Unknown action " + action);
}
} else {
throw new IOException("Could not parse action " + actionString);
}
}
private void assertParameters(String action, String[] params, int length) throws IOException {
if (params.length -1 != length) {
throw new IOException(String.format("Action %s expects exactly %d parameter(s) but %d given",
action, length, params.length -1));
}
}
private void maniphestEdit(String projectName, int taskId, String actions) throws IOException {
try {
ProjectInfo projectInfo = conduit.projectQuery(projectName);
String projectPhid = projectInfo.getPhid();
Set<String> projectPhids = Sets.newHashSet(projectPhid);
ManiphestInfo taskInfo = conduit.maniphestInfo(taskId);
for (JsonElement jsonElement :
taskInfo.getProjectPHIDs().getAsJsonArray()) {
projectPhids.add(jsonElement.getAsString());
}
conduit.maniphestEdit(taskId, projectPhids, actions);
} catch (ConduitException e) {
throw new IOException("Error on conduit", e);
}
}
@Override
public String healthCheck(final Check check) throws IOException {
// This method is not used, so there is no need to implement it.
return "unknown";
}
@Override
public String createLinkForWebui(String url, String text) {
String ret = "[[" + url;
if (text != null && !text.isEmpty() && !text.equals(url)) {
ret += "|" + text;
}
ret += "]]";
return ret;
}
}