Add PathToArc Parameter on Build Feature & Moving Logging Classes
Add a new field on the build feature dialog allowing the user to specify where arcanist command is located on the agent. We will need this information to execute the patching process upon which we will be building. This commit also add Command and CommandBuilder into Common which we will be using to execute arcanist to apply the `arc patch` during the build so we can actually build the changes from the revision, Also moved the three logging based files into a sub-folder causing many file updates of just an import.
This commit is contained in:
parent
cefb59b73a
commit
abfa8f840d
14 changed files with 150 additions and 6 deletions
|
@ -12,6 +12,7 @@ import jetbrains.buildServer.agent.AgentLifeCycleListener;
|
||||||
import jetbrains.buildServer.agent.AgentRunningBuild;
|
import jetbrains.buildServer.agent.AgentRunningBuild;
|
||||||
import jetbrains.buildServer.agent.BuildProgressLogger;
|
import jetbrains.buildServer.agent.BuildProgressLogger;
|
||||||
import jetbrains.buildServer.util.EventDispatcher;
|
import jetbrains.buildServer.util.EventDispatcher;
|
||||||
|
import uk.xlab.teamcity.phabricator.logging.PhabricatorAgentLogger;
|
||||||
|
|
||||||
public class AgentBuildExtension extends AgentLifeCycleAdapter {
|
public class AgentBuildExtension extends AgentLifeCycleAdapter {
|
||||||
|
|
||||||
|
|
|
@ -6,5 +6,5 @@
|
||||||
default-autowire="constructor">
|
default-autowire="constructor">
|
||||||
|
|
||||||
<bean class="uk.xlab.teamcity.phabricator.AgentBuildExtension" />
|
<bean class="uk.xlab.teamcity.phabricator.AgentBuildExtension" />
|
||||||
<bean class="uk.xlab.teamcity.phabricator.PhabricatorAgentLogger" />
|
<bean class="uk.xlab.teamcity.phabricator.logging.PhabricatorAgentLogger" />
|
||||||
</beans>
|
</beans>
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package uk.xlab.teamcity.phabricator;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import static uk.xlab.teamcity.phabricator.CommonUtils.*;
|
||||||
|
|
||||||
|
public class Command {
|
||||||
|
|
||||||
|
private final File workingDir;
|
||||||
|
private String[] fullCommand;
|
||||||
|
private ProcessBuilder processBuilder;
|
||||||
|
private Process process;
|
||||||
|
|
||||||
|
public Command(final String[] executableAndArguments, final String workingDirectory) {
|
||||||
|
workingDir = isNullOrEmpty(workingDirectory) ? null : new File(workingDirectory);
|
||||||
|
fullCommand = executableAndArguments;
|
||||||
|
|
||||||
|
// ProcessBuilder requires the full command to be an array to prepend the
|
||||||
|
// executable to the front;
|
||||||
|
processBuilder = new ProcessBuilder(executableAndArguments);
|
||||||
|
processBuilder.directory(workingDir);
|
||||||
|
processBuilder.inheritIO();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int executeAndWait() throws Exception {
|
||||||
|
// May well fail and throw an exception but we will handle that in the agent
|
||||||
|
// plugin.
|
||||||
|
process = processBuilder.start();
|
||||||
|
return process.waitFor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (fullCommand.length < 1) {
|
||||||
|
return "Command not setup";
|
||||||
|
}
|
||||||
|
|
||||||
|
String printableCommand = String.join(" ", fullCommand);
|
||||||
|
|
||||||
|
// The workingDir might not have been explicitly set
|
||||||
|
if (processBuilder.directory() == null) {
|
||||||
|
return String.format("Command: %s", printableCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.format("WorkingDir: %s - Command: %s", processBuilder.directory().toString(), printableCommand);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
package uk.xlab.teamcity.phabricator;
|
||||||
|
|
||||||
|
import static uk.xlab.teamcity.phabricator.CommonUtils.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class CommandBuilder {
|
||||||
|
|
||||||
|
private String command = null;
|
||||||
|
private String action = null;
|
||||||
|
private String workingDir = null;
|
||||||
|
private List<String> args = new ArrayList<String>();
|
||||||
|
|
||||||
|
public CommandBuilder setWorkingDir(String workingDir) {
|
||||||
|
if (isNullOrEmpty(workingDir))
|
||||||
|
throw new IllegalArgumentException("Need to provide valid working directory");
|
||||||
|
else
|
||||||
|
this.workingDir = workingDir;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder setCommand(String cmd) {
|
||||||
|
if (isNullOrEmpty(cmd))
|
||||||
|
throw new IllegalArgumentException("Need to provide a valid command");
|
||||||
|
else
|
||||||
|
this.command = cmd;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder setAction(String action) {
|
||||||
|
if (isNullOrEmpty(action))
|
||||||
|
throw new IllegalArgumentException("Need to provide a valid action");
|
||||||
|
else
|
||||||
|
this.action = action;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder setArg(String arg) {
|
||||||
|
if (isNullOrEmpty(arg))
|
||||||
|
throw new IllegalArgumentException("Need to provide a valid argument");
|
||||||
|
else
|
||||||
|
this.args.add(arg);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder setFlagWithValueEquals(String key, String value) {
|
||||||
|
this.args.add(String.format("%s=%s", formatFlag(key), value));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Command build() {
|
||||||
|
if (isNullOrEmpty(this.command)) {
|
||||||
|
throw new IllegalArgumentException("Must provide a command");
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
this.args.add(0, this.command);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNullOrEmpty(this.action)) {
|
||||||
|
this.args.add(1, this.action);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ public class Constants {
|
||||||
public static final String BUILD_FEATURE_TYPE = "phabricator-build-feature";
|
public static final String BUILD_FEATURE_TYPE = "phabricator-build-feature";
|
||||||
public static final String PHABRICATOR_URL_SETTING = "plugin.phabricatorUrl";
|
public static final String PHABRICATOR_URL_SETTING = "plugin.phabricatorUrl";
|
||||||
public static final String PHABRICATOR_CONDUIT_TOKEN_SETTING = "plugin.conduitToken";
|
public static final String PHABRICATOR_CONDUIT_TOKEN_SETTING = "plugin.conduitToken";
|
||||||
|
public static final String PHABRICATOR_ARCANIST_PATH_SETTING = "plugin.pathToArc";
|
||||||
|
|
||||||
// Build Config
|
// Build Config
|
||||||
public static final String BUILD_ID = "phabricator.BUILD_ID";
|
public static final String BUILD_ID = "phabricator.BUILD_ID";
|
||||||
|
|
|
@ -3,6 +3,9 @@ package uk.xlab.teamcity.phabricator;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import uk.xlab.teamcity.phabricator.logging.PhabricatorPluginLogger;
|
||||||
|
|
||||||
import static uk.xlab.teamcity.phabricator.CommonUtils.*;
|
import static uk.xlab.teamcity.phabricator.CommonUtils.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,6 +24,7 @@ public class PhabricatorPluginConfig {
|
||||||
// Build Feature Variables
|
// Build Feature Variables
|
||||||
private URL phabricatorUrl;
|
private URL phabricatorUrl;
|
||||||
private String conduitToken;
|
private String conduitToken;
|
||||||
|
private String pathToArcanist;
|
||||||
|
|
||||||
// Harbormaster Variables
|
// Harbormaster Variables
|
||||||
private String buildId;
|
private String buildId;
|
||||||
|
@ -66,6 +70,10 @@ public class PhabricatorPluginConfig {
|
||||||
logger.info("Found Phabricator Conduit Token");
|
logger.info("Found Phabricator Conduit Token");
|
||||||
conduitToken = params.get(Constants.PHABRICATOR_CONDUIT_TOKEN_SETTING);
|
conduitToken = params.get(Constants.PHABRICATOR_CONDUIT_TOKEN_SETTING);
|
||||||
break;
|
break;
|
||||||
|
case Constants.PHABRICATOR_ARCANIST_PATH_SETTING:
|
||||||
|
logger.info(String.format("Found Phabricator Arcanist Path: %s", params.get(Constants.PHABRICATOR_ARCANIST_PATH_SETTING)));
|
||||||
|
pathToArcanist = params.get(Constants.PHABRICATOR_ARCANIST_PATH_SETTING);
|
||||||
|
break;
|
||||||
case Constants.BUILD_ID:
|
case Constants.BUILD_ID:
|
||||||
logger.info(String.format("Found build id: %s", params.get(Constants.BUILD_ID)));
|
logger.info(String.format("Found build id: %s", params.get(Constants.BUILD_ID)));
|
||||||
buildId = params.get(Constants.BUILD_ID);
|
buildId = params.get(Constants.BUILD_ID);
|
||||||
|
@ -92,7 +100,7 @@ public class PhabricatorPluginConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPluginSetup() {
|
public boolean isPluginSetup() {
|
||||||
if (!isNull(phabricatorUrl) && !isNullOrEmpty(buildId) && !isNullOrEmpty(diffId)
|
if (!isNull(phabricatorUrl) && !isNull(pathToArcanist) && !isNullOrEmpty(buildId) && !isNullOrEmpty(diffId)
|
||||||
&& !isNullOrEmpty(harbormasterPHID) && !isNullOrEmpty(revisionId)) {
|
&& !isNullOrEmpty(harbormasterPHID) && !isNullOrEmpty(revisionId)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package uk.xlab.teamcity.phabricator;
|
package uk.xlab.teamcity.phabricator.logging;
|
||||||
|
|
||||||
import jetbrains.buildServer.log.Loggers;
|
import jetbrains.buildServer.log.Loggers;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package uk.xlab.teamcity.phabricator;
|
package uk.xlab.teamcity.phabricator.logging;
|
||||||
|
|
||||||
public interface PhabricatorPluginLogger {
|
public interface PhabricatorPluginLogger {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package uk.xlab.teamcity.phabricator;
|
package uk.xlab.teamcity.phabricator.logging;
|
||||||
|
|
||||||
import jetbrains.buildServer.log.Loggers;
|
import jetbrains.buildServer.log.Loggers;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.util.Map;
|
||||||
import jetbrains.buildServer.messages.Status;
|
import jetbrains.buildServer.messages.Status;
|
||||||
import jetbrains.buildServer.serverSide.SBuildFeatureDescriptor;
|
import jetbrains.buildServer.serverSide.SBuildFeatureDescriptor;
|
||||||
import jetbrains.buildServer.serverSide.SRunningBuild;
|
import jetbrains.buildServer.serverSide.SRunningBuild;
|
||||||
|
import uk.xlab.teamcity.phabricator.logging.PhabricatorServerLogger;
|
||||||
|
|
||||||
import org.apache.http.NameValuePair;
|
import org.apache.http.NameValuePair;
|
||||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import jetbrains.buildServer.serverSide.BuildServerAdapter;
|
||||||
import jetbrains.buildServer.serverSide.BuildServerListener;
|
import jetbrains.buildServer.serverSide.BuildServerListener;
|
||||||
import jetbrains.buildServer.serverSide.SRunningBuild;
|
import jetbrains.buildServer.serverSide.SRunningBuild;
|
||||||
import jetbrains.buildServer.util.EventDispatcher;
|
import jetbrains.buildServer.util.EventDispatcher;
|
||||||
|
import uk.xlab.teamcity.phabricator.logging.PhabricatorServerLogger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen for builds been started and track their progress with BuildTracker
|
* Listen for builds been started and track their progress with BuildTracker
|
||||||
|
|
|
@ -6,6 +6,7 @@ import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import jetbrains.buildServer.serverSide.BuildFeature;
|
import jetbrains.buildServer.serverSide.BuildFeature;
|
||||||
import jetbrains.buildServer.web.openapi.PluginDescriptor;
|
import jetbrains.buildServer.web.openapi.PluginDescriptor;
|
||||||
|
import uk.xlab.teamcity.phabricator.logging.PhabricatorServerLogger;
|
||||||
|
|
||||||
public class PhabricatorPluginBuildFeature extends BuildFeature {
|
public class PhabricatorPluginBuildFeature extends BuildFeature {
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
default-autowire="constructor">
|
default-autowire="constructor">
|
||||||
|
|
||||||
<bean class="uk.xlab.teamcity.phabricator.PhabricatorPluginBuildFeature" />
|
<bean class="uk.xlab.teamcity.phabricator.PhabricatorPluginBuildFeature" />
|
||||||
<bean class="uk.xlab.teamcity.phabricator.PhabricatorServerLogger" />
|
|
||||||
<bean class="uk.xlab.teamcity.phabricator.PhabricatorBuildServerAdapter" />
|
<bean class="uk.xlab.teamcity.phabricator.PhabricatorBuildServerAdapter" />
|
||||||
<bean class="uk.xlab.teamcity.phabricator.PhabricatorBuildStartContextProcessor" />
|
<bean class="uk.xlab.teamcity.phabricator.PhabricatorBuildStartContextProcessor" />
|
||||||
|
<bean class="uk.xlab.teamcity.phabricator.logging.PhabricatorServerLogger" />
|
||||||
</beans>
|
</beans>
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
|
|
||||||
<c:set var="phabricatorUrl" value="${propertiesBean.properties['plugin.phabricatorUrl']}" />
|
<c:set var="phabricatorUrl" value="${propertiesBean.properties['plugin.phabricatorUrl']}" />
|
||||||
<c:set var="conduitToken" value="${propertiesBean.properties['plugin.conduitToken']}" />
|
<c:set var="conduitToken" value="${propertiesBean.properties['plugin.conduitToken']}" />
|
||||||
|
<c:set var="pathToArc" value="${propertiesBean.properties['plugin.pathToArc']}" />
|
||||||
|
|
||||||
<tr><td colspan="2">Report build status in real-time to your Phabricator instance.</td></tr>
|
<tr><td colspan="2">Report build status in real-time to your Phabricator instance.</td></tr>
|
||||||
<tr><th>Phabricator URL:</th><td><props:textProperty name="plugin.phabricatorUrl"/></td></tr>
|
<tr><th>Phabricator URL:</th><td><props:textProperty name="plugin.phabricatorUrl"/></td></tr>
|
||||||
<tr><th>Conduit Token:</th><td><props:passwordProperty name="plugin.conduitToken" size="54"/></td></tr>
|
<tr><th>Conduit Token:</th><td><props:passwordProperty name="plugin.conduitToken" size="54"/></td></tr>
|
||||||
|
<tr><th>Path To Arcanist:</th><td><props:textProperty name="plugin.pathToArc"/></td></tr>
|
||||||
|
|
Loading…
Reference in a new issue