From 977d164e05ca211146afdfb937e65c8818c2c7c8 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 21 Jul 2023 15:42:20 +0000 Subject: [PATCH] fix(artifacts): consider requiredArtifactIds in expected artifacts when trigger is pipeline type (#4489) (#4490) (cherry picked from commit 45de5bc0e4632a42992eae13fe2d4bb8d964cb51) Co-authored-by: Nemesis Osorio --- .../front50/DependentPipelineStarter.groovy | 11 ++- .../DependentPipelineStarterSpec.groovy | 75 +++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarter.groovy b/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarter.groovy index 91e36beb8c..aa2f485b66 100644 --- a/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarter.groovy +++ b/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarter.groovy @@ -85,6 +85,15 @@ class DependentPipelineStarter implements ApplicationContextAware { it.expectedArtifactIds ?: [] } + // we are following a similar approach as triggers above + // expectedArtifacts can be used in triggers and stages + // for now we identified DeployManifestStage + // in ResolveDeploySourceManifestTask using ManifestEvaluator.getRequiredArtifacts + def requiredArtifactIds = pipelineConfig.get("stages", []).collectMany { + it.requiredArtifactIds ?: [] + } + expectedArtifactIds.addAll(requiredArtifactIds) + pipelineConfig.trigger = [ type : "pipeline", user : authenticationDetails?.user ?: user ?: "[anonymous]", @@ -93,7 +102,7 @@ class DependentPipelineStarter implements ApplicationContextAware { parameters : [:], strategy : suppliedParameters.strategy == true, correlationId : "${parentPipeline.id}_${parentPipelineStageId}_${pipelineConfig.id}_${parentPipeline.startTime}".toString(), - expectedArtifactIds : expectedArtifactIds + expectedArtifactIds : expectedArtifactIds.toSet().toList() ] /* correlationId is added so that two pipelines aren't triggered when a pipeline is canceled. * parentPipelineStageId is added so that a child pipeline (via pipeline stage) diff --git a/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarterSpec.groovy b/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarterSpec.groovy index 34ceb5c15c..c8d035def5 100644 --- a/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarterSpec.groovy +++ b/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarterSpec.groovy @@ -575,6 +575,81 @@ class DependentPipelineStarterSpec extends Specification { result.trigger.artifacts.findAll { it.name == "gcr.io/project/image" }.version.containsAll(["42", "1337"]) } + def "should find expected artifacts when pipeline has requiredArtifactIds and triggered by pipeline stage"() { + given: + def requiredArtifactId = "docker-artifact-id" + def expectedImage = Artifact.builder().type("docker/image").name("docker.io/org/image").build() + ArrayList expectedArtifacts = [ + ExpectedArtifact.builder().id(requiredArtifactId).matchArtifact(expectedImage).build() + ] + + def triggeredPipelineConfig = [ + name : "triggered-by-stage", + id : "triggered-id", + stages : [ + [ + name : "Deploy (Manifest)", + type : "deployManifest", + requiredArtifactIds: [requiredArtifactId] + ] + ], + expectedArtifacts: expectedArtifacts, + triggers : [], + ] + + Artifact testArtifact = Artifact.builder().type("docker/image").name("docker.io/org/image").version("alpine").build() + + def parentPipeline = pipeline { + name = "parent-pipeline" + authentication = new PipelineExecution.AuthenticationDetails("username", "account1") + pipelineConfigId = "f837d603-bcc8-41c4-8ebc-bf0b23f59108" + stage { + id = "stage1" + refId = "1" + outputs = [artifacts: [testArtifact]] + } + } + + def executionLauncher = Mock(ExecutionLauncher) + def applicationContext = new StaticApplicationContext() + applicationContext.beanFactory.registerSingleton("pipelineLauncher", executionLauncher) + dependentPipelineStarter = new DependentPipelineStarter( + applicationContext, + mapper, + new ContextParameterProcessor(), + Optional.empty(), + Optional.of(artifactUtils), + new NoopRegistry() + ) + + and: + executionLauncher.start(*_) >> { _, p -> + return pipeline { + name = p.name + id = p.name + trigger = mapper.convertValue(p.trigger, Trigger) + } + } + artifactUtils.getArtifactsForPipelineId(*_) >> { + return new ArrayList(); + } + + when: + def result = dependentPipelineStarter.trigger( + triggeredPipelineConfig, + null, + parentPipeline, + [:], + "stage1", + buildAuthenticatedUser("username", []) + ) + + then: + result.trigger.artifacts.size() == 1 + result.trigger.artifacts*.name.contains(testArtifact.name) + result.trigger.artifacts.findAll { it.name == "docker.io/org/image" }.version.containsAll(["alpine"]) + } + def "should resolve expressions in trigger"() { given: def triggeredPipelineConfig = [name: "triggered", id: "triggered", parameterConfig: [[name: 'a', default: '${2 == 2}']]]