/*************************GO-LICENSE-START*********************************
* Copyright 2014 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.
*************************GO-LICENSE-END***********************************/
package com.thoughtworks.go.server.service;
import com.thoughtworks.go.config.*;
import com.thoughtworks.go.domain.PipelineDependencyGraphOld;
import com.thoughtworks.go.domain.PipelineGroups;
import com.thoughtworks.go.domain.PipelinePauseInfo;
import com.thoughtworks.go.domain.PipelineTimelineEntry;
import com.thoughtworks.go.domain.buildcause.BuildCause;
import com.thoughtworks.go.i18n.LocalizedMessage;
import com.thoughtworks.go.presentation.PipelineStatusModel;
import com.thoughtworks.go.presentation.pipelinehistory.*;
import com.thoughtworks.go.server.dao.PipelineDao;
import com.thoughtworks.go.server.dao.StageDao;
import com.thoughtworks.go.server.domain.JobDurationStrategy;
import com.thoughtworks.go.server.domain.PipelineTimeline;
import com.thoughtworks.go.server.domain.Username;
import com.thoughtworks.go.server.domain.user.PipelineSelections;
import com.thoughtworks.go.server.persistence.MaterialRepository;
import com.thoughtworks.go.server.scheduling.TriggerMonitor;
import com.thoughtworks.go.server.service.result.HttpLocalizedOperationResult;
import com.thoughtworks.go.server.service.result.HttpOperationResult;
import com.thoughtworks.go.server.service.result.OperationResult;
import com.thoughtworks.go.server.service.result.ServerHealthStateOperationResult;
import com.thoughtworks.go.server.service.support.toggle.Toggles;
import com.thoughtworks.go.server.util.Pagination;
import com.thoughtworks.go.serverhealth.HealthStateScope;
import com.thoughtworks.go.serverhealth.HealthStateType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class PipelineHistoryService implements PipelineInstanceLoader {
private PipelineDao pipelineDao;
private final StageDao stageDao;
private GoConfigService goConfigService;
private SecurityService securityService;
private MaterialRepository materialRepository;
private ScheduleService scheduleService;
private TriggerMonitor triggerMonitor;
private JobDurationStrategy jobDurationStrategy;
private final PipelineTimeline pipelineTimeline;
private PipelineUnlockApiService pipelineUnlockService;
private SchedulingCheckerService schedulingCheckerService;
private PipelineLockService pipelineLockService;
private PipelinePauseService pipelinePauseService;
private static final String NOT_AUTHORIZED_TO_VIEW_PIPELINE = "Not authorized to view pipeline";
@Autowired
public PipelineHistoryService(PipelineDao pipelineDao,
StageDao stageDao,
GoConfigService goConfigService,
SecurityService securityService,
ScheduleService scheduleService,
MaterialRepository materialRepository,
JobDurationStrategy jobDurationStrategy,
TriggerMonitor triggerMonitor,
PipelineTimeline pipelineTimeline,
PipelineUnlockApiService pipelineUnlockService,
SchedulingCheckerService schedulingCheckerService, PipelineLockService pipelineLockService,
PipelinePauseService pipelinePauseService) {
this.pipelineDao = pipelineDao;
this.stageDao = stageDao;
this.goConfigService = goConfigService;
this.securityService = securityService;
this.scheduleService = scheduleService;
this.materialRepository = materialRepository;
this.triggerMonitor = triggerMonitor;
this.pipelineTimeline = pipelineTimeline;
this.jobDurationStrategy = jobDurationStrategy;
this.pipelineUnlockService = pipelineUnlockService;
this.schedulingCheckerService = schedulingCheckerService;
this.pipelineLockService = pipelineLockService;
this.pipelinePauseService = pipelinePauseService;
}
public int totalCount(String pipelineName) {
return pipelineDao.count(pipelineName);
}
public PipelineInstanceModel load(long id, Username username, OperationResult result) {
PipelineInstanceModel pipeline = pipelineDao.loadHistory(id);
if (pipeline == null) {
result.notFound("Not Found", "Pipeline not found", HealthStateType.general(HealthStateScope.GLOBAL));
return null;
}
PipelineConfig pipelineConfig = goConfigService.currentCruiseConfig().pipelineConfigByName(new CaseInsensitiveString(pipeline.getName()));
if (!securityService.hasViewPermissionForPipeline(username, pipeline.getName())) {
result.unauthorized("Unauthorized", NOT_AUTHORIZED_TO_VIEW_PIPELINE, HealthStateType.general(HealthStateScope.forPipeline(pipeline.getName())));
return null;
}
populatePipelineInstanceModel(username, false, pipelineConfig, pipeline);
return pipeline;
}
public PipelineInstanceModel loadPipelineForShine(long id) {// TODO: Fix method name - Sachin & JJ
PipelineInstanceModel pipeline = pipelineDao.loadHistory(id);
PipelineConfig pipelineConfig = goConfigService.currentCruiseConfig().pipelineConfigByName(new CaseInsensitiveString(pipeline.getName()));
populatePipelineInstanceModel(pipelineConfig, pipeline);
return pipeline;
}
public PipelineInstanceModels load(String pipelineName, Pagination pagination, String username, boolean populateCanRun) {
PipelineInstanceModels history = pipelineDao.loadHistory(pipelineName, pagination.getPageSize(), pagination.getOffset());
PipelineConfig pipelineConfig = goConfigService.pipelineConfigNamed(new CaseInsensitiveString(pipelineName));
for (PipelineInstanceModel pipelineInstanceModel : history) {
populatePipelineInstanceModel(new Username(new CaseInsensitiveString(username)), populateCanRun, pipelineConfig, pipelineInstanceModel);
}
addEmptyPipelineInstanceIfNeeded(pipelineName, history, new Username(new CaseInsensitiveString(username)), pipelineConfig, populateCanRun);
return history;
}
/*
* Load just enough data for Pipeline History API. The API is complete enough to build Pipeline History Page. Does following:
* Exists check, Authorized check, Loads paginated pipeline data, Populates build-cause,
* Populates future stages as empty, Populates can run for pipeline & each stage, Populate stage run permission
*/
public PipelineInstanceModels loadMinimalData(String pipelineName, Pagination pagination, Username username, OperationResult result) {
if (!goConfigService.currentCruiseConfig().hasPipelineNamed(new CaseInsensitiveString(pipelineName))) {
result.notFound("Not Found", "Pipeline " + pipelineName + " not found", HealthStateType.general(HealthStateScope.GLOBAL));
return null;
}
if (!securityService.hasViewPermissionForPipeline(username, pipelineName)) {
result.unauthorized("Unauthorized", NOT_AUTHORIZED_TO_VIEW_PIPELINE, HealthStateType.general(HealthStateScope.forPipeline(pipelineName)));
return null;
}
PipelineInstanceModels history = pipelineDao.loadHistory(pipelineName, pagination.getPageSize(), pagination.getOffset());
for (PipelineInstanceModel pipelineInstanceModel : history) {
populateMaterialRevisionsOnBuildCause(pipelineInstanceModel);
populatePlaceHolderStages(pipelineInstanceModel);
populateCanRunStatus(username, pipelineInstanceModel);
populateStageOperatePermission(pipelineInstanceModel, username);
}
return history;
}
public PipelineStatusModel getPipelineStatus(String pipelineName, String username, OperationResult result) {
PipelineConfig pipelineConfig = goConfigService.currentCruiseConfig().getPipelineConfigByName(new CaseInsensitiveString(pipelineName));
if (pipelineConfig == null) {
result.notFound("Not Found", "Pipeline not found", HealthStateType.general(HealthStateScope.GLOBAL));
return null;
}
if (!securityService.hasViewPermissionForPipeline(Username.valueOf(username), pipelineName)) {
result.unauthorized("Unauthorized", NOT_AUTHORIZED_TO_VIEW_PIPELINE, HealthStateType.general(HealthStateScope.forPipeline(pipelineName)));
return null;
}
PipelinePauseInfo pipelinePauseInfo = pipelinePauseService.pipelinePauseInfo(pipelineName);
boolean isCurrentlyLocked = pipelineLockService.isLocked(pipelineName);
boolean isSchedulable = schedulingCheckerService.canManuallyTrigger(pipelineConfig, username, new ServerHealthStateOperationResult());
return new PipelineStatusModel(isCurrentlyLocked, isSchedulable, pipelinePauseInfo);
}
private void populatePipelineInstanceModel(Username username, boolean populateCanRun, PipelineConfig pipelineConfig, PipelineInstanceModel pipelineInstanceModel) {
populatePipelineInstanceModel(pipelineConfig, pipelineInstanceModel);
if (populateCanRun) {
//make sure this happens after the placeholder stage is populated
populateCanRunStatus(username, pipelineInstanceModel);
}
populateStageOperatePermission(pipelineInstanceModel, username);
}
private void populatePipelineInstanceModel(PipelineConfig pipelineConfig, PipelineInstanceModel pipelineInstanceModel) {
if (pipelineInstanceModel.getId() > 0) {
CaseInsensitiveString pipelineName = new CaseInsensitiveString(pipelineInstanceModel.getName());
pipelineInstanceModel.setPipelineAfter(pipelineTimeline.runAfter(pipelineInstanceModel.getId(), pipelineName));
pipelineInstanceModel.setPipelineBefore(pipelineTimeline.runBefore(pipelineInstanceModel.getId(), pipelineName));
}
populatePlaceHolderStages(pipelineInstanceModel);
populateMaterialRevisionsOnBuildCause(pipelineInstanceModel);
pipelineInstanceModel.setMaterialConfigs(pipelineConfig.materialConfigs());
pipelineInstanceModel.setLatestRevisions(materialRepository.findLatestRevisions(pipelineConfig.materialConfigs()));
}
//we need placeholder stage for unscheduled stages in pipeline, so we can trigger it
private void populatePlaceHolderStages(PipelineInstanceModel pipeline) {
StageInstanceModels stageHistory = pipeline.getStageHistory();
String pipelineName = pipeline.getName();
appendFollowingStagesFromConfig(pipelineName, stageHistory);
}
private void appendFollowingStagesFromConfig(String pipelineName, StageInstanceModels stageHistory) {
PipelineConfig pipelineConfig = goConfigService.pipelineConfigNamed(new CaseInsensitiveString(pipelineName));
StageInstanceModel lastStage = stageHistory.last();
StageConfig nextStage = lastStage == null ? pipelineConfig.getFirstStageConfig() : pipelineConfig.nextStage(new CaseInsensitiveString(lastStage.getName()));
while (nextStage != null && !stageHistory.hasStage(CaseInsensitiveString.str(nextStage.name()))) {
stageHistory.addFutureStage(CaseInsensitiveString.str(nextStage.name()), !nextStage.requiresApproval());
nextStage = pipelineConfig.nextStage(nextStage.name());
}
}
private void populateCanRunStatus(Username username, PipelineInstanceModel pipelineInstanceModel) {
for (StageInstanceModel stageHistoryItem : pipelineInstanceModel.getStageHistory()) {
boolean canRun = scheduleService.canRun(
pipelineInstanceModel.getPipelineIdentifier(), stageHistoryItem.getName(),
CaseInsensitiveString.str(username.getUsername()), pipelineInstanceModel.hasPreviousStageBeenScheduled(
stageHistoryItem.getName()));
stageHistoryItem.setCanRun(canRun);
}
populatePipelineCanRunStatus(username, pipelineInstanceModel);
}
private void populatePipelineCanRunStatus(Username username, PipelineInstanceModel pipelineInstanceModel) {
boolean canPipelineRun = schedulingCheckerService.canManuallyTrigger(pipelineInstanceModel.getName(), username);
pipelineInstanceModel.setCanRun(canPipelineRun);
}
public PipelineInstanceModels findPipelineInstances(String pipelineName, String pipelineLabel, int count, String username) {
PipelineInstanceModels history = pipelineDao.loadHistory(pipelineName, count, pipelineLabel);
addPlaceholderStages(history);
addEmptyPipelineInstanceIfNeeded(pipelineName, history, new Username(new CaseInsensitiveString(username)), goConfigService.pipelineConfigNamed(new CaseInsensitiveString(pipelineName)), false);
applySecurity(history, pipelineName, username);
applyCanRun(new Username(new CaseInsensitiveString(username)), history);
return history;
}
public int getPageNumberForCounter(String pipelineName, int pipelineCounter, int limit) {
return pipelineDao.getPageNumberForCounter(pipelineName, pipelineCounter, limit);
}
private void addEmptyPipelineInstanceIfNeeded(String pipelineName, PipelineInstanceModels history, Username username, PipelineConfig pipelineConfig, boolean populateCanRun) {
if (history.isEmpty()) {
PipelineInstanceModel model = addEmptyPipelineInstance(pipelineName, username, pipelineConfig, populateCanRun);
history.add(model);
}
}
private PipelineInstanceModel addEmptyPipelineInstance(String pipelineName, Username username, PipelineConfig pipelineConfig, boolean populateCanRun) {
StageInstanceModels stageHistory = new StageInstanceModels();
appendFollowingStagesFromConfig(pipelineName, stageHistory);
PipelineInstanceModel model = PipelineInstanceModel.createEmptyPipelineInstanceModel(pipelineName, BuildCause.createWithEmptyModifications(), stageHistory);
populatePipelineInstanceModel(username, populateCanRun, pipelineConfig, model);
model.setCanRun(true);
return model;
}
private void applyCanRun(Username username, PipelineInstanceModels history) {
for (PipelineInstanceModel pipelineInstanceModel : history) {
populateCanRunStatus(username, pipelineInstanceModel);
}
}
private void addPlaceholderStages(PipelineInstanceModels history) {
for (PipelineInstanceModel pipelineInstanceModel : history) {
populatePlaceHolderStages(pipelineInstanceModel);
}
}
private void applySecurity(PipelineInstanceModels history, String pipelineName, String username) {
if (!securityService.hasViewPermissionForPipeline(new Username(new CaseInsensitiveString(username)), pipelineName)) {
history.clear();
}
}
public PipelineInstanceModels loadWithEmptyAsDefault(String pipelineName, Pagination pagination, String userName) {
if (!securityService.hasViewPermissionForPipeline(new Username(new CaseInsensitiveString(userName)), pipelineName)) {
return PipelineInstanceModels.createPipelineInstanceModels();
}
PipelineInstanceModels pipelineInstanceModels = null;
if (triggerMonitor.isAlreadyTriggered(pipelineName)) {
StageInstanceModels stageHistory = new StageInstanceModels();
appendFollowingStagesFromConfig(pipelineName, stageHistory);
PipelineInstanceModel model = PipelineInstanceModel.createPreparingToSchedule(pipelineName, stageHistory);
model.setCanRun(false);
pipelineInstanceModels = PipelineInstanceModels.createPipelineInstanceModels(model);
} else {
pipelineInstanceModels = load(pipelineName, pagination, userName, true);
}
return pipelineInstanceModels;
}
public PipelineInstanceModel latest(String pipelineName, Username username) {
PipelineInstanceModels models = loadWithEmptyAsDefault(pipelineName, Pagination.ONE_ITEM, CaseInsensitiveString.str(username.getUsername()));
return models.isEmpty() ? null : models.get(0);
}
public PipelineInstanceModels latestInstancesForConfiguredPipelines(Username username) {
PipelineInstanceModels pipelineInstances = PipelineInstanceModels.createPipelineInstanceModels();
for (PipelineConfigs group : goConfigService.currentCruiseConfig().getGroups()) {
for (PipelineConfig pipelineConfig : group) {
PipelineInstanceModel pipelineInstanceModel = latest(CaseInsensitiveString.str(pipelineConfig.name()), username);
if (pipelineInstanceModel != null) {
pipelineInstances.add(pipelineInstanceModel);
}
}
}
return pipelineInstances;
}
public PipelineInstanceModels findAllPipelineInstances(String pipelineName, Username username, HttpOperationResult result) {
if (!validate(pipelineName, username, result)) {
return null;
}
return pipelineDao.loadHistory(pipelineName);
}
public boolean validate(String pipelineName, Username username, OperationResult result) {
if (!goConfigService.hasPipelineNamed(new CaseInsensitiveString(pipelineName))) {
String pipelineNotKnown = String.format("Pipeline named [%s] is not known.", pipelineName);
result.notFound(pipelineNotKnown, pipelineNotKnown, HealthStateType.general(HealthStateScope.GLOBAL));
return false;
}
if (!securityService.hasViewPermissionForPipeline(username, pipelineName)) {
result.unauthorized(NOT_AUTHORIZED_TO_VIEW_PIPELINE, NOT_AUTHORIZED_TO_VIEW_PIPELINE, HealthStateType.general(HealthStateScope.forPipeline(pipelineName)));
return false;
}
return true;
}
public PipelineDependencyGraphOld pipelineDependencyGraph(String pipelineName, int pipelineCounter, final Username username, OperationResult result) {
if (!validate(pipelineName, username, result)) {
return null;
}
PipelineDependencyGraphOld graph = pipelineDao.pipelineGraphByNameAndCounter(pipelineName, pipelineCounter);
if (graph == null) {
String message = String.format("Pipeline [%s] with counter [%s] is not found", pipelineName, pipelineCounter);
result.notFound(message, message, HealthStateType.general(HealthStateScope.forPipeline(pipelineName)));
return null;
}
removePipelinesThatAreNotInConfig(username, graph);
addConfiguredPipelinesThatAreNotRunYet(username, graph, goConfigService.downstreamPipelinesOf(pipelineName));
populatePipelineState(graph.pipeline(), username);
for (PipelineInstanceModel pipelineInstanceModel : graph.dependencies()) {
populateDownstreamPipelineState(username, pipelineInstanceModel);
}
return graph;
}
private void populateDownstreamPipelineState(Username username, PipelineInstanceModel pipelineInstanceModel) {
populatePlaceHolderStages(pipelineInstanceModel);
populatePipelineCanRunStatus(username,pipelineInstanceModel);
populateCanRunStatus(username, pipelineInstanceModel);
populateStageOperatePermission(pipelineInstanceModel, username);
pipelineInstanceModel.setMaterialConfigs(goConfigService.materialConfigsFor(new CaseInsensitiveString(pipelineInstanceModel.getName())));
}
private void removePipelinesThatAreNotInConfig(final Username username, PipelineDependencyGraphOld graph) {
graph.filterDependencies(new PipelineDependencyGraphOld.Filterer() {
public boolean filterPipeline(String pipelineName) {
return goConfigService.hasPipelineNamed(new CaseInsensitiveString(pipelineName)) && securityService.hasViewPermissionForPipeline(username, pipelineName);
}
});
}
private void addConfiguredPipelinesThatAreNotRunYet(Username username, PipelineDependencyGraphOld graph, List<PipelineConfig> dependents) {
for (PipelineConfig dependent : dependents) {
if(!graph.hasDependent(CaseInsensitiveString.str(dependent.name()))){
graph.addDependent(addEmptyPipelineInstance(CaseInsensitiveString.str(dependent.name()), username, dependent, false));
}
}
}
private void populatePipelineState(PipelineInstanceModel instance, Username username) {
populatePlaceHolderStages(instance);
populateCanRunStatus(username,instance);
populateStageOperatePermission(instance,username);
populateLockStatus(instance.getName(), username, instance);
long id = pipelineTimeline.pipelineBefore(instance.getId());
if (id != -1) {
PipelineInstanceModel prevPipeline = pipelineDao.loadHistory(id);
instance.setPreviousPipelineLabel(prevPipeline.getLabel());
instance.setPreviousPipelineCounter(prevPipeline.getCounter());
}
}
public PipelineInstanceModel findPipelineInstance(String pipelineName, int pipelineCounter, Username username, OperationResult result) {
return decoratePIM(pipelineName, pipelineCounter, username, result, pipelineDao.findPipelineHistoryByNameAndCounter(pipelineName, pipelineCounter));
}
public PipelineInstanceModel findPipelineInstance(String pipelineName, int pipelineCounter, long id, Username username, OperationResult result) {
return decoratePIM(pipelineName, pipelineCounter, username, result, pipelineDao.loadHistoryByIdWithBuildCause(id));
}
private PipelineInstanceModel decoratePIM(String pipelineName, int pipelineCounter, Username username, OperationResult result, PipelineInstanceModel pipelineInstanceModel) {
if (!validate(pipelineName, username, result)) {
return null;
}
if (pipelineInstanceModel == null && pipelineCounter == 0){
pipelineInstanceModel = PipelineInstanceModel.createEmptyPipelineInstanceModel(pipelineName, BuildCause.createWithEmptyModifications(), new StageInstanceModels());
}
if (pipelineInstanceModel == null) {
String pipelineInstanceNotFound = String.format("Pipeline [%s/%s] not found.", pipelineName, pipelineCounter);
result.notFound(pipelineInstanceNotFound, pipelineInstanceNotFound, HealthStateType.general(HealthStateScope.GLOBAL));
return null;
}
populatePlaceHolderStages(pipelineInstanceModel);
populateStageOperatePermission(pipelineInstanceModel, username);
populateCanRunStatus(username, pipelineInstanceModel);
populateLockStatus(pipelineName, username, pipelineInstanceModel);
return pipelineInstanceModel;
}
private void populateLockStatus(String pipelineName, Username username, PipelineInstanceModel pipelineInstanceModel) {
pipelineInstanceModel.setCanUnlock(pipelineUnlockService.canUnlock(pipelineName, username, new HttpOperationResult()));
pipelineInstanceModel.setIsLockable(goConfigService.isLockable(pipelineName));
pipelineInstanceModel.setCurrentlyLocked(pipelineLockService.isLocked(pipelineName));
}
private void populateStageOperatePermission(PipelineInstanceModel pipelineInstanceModel, Username username) {
for (StageInstanceModel stage : pipelineInstanceModel.getStageHistory()) {
stage.setOperatePermission(securityService.hasOperatePermissionForStage(pipelineInstanceModel.getName(), stage.getName(), CaseInsensitiveString.str(username.getUsername())));
}
}
public List<PipelineGroupModel> allActivePipelineInstances(Username username, PipelineSelections pipelineSelections) {
PipelineGroupModels groupModels = allPipelineInstances(username);
filterSelections(groupModels,pipelineSelections);
removeEmptyGroups(groupModels);
updateGroupAdministrability(username, groupModels);
return groupModels.asList();
}
public List<PipelineGroupModel> getActivePipelineInstance(Username username, String pipeline) {
PipelineGroupModels models = allPipelineInstances(username);
filterSelections(models, PipelineSelections.singleSelection(pipeline));
removeEmptyGroups(models);
return models.asList();
}
private PipelineGroupModels allPipelineInstances(Username username) {
CruiseConfig currentConfig = goConfigService.currentCruiseConfig();
PipelineGroups groups = currentConfig.getGroups();
PipelineInstanceModels activePipelines = filterPermissions(pipelineDao.loadActivePipelines(), username);
PipelineGroupModels groupModels = new PipelineGroupModels();
for (PipelineConfig pipelineConfig : currentConfig.getAllPipelineConfigs()) {
CaseInsensitiveString pipelineName = pipelineConfig.name();
for (PipelineInstanceModel activePipeline : activePipelines.findAll(CaseInsensitiveString.str(pipelineName))) {
activePipeline.setTrackingTool(pipelineConfig.getTrackingTool());
activePipeline.setMingleConfig(pipelineConfig.getMingleConfig());
populatePlaceHolderStages(activePipeline);
String groupName = groups.findGroupNameByPipeline(pipelineName);
if (groupName == null) {
throw new RuntimeException("Unable to find group find pipeline " + pipelineName);
}
populatePreviousStageState(activePipeline);
populateLockStatus(activePipeline.getName(), username, activePipeline);
boolean canForce = schedulingCheckerService.canManuallyTrigger(CaseInsensitiveString.str(pipelineName), username);
PipelinePauseInfo pauseInfo = pipelinePauseService.pipelinePauseInfo(CaseInsensitiveString.str(pipelineName));
groupModels.addPipelineInstance(groupName, activePipeline, canForce, securityService.hasOperatePermissionForPipeline(
username.getUsername(), CaseInsensitiveString.str(pipelineName)
), pauseInfo);
}
}
for (PipelineConfigs group : groups) {
populateMissingPipelines(username, groupModels, group);
}
return groupModels;
}
private void filterSelections(PipelineGroupModels groupModels, PipelineSelections pipelineSelections) {
for (PipelineGroupModel groupModel : groupModels.asList()) {
for (PipelineModel pipelineModel : groupModel.getPipelineModels()) {
if(!pipelineSelections.includesPipeline(pipelineModel.getName())){
groupModels.removePipeline(groupModel,pipelineModel);
}
}
}
}
private void removeEmptyGroups(PipelineGroupModels groupModels) {
for (PipelineGroupModel pipelineGroupModel : groupModels.asList()) {
if(pipelineGroupModel.getPipelineModels().isEmpty()){
groupModels.remove(pipelineGroupModel);
}
}
}
private void updateGroupAdministrability(Username username, PipelineGroupModels groupModels) {
for (PipelineGroupModel groupModel : groupModels.asList()) {
if (!goConfigService.isUserAdminOfGroup(username.getUsername(), groupModel.getName())) {
continue;
}
for (PipelineModel pipelineModel : groupModel.getPipelineModels()) {
if(goConfigService.isPipelineEditableViaUI(pipelineModel.getName()))
pipelineModel.updateAdministrability(true);
}
}
}
private void populatePreviousStageState(PipelineInstanceModel activePipeline) {
if (activePipeline.isAnyStageActive()) {
StageInstanceModel activeStage = activePipeline.activeStage();
StageInstanceModel latestActive = null;
long id = activePipeline.getId();
do {
PipelineTimelineEntry timelineEntry = pipelineTimeline.runBefore(id, new CaseInsensitiveString(activePipeline.getName()));
if (timelineEntry == null) {
break;
}
id = timelineEntry.getId();
PipelineInstanceModel instanceModel = pipelineDao.loadHistory(id);
if (instanceModel != null && instanceModel.hasStageBeenRun(activeStage.getName())) {
latestActive = instanceModel.getStageHistory().byName(activeStage.getName());
}
} while (latestActive == null);
activeStage.setPreviousStage(latestActive);
}
}
private void populateMissingPipelines(Username username, PipelineGroupModels groupModels, PipelineConfigs group) {
String groupName = group.getGroup();
for (PipelineConfig pipelineConfig : group) {
if (!groupModels.containsPipeline(groupName, CaseInsensitiveString.str(pipelineConfig.name()))) {
PipelineModel latestPipeline = latestPipelineModel(username, CaseInsensitiveString.str(pipelineConfig.name()));
if (latestPipeline != null) {
groupModels.addPipelineInstance(groupName, latestPipeline.getLatestPipelineInstance(), latestPipeline.canForce(), latestPipeline.canOperate(), latestPipeline.getPausedInfo());
}
}
}
}
private PipelineInstanceModels filterPermissions(PipelineInstanceModels pipelineInstanceModels, Username username) {
PipelineInstanceModels newModels = PipelineInstanceModels.createPipelineInstanceModels();
for (PipelineInstanceModel pipelineInstanceModel : pipelineInstanceModels) {
if (securityService.hasViewPermissionForPipeline(username, pipelineInstanceModel.getName())) {
newModels.add(pipelineInstanceModel);
}
}
return newModels;
}
public PipelineModel latestPipelineModel(Username username, String pipelineName) {
PipelineInstanceModel instanceModel = latest(pipelineName, username);
if (instanceModel != null) {
boolean canForce = schedulingCheckerService.canManuallyTrigger(pipelineName, username);
PipelinePauseInfo pauseInfo = pipelinePauseService.pipelinePauseInfo(pipelineName);
PipelineModel pipelineModel = new PipelineModel(pipelineName, canForce, securityService.hasOperatePermissionForPipeline(
username.getUsername(), pipelineName
), pauseInfo);
populateLockStatus(instanceModel.getName(), username, instanceModel);
pipelineModel.addPipelineInstance(instanceModel);
String groupName = goConfigService.findGroupNameByPipeline(new CaseInsensitiveString(pipelineName));
if(goConfigService.isPipelineEditableViaUI(pipelineName))
pipelineModel.updateAdministrability(goConfigService.isUserAdminOfGroup(username.getUsername(), groupName));
else
pipelineModel.updateAdministrability(false);
return pipelineModel;
}
return null;
}
public PipelineInstanceModels findPipelineInstancesByPageNumber(String pipelineName, int pageNumber, int limit, String userName) {
Pagination pagination = Pagination.pageByNumber(pageNumber, totalCount(pipelineName), limit);
PipelineInstanceModels instanceModels = load(pipelineName, pagination, userName, false);
instanceModels.setPagination(pagination);
return instanceModels;
}
public PipelineInstanceModels findMatchingPipelineInstances(String pipelineName, String pattern, int limit, Username userName, HttpLocalizedOperationResult result) {
pattern = escapeWildCardsAndTrim(pattern.trim());
if (!securityService.hasViewPermissionForPipeline(userName, pipelineName)) {
result.unauthorized(LocalizedMessage.cannotViewPipeline(pipelineName), HealthStateType.general(HealthStateScope.forPipeline(pipelineName)));
return PipelineInstanceModels.createPipelineInstanceModels();
}
PipelineInstanceModels models = pipelineDao.findMatchingPipelineInstances(pipelineName, pattern, limitForPipeline(pipelineName, limit));
for (PipelineInstanceModel model : models) {
populatePlaceHolderStages(model);
populateMaterialRevisionsOnBuildCause(model);
}
return models;
}
private String escapeWildCardsAndTrim(String pattern) {
pattern = pattern.replace("%", "\\%" ).replace("_", "\\_");
return pattern;
}
private int limitForPipeline(String pipelineName, int limit) {
return goConfigService.pipelineConfigNamed(new CaseInsensitiveString(pipelineName)).size() * limit;
}
private void populateMaterialRevisionsOnBuildCause(PipelineInstanceModel model) {
model.setMaterialRevisionsOnBuildCause(materialRepository.findMaterialRevisionsForPipeline(model.getId()));
}
public void updateComment(String pipelineName, int pipelineCounter, String comment, Username username, HttpLocalizedOperationResult result) {
if (!Toggles.isToggleOn(Toggles.PIPELINE_COMMENT_FEATURE_TOGGLE_KEY)) {
result.notImplemented(LocalizedMessage.string("FEATURE_NOT_AVAILABLE", "Pipeline Comment"));
return;
}
if (securityService.hasOperatePermissionForPipeline(username.getUsername(), pipelineName)) {
pipelineDao.updateComment(pipelineName, pipelineCounter, comment);
} else {
result.unauthorized(LocalizedMessage.cannotOperatePipeline(pipelineName), HealthStateType.general(HealthStateScope.forPipeline(pipelineName)));
}
}
private static class PipelineGroupModels {
List<PipelineGroupModel> groupModels = new ArrayList<>();
public void addPipelineInstance(String groupName, PipelineInstanceModel pipelineInstanceModel, boolean canForce, boolean canOperate, PipelinePauseInfo pipelinePauseInfo) {
PipelineModel pipelineModel = pipelineModelForPipelineName(groupName, pipelineInstanceModel.getName(), canForce, canOperate, pipelinePauseInfo);
pipelineModel.addPipelineInstance(pipelineInstanceModel);
}
public boolean containsPipeline(String groupName, String pipelineName) {
return get(groupName).containsPipeline(pipelineName);
}
public List<PipelineGroupModel> asList() {
return new ArrayList<>(groupModels);
}
private PipelineModel pipelineModelForPipelineName(String groupName, String pipelineName, boolean canForce, boolean canOperate, PipelinePauseInfo pipelinePauseInfo){
PipelineGroupModel group = get(groupName);
return group.pipelineModelForPipelineName(pipelineName, canForce, canOperate, pipelinePauseInfo);
}
private PipelineGroupModel get(String groupName) {
for (PipelineGroupModel groupModel : groupModels) {
if (groupModel.getName().equals(groupName)) {
return groupModel;
}
}
PipelineGroupModel newGroupModel = new PipelineGroupModel(groupName);
groupModels.add(newGroupModel);
return newGroupModel;
}
public void removePipeline(PipelineGroupModel groupModel, PipelineModel pipelineModel) {
groupModel.remove(pipelineModel);
if(groupModel.getPipelineModels().isEmpty()){
groupModels.remove(groupModel);
}
}
public void remove(PipelineGroupModel pipelineGroupModel) {
groupModels.remove(pipelineGroupModel);
}
}
}