/*
* Copyright 2017 ThoughtWorks, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.thoughtworks.go.config;
import com.rits.cloning.Cloner;
import com.thoughtworks.go.config.materials.MaterialConfigs;
import com.thoughtworks.go.config.materials.PackageMaterialConfig;
import com.thoughtworks.go.config.materials.PluggableSCMMaterialConfig;
import com.thoughtworks.go.config.materials.dependency.DependencyMaterialConfig;
import com.thoughtworks.go.config.preprocessor.ParamResolver;
import com.thoughtworks.go.config.preprocessor.ParamScope;
import com.thoughtworks.go.config.preprocessor.SkipParameterResolution;
import com.thoughtworks.go.config.remote.ConfigOrigin;
import com.thoughtworks.go.config.remote.ConfigOriginTraceable;
import com.thoughtworks.go.config.remote.FileConfigOrigin;
import com.thoughtworks.go.config.remote.RepoConfigOrigin;
import com.thoughtworks.go.config.validation.NameTypeValidator;
import com.thoughtworks.go.domain.BaseCollection;
import com.thoughtworks.go.domain.CommentRenderer;
import com.thoughtworks.go.domain.ConfigErrors;
import com.thoughtworks.go.domain.Task;
import com.thoughtworks.go.domain.label.PipelineLabel;
import com.thoughtworks.go.domain.materials.MaterialConfig;
import com.thoughtworks.go.service.TaskFactory;
import com.thoughtworks.go.util.Node;
import com.thoughtworks.go.util.StringUtil;
import com.thoughtworks.go.util.XmlUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.StringUtils;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.thoughtworks.go.util.ExceptionUtils.bomb;
import static com.thoughtworks.go.util.ExceptionUtils.bombIf;
import static org.apache.commons.collections.CollectionUtils.select;
/**
* @understands how a cruise pipeline is configured by the user
*/
@ConfigTag("pipeline")
@ConfigCollection(StageConfig.class)
public class PipelineConfig extends BaseCollection<StageConfig> implements ParamScope, ParamsAttributeAware,
Validatable, EnvironmentVariableScope, ConfigOriginTraceable {
private static final Cloner CLONER = new Cloner();
private static final String ERR_TEMPLATE = "You have defined a label template in pipeline %s that refers to a material called %s, but no material with this name is defined.";
public static final String LABEL_TEMPLATE = "labelTemplate";
public static final String MINGLE_CONFIG = "mingleConfig";
public static final String TRACKING_TOOL = "trackingTool";
public static final String TIMER_CONFIG = "timer";
public static final String ENVIRONMENT_VARIABLES = "variables";
public static final String PARAMS = "params";
private static final String LABEL_TEMPLATE_ZERO_TRUNC_BLOCK = "(\\[:0+\\])";
private static final String LABEL_TEMPLATE_TRUNC_BLOCK = "(\\[:\\d+\\])?";
private static final String LABEL_TEMPLATE_CHARACTERS = "[a-zA-Z0-9_\\-.!~*'()#:]"; // why a '#'?
private static final String LABEL_TEMPLATE_VARIABLE_REGEX = "[$]\\{(" + LABEL_TEMPLATE_CHARACTERS + "+)" + LABEL_TEMPLATE_TRUNC_BLOCK + "\\}";
public static final String LABEL_TEMPLATE_FORMAT = "((" + LABEL_TEMPLATE_CHARACTERS + ")*[$]"
+ "\\{" + LABEL_TEMPLATE_CHARACTERS + "+" + LABEL_TEMPLATE_TRUNC_BLOCK + "\\}(" + LABEL_TEMPLATE_CHARACTERS + ")*)+";
private static final Pattern LABEL_TEMPLATE_FORMAT_REGEX = Pattern.compile(String.format("^(%s)$", LABEL_TEMPLATE_FORMAT));
public static final Pattern LABEL_TEMPATE_ZERO_TRUNC_BLOCK_PATTERN = Pattern.compile(LABEL_TEMPLATE_ZERO_TRUNC_BLOCK);
public static final String TEMPLATE_NAME = "templateName";
public static final String LOCK = "lock";
public static final String CONFIGURATION_TYPE = "configurationType";
public static final String CONFIGURATION_TYPE_STAGES = "configurationType_stages";
public static final String CONFIGURATION_TYPE_TEMPLATE = "configurationType_template";
public static final String LABEL_TEMPLATE_FORMAT_MESSAGE = "Label should be composed of alphanumeric text, it should contain the builder number as ${COUNT}, can contain a material revision as ${<material-name>} of ${<material-name>[:<number>]}, or use params as #{<param-name>}.";
public static final String LABEL_TEMPLATE_ERROR_MESSAGE = "Invalid label. ".concat(LABEL_TEMPLATE_FORMAT_MESSAGE);
public static final String BLANK_LABEL_TEMPLATE_ERROR_MESSAGE = "Label cannot be blank. ".concat(LABEL_TEMPLATE_FORMAT_MESSAGE);
@SkipParameterResolution
@ConfigAttribute(value = "name", optional = false)
private CaseInsensitiveString name;
@ConfigAttribute(value = "labeltemplate", optional = true)
private String labelTemplate = PipelineLabel.COUNT_TEMPLATE;
@ConfigSubtag
@SkipParameterResolution
private ParamsConfig params = new ParamsConfig();
@ConfigSubtag
private TrackingTool trackingTool;
@ConfigSubtag
private MingleConfig mingleConfig = new MingleConfig();
@ConfigSubtag(optional = true)
private TimerConfig timer;
@ConfigSubtag
private EnvironmentVariablesConfig variables = new EnvironmentVariablesConfig();
@ConfigSubtag(optional = false)
private MaterialConfigs materialConfigs = new MaterialConfigs();
@ConfigAttribute(value = "isLocked", optional = true, allowNull = true)
private String lock;
@SkipParameterResolution
@ConfigAttribute(value = "template", optional = true, allowNull = true)
private CaseInsensitiveString templateName;
private ConfigOrigin origin;
private boolean templateApplied;
private ConfigErrors errors = new ConfigErrors();
public static final String NAME = "name";
public static final String INTEGRATION_TYPE = "integrationType";
public static final String INTEGRATION_TYPE_NONE = "none";
public static final String INTEGRATION_TYPE_MINGLE = "mingle";
public static final String INTEGRATION_TYPE_TRACKING_TOOL = "trackingTool";
public static final String MATERIALS = "materials";
public static final String STAGE = "stage";
public PipelineConfig() {
}
public PipelineConfig(final CaseInsensitiveString name, MaterialConfigs materialConfigs, StageConfig... stageConfigs) {
super(stageConfigs);
this.name = name;
this.labelTemplate = PipelineLabel.COUNT_TEMPLATE;
this.materialConfigs = materialConfigs;
}
public PipelineConfig(CaseInsensitiveString name, String labelTemplate, String cronSpec, boolean timerShouldTriggerOnlyOnMaterialChanges, MaterialConfigs materialConfigs,
List<StageConfig> stageConfigs) {
super(stageConfigs);
this.name = name;
this.labelTemplate = labelTemplate;
this.setMaterialConfigs(materialConfigs);
if (cronSpec != null) {
this.timer = new TimerConfig(cronSpec, timerShouldTriggerOnlyOnMaterialChanges);
}
}
@Override
public String toString() {
return String.format("PipelineConfig: %s",name);
}
public boolean validateTree(PipelineConfigSaveValidationContext validationContext) {
return new PipelineConfigTreeValidator(this).validate(validationContext);
}
public void validate(ValidationContext validationContext) {
validateLabelTemplate();
validatePipelineName();
validateStageNameUniqueness();
if (!hasTemplate() && isEmpty()) {
addError("pipeline", String.format("Pipeline '%s' does not have any stages configured. A pipeline must have at least one stage.", name()));
}
}
public void validateTemplate(PipelineTemplateConfig templateConfig) {
if (hasTemplate()) {
if (new NameTypeValidator().isNameInvalid(templateName.toString())) {
errors().add(TEMPLATE_NAME, NameTypeValidator.errorMessage("template", templateName));
}
if (hasStages() && !hasTemplateApplied()) {
addError("stages", String.format("Cannot add stages to pipeline '%s' which already references template '%s'", this.name(), this.getTemplateName()));
addError("template", String.format("Cannot set template '%s' on pipeline '%s' because it already has stages defined", this.getTemplateName(), this.name()));
}
if (templateConfig == null) {
addError("pipeline", String.format("Pipeline '%s' refers to non-existent template '%s'.", name(), templateName));
}
}
}
private void validatePipelineName() {
if (!new NameTypeValidator().isNameValid(name)) {
errors().add(NAME, NameTypeValidator.errorMessage("pipeline", name));
}
}
private void validateStageNameUniqueness() {
Map<String, StageConfig> stageNameMap = new HashMap<>();
for (StageConfig stageConfig : this) {
stageConfig.validateNameUniqueness(stageNameMap);
}
}
private void validateLabelTemplate() {
if (StringUtil.isBlank(labelTemplate)) {
addError("labelTemplate", BLANK_LABEL_TEMPLATE_ERROR_MESSAGE);
return;
}
if (XmlUtils.doesNotMatchUsingXsdRegex(LABEL_TEMPLATE_FORMAT_REGEX, labelTemplate)) {
addError("labelTemplate", LABEL_TEMPLATE_ERROR_MESSAGE);
return;
}
if (validateLabelTemplateTruncation(labelTemplate)) {
addError("labelTemplate", String.format("Length of zero not allowed on label %s defined on pipeline %s.", labelTemplate, name));
return;
}
Set<String> templateVariables = getTemplateVariables();
List<String> materialNames = allowedTemplateVariables();
for (final String templateVariable : templateVariables) {
if (!CollectionUtils.exists(materialNames, withNameSameAs(templateVariable))) {
addError("labelTemplate", String.format(ERR_TEMPLATE, name(), templateVariable));
}
}
}
private boolean validateLabelTemplateTruncation(String labelTemplate) {
return LABEL_TEMPATE_ZERO_TRUNC_BLOCK_PATTERN.matcher(labelTemplate).find();
}
private boolean hasStages(){
return !isEmpty();
}
private Predicate withNameSameAs(final String templateVariable) {
return new Predicate() {
public boolean evaluate(Object materialName) {
return StringUtils.equalsIgnoreCase(materialName.toString(), templateVariable);
}
};
}
public void addError(String fieldName, String msg) {
errors.add(fieldName, msg);
}
public ConfigErrors errors() {
return errors;
}
public List<ConfigErrors> getAllErrors() {
return ErrorCollector.getAllErrors(this);
}
public PipelineConfig getStages() {
return this;
}
public StageConfig getStage(final CaseInsensitiveString stageName) {
return findBy(stageName);
}
public StageConfig getStage(String stageName) {
return getStage(new CaseInsensitiveString(stageName));
}
public StageConfig findBy(final CaseInsensitiveString stageName) {
for (StageConfig stageConfig : this) {
if (stageConfig.name().equals(stageName)) {
return stageConfig;
}
}
return null;
}
public StageConfig nextStage(final CaseInsensitiveString lastStageName) {
for (int i = 0; i < this.size(); i++) {
StageConfig stageConfig = this.get(i);
boolean hasNextStage = i + 1 < this.size();
if (hasNextStage && stageConfig.name().equals(lastStageName)) {
return this.get(i + 1);
}
}
return null;
}
public StageConfig getFirstStageConfig() {
return this.first();
}
public StageConfig set(int index, StageConfig stageConfig) {
verifyUniqueName(stageConfig, index);
return super.set(index, stageConfig);
}
public boolean add(StageConfig stageConfig) {
ensureNoTemplateDefined(stageConfig.name());
verifyUniqueName(stageConfig);
return addStageWithoutValidityAssertion(stageConfig);
}
public boolean addStageWithoutValidityAssertion(StageConfig stageConfig) {
return super.add(stageConfig);
}
private void verifyUniqueName(StageConfig stageConfig) {
if (alreadyContains(stageConfig)) {
throw bomb("You have defined multiple stages called '" + stageConfig.name() + "'. Stage names are case-insensitive and must be unique.");
}
}
private void verifyUniqueName(StageConfig stageConfig, int index) {
if (stageConfig.name().equals(super.get(index).name())) {
return;
}
verifyUniqueName(stageConfig);
}
private boolean alreadyContains(StageConfig stageConfig) {
return findBy(stageConfig.name()) != null;
}
public CaseInsensitiveString name() {
return name;
}
public CaseInsensitiveString getName() {
return name;
}
public StageConfig previousStage(final CaseInsensitiveString stageName) {
StageConfig lastStageConfig = null;
for (StageConfig currentStageConfig : this) {
if (currentStageConfig.name().equals(stageName)) {
return lastStageConfig;
}
lastStageConfig = currentStageConfig;
}
return null;
}
public boolean isConfigOriginSameAsOneOfMaterials() {
if (!(this.origin instanceof RepoConfigOrigin))
return false;
RepoConfigOrigin repoConfigOrigin = (RepoConfigOrigin) this.origin;
MaterialConfig configMaterial = repoConfigOrigin.getMaterial();
for(MaterialConfig material : this.materialConfigs())
{
if(material.getFingerprint().equals(configMaterial.getFingerprint()))
return true;
}
return false;
}
public boolean isConfigOriginFromRevision(String revision) {
if (!(this.origin instanceof RepoConfigOrigin))
return false;
RepoConfigOrigin repoConfigOrigin = (RepoConfigOrigin) this.origin;
return repoConfigOrigin.isFromRevision(revision);
}
private static <T> T as(Class<T> clazz, Object o) {
if (clazz.isInstance(o)) {
return clazz.cast(o);
}
return null;
}
public MaterialConfigs materialConfigs() {
return materialConfigs;
}
public void setMaterialConfigs(MaterialConfigs newMaterialConfigs) {
this.materialConfigs = newMaterialConfigs;
if (newMaterialConfigs == null || newMaterialConfigs.isEmpty()) {
this.materialConfigs = new MaterialConfigs();
}
}
public Node getDependenciesAsNode() {
List<Node.DependencyNode> pipelineDeps = new ArrayList<>();
for (MaterialConfig material : materialConfigs) {
if (material instanceof DependencyMaterialConfig) {
DependencyMaterialConfig dependencyMaterialConfig = (DependencyMaterialConfig) material;
pipelineDeps.add(new Node.DependencyNode(dependencyMaterialConfig.getPipelineName(), dependencyMaterialConfig.getStageName()));
}
}
return new Node(pipelineDeps);
}
public String getLabelTemplate() {
return labelTemplate;
}
public void setLabelTemplate(String labelFormat) {
this.labelTemplate = labelFormat;
}
public boolean hasNextStage(final CaseInsensitiveString lastStageName) {
if (this.isEmpty()) {
return false;
}
return nextStage(lastStageName) != null;
}
public TrackingTool getTrackingTool() {
return trackingTool;
}
public TrackingTool trackingTool() {
return trackingTool == null ? new TrackingTool() : trackingTool;
}
public void setTrackingTool(TrackingTool trackingTool) {
this.trackingTool = trackingTool;
}
public void addMaterialConfig(MaterialConfig materialConfig) {
this.materialConfigs.add(materialConfig);
}
public void removeMaterialConfig(MaterialConfig materialConfig) {
this.materialConfigs.remove(materialConfig);
}
public PipelineConfig duplicate() {
PipelineConfig clone = CLONER.deepClone(this);
clone.name = new CaseInsensitiveString("");
clearSelfPipelineNameInFetchTask(clone);
return clone;
}
private void clearSelfPipelineNameInFetchTask(PipelineConfig clone) {
for (StageConfig stage : clone) {
for (JobConfig job : stage.getJobs()) {
for (Task task : job.getTasks()) {
if (task instanceof FetchTask) {
FetchTask fetchTask = (FetchTask) task;
if (this.name().equals(fetchTask.getTargetPipelineName())) {
fetchTask.setPipelineName(new CaseInsensitiveString(""));
}
}
}
}
}
}
public boolean isFirstStageManualApproval() {
if (isEmpty()) {
throw new IllegalStateException(String.format("Pipeline [%s] doesn't have any stage", name));
}
return getFirstStageConfig().getApproval().isManual();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
PipelineConfig that = (PipelineConfig) o;
if (labelTemplate != null ? !labelTemplate.equals(that.labelTemplate) : that.labelTemplate != null) {
return false;
}
if (materialConfigs != null ? !materialConfigs.equals(that.materialConfigs) : that.materialConfigs != null) {
return false;
}
if (name != null ? !name.equals(that.name) : that.name != null) {
return false;
}
if (timer != null ? !timer.equals(that.timer) : that.timer != null) {
return false;
}
if (trackingTool != null ? !trackingTool.equals(that.trackingTool) : that.trackingTool != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + name.hashCode();
result = 31 * result + (labelTemplate != null ? labelTemplate.hashCode() : 0);
result = 31 * result + (trackingTool != null ? trackingTool.hashCode() : 0);
result = 31 * result + (materialConfigs != null ? materialConfigs.hashCode() : 0);
result = 31 * result + (timer != null ? timer.hashCode() : 0);
return result;
}
public Set<String> getTemplateVariables() {
Pattern pattern = Pattern.compile(LABEL_TEMPLATE_VARIABLE_REGEX);
Matcher matcher = pattern.matcher(this.labelTemplate);
LinkedHashSet<String> result = new LinkedHashSet<>();
while (matcher.find()) {
result.add(matcher.group(1));
}
return result;
}
public List<String> allowedTemplateVariables() {
List<String> names = new ArrayList<>();
for (MaterialConfig material : materialConfigs) {
if (!CaseInsensitiveString.isBlank(material.getName())) {
names.add(CaseInsensitiveString.str(material.getName()));
}
}
names.add("COUNT");
return names;
}
public TimerConfig getTimer() {
return timer;
}
public void setTimer(TimerConfig timer) {
this.timer = timer;
}
public boolean requiresApproval() {
if (isEmpty()) {
return false;
}
return first().requiresApproval();
}
public void lockExplicitly() {
this.lock = Boolean.TRUE.toString();
}
public void unlockExplicitly() {
lock = Boolean.FALSE.toString();
}
public boolean hasExplicitLock() {
return lock != null;
}
public void removeExplicitLocks() {
this.lock = null;
}
public Boolean explicitLock() {
if (!hasExplicitLock()) {
throw new RuntimeException(String.format("There is no explicit lock on the pipeline '%s'.", name));
}
return isLock();
}
public boolean isLock() {
return Boolean.parseBoolean(lock);
}
// only called from tests
public void setVariables(EnvironmentVariablesConfig variables) {
this.variables = variables;
}
public EnvironmentVariablesConfig getVariables() {
return variables;
}
public EnvironmentVariablesConfig getPlainTextVariables() {
return variables.getPlainTextVariables();
}
public EnvironmentVariablesConfig getSecureVariables() {
return variables.getSecureVariables();
}
public void addEnvironmentVariable(String name, String value) {
variables.add(new EnvironmentVariableConfig(name.trim(), value));
}
public boolean hasTemplate() {
return templateName != null && !StringUtil.isBlank(templateName.toString());
}
public CaseInsensitiveString getTemplateName() {
return templateName;
}
public void usingTemplate(PipelineTemplateConfig pipelineTemplate) {
this.addAll(CLONER.deepClone(pipelineTemplate));
this.templateApplied = true;
}
private void ensureNoTemplateDefined(CaseInsensitiveString stageName) {
if (hasTemplate()) {
throw new IllegalStateException(String.format("Cannot add stage '%s' to pipeline '%s', which already references template '%s'.", stageName, name, templateName));
}
}
public boolean hasTemplateApplied() {
return templateApplied;
}
public void setTemplateName(CaseInsensitiveString templateName) {
ensureNoStagesDefined(templateName);
this.templateName = templateName;
}
public void setMingleConfig(MingleConfig mingleConfig) {
this.mingleConfig = mingleConfig;
}
public MingleConfig getMingleConfig() {
return mingleConfig;
}
private void ensureNoStagesDefined(CaseInsensitiveString newTemplateName) {
bombIf(!isEmpty(), String.format("Cannot set template '%s' on pipeline '%s' because it already has stages defined", newTemplateName, name));
}
public PipelineConfig getCopyForEditing() {
PipelineConfig pipelineConfig = (PipelineConfig) clone();
if (pipelineConfig.hasTemplate()) {
pipelineConfig.clear();
}
return pipelineConfig;
}
public boolean dependsOn(final CaseInsensitiveString pipelineName) {
for (MaterialConfig material : materialConfigs) {
if (material instanceof DependencyMaterialConfig && ((DependencyMaterialConfig) material).getPipelineName().equals(pipelineName)) {
return true;
}
}
return false;
}
public List<DependencyMaterialConfig> dependencyMaterialConfigs() {
List<DependencyMaterialConfig> materialConfigs = new ArrayList<>();
for (MaterialConfig material : this.materialConfigs) {
if (material instanceof DependencyMaterialConfig) {
materialConfigs.add((DependencyMaterialConfig) material);
}
}
return materialConfigs;
}
public boolean hasVariableInScope(String variableName) {
if (variables.hasVariable(variableName)) {
return true;
}
for (StageConfig stageConfig : this) {
if (stageConfig.hasVariableInScope(variableName)) {
return true;
}
}
return false;
}
public List<CaseInsensitiveString> upstreamPipelines() {
return materialConfigs.getDependentPipelineNames();
}
public boolean hasMaterial(MaterialConfig material) {
return materialConfigs.hasMaterialWithFingerprint(material);
}
public void addParam(ParamConfig paramConfig) {
this.params.add(paramConfig);
}
public void setParams(ParamsConfig paramsConfig) {
this.params = paramsConfig;
}
public void setParams(List<ParamConfig> paramsConfig) {
setParams(new ParamsConfig(paramsConfig));
}
public ParamResolver applyOver(ParamResolver enclosingScope) {
return enclosingScope.override(CLONER.deepClone(params));
}
public ParamsConfig getParams() {
return params;
}
public void setConfigAttributes(Object attributes) {
setConfigAttributes(attributes, null);
}
public void setConfigAttributes(Object attributes, TaskFactory taskFactory) {
if (attributes == null) {
return;
}
Map attributeMap = (Map) attributes;
if (attributeMap.containsKey(NAME)) {
setName((String) attributeMap.get(NAME));
}
if (attributeMap.containsKey(MATERIALS)) {
materialConfigs.setConfigAttributes(attributeMap.get(MATERIALS));
}
if (attributeMap.containsKey(STAGE)) {
clear();
StageConfig stageConfig = new StageConfig();
stageConfig.setConfigAttributes(attributeMap.get(STAGE), taskFactory);
add(stageConfig);
}
if (attributeMap.containsKey(LABEL_TEMPLATE)) {
labelTemplate = (String) attributeMap.get(LABEL_TEMPLATE);
if (StringUtil.isBlank(labelTemplate)) {
labelTemplate = PipelineLabel.COUNT_TEMPLATE;
}
}
if (attributeMap.containsKey(TIMER_CONFIG)) {
timer = TimerConfig.createTimer(attributeMap.get(TIMER_CONFIG));
}
if (attributeMap.containsKey(LOCK)) {
lock = "1".equals(attributeMap.get(LOCK)) ? "true" : "false";
}
if (attributeMap.containsKey(INTEGRATION_TYPE)) {
setIntegrationType(attributeMap);
}
if (attributeMap.containsKey(CONFIGURATION_TYPE)) {
setConfigurationType(attributeMap);
}
if (attributeMap.containsKey(ENVIRONMENT_VARIABLES)) {
variables.setConfigAttributes(attributeMap.get(ENVIRONMENT_VARIABLES));
}
if (!attributeMap.containsKey(CONFIGURATION_TYPE) || (attributeMap.containsKey(CONFIGURATION_TYPE) && getConfigurationType().equals(CONFIGURATION_TYPE_TEMPLATE))) {
if (attributeMap.containsKey(PARAMS)) {
params.setConfigAttributes(attributeMap.get(PARAMS));
}
}
if (attributeMap.containsKey(StageConfig.APPROVAL)) {
StageConfig firstStage = first();
firstStage.setConfigAttributes(attributeMap);
}
}
public void setName(String name) {
this.name = new CaseInsensitiveString(name);
}
public void setName(CaseInsensitiveString name) {
this.name = name;
}
private void setConfigurationType(Map attributeMap) {
String configurationType = (String) attributeMap.get(CONFIGURATION_TYPE);
if (configurationType.equals(CONFIGURATION_TYPE_STAGES)) {
return;
}
if (configurationType.equals(CONFIGURATION_TYPE_TEMPLATE)) {
String templateName = (String) attributeMap.get(TEMPLATE_NAME);
this.clear();
this.setTemplateName(new CaseInsensitiveString(templateName));
}
}
private void setIntegrationType(Map attributeMap) {
String integrationType = (String) attributeMap.get(INTEGRATION_TYPE);
if (integrationType.equals(INTEGRATION_TYPE_NONE)) {
mingleConfig = new MingleConfig();
trackingTool = null;
} else if (integrationType.equals(INTEGRATION_TYPE_MINGLE)) {
mingleConfig = MingleConfig.create(attributeMap.get(MINGLE_CONFIG));
trackingTool = null;
} else if (integrationType.equals(INTEGRATION_TYPE_TRACKING_TOOL)) {
mingleConfig = new MingleConfig();
trackingTool = TrackingTool.createTrackingTool((Map) attributeMap.get(TRACKING_TOOL));
}
}
public String getIntegrationType() {
boolean isMingleConfigEmpty = (mingleConfig.equals(new MingleConfig()) && mingleConfig.errors().isEmpty());
boolean isTrackingToolEmpty = (trackingTool == null || (trackingTool.equals(new TrackingTool()) && trackingTool.errors().isEmpty()));
if (isMingleConfigEmpty && isTrackingToolEmpty) {
return INTEGRATION_TYPE_NONE;
}
if (!isTrackingToolEmpty && isMingleConfigEmpty) {
return INTEGRATION_TYPE_TRACKING_TOOL;
}
if (!isMingleConfigEmpty && isTrackingToolEmpty) {
return INTEGRATION_TYPE_MINGLE;
}
throw new RuntimeException("Cannot have both tracking tool and mingle config specified");
}
public String getConfigurationType() {
if (hasTemplate()) {
return CONFIGURATION_TYPE_TEMPLATE;
}
return CONFIGURATION_TYPE_STAGES;
}
public void incrementIndex(StageConfig stageToBeMoved) {
moveStage(stageToBeMoved, 1);
}
public void decrementIndex(StageConfig stageToBeMoved) {
moveStage(stageToBeMoved, -1);
}
private void moveStage(StageConfig moveMeStage, int moveBy) {
int current = this.indexOf(moveMeStage);
if (current == -1) {
throw new RuntimeException(String.format("Cannot find the stage '%s' in pipeline '%s'", moveMeStage.name(), name()));
}
this.remove(moveMeStage);
this.add(current + moveBy, moveMeStage);
}
public List<StageConfig> allStagesBefore(CaseInsensitiveString stage) {
List<StageConfig> stages = new ArrayList<>();
for (StageConfig stageConfig : this) {
if (stage.equals(stageConfig.name())) {
break;
}
stages.add(stageConfig);
}
return stages;
}
public List<StageConfig> validStagesForFetchArtifact(PipelineConfig downstreamPipeline, CaseInsensitiveString currentDownstreamStage) {
for (DependencyMaterialConfig dependencyMaterial : downstreamPipeline.dependencyMaterialConfigs()) {
if (dependencyMaterial.getPipelineName().equals(name)) {
List<StageConfig> stageConfigs = allStagesBefore(dependencyMaterial.getStageName());
stageConfigs.add(getStage(dependencyMaterial.getStageName())); // add this stage itself
return stageConfigs;
}
}
if (this.equals(downstreamPipeline)) {
return allStagesBefore(currentDownstreamStage);
}
return null;
}
public List<PipelineConfig> allFirstLevelUpstreamPipelines(CruiseConfig cruiseConfig) {
List<PipelineConfig> pipelinesForFetchArtifact = new ArrayList<>();
for (DependencyMaterialConfig dependencyMaterial : dependencyMaterialConfigs()) {
pipelinesForFetchArtifact.add(cruiseConfig.pipelineConfigByName(dependencyMaterial.getPipelineName()));
}
return pipelinesForFetchArtifact;
}
public CommentRenderer getCommentRenderer() {
if (getIntegrationType().equals(INTEGRATION_TYPE_MINGLE)) {
return mingleConfig;
} else {
return trackingTool();
}
}
public void validateNameUniqueness(Map<CaseInsensitiveString, PipelineConfig> pipelineNameMap) {
PipelineConfig pipelineWithSameName = pipelineNameMap.get(name);
if (pipelineWithSameName == null) {
pipelineNameMap.put(name, this);
} else {
pipelineWithSameName.nameConflictError();
this.nameConflictError();
}
}
private void nameConflictError() {
errors.add(NAME, String.format("You have defined multiple pipelines called '%s'. Pipeline names are case-insensitive and must be unique.", name));
}
public List<FetchTask> getFetchTasks() {
List<FetchTask> fetchTasks = new ArrayList<>();
for (StageConfig stage : this) {
for (JobConfig job : stage.getJobs()) {
for (Task task : job.tasks()) {
if (task instanceof FetchTask) {
fetchTasks.add((FetchTask) task);
}
}
}
}
return fetchTasks;
}
public void addEnvironmentVariable(EnvironmentVariableConfig environmentVariableConfig) {
variables.add(environmentVariableConfig);
}
public void cleanupAllUsagesOfRole(Role roleToDelete) {
for (StageConfig stageConfig : this) {
stageConfig.cleanupAllUsagesOfRole(roleToDelete);
}
}
public void templatize(CaseInsensitiveString templateName) {
clear();
this.templateName = templateName;
this.templateApplied = false;
}
public boolean hasMaterialWithFingerprint(MaterialConfig materialConfig) {
return this.materialConfigs.hasMaterialWithFingerprint(materialConfig);
}
public List<PackageMaterialConfig> packageMaterialConfigs() {
return new ArrayList<>(select(materialConfigs(), new Predicate() {
@Override
public boolean evaluate(Object materialConfig) {
return materialConfig instanceof PackageMaterialConfig;
}
}));
}
public List<PluggableSCMMaterialConfig> pluggableSCMMaterialConfigs() {
return new ArrayList<>(select(materialConfigs(), new Predicate() {
@Override
public boolean evaluate(Object materialConfig) {
return materialConfig instanceof PluggableSCMMaterialConfig;
}
}));
}
public ConfigOrigin getOrigin() {
return origin;
}
@Override
public void setOrigins(ConfigOrigin origins) {
this.origin = origins;
}
public void setOrigin(ConfigOrigin origin) {
this.origin = origin;
}
public boolean isLocal() {
return origin == null || this.origin.isLocal();
}
public void setLock(boolean lock) {
if(lock)
this.lockExplicitly();
else
this.unlockExplicitly();
}
public String getOriginDisplayName() {
return getOrigin() != null ? getOrigin().displayName() : new FileConfigOrigin().displayName();
}
}