diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/AbstractDeployStrategyStage.groovy b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/AbstractDeployStrategyStage.groovy index 97783392b4..bb54451069 100644 --- a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/AbstractDeployStrategyStage.groovy +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/AbstractDeployStrategyStage.groovy @@ -111,7 +111,7 @@ abstract class AbstractDeployStrategyStage extends AbstractCloudProviderAwareSta Strategy strategy = getStrategy(parent) def preProcessors = deployStagePreProcessors.findAll { it.supports(parent) } def stageData = parent.mapTo(StageData) - def stages = [] + List stages = new ArrayList<>() stages.addAll(strategy.composeBeforeStages(parent)) preProcessors.each { diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/MonitoredDeployStrategy.groovy b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/MonitoredDeployStrategy.groovy index a6a318e923..a1b1fc2b79 100644 --- a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/MonitoredDeployStrategy.groovy +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/MonitoredDeployStrategy.groovy @@ -22,6 +22,7 @@ import com.netflix.spinnaker.orca.clouddriver.pipeline.cluster.ScaleDownClusterS import com.netflix.spinnaker.orca.clouddriver.pipeline.monitoreddeploy.NotifyDeployCompletedStage import com.netflix.spinnaker.orca.clouddriver.pipeline.monitoreddeploy.NotifyDeployStartingStage import com.netflix.spinnaker.orca.clouddriver.pipeline.monitoreddeploy.EvaluateDeploymentHealthStage +import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.CloneServerGroupStage import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.CreateServerGroupStage import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.DisableServerGroupStage import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.ResizeServerGroupStage @@ -74,18 +75,28 @@ class MonitoredDeployStrategy implements Strategy { DeploymentMonitorServiceProvider deploymentMonitorServiceProvider @Override - List composeBeforeStages(Stage parent) { - return composeFlow(parent) - .findAll({ it.syntheticStageOwner == SyntheticStageOwner.STAGE_BEFORE }) - } + List composeBeforeStages(Stage stage) { + if (stage.context.useSourceCapacity) { + stage.context.useSourceCapacity = false + } - @Override - List composeAfterStages(Stage parent) { - return composeFlow(parent) - .findAll({ it.syntheticStageOwner == SyntheticStageOwner.STAGE_AFTER }) + // we expect a capacity object if a fixed capacity has been requested or as a fallback value when we are copying + // the capacity from the current server group + def savedCapacity = stage.context.savedCapacity ?: stage.context.capacity?.clone() + stage.context.savedCapacity = savedCapacity + + // FIXME: this clobbers the input capacity value (if any). Should find a better way to request a new asg of size 0 + stage.context.capacity = [ + min : 0, + max : 0, + desired: 0 + ] + + return Collections.emptyList() } - List composeFlow(Stage stage) { + @Override + List composeAfterStages(Stage stage) { def stages = [] def stageData = stage.mapTo(MonitoredDeployStageData) def cleanupConfig = AbstractDeployStrategyStage.CleanupConfig.fromStage(stage) @@ -98,21 +109,9 @@ class MonitoredDeployStrategy implements Strategy { cloudProvider : cleanupConfig.cloudProvider, ] - if (stage.context.useSourceCapacity) { - stage.context.useSourceCapacity = false - } - // we expect a capacity object if a fixed capacity has been requested or as a fallback value when we are copying // the capacity from the current server group - def savedCapacity = stage.context.savedCapacity ?: stage.context.capacity?.clone() - stage.context.savedCapacity = savedCapacity - - // FIXME: this clobbers the input capacity value (if any). Should find a better way to request a new asg of size 0 - stage.context.capacity = [ - min : 0, - max : 0, - desired: 0 - ] + def savedCapacity = stage.context.savedCapacity def deploySteps = stageData.getDeploySteps() if (deploySteps.isEmpty() || deploySteps[-1] != 100) { @@ -132,23 +131,16 @@ class MonitoredDeployStrategy implements Strategy { try { StageData.Source sourceServerGroup - Stage parentCreateServerGroupStage = stage.directAncestors().find() { it.type == CreateServerGroupStage.PIPELINE_CONFIG_TYPE } - - if (parentCreateServerGroupStage.status == ExecutionStatus.NOT_STARTED) { - // No point in composing the flow if we are called to plan "beforeStages" since we don't have any STAGE_BEFOREs. - // Also, we rely on the the source server group task to have run already. - // In the near future we will move composeFlow into beforeStages and afterStages instead of the - // deprecated aroundStages - return [] - } + Stage parentCreateServerGroupStage = stage.directAncestors() + .find() { it.type == CreateServerGroupStage.PIPELINE_CONFIG_TYPE || it.type == CloneServerGroupStage.PIPELINE_CONFIG_TYPE } StageData parentStageData = parentCreateServerGroupStage.mapTo(StageData) sourceServerGroup = parentStageData.source - if (sourceServerGroup != null && sourceServerGroup.serverGroupName != null) { + if (sourceServerGroup != null && (sourceServerGroup.serverGroupName != null || sourceServerGroup.asgName != null)) { source = new ResizeStrategy.Source( region: sourceServerGroup.region, - serverGroupName: sourceServerGroup.serverGroupName, + serverGroupName: sourceServerGroup.serverGroupName ?: sourceServerGroup.asgName, credentials: stageData.credentials ?: stageData.account, cloudProvider: stageData.cloudProvider ) diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RedBlackStrategy.groovy b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RedBlackStrategy.groovy index 1a6d226446..bc2a31ac41 100644 --- a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RedBlackStrategy.groovy +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RedBlackStrategy.groovy @@ -53,18 +53,12 @@ class RedBlackStrategy implements Strategy, ApplicationContextAware { @Override List composeBeforeStages(Stage parent) { - return composeFlow(parent) - .findAll({ it.syntheticStageOwner == SyntheticStageOwner.STAGE_BEFORE }) + return Collections.emptyList() } @Override - List composeAfterStages(Stage parent) { - return composeFlow(parent) - .findAll({ it.syntheticStageOwner == SyntheticStageOwner.STAGE_AFTER }) - } - - List composeFlow(Stage stage) { - List stages = [] + List composeAfterStages(Stage stage) { + List stages = new ArrayList<>() StageData stageData = stage.mapTo(StageData) Map baseContext = AbstractDeployStrategyStage.CleanupConfig.toContext(stageData) @@ -72,19 +66,12 @@ class RedBlackStrategy implements Strategy, ApplicationContextAware { if (parentCreateServerGroupStage == null) { throw new IllegalStateException("Failed to determine source server group from parent stage while planning red/black flow") } - if (parentCreateServerGroupStage.status == ExecutionStatus.NOT_STARTED) { - // No point in composing the flow if we are called to plan "beforeStages" since we don't have any STAGE_BEFOREs. - // Also, we rely on the the source server group task to have run already. - // In the near future we will move composeFlow into beforeStages and afterStages instead of the - // deprecated aroundStages - return [] - } StageData parentStageData = parentCreateServerGroupStage.mapTo(StageData) StageData.Source sourceServerGroup = parentStageData.source // Short-circuit if there is no source server group - if (sourceServerGroup == null || sourceServerGroup.serverGroupName == null) { + if (sourceServerGroup == null || (sourceServerGroup.serverGroupName == null && sourceServerGroup.asgName == null)) { return [] } diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RollingRedBlackStrategy.groovy b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RollingRedBlackStrategy.groovy index 58e22d6e6e..4faef14044 100644 --- a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RollingRedBlackStrategy.groovy +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RollingRedBlackStrategy.groovy @@ -15,8 +15,8 @@ */ package com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.strategies -import com.netflix.spinnaker.orca.ExecutionStatus import com.netflix.spinnaker.orca.clouddriver.pipeline.cluster.ScaleDownClusterStage +import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.CloneServerGroupStage import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.CreateServerGroupStage import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.DisableServerGroupStage import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.ResizeServerGroupStage @@ -60,42 +60,20 @@ class RollingRedBlackStrategy implements Strategy, ApplicationContextAware { ScaleDownClusterStage scaleDownClusterStage @Override - List composeBeforeStages(Stage parent) { - return composeFlow(parent) - .findAll({ it.syntheticStageOwner == SyntheticStageOwner.STAGE_BEFORE }) - } - - @Override - List composeAfterStages(Stage parent) { - return composeFlow(parent) - .findAll({ it.syntheticStageOwner == SyntheticStageOwner.STAGE_AFTER }) - } - - List composeFlow(Stage stage) { + List composeBeforeStages(Stage stage) { if (!pipelineStage) { throw new IllegalStateException("Rolling red/black cannot be run without front50 enabled. Please set 'front50.enabled: true' in your orca config.") } - def stages = [] def stageData = stage.mapTo(RollingRedBlackStageData) - def cleanupConfig = AbstractDeployStrategyStage.CleanupConfig.fromStage(stage) - - Map baseContext = [ - (cleanupConfig.location.singularType()): cleanupConfig.location.value, - cluster : cleanupConfig.cluster, - moniker : cleanupConfig.moniker, - credentials : cleanupConfig.account, - cloudProvider : cleanupConfig.cloudProvider, - ] + if (stage.context.useSourceCapacity) { + stage.context.useSourceCapacity = false + } if (stageData.targetSize) { stage.context.targetSize = 0 } - if (stage.context.useSourceCapacity) { - stage.context.useSourceCapacity = false - } - // we expect a capacity object if a fixed capacity has been requested or as a fallback value when we are copying // the capacity from the current server group def savedCapacity = stage.context.savedCapacity ?: stage.context.capacity?.clone() @@ -108,6 +86,27 @@ class RollingRedBlackStrategy implements Strategy, ApplicationContextAware { desired: 0 ] + return Collections.emptyList() + } + + @Override + List composeAfterStages(Stage stage) { + def stages = [] + def stageData = stage.mapTo(RollingRedBlackStageData) + def cleanupConfig = AbstractDeployStrategyStage.CleanupConfig.fromStage(stage) + + Map baseContext = [ + (cleanupConfig.location.singularType()): cleanupConfig.location.value, + cluster : cleanupConfig.cluster, + moniker : cleanupConfig.moniker, + credentials : cleanupConfig.account, + cloudProvider : cleanupConfig.cloudProvider, + ] + + // we expect a capacity object if a fixed capacity has been requested or as a fallback value when we are copying + // the capacity from the current server group + def savedCapacity = stage.context.savedCapacity + def targetPercentages = stageData.getTargetPercentages() if (targetPercentages.isEmpty() || targetPercentages[-1] != 100) { targetPercentages.add(100) @@ -124,23 +123,16 @@ class RollingRedBlackStrategy implements Strategy, ApplicationContextAware { try { StageData.Source sourceServerGroup - Stage parentCreateServerGroupStage = stage.directAncestors().find() { it.type == CreateServerGroupStage.PIPELINE_CONFIG_TYPE } - - if (parentCreateServerGroupStage.status == ExecutionStatus.NOT_STARTED) { - // No point in composing the flow if we are called to plan "beforeStages" since we don't have any STAGE_BEFOREs. - // Also, we rely on the the source server group task to have run already. - // In the near future we will move composeFlow into beforeStages and afterStages instead of the - // deprecated aroundStages - return [] - } + Stage parentCreateServerGroupStage = stage.directAncestors() + .find() { it.type == CreateServerGroupStage.PIPELINE_CONFIG_TYPE || it.type == CloneServerGroupStage.PIPELINE_CONFIG_TYPE } StageData parentStageData = parentCreateServerGroupStage.mapTo(StageData) sourceServerGroup = parentStageData.source - if (sourceServerGroup != null && sourceServerGroup.serverGroupName != null) { + if (sourceServerGroup != null && (sourceServerGroup.serverGroupName != null || sourceServerGroup.asgName != null)) { source = new ResizeStrategy.Source( region: sourceServerGroup.region, - serverGroupName: sourceServerGroup.serverGroupName, + serverGroupName: sourceServerGroup.serverGroupName ?: sourceServerGroup.asgName, credentials: stageData.credentials ?: stageData.account, cloudProvider: stageData.cloudProvider ) diff --git a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RedBlackStrategySpec.groovy b/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RedBlackStrategySpec.groovy index 96f9130d9c..ff6edc47a6 100644 --- a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RedBlackStrategySpec.groovy +++ b/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RedBlackStrategySpec.groovy @@ -17,16 +17,12 @@ package com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.strategies import com.netflix.spinnaker.kork.dynamicconfig.DynamicConfigService -import com.netflix.spinnaker.kork.dynamicconfig.SpringDynamicConfigService import com.netflix.spinnaker.moniker.Moniker import com.netflix.spinnaker.orca.ExecutionStatus import com.netflix.spinnaker.orca.clouddriver.pipeline.cluster.DisableClusterStage import com.netflix.spinnaker.orca.clouddriver.pipeline.cluster.ScaleDownClusterStage import com.netflix.spinnaker.orca.clouddriver.pipeline.cluster.ShrinkClusterStage -import com.netflix.spinnaker.orca.clouddriver.utils.TrafficGuard import com.netflix.spinnaker.orca.pipeline.WaitStage -import com.netflix.spinnaker.orca.pipeline.model.SyntheticStageOwner -import org.springframework.mock.env.MockEnvironment import spock.lang.Specification import static com.netflix.spinnaker.orca.test.model.ExecutionBuilder.pipeline @@ -34,9 +30,6 @@ import static com.netflix.spinnaker.orca.test.model.ExecutionBuilder.stage class RedBlackStrategySpec extends Specification { - def trafficGuard = Stub(TrafficGuard) - def env = new MockEnvironment() - def dynamicConfigService = Mock(DynamicConfigService) def disableClusterStage = new DisableClusterStage(dynamicConfigService) @@ -85,27 +78,23 @@ class RedBlackStrategySpec extends Specification { def stage = pipeline.stageByRef("2-deploy1") when: 'planning without having run createServerGroup' - def syntheticStages = strat.composeFlow(stage) + def beforeStages = strat.composeBeforeStages(stage) + def afterStages = strat.composeAfterStages(stage) then: - syntheticStages.size() == 0 + beforeStages.size() == 0 + afterStages.size() == 0 when: 'deploying into a new cluster (no source server group)' pipeline.stageByRef("1-create").status = ExecutionStatus.RUNNING - - then: - syntheticStages.size() == 0 - - when: 'deploying into an existing cluster' pipeline.stageByRef("1-create").context.source = [ account: "testAccount", region: "north", serverGroupName: "unit-tests-v000", asgName: "unit-tests-v000" ] - syntheticStages = strat.composeFlow(stage) - def beforeStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_BEFORE } - def afterStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_AFTER } + beforeStages = strat.composeBeforeStages(stage) + afterStages = strat.composeAfterStages(stage) then: beforeStages.isEmpty() @@ -123,9 +112,8 @@ class RedBlackStrategySpec extends Specification { when: 'maxRemainingAsgs is specified' pipeline.stageByRef("2-deploy1").context.maxRemainingAsgs = 10 - syntheticStages = strat.composeFlow(stage) - beforeStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_BEFORE } - afterStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_AFTER } + beforeStages = strat.composeBeforeStages(stage) + afterStages = strat.composeAfterStages(stage) then: beforeStages.isEmpty() @@ -136,9 +124,8 @@ class RedBlackStrategySpec extends Specification { when: 'scaleDown is true' pipeline.stageByRef("2-deploy1").context.scaleDown = true - syntheticStages = strat.composeFlow(stage) - beforeStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_BEFORE } - afterStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_AFTER } + beforeStages = strat.composeBeforeStages(stage) + afterStages = strat.composeAfterStages(stage) then: beforeStages.isEmpty() @@ -150,9 +137,8 @@ class RedBlackStrategySpec extends Specification { when: 'interestingHealthProviderNames is specified' pipeline.stageByRef("2-deploy1").context.interestingHealthProviderNames = ["Google"] - syntheticStages = strat.composeFlow(stage) - beforeStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_BEFORE } - afterStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_AFTER } + beforeStages = strat.composeBeforeStages(stage) + afterStages = strat.composeAfterStages(stage) then: beforeStages.isEmpty() @@ -163,9 +149,8 @@ class RedBlackStrategySpec extends Specification { when: 'delayBeforeDisableSec and delayBeforeScaleDownSec are specified' pipeline.stageByRef("2-deploy1").context.delayBeforeDisableSec = 5 pipeline.stageByRef("2-deploy1").context.delayBeforeScaleDownSec = 10 - syntheticStages = strat.composeFlow(stage) - beforeStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_BEFORE } - afterStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_AFTER } + beforeStages = strat.composeBeforeStages(stage) + afterStages = strat.composeAfterStages(stage) then: beforeStages.isEmpty() diff --git a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RollingRedBlackStrategySpec.groovy b/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RollingRedBlackStrategySpec.groovy index b21d4ba757..bc389ce22d 100644 --- a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RollingRedBlackStrategySpec.groovy +++ b/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/RollingRedBlackStrategySpec.groovy @@ -1,28 +1,22 @@ package com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.strategies import com.netflix.spinnaker.kork.dynamicconfig.DynamicConfigService -import com.netflix.spinnaker.kork.dynamicconfig.SpringDynamicConfigService import com.netflix.spinnaker.moniker.Moniker import com.netflix.spinnaker.orca.ExecutionStatus import com.netflix.spinnaker.orca.clouddriver.pipeline.cluster.ScaleDownClusterStage import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.DisableServerGroupStage import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.ResizeServerGroupStage import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.support.DetermineTargetServerGroupStage -import com.netflix.spinnaker.orca.clouddriver.utils.TrafficGuard import com.netflix.spinnaker.orca.front50.pipeline.PipelineStage import com.netflix.spinnaker.orca.kato.pipeline.support.ResizeStrategy import com.netflix.spinnaker.orca.pipeline.WaitStage -import com.netflix.spinnaker.orca.pipeline.model.SyntheticStageOwner -import org.springframework.mock.env.MockEnvironment import spock.lang.Specification import static com.netflix.spinnaker.orca.test.model.ExecutionBuilder.pipeline import static com.netflix.spinnaker.orca.test.model.ExecutionBuilder.stage class RollingRedBlackStrategySpec extends Specification { - def env = new MockEnvironment() def dynamicConfigService = Mock(DynamicConfigService) - def trafficGuard = Mock(TrafficGuard) def disableServerGroupStage = new DisableServerGroupStage(dynamicConfigService) def scaleDownClusterStage = new ScaleDownClusterStage(dynamicConfigService) def resizeServerGroupStage = new ResizeServerGroupStage() @@ -109,18 +103,11 @@ class RollingRedBlackStrategySpec extends Specification { determineTargetServerGroupStage: determineTargetServerGroupStage, ) - when: 'planning without having run createServerGroup' - def stage = pipeline.stageByRef("2-deploy1") - def syntheticStages = strat.composeFlow(stage) - - then: - syntheticStages.size() == 0 - when: 'planning with no targetPercentages' - pipeline.stageByRef("1-create").status = ExecutionStatus.RUNNING - syntheticStages = strat.composeFlow(stage) - def beforeStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_BEFORE } - def afterStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_AFTER } + def stage = pipeline.stageByRef("2-deploy1") + stage.status = ExecutionStatus.RUNNING + def beforeStages = strat.composeBeforeStages(stage) + def afterStages = strat.composeAfterStages(stage) then: 'default to rolling out at 100%' // we expect the output context to have a capacity of 0 so that the new asg gets created at with 0 instances @@ -139,9 +126,8 @@ class RollingRedBlackStrategySpec extends Specification { when: 'planning with [targetPercentages: [50]' stage = pipeline.stageByRef("2-deploy2") - syntheticStages = strat.composeFlow(stage) - beforeStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_BEFORE } - afterStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_AFTER } + beforeStages = strat.composeBeforeStages(stage) + afterStages = strat.composeAfterStages(stage) then: 'we roll out at 50% and then 100%' beforeStages.isEmpty() @@ -164,8 +150,7 @@ class RollingRedBlackStrategySpec extends Specification { when: 'planning with cleanup pipeline' stage = pipeline.stageByRef("2-deploy3") - syntheticStages = strat.composeFlow(stage) - afterStages = syntheticStages.findAll { it.syntheticStageOwner == SyntheticStageOwner.STAGE_AFTER } + afterStages = strat.composeAfterStages(stage) then: noExceptionThrown()