Search in sources :

Example 1 with GenericStatus

use of org.jenkinsci.plugins.workflow.pipelinegraphanalysis.GenericStatus in project blueocean-plugin by jenkinsci.

the class PipelineNodeGraphVisitor method parallelStart.

@Override
public void parallelStart(@Nonnull FlowNode parallelStartNode, @Nonnull FlowNode branchNode, @Nonnull ForkScanner scanner) {
    if (isNodeVisitorDumpEnabled) {
        dump(String.format("parallelStart=> id: %s, name: %s, function: %s", parallelStartNode.getId(), parallelStartNode.getDisplayName(), parallelStartNode.getDisplayFunctionName()));
        dump(String.format("\tbranch=> id: %s, name: %s, function: %s", branchNode.getId(), branchNode.getDisplayName(), branchNode.getDisplayFunctionName()));
    }
    if (nestedbranches.size() != parallelBranchEndNodes.size()) {
        logger.debug(String.format("nestedBranches size: %s not equal to parallelBranchEndNodes: %s", nestedbranches.size(), parallelBranchEndNodes.size()));
        if (!parallelEnds.isEmpty()) {
            parallelEnds.pop();
        }
        return;
    }
    if (!pendingBranchEndNodes.isEmpty()) {
        logger.debug("Found parallelBranchEndNodes, but the corresponding branchStartNode yet");
        if (!parallelEnds.isEmpty()) {
            parallelEnds.pop();
        }
        return;
    }
    while (!nestedbranches.empty() && !parallelBranchEndNodes.empty()) {
        FlowNode branchStartNode = nestedbranches.pop();
        FlowNode endNode = parallelBranchEndNodes.pop();
        if (isNodeVisitorDumpEnabled) {
            dump(String.format("\tBranch with start node id: %s", branchStartNode.getId()));
        }
        TimingInfo times;
        NodeRunStatus status;
        if (endNode != null) {
            // Branch has completed
            times = StatusAndTiming.computeChunkTiming(run, chunk.getPauseTimeMillis(), branchStartNode, endNode, chunk.getNodeAfter());
            if (endNode instanceof StepAtomNode) {
                if (PipelineNodeUtil.isPausedForInputStep((StepAtomNode) endNode, inputAction)) {
                    status = new NodeRunStatus(BlueRun.BlueRunResult.UNKNOWN, BlueRun.BlueRunState.PAUSED);
                } else {
                    status = new NodeRunStatus(endNode);
                }
            } else {
                FlowNode parallelEnd = null;
                if (!parallelEnds.isEmpty()) {
                    parallelEnd = parallelEnds.peek();
                }
                GenericStatus genericStatus = StatusAndTiming.computeChunkStatus2(run, parallelStartNode, branchStartNode, endNode, parallelEnd);
                status = new NodeRunStatus(genericStatus);
            }
        } else {
            // Branch still running / paused
            long startTime = System.currentTimeMillis();
            if (branchStartNode.getAction(TimingAction.class) != null) {
                startTime = TimingAction.getStartTime(branchStartNode);
            }
            times = new TimingInfo(System.currentTimeMillis() - startTime, chunk.getPauseTimeMillis(), startTime);
            status = new NodeRunStatus(BlueRun.BlueRunResult.UNKNOWN, BlueRun.BlueRunState.RUNNING);
        }
        // keep FB happy
        assert times != null;
        FlowNodeWrapper branch = new FlowNodeWrapper(branchStartNode, status, times, run);
        // Collect any pending actions (required for most-recently-handled branch)
        ArrayList<Action> branchActions = new ArrayList<>(drainPipelineActions());
        // Add actions for this branch, which are collected when changing branches
        if (pendingActionsForBranches.containsKey(branchStartNode)) {
            branchActions.addAll(pendingActionsForBranches.get(branchStartNode));
            pendingActionsForBranches.remove(branchStartNode);
        }
        if (isNodeVisitorDumpEnabled && branchActions.size() > 0) {
            dump("\t\tAdding " + branchActions.size() + " actions to branch id: " + branch.getId());
        }
        // Check the stack for this branch, for declarative pipelines it should be non-empty even if only 1 stage
        Stack<FlowNodeWrapper> stack = stackPerEnd.get(endNode.getId());
        if (stack != null && !stack.isEmpty()) {
            if (isNodeVisitorDumpEnabled) {
                dump(String.format("\t\t\"Complex\" stages detected (%d)", stack.size()));
            }
            if (stack.size() == 1) {
                FlowNodeWrapper firstNodeWrapper = stack.pop();
                if (isNodeVisitorDumpEnabled) {
                    dump("\t\tSingle-stage branch");
                }
                // ...but first we need to poach any actions from the stage node we'll be discarding
                branchActions.addAll(firstNodeWrapper.getPipelineActions());
                if (nextStage != null) {
                    branch.addEdge(nextStage);
                }
            } else {
                if (isDeclarative()) {
                    // Declarative parallel pipeline scenario
                    // We've got nested stages for sequential stage branches and/or branch labelling purposes
                    FlowNodeWrapper firstNodeWrapper = stack.pop();
                    // Usually ignore firstNodeWrapper, but if the first stage has a different name...
                    if (!StringUtils.equals(firstNodeWrapper.getDisplayName(), branch.getDisplayName())) {
                        // we record this node so the UI can show the label for the branch...
                        if (isNodeVisitorDumpEnabled) {
                            dump("\t\tNested labelling stage detected");
                        }
                        branch.addEdge(firstNodeWrapper);
                        firstNodeWrapper.addParent(branch);
                        nodes.add(firstNodeWrapper);
                    // Note that there's no edge from this labelling node to the rest of the branch stages
                    }
                }
                // Declarative and scripted parallel pipeline scenario
                FlowNodeWrapper previousNode = branch;
                while (!stack.isEmpty()) {
                    // Grab next, link to prev, add to result
                    FlowNodeWrapper currentStage = stack.pop();
                    previousNode.addEdge(currentStage);
                    currentStage.addParent(previousNode);
                    nodes.add(currentStage);
                    previousNode = currentStage;
                }
                if (nextStage != null) {
                    previousNode.addEdge(nextStage);
                }
            }
        } else {
            if (isNodeVisitorDumpEnabled) {
                dump("\t\tSimple branch (classic pipeline)");
            }
            if (nextStage != null) {
                branch.addEdge(nextStage);
            }
        }
        branch.setPipelineActions(branchActions);
        parallelBranches.push(branch);
    }
    FlowNodeWrapper[] sortedBranches = parallelBranches.toArray(new FlowNodeWrapper[0]);
    Arrays.sort(sortedBranches, Comparator.comparing(FlowNodeWrapper::getDisplayName));
    parallelBranches.clear();
    for (FlowNodeWrapper sortedBranch : sortedBranches) {
        parallelBranches.push(sortedBranch);
    }
    for (FlowNodeWrapper p : parallelBranches) {
        nodes.push(p);
        nodeMap.put(p.getId(), p);
    }
    // Removes parallelEnd node for next parallel block
    if (!parallelEnds.isEmpty()) {
        parallelEnds.pop();
    }
}
Also used : InputAction(org.jenkinsci.plugins.workflow.support.steps.input.InputAction) LabelAction(org.jenkinsci.plugins.workflow.actions.LabelAction) ExecutionModelAction(org.jenkinsci.plugins.pipeline.modeldefinition.actions.ExecutionModelAction) Action(hudson.model.Action) PauseAction(org.jenkinsci.plugins.workflow.support.actions.PauseAction) TimingAction(org.jenkinsci.plugins.workflow.actions.TimingAction) NotExecutedNodeAction(org.jenkinsci.plugins.workflow.actions.NotExecutedNodeAction) TimingInfo(org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo) TimingAction(org.jenkinsci.plugins.workflow.actions.TimingAction) ArrayList(java.util.ArrayList) StepAtomNode(org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode) GenericStatus(org.jenkinsci.plugins.workflow.pipelinegraphanalysis.GenericStatus) FlowNode(org.jenkinsci.plugins.workflow.graph.FlowNode)

Aggregations

Action (hudson.model.Action)1 ArrayList (java.util.ArrayList)1 ExecutionModelAction (org.jenkinsci.plugins.pipeline.modeldefinition.actions.ExecutionModelAction)1 LabelAction (org.jenkinsci.plugins.workflow.actions.LabelAction)1 NotExecutedNodeAction (org.jenkinsci.plugins.workflow.actions.NotExecutedNodeAction)1 TimingAction (org.jenkinsci.plugins.workflow.actions.TimingAction)1 StepAtomNode (org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode)1 FlowNode (org.jenkinsci.plugins.workflow.graph.FlowNode)1 GenericStatus (org.jenkinsci.plugins.workflow.pipelinegraphanalysis.GenericStatus)1 TimingInfo (org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo)1 PauseAction (org.jenkinsci.plugins.workflow.support.actions.PauseAction)1 InputAction (org.jenkinsci.plugins.workflow.support.steps.input.InputAction)1