Remove some Logging duplication and Tidy-up
Tidied up some of the logging to the build log by adding a wrapper class to do some formatting and pulling out hard-coded prefixing. Also improved the commenting through the TeamCity plugin.
This commit is contained in:
parent
3564d14927
commit
694b6413ee
14 changed files with 245 additions and 91 deletions
|
@ -10,15 +10,20 @@ import jetbrains.buildServer.agent.AgentBuildFeature;
|
||||||
import jetbrains.buildServer.agent.AgentLifeCycleAdapter;
|
import jetbrains.buildServer.agent.AgentLifeCycleAdapter;
|
||||||
import jetbrains.buildServer.agent.AgentLifeCycleListener;
|
import jetbrains.buildServer.agent.AgentLifeCycleListener;
|
||||||
import jetbrains.buildServer.agent.AgentRunningBuild;
|
import jetbrains.buildServer.agent.AgentRunningBuild;
|
||||||
import jetbrains.buildServer.agent.BuildProgressLogger;
|
|
||||||
import jetbrains.buildServer.util.EventDispatcher;
|
import jetbrains.buildServer.util.EventDispatcher;
|
||||||
import uk.xlab.teamcity.phabricator.logging.PhabricatorAgentLogger;
|
import uk.xlab.teamcity.phabricator.logging.PhabricatorAgentLogger;
|
||||||
|
import uk.xlab.teamcity.phabricator.logging.PhabricatorBuildProgressLogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend the AgentLifeCycleAdapter to check for builds which have the
|
||||||
|
* Phabricator build feature enabled. If enabled then patch the updated code
|
||||||
|
* using arcanist making sure the build is against these changed sources.
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class AgentBuildExtension extends AgentLifeCycleAdapter {
|
public class AgentBuildExtension extends AgentLifeCycleAdapter {
|
||||||
|
|
||||||
private static final String OUTPUT_PREFIX = "Phabricator Plugin - %s";
|
|
||||||
private PhabricatorAgentLogger agentLogLogger;
|
private PhabricatorAgentLogger agentLogLogger;
|
||||||
private BuildProgressLogger buildLogger;
|
private PhabricatorBuildProgressLogger buildLogger;
|
||||||
private PhabricatorPluginConfig phabricatorConfig;
|
private PhabricatorPluginConfig phabricatorConfig;
|
||||||
private boolean phabricatorTriggeredBuild = false;
|
private boolean phabricatorTriggeredBuild = false;
|
||||||
|
|
||||||
|
@ -31,10 +36,18 @@ public class AgentBuildExtension extends AgentLifeCycleAdapter {
|
||||||
phabricatorConfig.setLogger(agentLogLogger);
|
phabricatorConfig.setLogger(agentLogLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From the associated parameters determine if the phabricator build feature is
|
||||||
|
* enabled and we have all the information to successfully patch changes from
|
||||||
|
* the phabricator differential revision
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void buildStarted(@NotNull AgentRunningBuild runningBuild) {
|
public void buildStarted(@NotNull AgentRunningBuild runningBuild) {
|
||||||
|
// Reset the check for a phabricator build
|
||||||
|
phabricatorTriggeredBuild = false;
|
||||||
|
|
||||||
// Setup logger to print to build output
|
// Setup logger to print to build output
|
||||||
buildLogger = runningBuild.getBuildLogger();
|
buildLogger = new PhabricatorBuildProgressLogger(runningBuild.getBuildLogger());
|
||||||
|
|
||||||
// Attempt to get the parameters set by the phabricator build feature. If non
|
// Attempt to get the parameters set by the phabricator build feature. If non
|
||||||
// are set then the feature is not turned on.
|
// are set then the feature is not turned on.
|
||||||
|
@ -42,7 +55,6 @@ public class AgentBuildExtension extends AgentLifeCycleAdapter {
|
||||||
.getBuildFeaturesOfType(Constants.BUILD_FEATURE_TYPE);
|
.getBuildFeaturesOfType(Constants.BUILD_FEATURE_TYPE);
|
||||||
|
|
||||||
if (phabricatorBuildFeatureParameters.isEmpty()) {
|
if (phabricatorBuildFeatureParameters.isEmpty()) {
|
||||||
phabricatorTriggeredBuild = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,28 +71,26 @@ public class AgentBuildExtension extends AgentLifeCycleAdapter {
|
||||||
// everything is present and correct for us to continue
|
// everything is present and correct for us to continue
|
||||||
if (!phabricatorConfig.isPluginSetup()) {
|
if (!phabricatorConfig.isPluginSetup()) {
|
||||||
agentLogLogger.info("Plugin incorrectly configured");
|
agentLogLogger.info("Plugin incorrectly configured");
|
||||||
phabricatorTriggeredBuild = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
phabricatorTriggeredBuild = true;
|
phabricatorTriggeredBuild = true;
|
||||||
agentLogLogger.info("Plugin ready");
|
agentLogLogger.info("Plugin ready");
|
||||||
buildLogger.message(String.format(OUTPUT_PREFIX, "Active"));
|
buildLogger.message("Active");
|
||||||
|
|
||||||
buildLogger.message(String.format(OUTPUT_PREFIX, String.format("%s: %s", Constants.PHABRICATOR_URL_SETTING,
|
buildLogger.logParameter(Constants.PHABRICATOR_URL_SETTING, phabricatorConfig.getPhabricatorURL().toString());
|
||||||
phabricatorConfig.getPhabricatorURL().toString())));
|
buildLogger.logParameter(Constants.PHABRICATOR_ARCANIST_PATH_SETTING, phabricatorConfig.getPathToArcanist());
|
||||||
buildLogger.message(String.format(OUTPUT_PREFIX, String.format("%s: %s",
|
buildLogger.logParameter(Constants.BUILD_ID, phabricatorConfig.getBuildId());
|
||||||
Constants.PHABRICATOR_ARCANIST_PATH_SETTING, phabricatorConfig.getPathToArcanist())));
|
buildLogger.logParameter(Constants.DIFF_ID, phabricatorConfig.getDiffId());
|
||||||
buildLogger.message(String.format(OUTPUT_PREFIX,
|
buildLogger.logParameter(Constants.HARBORMASTER_PHID, phabricatorConfig.getHarbormasterPHID());
|
||||||
String.format("%s: %s", Constants.BUILD_ID, phabricatorConfig.getBuildId())));
|
buildLogger.logParameter(Constants.REVISION_ID, phabricatorConfig.getRevisionId());
|
||||||
buildLogger.message(String.format(OUTPUT_PREFIX,
|
|
||||||
String.format("%s: %s", Constants.DIFF_ID, phabricatorConfig.getDiffId())));
|
|
||||||
buildLogger.message(String.format(OUTPUT_PREFIX, String.format("%s: %s", Constants.HARBORMASTER_PHID,
|
|
||||||
phabricatorConfig.getPhabricatorURL().toString())));
|
|
||||||
buildLogger.message(String.format(OUTPUT_PREFIX,
|
|
||||||
String.format("%s: %s", Constants.REVISION_ID, phabricatorConfig.getRevisionId())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Once the sources have been updated via the native TeamCity process check if
|
||||||
|
* the Phabricator build feature is enabled and use arcanist to patch in changes
|
||||||
|
* from a associated phabricator differential revision.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void sourcesUpdated(@NotNull AgentRunningBuild runningBuild) {
|
public void sourcesUpdated(@NotNull AgentRunningBuild runningBuild) {
|
||||||
|
|
||||||
|
@ -88,7 +98,7 @@ public class AgentBuildExtension extends AgentLifeCycleAdapter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buildLogger.message(String.format(OUTPUT_PREFIX, "Attempting arc patch"));
|
buildLogger.message(String.format(Constants.LOGGING_PREFIX_TEMPLATE, "Attempting arc patch"));
|
||||||
agentLogLogger.info("Attempting arc patch");
|
agentLogLogger.info("Attempting arc patch");
|
||||||
|
|
||||||
ArcanistClient arcanistClient = new ArcanistClient(phabricatorConfig.getPathToArcanist(),
|
ArcanistClient arcanistClient = new ArcanistClient(phabricatorConfig.getPathToArcanist(),
|
||||||
|
@ -96,13 +106,15 @@ public class AgentBuildExtension extends AgentLifeCycleAdapter {
|
||||||
phabricatorConfig.getConduitToken(), agentLogLogger);
|
phabricatorConfig.getConduitToken(), agentLogLogger);
|
||||||
|
|
||||||
int patchCode = arcanistClient.patch(phabricatorConfig.getDiffId());
|
int patchCode = arcanistClient.patch(phabricatorConfig.getDiffId());
|
||||||
|
agentLogLogger.info(String.format("Arc patch exited with code: %s", patchCode));
|
||||||
|
|
||||||
if (patchCode > 0) {
|
if (patchCode > 0) {
|
||||||
runningBuild.stopBuild("Patch failed to apply. Check the agent output log for patch failure detals.");
|
runningBuild.stopBuild("Patch failed to apply. Check the agent output log for patch failure detals.");
|
||||||
|
agentLogLogger.info("Patch failed to apply, stopping build");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buildLogger.message(String.format(OUTPUT_PREFIX, "Patch completed"));
|
buildLogger.message(String.format(Constants.LOGGING_PREFIX_TEMPLATE, "Patch completed"));
|
||||||
agentLogLogger.info("Patch completed");
|
agentLogLogger.info("Patch completed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,10 @@ package uk.xlab.teamcity.phabricator;
|
||||||
|
|
||||||
import uk.xlab.teamcity.phabricator.logging.PhabricatorAgentLogger;
|
import uk.xlab.teamcity.phabricator.logging.PhabricatorAgentLogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for arcanist and patching in changes from differential revisions
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class ArcanistClient {
|
public class ArcanistClient {
|
||||||
|
|
||||||
private final String arcPath;
|
private final String arcPath;
|
||||||
|
@ -11,13 +15,8 @@ public class ArcanistClient {
|
||||||
|
|
||||||
private final PhabricatorAgentLogger agentLogLogger;
|
private final PhabricatorAgentLogger agentLogLogger;
|
||||||
|
|
||||||
public ArcanistClient(
|
public ArcanistClient(final String pathToArcanist, final String workingDirectory, final String phabricatorURL,
|
||||||
final String pathToArcanist,
|
final String conduitToken, final PhabricatorAgentLogger logger) {
|
||||||
final String workingDirectory,
|
|
||||||
final String phabricatorURL,
|
|
||||||
final String conduitToken,
|
|
||||||
final PhabricatorAgentLogger logger
|
|
||||||
) {
|
|
||||||
arcPath = pathToArcanist;
|
arcPath = pathToArcanist;
|
||||||
workingDir = workingDirectory;
|
workingDir = workingDirectory;
|
||||||
conduitAPI = phabricatorURL;
|
conduitAPI = phabricatorURL;
|
||||||
|
@ -25,18 +24,24 @@ public class ArcanistClient {
|
||||||
agentLogLogger = logger;
|
agentLogLogger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run "arc patch" using arcanist on the build agent to pull in changes from a
|
||||||
|
* differential revision.
|
||||||
|
*
|
||||||
|
* @param diffId The identifying diff which has the changes to patch within
|
||||||
|
* differential
|
||||||
|
* @return The exit code for "arc patch" or 1 if exceptions occur
|
||||||
|
*/
|
||||||
public int patch(String diffId) {
|
public int patch(String diffId) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
Command commandToExecute = new CommandBuilder()
|
Command commandToExecute = new CommandBuilder().setCommand(arcPath).setAction("patch")
|
||||||
.setCommand(arcPath)
|
.setWorkingDir(workingDir).setArg("--diff").setArg(diffId)
|
||||||
.setAction("patch")
|
|
||||||
.setWorkingDir(workingDir)
|
|
||||||
.setArg("--diff")
|
|
||||||
.setArg(diffId)
|
|
||||||
.setFlagWithValueEquals("--conduit-uri", conduitAPI)
|
.setFlagWithValueEquals("--conduit-uri", conduitAPI)
|
||||||
.setFlagWithValueEquals("--conduit-token", token)
|
.setFlagWithValueEquals("--conduit-token", token).build();
|
||||||
.build();
|
|
||||||
|
agentLogLogger.info(String.format("Running Command: %s", commandToExecute.toString()));
|
||||||
|
|
||||||
return commandToExecute.executeAndWait();
|
return commandToExecute.executeAndWait();
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
|
|
|
@ -4,6 +4,10 @@ import java.io.File;
|
||||||
|
|
||||||
import static uk.xlab.teamcity.phabricator.CommonUtils.*;
|
import static uk.xlab.teamcity.phabricator.CommonUtils.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for executing a command on the host system
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class Command {
|
public class Command {
|
||||||
|
|
||||||
private final File workingDir;
|
private final File workingDir;
|
||||||
|
@ -11,17 +15,32 @@ public class Command {
|
||||||
private ProcessBuilder processBuilder;
|
private ProcessBuilder processBuilder;
|
||||||
private Process process;
|
private Process process;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compose the command which is to be executed
|
||||||
|
*
|
||||||
|
* @param executableAndArguments An array of the command to be executed.
|
||||||
|
* @param workingDirectory The directory the command will be executed
|
||||||
|
* from.
|
||||||
|
*/
|
||||||
public Command(final String[] executableAndArguments, final String workingDirectory) {
|
public Command(final String[] executableAndArguments, final String workingDirectory) {
|
||||||
workingDir = isNullOrEmpty(workingDirectory) ? null : new File(workingDirectory);
|
workingDir = isNullOrEmpty(workingDirectory) ? null : new File(workingDirectory);
|
||||||
fullCommand = executableAndArguments;
|
fullCommand = executableAndArguments;
|
||||||
|
|
||||||
// ProcessBuilder requires the full command to be an array to prepend the
|
// ProcessBuilder requires the full command to be an array with the
|
||||||
// executable to the front;
|
// executable the first element;
|
||||||
processBuilder = new ProcessBuilder(executableAndArguments);
|
processBuilder = new ProcessBuilder(executableAndArguments);
|
||||||
processBuilder.directory(workingDir);
|
processBuilder.directory(workingDir);
|
||||||
processBuilder.inheritIO();
|
processBuilder.inheritIO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the command and wait for it to finish gathering the exit code of the
|
||||||
|
* process
|
||||||
|
*
|
||||||
|
* @return The exit code from the command which has been executed.
|
||||||
|
* @throws Exception If there is an exception when running the command throw to
|
||||||
|
* allowing the executing class to deal with error handling.
|
||||||
|
*/
|
||||||
public int executeAndWait() throws Exception {
|
public int executeAndWait() throws Exception {
|
||||||
// May well fail and throw an exception but we will handle that in the agent
|
// May well fail and throw an exception but we will handle that in the agent
|
||||||
// plugin.
|
// plugin.
|
||||||
|
@ -29,6 +48,10 @@ public class Command {
|
||||||
return process.waitFor();
|
return process.waitFor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output the command and working directory for this class. It should only be
|
||||||
|
* used sparingly.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (fullCommand.length < 1) {
|
if (fullCommand.length < 1) {
|
||||||
|
|
|
@ -3,9 +3,12 @@ package uk.xlab.teamcity.phabricator;
|
||||||
import static uk.xlab.teamcity.phabricator.CommonUtils.*;
|
import static uk.xlab.teamcity.phabricator.CommonUtils.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build up the command which will be executed on the agent during relevant
|
||||||
|
* builds
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class CommandBuilder {
|
public class CommandBuilder {
|
||||||
|
|
||||||
private String command = null;
|
private String command = null;
|
||||||
|
@ -13,49 +16,90 @@ public class CommandBuilder {
|
||||||
private String workingDir = null;
|
private String workingDir = null;
|
||||||
private List<String> args = new ArrayList<String>();
|
private List<String> args = new ArrayList<String>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the directory which the command should be run from.
|
||||||
|
*
|
||||||
|
* @param workingDir The directory the command should be run from.
|
||||||
|
* @return The builder instance so things can be chained.
|
||||||
|
*/
|
||||||
public CommandBuilder setWorkingDir(String workingDir) {
|
public CommandBuilder setWorkingDir(String workingDir) {
|
||||||
if (isNullOrEmpty(workingDir))
|
if (isNullOrEmpty(workingDir)) {
|
||||||
throw new IllegalArgumentException("Need to provide valid working directory");
|
throw new IllegalArgumentException("Need to provide valid working directory");
|
||||||
else
|
} else {
|
||||||
this.workingDir = workingDir;
|
this.workingDir = workingDir;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the command/executable that will be run.
|
||||||
|
*
|
||||||
|
* @param cmd The command to be executed.
|
||||||
|
* @return The builder instance so things can be chained.
|
||||||
|
*/
|
||||||
public CommandBuilder setCommand(String cmd) {
|
public CommandBuilder setCommand(String cmd) {
|
||||||
if (isNullOrEmpty(cmd))
|
if (isNullOrEmpty(cmd)) {
|
||||||
throw new IllegalArgumentException("Need to provide a valid command");
|
throw new IllegalArgumentException("Need to provide a valid command");
|
||||||
else
|
} else {
|
||||||
this.command = cmd;
|
this.command = cmd;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the action the command will perform this comes immediately after the
|
||||||
|
* executable. E.g git pull where pull is the action.
|
||||||
|
*
|
||||||
|
* @param action
|
||||||
|
* @return The builder instance so things can be chained.
|
||||||
|
*/
|
||||||
public CommandBuilder setAction(String action) {
|
public CommandBuilder setAction(String action) {
|
||||||
if (isNullOrEmpty(action))
|
if (isNullOrEmpty(action)) {
|
||||||
throw new IllegalArgumentException("Need to provide a valid action");
|
throw new IllegalArgumentException("Need to provide a valid action");
|
||||||
else
|
} else {
|
||||||
this.action = action;
|
this.action = action;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set arguments that will be added to the command which will be executed
|
||||||
|
*
|
||||||
|
* @param arg An argument to be added to the command
|
||||||
|
* @return The builder instance so things can be chained.
|
||||||
|
*/
|
||||||
public CommandBuilder setArg(String arg) {
|
public CommandBuilder setArg(String arg) {
|
||||||
if (isNullOrEmpty(arg))
|
if (isNullOrEmpty(arg)) {
|
||||||
throw new IllegalArgumentException("Need to provide a valid argument");
|
throw new IllegalArgumentException("Need to provide a valid argument");
|
||||||
else
|
} else {
|
||||||
this.args.add(arg);
|
this.args.add(arg);
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set arguments which take the form of a key value pair. E.g token=12344
|
||||||
|
*
|
||||||
|
* @param key The initial part of the argument
|
||||||
|
* @param value The value of the argument to be added after an the key and
|
||||||
|
* equals
|
||||||
|
* @return The builder instance so things can be chained.
|
||||||
|
*/
|
||||||
public CommandBuilder setFlagWithValueEquals(String key, String value) {
|
public CommandBuilder setFlagWithValueEquals(String key, String value) {
|
||||||
this.args.add(String.format("%s=%s", formatFlag(key), value));
|
this.args.add(String.format("%s=%s", key, value));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using the values set on this builder create a Command object than can be
|
||||||
|
* executed.
|
||||||
|
*
|
||||||
|
* @return Command which and be executed at a later point
|
||||||
|
*/
|
||||||
public Command build() {
|
public Command build() {
|
||||||
if (isNullOrEmpty(this.command)) {
|
if (isNullOrEmpty(this.command)) {
|
||||||
throw new IllegalArgumentException("Must provide a command");
|
throw new IllegalArgumentException("Must provide a command");
|
||||||
}
|
} else {
|
||||||
|
|
||||||
else {
|
|
||||||
this.args.add(0, this.command);
|
this.args.add(0, this.command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,18 +109,4 @@ public class CommandBuilder {
|
||||||
|
|
||||||
return new Command(args.toArray(new String[args.size()]), this.workingDir);
|
return new Command(args.toArray(new String[args.size()]), this.workingDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String formatFlag(String flag) {
|
|
||||||
Pattern withFlag = Pattern.compile("^\\-\\-[a-zA-Z0-9-]+$");
|
|
||||||
Pattern singleWord = Pattern.compile("^\\w$");
|
|
||||||
Matcher m = withFlag.matcher(flag.trim());
|
|
||||||
Matcher m1 = singleWord.matcher(flag.trim());
|
|
||||||
if (m.matches()) {
|
|
||||||
return flag.trim();
|
|
||||||
} else if (m1.matches()) {
|
|
||||||
return String.format("--%s", flag);
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(String.format("%s is not a valid flag", flag));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,27 @@
|
||||||
package uk.xlab.teamcity.phabricator;
|
package uk.xlab.teamcity.phabricator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A collection of helper methods that are used throughout the plugin
|
||||||
|
*
|
||||||
|
*/
|
||||||
public final class CommonUtils {
|
public final class CommonUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given string is NULL or an empty string
|
||||||
|
*
|
||||||
|
* @param str String to be checked
|
||||||
|
* @return Whether the string is NULL or empty
|
||||||
|
*/
|
||||||
public static Boolean isNullOrEmpty(String str) {
|
public static Boolean isNullOrEmpty(String str) {
|
||||||
return str == null || str.equals("");
|
return str == null || str.equals("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given object is NULL
|
||||||
|
*
|
||||||
|
* @param obj Object to be checked for NULL
|
||||||
|
* @return Whether the object is NULL
|
||||||
|
*/
|
||||||
public static Boolean isNull(Object obj) {
|
public static Boolean isNull(Object obj) {
|
||||||
return obj == null;
|
return obj == null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
package uk.xlab.teamcity.phabricator;
|
package uk.xlab.teamcity.phabricator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of constants that are used throughout the server and agent plugins
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class Constants {
|
public class Constants {
|
||||||
|
|
||||||
public static final String PLUGIN_NAME = "phabricator";
|
public static final String PLUGIN_NAME = "phabricator";
|
||||||
public static final String PLUGIN_DISPLAY_NAME = "Phabricator Plugin";
|
public static final String PLUGIN_DISPLAY_NAME = "Phabricator Plugin";
|
||||||
|
public static final String LOGGING_PREFIX_TEMPLATE = "Phabricator Plugin - %s";
|
||||||
|
|
||||||
// Build Feature Settings
|
// Build Feature Settings
|
||||||
public static final String BUILD_FEATURE_TYPE = "phabricator-build-feature";
|
public static final String BUILD_FEATURE_TYPE = "phabricator-build-feature";
|
||||||
|
|
|
@ -48,14 +48,9 @@ public class PhabricatorPluginConfig {
|
||||||
* @param parameters
|
* @param parameters
|
||||||
*/
|
*/
|
||||||
public void setParameters(Map<String, String> parameters) {
|
public void setParameters(Map<String, String> parameters) {
|
||||||
// Clear the class variables to avoid any lingering references
|
// Clear the class variables to avoid any previous build configurations staying
|
||||||
phabricatorUrl = null;
|
// around
|
||||||
conduitToken = null;
|
clearParameters();
|
||||||
pathToArcanist = null;
|
|
||||||
buildId = null;
|
|
||||||
diffId = null;
|
|
||||||
harbormasterPHID = null;
|
|
||||||
revisionId = null;
|
|
||||||
|
|
||||||
params = parameters;
|
params = parameters;
|
||||||
|
|
||||||
|
@ -109,6 +104,26 @@ public class PhabricatorPluginConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A little method than can be used to clear all the parameters we want to set
|
||||||
|
*/
|
||||||
|
private void clearParameters() {
|
||||||
|
phabricatorUrl = null;
|
||||||
|
conduitToken = null;
|
||||||
|
pathToArcanist = null;
|
||||||
|
buildId = null;
|
||||||
|
diffId = null;
|
||||||
|
harbormasterPHID = null;
|
||||||
|
revisionId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that all the required parameters are set and we can continue to attempt
|
||||||
|
* patching changes from Arcanist
|
||||||
|
*
|
||||||
|
* @return Result of whether or not the plugin has the appropriate parameter to
|
||||||
|
* be used by an agent.
|
||||||
|
*/
|
||||||
public boolean isPluginSetup() {
|
public boolean isPluginSetup() {
|
||||||
if (!isNull(phabricatorUrl) && !isNull(pathToArcanist) && !isNullOrEmpty(buildId) && !isNullOrEmpty(diffId)
|
if (!isNull(phabricatorUrl) && !isNull(pathToArcanist) && !isNullOrEmpty(buildId) && !isNullOrEmpty(diffId)
|
||||||
&& !isNullOrEmpty(harbormasterPHID) && !isNullOrEmpty(revisionId)) {
|
&& !isNullOrEmpty(harbormasterPHID) && !isNullOrEmpty(revisionId)) {
|
||||||
|
@ -146,6 +161,13 @@ public class PhabricatorPluginConfig {
|
||||||
return revisionId;
|
return revisionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the given URL for phabricator to verify it is not just a random string
|
||||||
|
*
|
||||||
|
* @param input phabricator URL
|
||||||
|
* @return Parsed URL object of the given string phabricator URL
|
||||||
|
* @throws MalformedURLException The given string is not a URL
|
||||||
|
*/
|
||||||
private URL parsePhabricatorURL(String input) throws MalformedURLException {
|
private URL parsePhabricatorURL(String input) throws MalformedURLException {
|
||||||
URL inputURL = new URL(input);
|
URL inputURL = new URL(input);
|
||||||
return inputURL;
|
return inputURL;
|
||||||
|
|
|
@ -1,23 +1,27 @@
|
||||||
package uk.xlab.teamcity.phabricator.logging;
|
package uk.xlab.teamcity.phabricator.logging;
|
||||||
|
|
||||||
import jetbrains.buildServer.log.Loggers;
|
import jetbrains.buildServer.log.Loggers;
|
||||||
|
import uk.xlab.teamcity.phabricator.Constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logging class which outputs messages to TeamCity Agent Logs. Any logging from
|
||||||
|
* this class is also prefixed with this plugin's name
|
||||||
|
*
|
||||||
|
*/
|
||||||
public final class PhabricatorAgentLogger implements PhabricatorPluginLogger {
|
public final class PhabricatorAgentLogger implements PhabricatorPluginLogger {
|
||||||
|
|
||||||
private final String LOGGING_PREFIX_TEMPLATE = "Phabricator Plugin - %s";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void info(String message) {
|
public void info(String message) {
|
||||||
Loggers.AGENT.info(String.format(LOGGING_PREFIX_TEMPLATE, message));
|
Loggers.AGENT.info(String.format(Constants.LOGGING_PREFIX_TEMPLATE, message));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void warn(String message, Exception e) {
|
public void warn(String message, Exception e) {
|
||||||
Loggers.AGENT.warn(String.format(LOGGING_PREFIX_TEMPLATE, message), e);
|
Loggers.AGENT.warn(String.format(Constants.LOGGING_PREFIX_TEMPLATE, message), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void error(String message, Exception e) {
|
public void error(String message, Exception e) {
|
||||||
Loggers.AGENT.error(String.format(LOGGING_PREFIX_TEMPLATE, message), e);
|
Loggers.AGENT.error(String.format(Constants.LOGGING_PREFIX_TEMPLATE, message), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package uk.xlab.teamcity.phabricator.logging;
|
||||||
|
|
||||||
|
import jetbrains.buildServer.agent.BuildProgressLogger;
|
||||||
|
import uk.xlab.teamcity.phabricator.Constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logging class which outputs messages to the Build Log. Any logging from this
|
||||||
|
* class is also prefixed with this plugin's name
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class PhabricatorBuildProgressLogger {
|
||||||
|
private BuildProgressLogger buildLogger;
|
||||||
|
|
||||||
|
public PhabricatorBuildProgressLogger(BuildProgressLogger buildProcessLogger) {
|
||||||
|
buildLogger = buildProcessLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void message(String message) {
|
||||||
|
buildLogger.message(String.format(Constants.LOGGING_PREFIX_TEMPLATE, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void logParameter(String parameter, String value) {
|
||||||
|
buildLogger.message(String.format(Constants.LOGGING_PREFIX_TEMPLATE, String.format("%s: %s", parameter, value)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,23 +1,27 @@
|
||||||
package uk.xlab.teamcity.phabricator.logging;
|
package uk.xlab.teamcity.phabricator.logging;
|
||||||
|
|
||||||
import jetbrains.buildServer.log.Loggers;
|
import jetbrains.buildServer.log.Loggers;
|
||||||
|
import uk.xlab.teamcity.phabricator.Constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logging class which outputs messages to TeamCity Server Logs. Any logging
|
||||||
|
* from this class is also prefixed with this plugin's name
|
||||||
|
*
|
||||||
|
*/
|
||||||
public final class PhabricatorServerLogger implements PhabricatorPluginLogger {
|
public final class PhabricatorServerLogger implements PhabricatorPluginLogger {
|
||||||
|
|
||||||
private final String LOGGING_PREFIX_TEMPLATE = "Phabricator Plugin - %s";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void info(String message) {
|
public void info(String message) {
|
||||||
Loggers.SERVER.info(String.format(LOGGING_PREFIX_TEMPLATE, message));
|
Loggers.SERVER.info(String.format(Constants.LOGGING_PREFIX_TEMPLATE, message));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void warn(String message, Exception e) {
|
public void warn(String message, Exception e) {
|
||||||
Loggers.SERVER.warn(String.format(LOGGING_PREFIX_TEMPLATE, message), e);
|
Loggers.SERVER.warn(String.format(Constants.LOGGING_PREFIX_TEMPLATE, message), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void error(String message, Exception e) {
|
public void error(String message, Exception e) {
|
||||||
Loggers.SERVER.error(String.format(LOGGING_PREFIX_TEMPLATE, message), e);
|
Loggers.SERVER.error(String.format(Constants.LOGGING_PREFIX_TEMPLATE, message), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,6 @@ import org.apache.http.util.EntityUtils;
|
||||||
* Class that is run in a thread once a build has started. If the build does not
|
* Class that is run in a thread once a build has started. If the build does not
|
||||||
* have the phabricator build feature then the tread should come to an end
|
* have the phabricator build feature then the tread should come to an end
|
||||||
* otherwise wait for the build to finish and report back to phabricator
|
* otherwise wait for the build to finish and report back to phabricator
|
||||||
*
|
|
||||||
* @author steven.cooney
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class BuildTracker implements Runnable {
|
public class BuildTracker implements Runnable {
|
||||||
|
@ -61,7 +59,6 @@ public class BuildTracker implements Runnable {
|
||||||
params.putAll(phabricatorBuildFeatureParameters.iterator().next().getParameters());
|
params.putAll(phabricatorBuildFeatureParameters.iterator().next().getParameters());
|
||||||
|
|
||||||
// Setup plugin specific configuration
|
// Setup plugin specific configuration
|
||||||
// TODO: implement AppConfig as PluginConfig
|
|
||||||
phabricatorConfig.setParameters(params);
|
phabricatorConfig.setParameters(params);
|
||||||
|
|
||||||
// Now we have set all the parameters we need to check if
|
// Now we have set all the parameters we need to check if
|
||||||
|
|
|
@ -9,9 +9,9 @@ import jetbrains.buildServer.util.EventDispatcher;
|
||||||
import uk.xlab.teamcity.phabricator.logging.PhabricatorServerLogger;
|
import uk.xlab.teamcity.phabricator.logging.PhabricatorServerLogger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen for builds been started and track their progress with BuildTracker
|
* Listen for builds to start by extending BuildServerAdapter. When a build
|
||||||
*
|
* starts spin up a thread of BuildTracker class to follow the progress of the
|
||||||
* @author steven.cooney
|
* build.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class PhabricatorBuildServerAdapter extends BuildServerAdapter {
|
public class PhabricatorBuildServerAdapter extends BuildServerAdapter {
|
||||||
|
|
|
@ -5,6 +5,12 @@ import java.util.Map;
|
||||||
import jetbrains.buildServer.serverSide.BuildStartContext;
|
import jetbrains.buildServer.serverSide.BuildStartContext;
|
||||||
import jetbrains.buildServer.serverSide.BuildStartContextProcessor;
|
import jetbrains.buildServer.serverSide.BuildStartContextProcessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* At the start of a build gather the parameters the agent plugin requires and
|
||||||
|
* set them in shared parameters. The agent can then read them from the shared
|
||||||
|
* parameters.
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class PhabricatorBuildStartContextProcessor implements BuildStartContextProcessor {
|
public class PhabricatorBuildStartContextProcessor implements BuildStartContextProcessor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -8,6 +8,11 @@ import jetbrains.buildServer.serverSide.BuildFeature;
|
||||||
import jetbrains.buildServer.web.openapi.PluginDescriptor;
|
import jetbrains.buildServer.web.openapi.PluginDescriptor;
|
||||||
import uk.xlab.teamcity.phabricator.logging.PhabricatorServerLogger;
|
import uk.xlab.teamcity.phabricator.logging.PhabricatorServerLogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up a Build Feature for the phabricator plugin. Ultimately allowing the
|
||||||
|
* plugin to be configured through the TeamCity BuildFeature UI.
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class PhabricatorPluginBuildFeature extends BuildFeature {
|
public class PhabricatorPluginBuildFeature extends BuildFeature {
|
||||||
|
|
||||||
private final String myEditUrl;
|
private final String myEditUrl;
|
||||||
|
|
Loading…
Reference in a new issue