diff --git a/README.md b/README.md index 2338fb1..91691d7 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,8 @@ These plugins require GoCD version v15.x or above. - Build status notifier plugin will update Pull Request with build status ![On successful run of new pipeline][13] +- In order to force GoCD to build every commit the pipeline name has be defined for the material. + ### Github **Authentication:** diff --git a/src/main/java/in/ashwanthkumar/gocd/github/GitHubPRBuildPlugin.java b/src/main/java/in/ashwanthkumar/gocd/github/GitHubPRBuildPlugin.java index 867ef7f..a5d9c73 100644 --- a/src/main/java/in/ashwanthkumar/gocd/github/GitHubPRBuildPlugin.java +++ b/src/main/java/in/ashwanthkumar/gocd/github/GitHubPRBuildPlugin.java @@ -5,6 +5,7 @@ import com.thoughtworks.go.plugin.api.GoPluginIdentifier; import com.thoughtworks.go.plugin.api.annotation.Extension; import com.thoughtworks.go.plugin.api.logging.Logger; +import com.thoughtworks.go.plugin.api.request.DefaultGoApiRequest; import com.thoughtworks.go.plugin.api.request.GoPluginApiRequest; import com.thoughtworks.go.plugin.api.response.GoPluginApiResponse; import com.tw.go.plugin.GitHelper; @@ -13,12 +14,19 @@ import com.tw.go.plugin.model.Revision; import com.tw.go.plugin.util.ListUtil; import com.tw.go.plugin.util.StringUtil; +import in.ashwanthkumar.gocd.github.jsonapi.PipelineHistory; +import in.ashwanthkumar.gocd.github.jsonapi.PipelineStatus; +import in.ashwanthkumar.gocd.github.jsonapi.Server; +import in.ashwanthkumar.gocd.github.jsonapi.ServerFactory; import in.ashwanthkumar.gocd.github.provider.Provider; +import in.ashwanthkumar.gocd.github.settings.general.GeneralPluginSettings; import in.ashwanthkumar.gocd.github.settings.scm.PluginConfigurationView; +import in.ashwanthkumar.gocd.github.settings.scm.ScmPluginSettings; import in.ashwanthkumar.gocd.github.util.BranchFilter; import in.ashwanthkumar.gocd.github.util.GitFactory; import in.ashwanthkumar.gocd.github.util.GitFolderFactory; import in.ashwanthkumar.gocd.github.util.JSONUtils; +import in.ashwanthkumar.utils.lang.option.Option; import org.apache.commons.io.IOUtils; import java.io.IOException; @@ -31,6 +39,7 @@ @Extension public class GitHubPRBuildPlugin implements GoPlugin { + private static Logger LOGGER = Logger.getLoggerFor(GitHubPRBuildPlugin.class); public static final String EXTENSION_NAME = "scm"; @@ -61,6 +70,7 @@ public class GitHubPRBuildPlugin implements GoPlugin { private GitFactory gitFactory; private GitFolderFactory gitFolderFactory; private GoApplicationAccessor goApplicationAccessor; + private ServerFactory serverFactory; public GitHubPRBuildPlugin() { try { @@ -72,15 +82,17 @@ public GitHubPRBuildPlugin() { provider = (Provider) constructor.newInstance(); gitFactory = new GitFactory(); gitFolderFactory = new GitFolderFactory(); + serverFactory = new ServerFactory(); } catch (Exception e) { throw new RuntimeException("could not create provider", e); } } - public GitHubPRBuildPlugin(Provider provider, GitFactory gitFactory, GitFolderFactory gitFolderFactory, GoApplicationAccessor goApplicationAccessor) { + public GitHubPRBuildPlugin(Provider provider, GitFactory gitFactory, GitFolderFactory gitFolderFactory, ServerFactory serverFactory, GoApplicationAccessor goApplicationAccessor) { this.provider = provider; this.gitFactory = gitFactory; this.gitFolderFactory = gitFolderFactory; + this.serverFactory = serverFactory; this.goApplicationAccessor = goApplicationAccessor; } @@ -138,6 +150,16 @@ void setProvider(Provider provider) { this.provider = provider; } + public Provider getProvider() { + return provider; + } + + GitConfig getGitConfig(ScmPluginSettings scmPluginSettings) { + GitConfig gitConfig = scmPluginSettings.getGitConfig(); + provider.addConfigData(gitConfig); + return gitConfig; + } + private GoPluginApiResponse handlePluginView() throws IOException { return getPluginView(provider, provider.getGeneralConfigurationView()); } @@ -173,7 +195,9 @@ private GoPluginApiResponse getPluginConfiguration(PluginConfigurationView view) private GoPluginApiResponse handleSCMValidation(GoPluginApiRequest goPluginApiRequest) { Map requestBodyMap = (Map) fromJSON(goPluginApiRequest.requestBody()); final Map configuration = keyValuePairs(requestBodyMap, "scm-configuration"); - final GitConfig gitConfig = getGitConfig(configuration); + ScmPluginSettings scmSettings = provider.getScmConfigurationView().getSettings(configuration); + + final GitConfig gitConfig = getGitConfig(scmSettings); List> response = new ArrayList>(); validate(response, new FieldValidator() { @@ -188,7 +212,9 @@ public void validate(Map fieldValidation) { private GoPluginApiResponse handleSCMCheckConnection(GoPluginApiRequest goPluginApiRequest) { Map requestBodyMap = (Map) fromJSON(goPluginApiRequest.requestBody()); Map configuration = keyValuePairs(requestBodyMap, "scm-configuration"); - GitConfig gitConfig = getGitConfig(configuration); + ScmPluginSettings scmSettings = provider.getScmConfigurationView().getSettings(configuration); + + GitConfig gitConfig = getGitConfig(scmSettings); Map response = new HashMap(); List messages = new ArrayList(); @@ -206,7 +232,12 @@ private GoPluginApiResponse handleSCMCheckConnection(GoPluginApiRequest goPlugin GoPluginApiResponse handleGetLatestRevision(GoPluginApiRequest goPluginApiRequest) { Map requestBodyMap = (Map) fromJSON(goPluginApiRequest.requestBody()); Map configuration = keyValuePairs(requestBodyMap, "scm-configuration"); - GitConfig gitConfig = getGitConfig(configuration); + + ScmPluginSettings scmSettings = provider.getScmConfigurationView().getSettings(configuration); + + GitConfig gitConfig = getGitConfig(scmSettings); + + String flyweightFolder = (String) requestBodyMap.get("flyweight-folder"); LOGGER.info(String.format("Flyweight: %s", flyweightFolder)); @@ -233,11 +264,15 @@ GoPluginApiResponse handleGetLatestRevision(GoPluginApiRequest goPluginApiReques GoPluginApiResponse handleLatestRevisionSince(GoPluginApiRequest goPluginApiRequest) { Map requestBodyMap = (Map) fromJSON(goPluginApiRequest.requestBody()); Map configuration = keyValuePairs(requestBodyMap, "scm-configuration"); - GitConfig gitConfig = getGitConfig(configuration); + ScmPluginSettings scmSettings = provider.getScmConfigurationView().getSettings(configuration); + + GitConfig gitConfig = getGitConfig(scmSettings); + Map scmData = (Map) requestBodyMap.get("scm-data"); Map oldBranchToRevisionMap = (Map) fromJSON(scmData.get(BRANCH_TO_REVISION_MAP)); String flyweightFolder = (String) requestBodyMap.get("flyweight-folder"); LOGGER.debug(String.format("Fetching latest for: %s", gitConfig.getUrl())); + Option pipelineName = Option.option(scmSettings.getPipelineName()); try { GitHelper git = gitFactory.create(gitConfig, gitFolderFactory.create(flyweightFolder)); @@ -257,7 +292,9 @@ GoPluginApiResponse handleLatestRevisionSince(GoPluginApiRequest goPluginApiRequ BranchFilter branchFilter = provider .getScmConfigurationView() - .getBranchFilter(configuration); + .getBranchFilter(scmSettings); + + Server server = serverFactory.getServer(getPluginSettings()); for (String branch : newBranchToRevisionMap.keySet()) { if (branchFilter.isBranchValid(branch)) { @@ -266,18 +303,40 @@ GoPluginApiResponse handleLatestRevisionSince(GoPluginApiRequest goPluginApiRequ // Otherwise Go.CD skips other changes (revisions) in this call. // You can think about it like if we always return a minimum item // of a set with comparable items. - String newValue = newBranchToRevisionMap.get(branch); - newerRevisions.put(branch, newValue); - oldBranchToRevisionMap.put(branch, newValue); - break; + + // Only schedule new revision if the pipeline doesn't have + // anything running at the moment. This should further prevent + // skipping revisions when the revisions are built in-order + // This is only checked if the pipeline name option is given + if (canSchedule(server, pipelineName)) { + String newValue = newBranchToRevisionMap.get(branch); + + LOGGER.debug("Schedule pipeline for branch " + branch + "@" + newValue); + + newerRevisions.put(branch, newValue); + oldBranchToRevisionMap.put(branch, newValue); + break; + } else { + // If can't schedule yet, just skip this round + // and return the old branches to revision map + // back so that we can continue where we left + // on the next round of polling for changes + + LOGGER.info("Schedule " + branch + " later"); + + Map response = new HashMap(); + Map scmDataMap = new HashMap(); + scmDataMap.put(BRANCH_TO_REVISION_MAP, JSONUtils.toJSON(oldBranchToRevisionMap)); + response.put("scm-data", scmDataMap); + return renderJSON(SUCCESS_RESPONSE_CODE, response); + } } - } else { - LOGGER.debug(String.format("Branch %s is filtered by branch matcher", branch)); } } if (newerRevisions.isEmpty()) { - LOGGER.debug(String.format("No updated PRs found. Old: %s New: %s", oldBranchToRevisionMap, newBranchToRevisionMap)); + LOGGER.debug("No updated PRs found."); + LOGGER.debug(String.format("Old: %s New: %s", oldBranchToRevisionMap, newBranchToRevisionMap)); Map response = new HashMap(); Map scmDataMap = new HashMap(); @@ -313,14 +372,43 @@ GoPluginApiResponse handleLatestRevisionSince(GoPluginApiRequest goPluginApiRequ } } + boolean canSchedule(Server server, Option pipelineNameOption) throws IOException { + if (pipelineNameOption.isEmpty()) { + LOGGER.debug("Pipeline name not given. Can schedule"); + return true; + } + + final String pipelineName = pipelineNameOption.get(); + + LOGGER.info(String.format("Check can schedule pipeline %s", pipelineName)); + + PipelineStatus pipelineStatus = server.getPipelineStatus(pipelineName); + if (pipelineStatus != null) { + if (pipelineStatus.schedulable) { + PipelineHistory pipelineHistory = server.getPipelineHistory(pipelineName); + return pipelineHistory == null + || !pipelineHistory.isPipelineRunningOrScheduled(); + } else { + return false; + } + } else { + return true; + } + } + private boolean branchHasNewChange(String previousSHA, String latestSHA) { return previousSHA == null || !previousSHA.equals(latestSHA); } private GoPluginApiResponse handleCheckout(GoPluginApiRequest goPluginApiRequest) { Map requestBodyMap = (Map) fromJSON(goPluginApiRequest.requestBody()); + Map configuration = keyValuePairs(requestBodyMap, "scm-configuration"); - GitConfig gitConfig = getGitConfig(configuration); + ScmPluginSettings scmSettings = provider.getScmConfigurationView().getSettings(configuration); + + GitConfig gitConfig = getGitConfig(scmSettings); + provider.addConfigData(gitConfig); + String destinationFolder = (String) requestBodyMap.get("destination-folder"); Map revisionMap = (Map) requestBodyMap.get("revision"); String revision = (String) revisionMap.get("revision"); @@ -342,12 +430,6 @@ private GoPluginApiResponse handleCheckout(GoPluginApiRequest goPluginApiRequest } } - GitConfig getGitConfig(Map configuration) { - GitConfig gitConfig = new GitConfig(configuration.get("url"), configuration.get("username"), configuration.get("password"), null); - provider.addConfigData(gitConfig); - return gitConfig; - } - private void validate(List> response, FieldValidator fieldValidator) { Map fieldValidation = new HashMap(); fieldValidator.validate(fieldValidation); @@ -440,4 +522,18 @@ public String responseBody() { }; } + public GeneralPluginSettings getPluginSettings() { + if (provider.getGeneralConfigurationView().hasConfigurationView()) { + DefaultGoApiRequest request = + new DefaultGoApiRequest(GET_PLUGIN_SETTINGS, "1.0", provider.getPluginId()); + request.setRequestBody("{\"plugin-id\": \"" + provider.getPluginId().getExtension() + "\"}"); + String response = goApplicationAccessor.submit(request).responseBody(); + Map settings = JSONUtils.fromJSON(response, Map.class); + return provider.getGeneralConfigurationView().getSettings(settings); + } else { + return provider + .getGeneralConfigurationView() + .getSettings(Collections.emptyMap()); + } + } } diff --git a/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/HttpConnectionUtil.java b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/HttpConnectionUtil.java new file mode 100644 index 0000000..8297552 --- /dev/null +++ b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/HttpConnectionUtil.java @@ -0,0 +1,33 @@ +package in.ashwanthkumar.gocd.github.jsonapi; + +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +public class HttpConnectionUtil { + + public HttpURLConnection getConnection(URL url) throws IOException { + return (HttpURLConnection) url.openConnection(); + } + + JsonElement responseToJson(Object content) { + JsonParser parser = new JsonParser(); + return parser.parse(new InputStreamReader((InputStream) content)); + } + + T convertResponse(JsonElement json, Class type) { + return new GsonBuilder().create().fromJson(json, type); + } + + public T responseToType(Object content, Class type) { + JsonElement element = responseToJson(content); + return convertResponse(element, type); + } + +} diff --git a/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/Job.java b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/Job.java new file mode 100644 index 0000000..a43ad27 --- /dev/null +++ b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/Job.java @@ -0,0 +1,34 @@ +package in.ashwanthkumar.gocd.github.jsonapi; + +import com.google.gson.annotations.SerializedName; + +public class Job { + + @SerializedName("state") + private String state; + + public Job() { + } + + public Job(String state) { + this.state = state; + } + + public String getState() { + return state; + } + + public boolean isRunningOrScheduled() { + return "assigned".equalsIgnoreCase(state) + || "scheduled".equalsIgnoreCase(state) + || "building".equalsIgnoreCase(state); + + } + + @Override + public String toString() { + return "Job{" + + "state='" + state + '\'' + + '}'; + } +} diff --git a/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/Pipeline.java b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/Pipeline.java new file mode 100644 index 0000000..63c95fe --- /dev/null +++ b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/Pipeline.java @@ -0,0 +1,55 @@ +package in.ashwanthkumar.gocd.github.jsonapi; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class Pipeline { + + @SerializedName("stages") + private List stages; + + @SerializedName("preparing_to_schedule") + private boolean preparingToSchedule; + + @SerializedName("can_run") + private boolean canRun; + + public Pipeline() { + } + + public Pipeline(boolean preparingToSchedule, boolean canRun, List stages) { + this.stages = stages; + this.preparingToSchedule = preparingToSchedule; + this.canRun = canRun; + } + + public boolean isPreparingToSchedule() { + return preparingToSchedule; + } + + public List getStages() { + return stages; + } + + public boolean isCanRun() { + return canRun; + } + + public boolean isRunningOrScheduled() { + if (preparingToSchedule) { + return true; + } + + if (!canRun) { + return true; + } + + for (Stage stage : stages) { + if (stage.isRunningOrScheduled()) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/PipelineHistory.java b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/PipelineHistory.java new file mode 100644 index 0000000..763bb63 --- /dev/null +++ b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/PipelineHistory.java @@ -0,0 +1,31 @@ +package in.ashwanthkumar.gocd.github.jsonapi; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class PipelineHistory { + + @SerializedName("pipelines") + private List pipelines; + + public PipelineHistory() { + } + + public PipelineHistory(List pipelines) { + this.pipelines = pipelines; + } + + public List getPipelines() { + return pipelines; + } + + public boolean isPipelineRunningOrScheduled() { + for (Pipeline pipeline : pipelines) { + if (pipeline.isRunningOrScheduled()) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/PipelineStatus.java b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/PipelineStatus.java new file mode 100644 index 0000000..a153826 --- /dev/null +++ b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/PipelineStatus.java @@ -0,0 +1,16 @@ +package in.ashwanthkumar.gocd.github.jsonapi; + +import com.google.gson.annotations.SerializedName; + +public class PipelineStatus { + + @SerializedName("schedulable") + public boolean schedulable; + + public PipelineStatus() { + } + + public PipelineStatus(boolean schedulable) { + this.schedulable = schedulable; + } +} diff --git a/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/Server.java b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/Server.java new file mode 100644 index 0000000..c7e91dd --- /dev/null +++ b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/Server.java @@ -0,0 +1,86 @@ +package in.ashwanthkumar.gocd.github.jsonapi; + +import com.thoughtworks.go.plugin.api.logging.Logger; +import in.ashwanthkumar.gocd.github.settings.general.GeneralPluginSettings; +import in.ashwanthkumar.gocd.github.settings.general.GoApiSettings; + +import javax.xml.bind.DatatypeConverter; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; + +import static in.ashwanthkumar.utils.lang.StringUtils.isEmpty; + +public class Server { + private Logger LOG = Logger.getLoggerFor(Server.class); + + private GeneralPluginSettings settings; + private HttpConnectionUtil httpConnectionUtil; + + /** + * Construct a new server object, using credentials from PluginSettings. + */ + public Server(GeneralPluginSettings settings) { + this.settings = settings; + httpConnectionUtil = new HttpConnectionUtil(); + } + + Server(GeneralPluginSettings settings, HttpConnectionUtil httpConnectionUtil) { + this.settings = settings; + this.httpConnectionUtil = httpConnectionUtil; + } + + public T getResourceAs(URL url, Class type) + throws IOException { + URL normalizedUrl; + try { + normalizedUrl = url.toURI().normalize().toURL(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + LOG.info("Fetching " + normalizedUrl.toString()); + + HttpURLConnection request = httpConnectionUtil.getConnection(normalizedUrl); + + GoApiSettings goApiSettings = (GoApiSettings) settings; + final String login = goApiSettings.getGoApiUsername(); + final String password = goApiSettings.getGoApiPassword(); + // Add in our HTTP authorization credentials if we have them. + if (!isEmpty(login) && !isEmpty(password)) { + String userpass = login + ":" + password; + String basicAuth = "Basic " + + DatatypeConverter.printBase64Binary(userpass.getBytes()); + request.setRequestProperty("Authorization", basicAuth); + } + + request.connect(); + + return httpConnectionUtil.responseToType(request.getContent(), type); + } + + public PipelineStatus getPipelineStatus(String pipelineName) + throws MalformedURLException, IOException { + GoApiSettings goApiSettings = (GoApiSettings) settings; + + final String apiHost = goApiSettings.getGoApiHost(); + URL url = new URL(String.format("%s/go/api/pipelines/%s/status", + apiHost, pipelineName)); + + LOG.info(String.format("Fetch pipeline %s status from %s", pipelineName, url)); + return getResourceAs(url, PipelineStatus.class); + } + + public PipelineHistory getPipelineHistory(String pipelineName) + throws MalformedURLException, IOException { + GoApiSettings goApiSettings = (GoApiSettings) settings; + + final String apiHost = goApiSettings.getGoApiHost(); + URL url = new URL(String.format("%s/go/api/pipelines/%s/history", + apiHost, pipelineName)); + + LOG.info(String.format("Fetch pipeline %s history from %s", pipelineName, url)); + return getResourceAs(url, PipelineHistory.class); + } +} diff --git a/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/ServerFactory.java b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/ServerFactory.java new file mode 100644 index 0000000..2dedd84 --- /dev/null +++ b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/ServerFactory.java @@ -0,0 +1,10 @@ +package in.ashwanthkumar.gocd.github.jsonapi; + +import in.ashwanthkumar.gocd.github.settings.general.GeneralPluginSettings; + +public class ServerFactory { + + public Server getServer(GeneralPluginSettings settings) { + return new Server(settings); + } +} diff --git a/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/Stage.java b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/Stage.java new file mode 100644 index 0000000..3e8983d --- /dev/null +++ b/src/main/java/in/ashwanthkumar/gocd/github/jsonapi/Stage.java @@ -0,0 +1,37 @@ +package in.ashwanthkumar.gocd.github.jsonapi; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class Stage { + + + @SerializedName("can_run") + private boolean canRun; + + @SerializedName("jobs") + private List jobs; + + public Stage() { + } + + public Stage(boolean canRun, List jobs) { + this.canRun = canRun; + this.jobs = jobs; + } + + + public boolean isRunningOrScheduled() { + if (!canRun) { + return true; + } + + for (Job job : jobs) { + if (job.isRunningOrScheduled()) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/in/ashwanthkumar/gocd/github/provider/gerrit/GerritPluginConfigurationView.java b/src/main/java/in/ashwanthkumar/gocd/github/provider/gerrit/GerritPluginConfigurationView.java new file mode 100644 index 0000000..07f62c9 --- /dev/null +++ b/src/main/java/in/ashwanthkumar/gocd/github/provider/gerrit/GerritPluginConfigurationView.java @@ -0,0 +1,42 @@ +package in.ashwanthkumar.gocd.github.provider.gerrit; + +import in.ashwanthkumar.gocd.github.settings.general.GeneralPluginConfigurationView; +import in.ashwanthkumar.gocd.github.settings.general.GeneralPluginSettings; +import in.ashwanthkumar.gocd.github.util.FieldFactory; + +import java.util.HashMap; +import java.util.Map; + +public class GerritPluginConfigurationView implements GeneralPluginConfigurationView { + + + @Override + public String templateName() { + return "/views/gerrit.plugin.template.html"; + } + + @Override + public Map fields() { + Map response = new HashMap(); + response.put("go_api_host", FieldFactory.createForGeneral("Go API Host", null, false, false, "0")); + response.put("go_api_username", FieldFactory.createForGeneral("Go Username", null, false, false, "1")); + response.put("go_api_password", FieldFactory.createForGeneral("Go Password", null, false, true, "2")); + return response; + } + + @Override + public boolean hasConfigurationView() { + return true; + } + + @Override + public GeneralPluginSettings getSettings(Map rawSettings) { + GerritPluginSettings settings = new GerritPluginSettings( + (String)rawSettings.get("go_api_host"), + (String)rawSettings.get("go_api_username"), + (String)rawSettings.get("go_api_password") + ); + + return settings; + } +} diff --git a/src/main/java/in/ashwanthkumar/gocd/github/provider/gerrit/GerritPluginSettings.java b/src/main/java/in/ashwanthkumar/gocd/github/provider/gerrit/GerritPluginSettings.java new file mode 100644 index 0000000..fc4070e --- /dev/null +++ b/src/main/java/in/ashwanthkumar/gocd/github/provider/gerrit/GerritPluginSettings.java @@ -0,0 +1,32 @@ +package in.ashwanthkumar.gocd.github.provider.gerrit; + +import in.ashwanthkumar.gocd.github.settings.general.GeneralPluginSettings; +import in.ashwanthkumar.gocd.github.settings.general.GoApiSettings; + +public class GerritPluginSettings implements GoApiSettings, GeneralPluginSettings { + + private String goApiHost; + private String goApiUsername; + private String goApiPassword; + + public GerritPluginSettings(String goApiHost, String goApiUsername, String goApiPassword) { + this.goApiHost = goApiHost; + this.goApiUsername = goApiUsername; + this.goApiPassword = goApiPassword; + } + + @Override + public String getGoApiHost() { + return goApiHost; + } + + @Override + public String getGoApiUsername() { + return goApiUsername; + } + + @Override + public String getGoApiPassword() { + return goApiPassword; + } +} diff --git a/src/main/java/in/ashwanthkumar/gocd/github/provider/gerrit/GerritProvider.java b/src/main/java/in/ashwanthkumar/gocd/github/provider/gerrit/GerritProvider.java index 0040cbb..f97e8bf 100644 --- a/src/main/java/in/ashwanthkumar/gocd/github/provider/gerrit/GerritProvider.java +++ b/src/main/java/in/ashwanthkumar/gocd/github/provider/gerrit/GerritProvider.java @@ -4,7 +4,6 @@ import com.tw.go.plugin.HelperFactory; import com.tw.go.plugin.model.GitConfig; import in.ashwanthkumar.gocd.github.provider.Provider; -import in.ashwanthkumar.gocd.github.settings.general.DefaultGeneralPluginConfigurationView; import in.ashwanthkumar.gocd.github.settings.general.GeneralPluginConfigurationView; import in.ashwanthkumar.gocd.github.settings.scm.DefaultScmPluginConfigurationView; import in.ashwanthkumar.gocd.github.settings.scm.ScmPluginConfigurationView; @@ -63,6 +62,6 @@ public ScmPluginConfigurationView getScmConfigurationView() { @Override public GeneralPluginConfigurationView getGeneralConfigurationView() { - return new DefaultGeneralPluginConfigurationView(); + return new GerritPluginConfigurationView(); } } diff --git a/src/main/java/in/ashwanthkumar/gocd/github/provider/git/GitScmPluginConfigurationView.java b/src/main/java/in/ashwanthkumar/gocd/github/provider/git/GitScmPluginConfigurationView.java index 7c1d3e9..b2d1080 100644 --- a/src/main/java/in/ashwanthkumar/gocd/github/provider/git/GitScmPluginConfigurationView.java +++ b/src/main/java/in/ashwanthkumar/gocd/github/provider/git/GitScmPluginConfigurationView.java @@ -1,6 +1,7 @@ package in.ashwanthkumar.gocd.github.provider.git; import in.ashwanthkumar.gocd.github.settings.scm.DefaultScmPluginConfigurationView; +import in.ashwanthkumar.gocd.github.settings.scm.ScmPluginSettings; import in.ashwanthkumar.gocd.github.util.BranchFilter; import in.ashwanthkumar.gocd.github.util.FieldFactory; @@ -27,11 +28,27 @@ public Map fields() { } @Override - public BranchFilter getBranchFilter(Map configuration) { - String blacklist = configuration.get(BRANCH_BLACKLIST_PROPERTY_NAME); - String whitelist = configuration.get(BRANCH_WHITELIST_PROPERTY_NAME); + public BranchFilter getBranchFilter(ScmPluginSettings scmSettings) { + GitScmPluginSettings gitScmSettings = (GitScmPluginSettings) scmSettings; - return new BranchFilter(blacklist, whitelist); + return new BranchFilter( + gitScmSettings.getBranchBlacklist(), + gitScmSettings.getBranchWhitelist() + ); } + @Override + public ScmPluginSettings getSettings(Map rawSettings) { + ScmPluginSettings settings = new GitScmPluginSettings( + rawSettings.get("url"), + rawSettings.get("username"), + rawSettings.get("password"), + null, + rawSettings.get("pipeline_name"), + rawSettings.get(BRANCH_BLACKLIST_PROPERTY_NAME), + rawSettings.get(BRANCH_WHITELIST_PROPERTY_NAME) + ); + + return settings; + } } diff --git a/src/main/java/in/ashwanthkumar/gocd/github/provider/git/GitScmPluginSettings.java b/src/main/java/in/ashwanthkumar/gocd/github/provider/git/GitScmPluginSettings.java new file mode 100644 index 0000000..41073d4 --- /dev/null +++ b/src/main/java/in/ashwanthkumar/gocd/github/provider/git/GitScmPluginSettings.java @@ -0,0 +1,23 @@ +package in.ashwanthkumar.gocd.github.provider.git; + +import in.ashwanthkumar.gocd.github.settings.scm.DefaultScmPluginSettings; + +public class GitScmPluginSettings extends DefaultScmPluginSettings { + + private String branchBlacklist; + private String branchWhitelist; + + public GitScmPluginSettings(String url, String username, String password, String branch, String pipelineName, String branchBlacklist, String branchWhitelist) { + super(url, username, password, branch, pipelineName); + this.branchBlacklist = branchBlacklist; + this.branchWhitelist = branchWhitelist; + } + + public String getBranchBlacklist() { + return branchBlacklist; + } + + public String getBranchWhitelist() { + return branchWhitelist; + } +} diff --git a/src/main/java/in/ashwanthkumar/gocd/github/settings/general/DefaultGeneralPluginConfigurationView.java b/src/main/java/in/ashwanthkumar/gocd/github/settings/general/DefaultGeneralPluginConfigurationView.java index 3f12c25..f9c4916 100644 --- a/src/main/java/in/ashwanthkumar/gocd/github/settings/general/DefaultGeneralPluginConfigurationView.java +++ b/src/main/java/in/ashwanthkumar/gocd/github/settings/general/DefaultGeneralPluginConfigurationView.java @@ -21,4 +21,8 @@ public Map fields() { public boolean hasConfigurationView() { return false; } + + public GeneralPluginSettings getSettings(Map rawSettings) { + return new DefaultGeneralPluginSettings(); + } } diff --git a/src/main/java/in/ashwanthkumar/gocd/github/settings/general/DefaultGeneralPluginSettings.java b/src/main/java/in/ashwanthkumar/gocd/github/settings/general/DefaultGeneralPluginSettings.java index 8a194aa..0e2c590 100644 --- a/src/main/java/in/ashwanthkumar/gocd/github/settings/general/DefaultGeneralPluginSettings.java +++ b/src/main/java/in/ashwanthkumar/gocd/github/settings/general/DefaultGeneralPluginSettings.java @@ -1,6 +1,5 @@ package in.ashwanthkumar.gocd.github.settings.general; -import in.ashwanthkumar.gocd.github.settings.scm.ScmPluginSettings; +public class DefaultGeneralPluginSettings implements GeneralPluginSettings { -public class DefaultGeneralPluginSettings implements ScmPluginSettings { } diff --git a/src/main/java/in/ashwanthkumar/gocd/github/settings/general/GeneralPluginConfigurationView.java b/src/main/java/in/ashwanthkumar/gocd/github/settings/general/GeneralPluginConfigurationView.java index 3b5aab6..46f167f 100644 --- a/src/main/java/in/ashwanthkumar/gocd/github/settings/general/GeneralPluginConfigurationView.java +++ b/src/main/java/in/ashwanthkumar/gocd/github/settings/general/GeneralPluginConfigurationView.java @@ -2,5 +2,10 @@ import in.ashwanthkumar.gocd.github.settings.scm.PluginConfigurationView; +import java.util.Map; + public interface GeneralPluginConfigurationView extends PluginConfigurationView { + + GeneralPluginSettings getSettings(Map rawSettings); + } diff --git a/src/main/java/in/ashwanthkumar/gocd/github/settings/general/GoApiSettings.java b/src/main/java/in/ashwanthkumar/gocd/github/settings/general/GoApiSettings.java new file mode 100644 index 0000000..428884b --- /dev/null +++ b/src/main/java/in/ashwanthkumar/gocd/github/settings/general/GoApiSettings.java @@ -0,0 +1,8 @@ +package in.ashwanthkumar.gocd.github.settings.general; + +public interface GoApiSettings { + + String getGoApiHost(); + String getGoApiUsername(); + String getGoApiPassword(); +} diff --git a/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/DefaultScmPluginConfigurationView.java b/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/DefaultScmPluginConfigurationView.java index b4f4f8b..080703f 100644 --- a/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/DefaultScmPluginConfigurationView.java +++ b/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/DefaultScmPluginConfigurationView.java @@ -20,11 +20,12 @@ public Map fields() { response.put("url", FieldFactory.createForScm("URL", null, true, true, false, "0")); response.put("username", FieldFactory.createForScm("Username", null, false, false, false, "1")); response.put("password", FieldFactory.createForScm("Password", null, false, false, true, "2")); + response.put("pipeline_name", FieldFactory.createForScm("Pipeline name", null, false, false, false, "3")); return response; } @Override - public BranchFilter getBranchFilter(Map configuration) { + public BranchFilter getBranchFilter(ScmPluginSettings scmSettings) { return new BranchFilter(); } @@ -32,4 +33,17 @@ public BranchFilter getBranchFilter(Map configuration) { public boolean hasConfigurationView() { return true; } + + public ScmPluginSettings getSettings(Map rawSettings) { + ScmPluginSettings settings = new DefaultScmPluginSettings( + rawSettings.get("url"), + rawSettings.get("username"), + rawSettings.get("password"), + null, + rawSettings.get("pipeline_name") + ); + + return settings; + } + } diff --git a/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/DefaultScmPluginSettings.java b/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/DefaultScmPluginSettings.java index 55ef2c6..f1d725b 100644 --- a/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/DefaultScmPluginSettings.java +++ b/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/DefaultScmPluginSettings.java @@ -1,4 +1,24 @@ package in.ashwanthkumar.gocd.github.settings.scm; +import com.tw.go.plugin.model.GitConfig; + public class DefaultScmPluginSettings implements ScmPluginSettings { + + private GitConfig gitConfig; + private String pipelineName; + + public DefaultScmPluginSettings(String url, String username, String password, String branch, String pipelineName) { + this.gitConfig = new GitConfig(url, username, password, branch); + this.pipelineName = pipelineName; + } + + @Override + public GitConfig getGitConfig() { + return gitConfig; + } + + @Override + public String getPipelineName() { + return pipelineName; + } } diff --git a/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/ScmPluginConfigurationView.java b/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/ScmPluginConfigurationView.java index eb48b88..9bff842 100644 --- a/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/ScmPluginConfigurationView.java +++ b/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/ScmPluginConfigurationView.java @@ -6,5 +6,7 @@ public interface ScmPluginConfigurationView extends PluginConfigurationView { - BranchFilter getBranchFilter(Map configuration); + BranchFilter getBranchFilter(ScmPluginSettings scmSettings); + + ScmPluginSettings getSettings(Map rawSettings); } diff --git a/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/ScmPluginSettings.java b/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/ScmPluginSettings.java index b3e6e1b..801bc62 100644 --- a/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/ScmPluginSettings.java +++ b/src/main/java/in/ashwanthkumar/gocd/github/settings/scm/ScmPluginSettings.java @@ -1,4 +1,11 @@ package in.ashwanthkumar.gocd.github.settings.scm; +import com.tw.go.plugin.model.GitConfig; + public interface ScmPluginSettings { + + GitConfig getGitConfig(); + + String getPipelineName(); + } diff --git a/src/main/java/in/ashwanthkumar/gocd/github/util/PluginSettings.java b/src/main/java/in/ashwanthkumar/gocd/github/util/PluginSettings.java deleted file mode 100644 index a3318a2..0000000 --- a/src/main/java/in/ashwanthkumar/gocd/github/util/PluginSettings.java +++ /dev/null @@ -1,8 +0,0 @@ -package in.ashwanthkumar.gocd.github.util; - -public class PluginSettings { - - public PluginSettings() { - } - -} diff --git a/src/main/resources/views/gerrit.plugin.template.html b/src/main/resources/views/gerrit.plugin.template.html new file mode 100644 index 0000000..0f27c9e --- /dev/null +++ b/src/main/resources/views/gerrit.plugin.template.html @@ -0,0 +1,15 @@ +
+ + + {{ GOINPUTNAME[go_api_host].$error.server }} +
+
+ + + {{ GOINPUTNAME[go_api_username].$error.server }} +
+
+ + + {{ GOINPUTNAME[go_api_password].$error.server }} +
diff --git a/src/main/resources/views/scm.template.branch.filter.html b/src/main/resources/views/scm.template.branch.filter.html index e1bc3da..96ccaf4 100644 --- a/src/main/resources/views/scm.template.branch.filter.html +++ b/src/main/resources/views/scm.template.branch.filter.html @@ -13,6 +13,11 @@ {{ GOINPUTNAME[password].$error.server }} +
+ + + {{ GOINPUTNAME[pipeline_name].$error.server }} +
diff --git a/src/main/resources/views/scm.template.html b/src/main/resources/views/scm.template.html index 14bab45..6b937a7 100644 --- a/src/main/resources/views/scm.template.html +++ b/src/main/resources/views/scm.template.html @@ -12,4 +12,9 @@ {{ GOINPUTNAME[password].$error.server }} +
+
+ + + {{ GOINPUTNAME[pipeline_name].$error.server }}
\ No newline at end of file diff --git a/src/test/java/in/ashwanthkumar/gocd/github/GitHubPRBuildPluginTest.java b/src/test/java/in/ashwanthkumar/gocd/github/GitHubPRBuildPluginTest.java index 48377f8..f009bc7 100644 --- a/src/test/java/in/ashwanthkumar/gocd/github/GitHubPRBuildPluginTest.java +++ b/src/test/java/in/ashwanthkumar/gocd/github/GitHubPRBuildPluginTest.java @@ -10,13 +10,19 @@ import com.tw.go.plugin.model.GitConfig; import com.tw.go.plugin.model.ModifiedFile; import com.tw.go.plugin.model.Revision; +import in.ashwanthkumar.gocd.github.jsonapi.PipelineHistory; +import in.ashwanthkumar.gocd.github.jsonapi.PipelineStatus; +import in.ashwanthkumar.gocd.github.jsonapi.Server; +import in.ashwanthkumar.gocd.github.jsonapi.ServerFactory; import in.ashwanthkumar.gocd.github.provider.gerrit.GerritProvider; import in.ashwanthkumar.gocd.github.provider.git.GitProvider; import in.ashwanthkumar.gocd.github.provider.github.GHUtils; import in.ashwanthkumar.gocd.github.provider.github.GitHubProvider; +import in.ashwanthkumar.gocd.github.settings.general.GeneralPluginSettings; import in.ashwanthkumar.gocd.github.util.GitFactory; import in.ashwanthkumar.gocd.github.util.GitFolderFactory; import in.ashwanthkumar.gocd.github.util.JSONUtils; +import in.ashwanthkumar.utils.lang.option.Option; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; @@ -76,7 +82,7 @@ public void shouldBuildGitConfig() { GitHubPRBuildPlugin plugin = new GitHubPRBuildPlugin(); plugin.setProvider(new GitHubProvider()); - GitConfig gitConfig = plugin.getGitConfig(configuration); + GitConfig gitConfig = plugin.getGitConfig(plugin.getProvider().getScmConfigurationView().getSettings(configuration)); assertThat(gitConfig.getUrl(), is("url")); assertThat(gitConfig.getUsername(), is("config-username")); @@ -85,7 +91,7 @@ public void shouldBuildGitConfig() { configuration.remove("username"); configuration.remove("password"); - gitConfig = plugin.getGitConfig(configuration); + gitConfig = plugin.getGitConfig(plugin.getProvider().getScmConfigurationView().getSettings(configuration)); assertThat(gitConfig.getUrl(), is("url")); assertThat(gitConfig.getUsername(), is(usernameProperty)); @@ -180,13 +186,14 @@ public void shouldParseJSONMapCorrectly() { } @Test - public void shouldBuildWhitelistedBranch() { + public void shouldBuildWhitelistedBranch() throws Exception { GitFactory gitFactory = mock(GitFactory.class); GitFolderFactory gitFolderFactory = mock(GitFolderFactory.class); GitHubPRBuildPlugin plugin = new GitHubPRBuildPlugin( new GitProvider(), gitFactory, gitFolderFactory, + mockServerFactory(), mockGoApplicationAccessor() ); GitHubPRBuildPlugin pluginSpy = spy(plugin); @@ -202,13 +209,14 @@ public void shouldBuildWhitelistedBranch() { } @Test - public void shouldNotBuildBlacklistedBranch() { + public void shouldNotBuildBlacklistedBranch() throws Exception { GitFactory gitFactory = mock(GitFactory.class); GitFolderFactory gitFolderFactory = mock(GitFolderFactory.class); GitHubPRBuildPlugin plugin = new GitHubPRBuildPlugin( new GitProvider(), gitFactory, gitFolderFactory, + mockServerFactory(), mockGoApplicationAccessor() ); GitHubPRBuildPlugin pluginSpy = spy(plugin); @@ -224,13 +232,14 @@ public void shouldNotBuildBlacklistedBranch() { } @Test - public void shouldBuildBlacklistedBranchIfBlacklistingNotEnabled() { + public void shouldBuildBlacklistedBranchIfBlacklistingNotEnabled() throws Exception { GitFactory gitFactory = mock(GitFactory.class); GitFolderFactory gitFolderFactory = mock(GitFolderFactory.class); GitHubPRBuildPlugin plugin = new GitHubPRBuildPlugin( new GerritProvider(), gitFactory, gitFolderFactory, + mockServerFactory(), mockGoApplicationAccessor() ); GitHubPRBuildPlugin pluginSpy = spy(plugin); @@ -245,6 +254,107 @@ public void shouldBuildBlacklistedBranchIfBlacklistingNotEnabled() { assertThat(response.responseCode(), is(200)); } + @Test + public void shouldSchedule() throws Exception { + GitFactory gitFactory = mock(GitFactory.class); + GitFolderFactory gitFolderFactory = mock(GitFolderFactory.class); + GitHubPRBuildPlugin plugin = new GitHubPRBuildPlugin( + new GerritProvider(), + gitFactory, + gitFolderFactory, + mockServerFactory(), + mockGoApplicationAccessor() + ); + + Server server = mock(Server.class); + when(server.getPipelineStatus("pipeline")).thenReturn(new PipelineStatus(true)); + PipelineHistory pipelineHistory = mockPipelineHistory(false); + when(server.getPipelineHistory("pipeline")).thenReturn(pipelineHistory); + + assertThat(plugin.canSchedule(server, Option.option("pipeline")), is(true)); + } + + @Test + public void shouldNotScheduleIfPipelineNotSchedulable() throws Exception { + GitFactory gitFactory = mock(GitFactory.class); + GitFolderFactory gitFolderFactory = mock(GitFolderFactory.class); + GitHubPRBuildPlugin plugin = new GitHubPRBuildPlugin( + new GerritProvider(), + gitFactory, + gitFolderFactory, + mockServerFactory(), + mockGoApplicationAccessor() + ); + + Server server = mock(Server.class); + when(server.getPipelineStatus("pipeline")).thenReturn(new PipelineStatus(false)); + PipelineHistory pipelineHistory = mockPipelineHistory(false); + when(server.getPipelineHistory("pipeline")).thenReturn(pipelineHistory); + + assertThat(plugin.canSchedule(server, Option.option("pipeline")), is(false)); + } + + @Test + public void shouldNotScheduleIfPipelineHistoryContainsRunningJobs() throws Exception { + GitFactory gitFactory = mock(GitFactory.class); + GitFolderFactory gitFolderFactory = mock(GitFolderFactory.class); + GitHubPRBuildPlugin plugin = new GitHubPRBuildPlugin( + new GerritProvider(), + gitFactory, + gitFolderFactory, + mockServerFactory(), + mockGoApplicationAccessor() + ); + + Server server = mock(Server.class); + when(server.getPipelineStatus("pipeline")).thenReturn(new PipelineStatus(true)); + PipelineHistory pipelineHistory = mockPipelineHistory(true); + when(server.getPipelineHistory("pipeline")).thenReturn(pipelineHistory); + + assertThat(plugin.canSchedule(server, Option.option("pipeline")), is(false)); + } + + @Test + public void shouldScheduleIfNoPipelineStatusFound() throws Exception { + GitFactory gitFactory = mock(GitFactory.class); + GitFolderFactory gitFolderFactory = mock(GitFolderFactory.class); + GitHubPRBuildPlugin plugin = new GitHubPRBuildPlugin( + new GerritProvider(), + gitFactory, + gitFolderFactory, + mockServerFactory(), + mockGoApplicationAccessor() + ); + + Server server = mock(Server.class); + + assertThat(plugin.canSchedule(server, Option.option("pipeline")), is(true)); + } + + @Test + public void shouldScheduleIfNoPipelineHistoryFound() throws Exception { + GitFactory gitFactory = mock(GitFactory.class); + GitFolderFactory gitFolderFactory = mock(GitFolderFactory.class); + GitHubPRBuildPlugin plugin = new GitHubPRBuildPlugin( + new GerritProvider(), + gitFactory, + gitFolderFactory, + mockServerFactory(), + mockGoApplicationAccessor() + ); + + Server server = mock(Server.class); + when(server.getPipelineStatus("pipeline")).thenReturn(new PipelineStatus(true)); + + assertThat(plugin.canSchedule(server, Option.option("pipeline")), is(true)); + } + + private PipelineHistory mockPipelineHistory(boolean isRunning) { + PipelineHistory pipelineHistory = mock(PipelineHistory.class); + when(pipelineHistory.isPipelineRunningOrScheduled()).thenReturn(isRunning); + return pipelineHistory; + } + private GoPluginApiRequest mockRequest() { GoPluginApiRequest request = mock(GoPluginApiRequest.class); when(request.requestBody()).thenReturn("{\n" + @@ -325,6 +435,25 @@ private void verifyResponse(String responseBody, List pairs) { } } + private ServerFactory mockServerFactory() throws Exception { + ServerFactory serverFactory = mock(ServerFactory.class); + Server server = mock(Server.class); + PipelineStatus status = new PipelineStatus(); + status.schedulable = true; + when(server.getPipelineStatus(anyString())).thenReturn(status); + + when(serverFactory.getServer(any(GeneralPluginSettings.class))).thenReturn(server); + return serverFactory; + } + + private GoApplicationAccessor mockApplicationAccessor() { + GoApplicationAccessor accessor = mock(GoApplicationAccessor.class); + DefaultGoApiResponse respose = new DefaultGoApiResponse(200); + respose.setResponseBody("{}"); + when(accessor.submit(any(GoApiRequest.class))).thenReturn(respose); + return accessor; + } + private GoPluginApiRequest createGoPluginApiRequest(final String requestName, final Map request) { return new GoPluginApiRequest() { @Override diff --git a/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/CanRun.java b/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/CanRun.java new file mode 100644 index 0000000..f108a15 --- /dev/null +++ b/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/CanRun.java @@ -0,0 +1,5 @@ +package in.ashwanthkumar.gocd.github.jsonapi; + +enum CanRun { + YES, NO +} diff --git a/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/JobTest.java b/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/JobTest.java new file mode 100644 index 0000000..566ebc7 --- /dev/null +++ b/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/JobTest.java @@ -0,0 +1,39 @@ +package in.ashwanthkumar.gocd.github.jsonapi; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.Collection; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +@RunWith(Parameterized.class) +public class JobTest { + + @Parameterized.Parameters(name = "Job state {0}. Job running or scheduled expected {1}") + public static Collection data() { + return Arrays.asList(new Object[][] { + {"assigned", true}, + {"building", true}, + {"scheduled", true}, + {"completed", false}, + }); + } + + private final String state; + private final boolean result; + + public JobTest(String state, boolean result) { + this.state = state; + this.result = result; + } + + @Test + public void shouldReturnCorrectBuildingStatus() { + assertThat(new Job(state).isRunningOrScheduled(), is(result)); + } + +} \ No newline at end of file diff --git a/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/PipelineHistoryTest.java b/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/PipelineHistoryTest.java new file mode 100644 index 0000000..5e96695 --- /dev/null +++ b/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/PipelineHistoryTest.java @@ -0,0 +1,120 @@ +package in.ashwanthkumar.gocd.github.jsonapi; + +import org.junit.Test; + +import java.util.List; + +import static java.util.Arrays.asList; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +public class PipelineHistoryTest { + + @Test + public void shouldShowPipelineRunnableWhenJobsCompleted() { + + final boolean canRunPipeline = true; + final boolean preparingToSchedule = false; + final boolean canRunStage = true; + final String jobStage = "Completed"; + + List pipelines = asList( + new Pipeline( + preparingToSchedule, + canRunPipeline, + asList( + new Stage( + canRunStage, + asList(new Job(jobStage)) + ) + ) + ) + ); + + PipelineHistory history = new PipelineHistory(pipelines); + + assertThat(history.isPipelineRunningOrScheduled(), is(false)); + } + + @Test + public void shouldShowPipelineNotRunnableWhenJobsAssigned() { + + final boolean canRunPipeline = true; + final boolean preparingToSchedule = false; + final boolean canRunStage = true; + final String jobStage = "Assigned"; + + List pipelines = asList( + new Pipeline( + preparingToSchedule, + canRunPipeline, + asList( + new Stage( + canRunStage, + asList(new Job(jobStage)) + ) + ) + ) + ); + + PipelineHistory history = new PipelineHistory(pipelines); + + assertThat(history.isPipelineRunningOrScheduled(), is(true)); + } + + @Test + public void shouldShowPipelineNotRunnableWhenJobsBuilding() { + + final boolean canRunPipeline = true; + final boolean preparingToSchedule = false; + final boolean canRunStage = true; + final String jobStage = "Building"; + + List pipelines = asList( + new Pipeline( + preparingToSchedule, + canRunPipeline, + asList( + new Stage( + canRunStage, + asList(new Job(jobStage)) + ) + ) + ) + ); + + PipelineHistory history = new PipelineHistory(pipelines); + + assertThat(history.isPipelineRunningOrScheduled(), is(true)); + } + + @Test + public void shouldShowPipelineNotRunnableWhenOneOfMultipleJobsBuilding() { + + final boolean canRunPipeline = true; + final boolean preparingToSchedule = false; + final boolean canRunStage = true; + + List pipelines = asList( + new Pipeline( + preparingToSchedule, + canRunPipeline, + asList( + new Stage( + canRunStage, + asList( + new Job("Completed"), + new Job("Building"), + new Job("Completed") + ) + ) + ) + ) + ); + + PipelineHistory history = new PipelineHistory(pipelines); + + assertThat(history.isPipelineRunningOrScheduled(), is(true)); + } + +} \ No newline at end of file diff --git a/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/PipelineTest.java b/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/PipelineTest.java new file mode 100644 index 0000000..21c47b5 --- /dev/null +++ b/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/PipelineTest.java @@ -0,0 +1,79 @@ +package in.ashwanthkumar.gocd.github.jsonapi; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(Parameterized.class) +public class PipelineTest { + + private enum PreparingToSchedule { + YES, NO + } + + private static List stagesRunningOrScheduled(boolean... states) { + List stages = new ArrayList<>(states.length); + for (boolean state : states) { + Stage stage = mock(Stage.class); + when(stage.isRunningOrScheduled()).thenReturn(state); + when(stage.toString()).thenReturn("Stage.isRunningOrScheduled=" + state); + stages.add(stage); + } + return stages; + } + + @Parameterized.Parameters(name = "Pipeline can run: {0}, preparing to schedule: {1}, stages: {2}. Expected {3}") + public static Collection data() { + return Arrays.asList(new Object[][] { + {PreparingToSchedule.YES, CanRun.YES, stagesRunningOrScheduled(true), true}, + {PreparingToSchedule.YES, CanRun.NO, stagesRunningOrScheduled(true), true}, + {PreparingToSchedule.NO, CanRun.YES, stagesRunningOrScheduled(true), true}, + {PreparingToSchedule.NO, CanRun.NO, stagesRunningOrScheduled(true), true}, + + {PreparingToSchedule.YES, CanRun.YES, stagesRunningOrScheduled(false), true}, + {PreparingToSchedule.YES, CanRun.NO, stagesRunningOrScheduled(false), true}, + {PreparingToSchedule.NO, CanRun.YES, stagesRunningOrScheduled(false), false}, + {PreparingToSchedule.NO, CanRun.NO, stagesRunningOrScheduled(false), true}, + + // Multiple stages + {PreparingToSchedule.YES, CanRun.YES, stagesRunningOrScheduled(false, false, true), true}, + {PreparingToSchedule.YES, CanRun.NO, stagesRunningOrScheduled(false, false, true), true}, + {PreparingToSchedule.NO, CanRun.YES, stagesRunningOrScheduled(false, false, true), true}, + {PreparingToSchedule.NO, CanRun.NO, stagesRunningOrScheduled(false, false, true), true}, + + {PreparingToSchedule.YES, CanRun.YES, stagesRunningOrScheduled(false, false, true, false), true}, + {PreparingToSchedule.YES, CanRun.NO, stagesRunningOrScheduled(false, false, true, false), true}, + {PreparingToSchedule.NO, CanRun.YES, stagesRunningOrScheduled(false, false, true, false), true}, + {PreparingToSchedule.NO, CanRun.NO, stagesRunningOrScheduled(false, false, true, false), true}, + }); + } + + private final boolean preparingToSchedule; + private final boolean canRun; + private final List stages; + private final boolean expected; + + public PipelineTest(PreparingToSchedule preparingToSchedule, CanRun canRun, List stages, boolean expected) { + this.preparingToSchedule = preparingToSchedule.equals(PreparingToSchedule.YES); + this.canRun = canRun.equals(CanRun.YES); + this.stages = stages; + this.expected = expected; + } + + @Test + public void shouldReturnCorrectStatus() { + assertThat(new Pipeline(preparingToSchedule, canRun, stages) + .isRunningOrScheduled(), is(expected)); + } + +} \ No newline at end of file diff --git a/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/StageTest.java b/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/StageTest.java new file mode 100644 index 0000000..aba52cb --- /dev/null +++ b/src/test/java/in/ashwanthkumar/gocd/github/jsonapi/StageTest.java @@ -0,0 +1,56 @@ +package in.ashwanthkumar.gocd.github.jsonapi; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(Parameterized.class) +public class StageTest { + + private static List jobsRunningOrScheduled(boolean... states) { + List jobs = new ArrayList<>(states.length); + for (boolean state : states) { + Job stage = mock(Job.class); + when(stage.isRunningOrScheduled()).thenReturn(state); + when(stage.toString()).thenReturn("Job.isRunningOrScheduled=" + state); + jobs.add(stage); + } + return jobs; + } + + @Parameterized.Parameters(name = "Stage can run {0}, job statuses: {1}. Expected {2}") + public static Collection data() { + return Arrays.asList(new Object[][] { + {CanRun.YES, jobsRunningOrScheduled(false), false}, + {CanRun.NO, jobsRunningOrScheduled(true), true}, + {CanRun.YES, jobsRunningOrScheduled(true), true}, + {CanRun.YES, jobsRunningOrScheduled(false, false, true), true}, + {CanRun.YES, jobsRunningOrScheduled(false, true, false), true}, + }); + } + + private final boolean canRun; + private final List jobs; + private final boolean expected; + + public StageTest(CanRun canRun, List jobs, boolean expected) { + this.canRun = canRun.equals(CanRun.YES); + this.jobs = jobs; + this.expected = expected; + } + + @Test + public void shouldReturnCorrectStatus() { + assertThat(new Stage(canRun, jobs).isRunningOrScheduled(), is(expected)); + } +} \ No newline at end of file diff --git a/src/test/java/in/ashwanthkumar/gocd/github/provider/gerrit/GerritProviderTest.java b/src/test/java/in/ashwanthkumar/gocd/github/provider/gerrit/GerritProviderTest.java index 23c3258..b715168 100644 --- a/src/test/java/in/ashwanthkumar/gocd/github/provider/gerrit/GerritProviderTest.java +++ b/src/test/java/in/ashwanthkumar/gocd/github/provider/gerrit/GerritProviderTest.java @@ -23,17 +23,27 @@ public void shouldReturnCorrectScmSettingsFields() throws Exception { PluginConfigurationView scmConfigurationView = getScmView(); assertThat(scmConfigurationView.fields().keySet(), - hasItems("url", "username", "password") + hasItems("url", "username", "password", "pipeline_name") ); - assertThat(scmConfigurationView.fields().size(), is(3)); + assertThat(scmConfigurationView.fields().size(), is(4)); } @Test public void shouldReturnCorrectGeneralSettingsTemplate() throws Exception { PluginConfigurationView generalConfigurationView = getGeneralView(); - assertThat(generalConfigurationView.templateName(), is("")); - assertThat(generalConfigurationView.hasConfigurationView(), is(false)); + assertThat(generalConfigurationView.templateName(), is("/views/gerrit.plugin.template.html")); + assertThat(generalConfigurationView.hasConfigurationView(), is(true)); + } + + @Test + public void shouldReturnCorrectGeneralSettingsFields() throws Exception { + PluginConfigurationView generalConfigurationView = getGeneralView(); + + assertThat(generalConfigurationView.fields().keySet(), + hasItems("go_api_host", "go_api_username", "go_api_password") + ); + assertThat(generalConfigurationView.fields().size(), is(3)); } @Override diff --git a/src/test/java/in/ashwanthkumar/gocd/github/provider/git/GitProviderTest.java b/src/test/java/in/ashwanthkumar/gocd/github/provider/git/GitProviderTest.java index e73a2b1..e666402 100644 --- a/src/test/java/in/ashwanthkumar/gocd/github/provider/git/GitProviderTest.java +++ b/src/test/java/in/ashwanthkumar/gocd/github/provider/git/GitProviderTest.java @@ -23,9 +23,9 @@ public void shouldReturnCorrectScmSettingsFields() throws Exception { PluginConfigurationView scmConfigurationView = getScmView(); assertThat(scmConfigurationView.fields().keySet(), - hasItems("url", "username", "password", "branchwhitelist", "branchblacklist") + hasItems("url", "username", "password", "pipeline_name", "branchwhitelist", "branchblacklist") ); - assertThat(scmConfigurationView.fields().size(), is(5)); + assertThat(scmConfigurationView.fields().size(), is(6)); } @Test @@ -36,6 +36,13 @@ public void shouldReturnCorrectGeneralSettingsTemplate() throws Exception { assertThat(generalConfigurationView.hasConfigurationView(), is(false)); } + @Test + public void shouldReturnCorrectGeneralSettingsFields() throws Exception { + PluginConfigurationView generalConfigurationView = getGeneralView(); + + assertThat(generalConfigurationView.fields().size(), is(0)); + } + @Override protected Provider getProvider() { return new GitProvider(); diff --git a/src/test/java/in/ashwanthkumar/gocd/github/provider/github/GitHubProviderTest.java b/src/test/java/in/ashwanthkumar/gocd/github/provider/github/GitHubProviderTest.java index d680c29..0be5d92 100644 --- a/src/test/java/in/ashwanthkumar/gocd/github/provider/github/GitHubProviderTest.java +++ b/src/test/java/in/ashwanthkumar/gocd/github/provider/github/GitHubProviderTest.java @@ -23,9 +23,9 @@ public void shouldReturnCorrectScmSettingsFields() throws Exception { PluginConfigurationView scmConfigurationView = getScmView(); assertThat(scmConfigurationView.fields().keySet(), - hasItems("url", "username", "password") + hasItems("url", "username", "password", "pipeline_name") ); - assertThat(scmConfigurationView.fields().size(), is(3)); + assertThat(scmConfigurationView.fields().size(), is(4)); } @Test @@ -36,6 +36,13 @@ public void shouldReturnCorrectGeneralSettingsTemplate() throws Exception { assertThat(generalConfigurationView.hasConfigurationView(), is(false)); } + @Test + public void shouldReturnCorrectGeneralSettingsFields() throws Exception { + PluginConfigurationView generalConfigurationView = getGeneralView(); + + assertThat(generalConfigurationView.fields().size(), is(0)); + } + @Override protected Provider getProvider() { return new GitHubProvider(); diff --git a/src/test/java/in/ashwanthkumar/gocd/github/provider/stash/StashProviderTest.java b/src/test/java/in/ashwanthkumar/gocd/github/provider/stash/StashProviderTest.java index b16d2e9..89fbfac 100644 --- a/src/test/java/in/ashwanthkumar/gocd/github/provider/stash/StashProviderTest.java +++ b/src/test/java/in/ashwanthkumar/gocd/github/provider/stash/StashProviderTest.java @@ -23,9 +23,9 @@ public void shouldReturnCorrectScmSettingsFields() throws Exception { PluginConfigurationView scmConfigurationView = getScmView(); assertThat(scmConfigurationView.fields().keySet(), - hasItems("url", "username", "password") + hasItems("url", "username", "password", "pipeline_name") ); - assertThat(scmConfigurationView.fields().size(), is(3)); + assertThat(scmConfigurationView.fields().size(), is(4)); } @Test @@ -36,6 +36,13 @@ public void shouldReturnCorrectGeneralSettingsTemplate() throws Exception { assertThat(generalConfigurationView.hasConfigurationView(), is(false)); } + @Test + public void shouldReturnCorrectGeneralSettingsFields() throws Exception { + PluginConfigurationView generalConfigurationView = getGeneralView(); + + assertThat(generalConfigurationView.fields().size(), is(0)); + } + @Override protected Provider getProvider() { return new StashProvider();