/* * Copyright 2016 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.server.presentation; import com.thoughtworks.go.config.*; import com.thoughtworks.go.config.materials.dependency.DependencyMaterialConfig; import com.thoughtworks.go.domain.materials.MaterialConfig; import com.thoughtworks.go.util.SystemEnvironment; import java.util.*; public class FetchArtifactViewHelper { private SystemEnvironment systemEnvironment; private final CruiseConfig cruiseConfig; private final CaseInsensitiveString pipelineName; private final CaseInsensitiveString stageName; private final boolean template; private static final String NULL_STR = new String(); public FetchArtifactViewHelper(SystemEnvironment systemEnvironment, CruiseConfig cruiseConfig, CaseInsensitiveString pipelineName, CaseInsensitiveString stageName, boolean template) { this.systemEnvironment = systemEnvironment; this.cruiseConfig = cruiseConfig; this.pipelineName = pipelineName; this.stageName = stageName; this.template = template; } private static final class JobHierarchyQueueEntry { final String pathFromNode; final CaseInsensitiveString stageName; final CaseInsensitiveString pipelineName; private JobHierarchyQueueEntry(String pathFromNode, CaseInsensitiveString pipelineName, CaseInsensitiveString stageName) { this.pathFromNode = pathFromNode; this.pipelineName = pipelineName; this.stageName = stageName; } public String pathFromAncestor() { return pathFromNode.length() > 0 ? pipelineName + PathFromAncestor.DELIMITER + pathFromNode : CaseInsensitiveString.str(pipelineName); } } private static final class FetchSuggestionHierarchy extends HashMap<CaseInsensitiveString, Map<CaseInsensitiveString, List<CaseInsensitiveString>>> { private void addStagesToHierarchy(CaseInsensitiveString pipelineName, List<StageConfig> currentPipelineStages) { Map<CaseInsensitiveString, List<CaseInsensitiveString>> stageMap = new HashMap<>(); for (StageConfig stg : currentPipelineStages) { stageMap.put(stg.name(), stg.getJobs().names()); } put(pipelineName, stageMap); } private void populateFetchableJobHierarchyFor(Queue<JobHierarchyQueueEntry> bfsQueue, CruiseConfig cruiseConfig) { while (!bfsQueue.isEmpty()) { JobHierarchyQueueEntry entry = bfsQueue.remove(); CaseInsensitiveString pipelineName = entry.pipelineName; PipelineConfig pipelineConfig = cruiseConfig.pipelineConfigByName(pipelineName); List<StageConfig> fetchableStages = new ArrayList<>(); for (StageConfig stageConfig : pipelineConfig) { fetchableStages.add(stageConfig); if (entry.stageName.equals(stageConfig.name())) { break; } } addStagesToHierarchy(new CaseInsensitiveString(entry.pathFromAncestor()), fetchableStages); addMaterialsToQueue(bfsQueue, pipelineConfig, entry.pathFromAncestor()); } } } public FetchSuggestionHierarchy autosuggestMap() { if (!systemEnvironment.get(SystemEnvironment.FETCH_ARTIFACT_AUTO_SUGGEST)) { return new FetchSuggestionHierarchy(); } if(template && !systemEnvironment.isFetchArtifactTemplateAutoSuggestEnabled()) { return new FetchSuggestionHierarchy(); } return fetchArtifactSuggestionsForPipeline(template ? createPipelineConfigForTemplate() : cruiseConfig.pipelineConfigByName(pipelineName)); } private PipelineConfig createPipelineConfigForTemplate() { List<PipelineConfig> pipelineConfigs = cruiseConfig.allPipelines(); PipelineConfig dummyPipeline = new PipelineConfig(); for (PipelineConfig pipelineConfig : pipelineConfigs) { dummyPipeline.addMaterialConfig(new DependencyMaterialConfig(pipelineConfig.name(), pipelineConfig.last().name())); } PipelineTemplateConfig pipelineTemplateConfig = cruiseConfig.getTemplates().templateByName(pipelineName); for (StageConfig stageConfig : pipelineTemplateConfig) { if (stageName.equals(stageConfig.name())) { break; } dummyPipeline.add(stageConfig); } return dummyPipeline; } private FetchSuggestionHierarchy fetchArtifactSuggestionsForPipeline(PipelineConfig pipelineConfig) { FetchSuggestionHierarchy hierarchy = new FetchSuggestionHierarchy(); Queue<JobHierarchyQueueEntry> bfsQueue = new ArrayDeque<>(); addLocalUpstreamStages(hierarchy, pipelineConfig); HashSet<DependencyMaterialConfig> handled = new HashSet<>(); addMaterialsToQueue(bfsQueue, pipelineConfig, ""); hierarchy.populateFetchableJobHierarchyFor(bfsQueue, cruiseConfig); return hierarchy; } private void addLocalUpstreamStages(FetchSuggestionHierarchy hierarchy, PipelineConfig pipelineConfig) { List<StageConfig> currentPipelineStages = pipelineConfig.allStagesBefore(stageName); if (!currentPipelineStages.isEmpty()) { if (!template) { hierarchy.addStagesToHierarchy(pipelineName, currentPipelineStages); } hierarchy.addStagesToHierarchy(new CaseInsensitiveString(NULL_STR), currentPipelineStages); } } private static void addMaterialsToQueue(Queue<JobHierarchyQueueEntry> bfsQueue, PipelineConfig pipelineConfig, String pathFromThisPipeline) { for (MaterialConfig mat : pipelineConfig.materialConfigs()) { if (mat instanceof DependencyMaterialConfig) { DependencyMaterialConfig depMat = (DependencyMaterialConfig) mat; bfsQueue.add(new JobHierarchyQueueEntry(pathFromThisPipeline, depMat.getPipelineName(), depMat.getStageName())); } } } }