github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/tests/build/build.go (about)

     1  package build
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"os"
     8  	"strings"
     9  	"time"
    10  
    11  	tektonutils "github.com/redhat-appstudio/release-service/tekton/utils"
    12  	"k8s.io/apimachinery/pkg/runtime"
    13  
    14  	pointer "k8s.io/utils/ptr"
    15  
    16  	"github.com/google/go-github/v44/github"
    17  	appservice "github.com/redhat-appstudio/application-api/api/v1alpha1"
    18  	"github.com/redhat-appstudio/e2e-tests/pkg/clients/has"
    19  	"github.com/redhat-appstudio/e2e-tests/pkg/utils/build"
    20  	"github.com/redhat-appstudio/e2e-tests/pkg/utils/tekton"
    21  
    22  	"github.com/devfile/library/v2/pkg/util"
    23  	"github.com/redhat-appstudio/e2e-tests/pkg/constants"
    24  	"github.com/redhat-appstudio/e2e-tests/pkg/utils"
    25  	pipeline "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
    26  	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  
    29  	imagecontollers "github.com/konflux-ci/image-controller/controllers"
    30  	. "github.com/onsi/ginkgo/v2"
    31  	. "github.com/onsi/gomega"
    32  	buildservice "github.com/redhat-appstudio/build-service/api/v1alpha1"
    33  	"github.com/redhat-appstudio/build-service/controllers"
    34  	"github.com/redhat-appstudio/e2e-tests/pkg/framework"
    35  	releasecommon "github.com/redhat-appstudio/e2e-tests/tests/release"
    36  	v1 "k8s.io/api/core/v1"
    37  )
    38  
    39  var _ = framework.BuildSuiteDescribe("Build service E2E tests", Label("build", "HACBS"), func() {
    40  
    41  	var f *framework.Framework
    42  	AfterEach(framework.ReportFailure(&f))
    43  
    44  	var err error
    45  	var osConsoleHost string
    46  	defer GinkgoRecover()
    47  
    48  	Describe("test PaC component build", Ordered, Label("github-webhook", "pac-build", "pipeline", "image-controller"), func() {
    49  		var applicationName, componentName, componentBaseBranchName, pacBranchName, testNamespace, defaultBranchTestComponentName, imageRepoName, robotAccountName string
    50  		var component *appservice.Component
    51  
    52  		var timeout, interval time.Duration
    53  
    54  		var prNumber int
    55  		var prHeadSha string
    56  
    57  		BeforeAll(func() {
    58  			if os.Getenv(constants.SKIP_PAC_TESTS_ENV) == "true" {
    59  				Skip("Skipping this test due to configuration issue with Spray proxy")
    60  			}
    61  
    62  			f, err = framework.NewFramework(utils.GetGeneratedNamespace("build-e2e"))
    63  			Expect(err).NotTo(HaveOccurred())
    64  			testNamespace = f.UserNamespace
    65  
    66  			if utils.IsPrivateHostname(f.OpenshiftConsoleHost) {
    67  				Skip("Using private cluster (not reachable from Github), skipping...")
    68  			}
    69  
    70  			quayOrg := utils.GetEnv("DEFAULT_QUAY_ORG", "")
    71  			supports, err := build.DoesQuayOrgSupportPrivateRepo()
    72  			Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("error while checking if quay org supports private repo: %+v", err))
    73  			if !supports {
    74  				if quayOrg == "redhat-appstudio-qe" {
    75  					Fail("Failed to create private image repo in redhat-appstudio-qe org")
    76  				} else {
    77  					Skip("Quay org does not support private quay repository creation, please add support for private repo creation before running this test")
    78  				}
    79  			}
    80  			Expect(err).ShouldNot(HaveOccurred())
    81  
    82  			applicationName = fmt.Sprintf("build-suite-test-application-%s", util.GenerateRandomString(4))
    83  			_, err = f.AsKubeAdmin.HasController.CreateApplication(applicationName, testNamespace)
    84  			Expect(err).NotTo(HaveOccurred())
    85  
    86  			componentName = fmt.Sprintf("%s-%s", "test-component-pac", util.GenerateRandomString(6))
    87  			pacBranchName = constants.PaCPullRequestBranchPrefix + componentName
    88  			componentBaseBranchName = fmt.Sprintf("base-%s", util.GenerateRandomString(6))
    89  
    90  			err = f.AsKubeAdmin.CommonController.Github.CreateRef(helloWorldComponentGitSourceRepoName, helloWorldComponentDefaultBranch, helloWorldComponentRevision, componentBaseBranchName)
    91  			Expect(err).ShouldNot(HaveOccurred())
    92  
    93  			defaultBranchTestComponentName = fmt.Sprintf("test-custom-default-branch-%s", util.GenerateRandomString(6))
    94  		})
    95  
    96  		AfterAll(func() {
    97  			if !CurrentSpecReport().Failed() {
    98  				Expect(f.AsKubeAdmin.HasController.DeleteApplication(applicationName, testNamespace, false)).To(Succeed())
    99  				Expect(f.SandboxController.DeleteUserSignup(f.UserName)).To(BeTrue())
   100  			}
   101  
   102  			// Delete new branches created by PaC and a testing branch used as a component's base branch
   103  			err = f.AsKubeAdmin.CommonController.Github.DeleteRef(helloWorldComponentGitSourceRepoName, pacBranchName)
   104  			if err != nil {
   105  				Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   106  			}
   107  			err = f.AsKubeAdmin.CommonController.Github.DeleteRef(helloWorldComponentGitSourceRepoName, componentBaseBranchName)
   108  			if err != nil {
   109  				Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   110  			}
   111  			err = f.AsKubeAdmin.CommonController.Github.DeleteRef(helloWorldComponentGitSourceRepoName, constants.PaCPullRequestBranchPrefix+defaultBranchTestComponentName)
   112  			if err != nil {
   113  				Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   114  			}
   115  
   116  			// Delete created webhook from GitHub
   117  			cleanupWebhooks(f, helloWorldComponentGitSourceRepoName)
   118  
   119  		})
   120  
   121  		validateChecks := func() {
   122  			var checkRun *github.CheckRun
   123  			timeout = time.Minute * 15
   124  			interval = time.Second * 10
   125  
   126  			Eventually(func() *github.CheckRun {
   127  				checkRuns, err := f.AsKubeAdmin.CommonController.Github.ListCheckRuns(helloWorldComponentGitSourceRepoName, prHeadSha)
   128  				Expect(err).ShouldNot(HaveOccurred())
   129  				for _, cr := range checkRuns {
   130  					if strings.Contains(cr.GetDetailsURL(), osConsoleHost) {
   131  						checkRun = cr
   132  						return cr
   133  					}
   134  				}
   135  				return nil
   136  			}, timeout, interval).ShouldNot(BeNil(), fmt.Sprintf("timed out when waiting for the PaC Check run with `Details URL` field containing %s to appear in the Component repo %s in PR #%d", osConsoleHost, helloWorldComponentGitSourceRepoName, prNumber))
   137  
   138  			Eventually(func() string {
   139  				checkRun, err = f.AsKubeAdmin.CommonController.Github.GetCheckRun(helloWorldComponentGitSourceRepoName, checkRun.GetID())
   140  				Expect(err).ShouldNot(HaveOccurred())
   141  				return checkRun.GetStatus()
   142  			}, timeout, interval).Should(Equal("completed"), fmt.Sprintf("timed out when waiting for the PaC Check suite status to be 'completed' in the Component repo %s in PR #%d", helloWorldComponentGitSourceRepoName, prNumber))
   143  			Expect(checkRun.GetConclusion()).To(Equal("success"), fmt.Sprintf("the initial PR %d in %s repo doesn't contain the info about successful pipelinerun", prNumber, helloWorldComponentGitSourceRepoName))
   144  		}
   145  
   146  		When("a new component without specified branch is created and with visibility private", Label("pac-custom-default-branch"), func() {
   147  			BeforeAll(func() {
   148  				componentObj := appservice.ComponentSpec{
   149  					ComponentName: defaultBranchTestComponentName,
   150  					Application:   applicationName,
   151  					Source: appservice.ComponentSource{
   152  						ComponentSourceUnion: appservice.ComponentSourceUnion{
   153  							GitSource: &appservice.GitSource{
   154  								URL:      helloWorldComponentGitSourceURL,
   155  								Revision: "",
   156  							},
   157  						},
   158  					},
   159  				}
   160  				_, err = f.AsKubeAdmin.HasController.CreateComponent(componentObj, testNamespace, "", "", applicationName, false, utils.MergeMaps(constants.ComponentPaCRequestAnnotation, constants.ImageControllerAnnotationRequestPrivateRepo))
   161  				Expect(err).ShouldNot(HaveOccurred())
   162  			})
   163  
   164  			It("correctly targets the default branch (that is not named 'main') with PaC", func() {
   165  				timeout = time.Second * 300
   166  				interval = time.Second * 1
   167  				Eventually(func() bool {
   168  					prs, err := f.AsKubeAdmin.CommonController.Github.ListPullRequests(helloWorldComponentGitSourceRepoName)
   169  					Expect(err).ShouldNot(HaveOccurred())
   170  
   171  					for _, pr := range prs {
   172  						if pr.Head.GetRef() == constants.PaCPullRequestBranchPrefix+defaultBranchTestComponentName {
   173  							Expect(pr.GetBase().GetRef()).To(Equal(helloWorldComponentDefaultBranch))
   174  							return true
   175  						}
   176  					}
   177  					return false
   178  				}, timeout, interval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for init PaC PR to be created against %s branch in %s repository", helloWorldComponentDefaultBranch, helloWorldComponentGitSourceRepoName))
   179  			})
   180  			It("workspace parameter is set correctly in PaC repository CR", func() {
   181  				nsObj, err := f.AsKubeAdmin.CommonController.GetNamespace(testNamespace)
   182  				Expect(err).ShouldNot(HaveOccurred())
   183  				wsName := nsObj.Labels["appstudio.redhat.com/workspace_name"]
   184  				repositoryParams, err := f.AsKubeAdmin.TektonController.GetRepositoryParams(defaultBranchTestComponentName, testNamespace)
   185  				Expect(err).ShouldNot(HaveOccurred(), "error while trying to get repository params")
   186  				paramExists := false
   187  				for _, param := range repositoryParams {
   188  					if param.Name == "appstudio_workspace" {
   189  						paramExists = true
   190  						Expect(param.Value).To(Equal(wsName), fmt.Sprintf("got workspace param value: %s, expected %s", param.Value, wsName))
   191  					}
   192  				}
   193  				Expect(paramExists).To(BeTrue(), "appstudio_workspace param does not exists in repository CR")
   194  
   195  			})
   196  			It("triggers a PipelineRun", func() {
   197  				timeout = time.Minute * 5
   198  				Eventually(func() error {
   199  					pr, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(defaultBranchTestComponentName, applicationName, testNamespace, "")
   200  					if err != nil {
   201  						GinkgoWriter.Printf("PipelineRun has not been created yet for the component %s/%s\n", testNamespace, defaultBranchTestComponentName)
   202  						return err
   203  					}
   204  					if !pr.HasStarted() {
   205  						return fmt.Errorf("pipelinerun %s/%s hasn't started yet", pr.GetNamespace(), pr.GetName())
   206  					}
   207  					return nil
   208  				}, timeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the PipelineRun to start for the component %s/%s", defaultBranchTestComponentName, testNamespace))
   209  			})
   210  			It("component build status is set correctly", func() {
   211  				var buildStatus *controllers.BuildStatus
   212  				Eventually(func() (bool, error) {
   213  					component, err := f.AsKubeAdmin.HasController.GetComponent(defaultBranchTestComponentName, testNamespace)
   214  					if err != nil {
   215  						return false, err
   216  					}
   217  
   218  					buildStatusAnnotationValue := component.Annotations[controllers.BuildStatusAnnotationName]
   219  					GinkgoWriter.Printf(buildStatusAnnotationValueLoggingFormat, buildStatusAnnotationValue)
   220  					statusBytes := []byte(buildStatusAnnotationValue)
   221  
   222  					err = json.Unmarshal(statusBytes, &buildStatus)
   223  					if err != nil {
   224  						return false, err
   225  					}
   226  
   227  					if buildStatus.PaC != nil {
   228  						GinkgoWriter.Printf("state: %s\n", buildStatus.PaC.State)
   229  						GinkgoWriter.Printf("mergeUrl: %s\n", buildStatus.PaC.MergeUrl)
   230  						GinkgoWriter.Printf("errId: %d\n", buildStatus.PaC.ErrId)
   231  						GinkgoWriter.Printf("errMessage: %s\n", buildStatus.PaC.ErrMessage)
   232  						GinkgoWriter.Printf("configurationTime: %s\n", buildStatus.PaC.ConfigurationTime)
   233  					} else {
   234  						GinkgoWriter.Println("build status does not have PaC field")
   235  					}
   236  
   237  					return buildStatus.PaC != nil && buildStatus.PaC.State == "enabled" && buildStatus.PaC.MergeUrl != "" && buildStatus.PaC.ErrId == 0 && buildStatus.PaC.ConfigurationTime != "", nil
   238  				}, timeout, interval).Should(BeTrue(), "component build status has unexpected content")
   239  			})
   240  			It("image repo and robot account created successfully", func() {
   241  				component, err := f.AsKubeAdmin.HasController.GetComponent(defaultBranchTestComponentName, testNamespace)
   242  				Expect(err).ShouldNot(HaveOccurred(), "could not get component %s in the %s namespace", defaultBranchTestComponentName, testNamespace)
   243  
   244  				annotations := component.GetAnnotations()
   245  				imageRepoName, err = build.GetQuayImageName(annotations)
   246  				Expect(err).ShouldNot(HaveOccurred(), "failed to read image repo name from %+v", annotations)
   247  
   248  				imageExist, err := build.DoesImageRepoExistInQuay(imageRepoName)
   249  				Expect(err).ShouldNot(HaveOccurred(), "failed while checking if image repo exists in quay with error: %+v", err)
   250  				Expect(imageExist).To(BeTrue(), "quay image does not exists")
   251  
   252  				robotAccountName = build.GetRobotAccountName(imageRepoName)
   253  				robotAccountExist, err := build.DoesRobotAccountExistInQuay(robotAccountName)
   254  				Expect(err).ShouldNot(HaveOccurred(), "failed while checking if robot account exists in quay with error: %+v", err)
   255  				Expect(robotAccountExist).To(BeTrue(), "quay robot account does not exists")
   256  			})
   257  			It("created image repo is private", func() {
   258  				isPublic, err := build.IsImageRepoPublic(imageRepoName)
   259  				Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("failed while checking if the image repo %s is private", imageRepoName))
   260  				Expect(isPublic).To(BeFalse(), "Expected image repo to be private, but it is public")
   261  			})
   262  			// skipped due to RHTAPBUGS-978
   263  			It("a related PipelineRun should be deleted after deleting the component", Pending, func() {
   264  				timeout = time.Second * 60
   265  				interval = time.Second * 1
   266  				Expect(f.AsKubeAdmin.HasController.DeleteComponent(defaultBranchTestComponentName, testNamespace, true)).To(Succeed())
   267  				// Test removal of PipelineRun
   268  				var pr *pipeline.PipelineRun
   269  				Eventually(func() error {
   270  					pr, err = f.AsKubeAdmin.HasController.GetComponentPipelineRun(defaultBranchTestComponentName, applicationName, testNamespace, "")
   271  					if err == nil {
   272  						return fmt.Errorf("pipelinerun %s/%s is not removed yet", pr.GetNamespace(), pr.GetName())
   273  					}
   274  					return err
   275  				}, timeout, constants.PipelineRunPollingInterval).Should(MatchError(ContainSubstring("no pipelinerun found")), fmt.Sprintf("timed out when waiting for the PipelineRun to be removed for Component %s/%s", testNamespace, defaultBranchTestComponentName))
   276  			})
   277  			// skipped due to RHTAPBUGS-978
   278  			It("PR branch should not exist in the repo", Pending, func() {
   279  				timeout = time.Second * 60
   280  				interval = time.Second * 1
   281  				branchName := constants.PaCPullRequestBranchPrefix + defaultBranchTestComponentName
   282  				Eventually(func() bool {
   283  					exists, err := f.AsKubeAdmin.CommonController.Github.ExistsRef(helloWorldComponentGitSourceRepoName, constants.PaCPullRequestBranchPrefix+defaultBranchTestComponentName)
   284  					Expect(err).ShouldNot(HaveOccurred())
   285  					return exists
   286  				}, timeout, interval).Should(BeFalse(), fmt.Sprintf("timed out when waiting for the branch %s to be deleted from %s repository", branchName, helloWorldComponentGitSourceRepoName))
   287  			})
   288  			// skipped due to RHTAPBUGS-978
   289  			It("related image repo and the robot account should be deleted after deleting the component", Pending, func() {
   290  				timeout = time.Second * 10
   291  				interval = time.Second * 1
   292  				// Check image repo should not be deleted
   293  				Consistently(func() (bool, error) {
   294  					return build.DoesImageRepoExistInQuay(imageRepoName)
   295  				}, timeout, interval).Should(BeFalse(), fmt.Sprintf("image repo %s got deleted while it should not have", imageRepoName))
   296  				// Check robot account should be deleted
   297  				timeout = time.Second * 60
   298  				Eventually(func() (bool, error) {
   299  					return build.DoesRobotAccountExistInQuay(robotAccountName)
   300  				}, timeout, interval).Should(BeFalse(), fmt.Sprintf("timed out when checking if robot account %s got deleted", robotAccountName))
   301  
   302  			})
   303  		})
   304  
   305  		When("a new Component with specified custom branch is created", Label("build-custom-branch"), func() {
   306  			var outputImage string
   307  			BeforeAll(func() {
   308  
   309  				// create the build secret in the user namespace
   310  				secretName := "build-secret"
   311  				token := os.Getenv("GITHUB_TOKEN")
   312  				secretAnnotations := map[string]string{
   313  					"appstudio.redhat.com/scm.repository": os.Getenv("MY_GITHUB_ORG") + "/*",
   314  				}
   315  				err = createBuildSecret(f, secretName, secretAnnotations, token)
   316  				Expect(err).ShouldNot(HaveOccurred())
   317  
   318  				componentObj := appservice.ComponentSpec{
   319  					ComponentName: componentName,
   320  					Application:   applicationName,
   321  					Source: appservice.ComponentSource{
   322  						ComponentSourceUnion: appservice.ComponentSourceUnion{
   323  							GitSource: &appservice.GitSource{
   324  								URL:      helloWorldComponentGitSourceURL,
   325  								Revision: componentBaseBranchName,
   326  							},
   327  						},
   328  					},
   329  				}
   330  				// Create a component with Git Source URL, a specified git branch and marking delete-repo=true
   331  				component, err = f.AsKubeAdmin.HasController.CreateComponent(componentObj, testNamespace, "", "", applicationName, false, utils.MergeMaps(constants.ComponentPaCRequestAnnotation, constants.ImageControllerAnnotationRequestPublicRepo))
   332  				Expect(err).ShouldNot(HaveOccurred())
   333  			})
   334  			It("triggers a PipelineRun", func() {
   335  				timeout = time.Second * 600
   336  				interval = time.Second * 1
   337  				Eventually(func() error {
   338  					pr, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "")
   339  					if err != nil {
   340  						GinkgoWriter.Printf("PipelineRun has not been created yet for the component %s/%s\n", testNamespace, componentName)
   341  						return err
   342  					}
   343  					if !pr.HasStarted() {
   344  						return fmt.Errorf("pipelinerun %s/%s hasn't started yet", pr.GetNamespace(), pr.GetName())
   345  					}
   346  					return nil
   347  				}, timeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the PipelineRun to start for the component %s/%s", testNamespace, componentName))
   348  			})
   349  			It("should lead to a PaC init PR creation", func() {
   350  				timeout = time.Second * 300
   351  				interval = time.Second * 1
   352  
   353  				Eventually(func() bool {
   354  					prs, err := f.AsKubeAdmin.CommonController.Github.ListPullRequests(helloWorldComponentGitSourceRepoName)
   355  					Expect(err).ShouldNot(HaveOccurred())
   356  
   357  					for _, pr := range prs {
   358  						if pr.Head.GetRef() == pacBranchName {
   359  							prNumber = pr.GetNumber()
   360  							prHeadSha = pr.Head.GetSHA()
   361  							return true
   362  						}
   363  					}
   364  					return false
   365  				}, timeout, interval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for init PaC PR (branch name '%s') to be created in %s repository", pacBranchName, helloWorldComponentGitSourceRepoName))
   366  			})
   367  			It("the PipelineRun should eventually finish successfully", func() {
   368  				Expect(f.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(component, "",
   369  					f.AsKubeAdmin.TektonController, &has.RetryOptions{Retries: 2, Always: true}, nil)).To(Succeed())
   370  			})
   371  			It("image repo and robot account created successfully", func() {
   372  
   373  				component, err := f.AsKubeAdmin.HasController.GetComponent(componentName, testNamespace)
   374  				Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("could not get component %s in the %s namespace", componentName, testNamespace))
   375  
   376  				annotations := component.GetAnnotations()
   377  				imageRepoName, err = build.GetQuayImageName(annotations)
   378  				Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("failed to read image repo name from %+v", annotations))
   379  
   380  				imageExist, err := build.DoesImageRepoExistInQuay(imageRepoName)
   381  				Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("failed while checking if image repo exists in quay with error: %+v", err))
   382  				Expect(imageExist).To(BeTrue(), fmt.Sprintf("quay image for repo %s does not exists", imageRepoName))
   383  
   384  				robotAccountName = build.GetRobotAccountName(imageRepoName)
   385  				robotAccountExist, err := build.DoesRobotAccountExistInQuay(robotAccountName)
   386  				Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("failed while checking if robot account exists in quay with error: %+v", err))
   387  				Expect(robotAccountExist).To(BeTrue(), fmt.Sprintf("quay robot account %s does not exists", robotAccountName))
   388  
   389  			})
   390  			It("created image repo is public", func() {
   391  				isPublic, err := build.IsImageRepoPublic(imageRepoName)
   392  				Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("failed while checking if the image repo %s is public", imageRepoName))
   393  				Expect(isPublic).To(BeTrue(), "Expected image repo to changed to public, but it is private")
   394  			})
   395  			It("image tag is updated successfully", func() {
   396  				// check if the image tag exists in quay
   397  				pipelineRun, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "")
   398  				Expect(err).ShouldNot(HaveOccurred())
   399  
   400  				for _, p := range pipelineRun.Spec.Params {
   401  					if p.Name == "output-image" {
   402  						outputImage = p.Value.StringVal
   403  					}
   404  				}
   405  				Expect(outputImage).ToNot(BeEmpty(), "output image %s of the component could not be found", outputImage)
   406  				isExists, err := build.DoesTagExistsInQuay(outputImage)
   407  				Expect(err).ShouldNot(HaveOccurred(), "error while checking if the output image %s exists in quay", outputImage)
   408  				Expect(isExists).To(BeTrue(), "image tag does not exists in quay")
   409  			})
   410  
   411  			It("should ensure pruning labels are set", func() {
   412  				pipelineRun, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "")
   413  				Expect(err).ShouldNot(HaveOccurred())
   414  
   415  				image, err := build.ImageFromPipelineRun(pipelineRun)
   416  				Expect(err).ShouldNot(HaveOccurred())
   417  
   418  				labels := image.Config.Config.Labels
   419  				Expect(labels).ToNot(BeEmpty())
   420  
   421  				expiration, ok := labels["quay.expires-after"]
   422  				Expect(ok).To(BeTrue())
   423  				Expect(expiration).To(Equal(utils.GetEnv(constants.IMAGE_TAG_EXPIRATION_ENV, constants.DefaultImageTagExpiration)))
   424  			})
   425  			It("eventually leads to the PipelineRun status report at Checks tab", func() {
   426  				validateChecks()
   427  			})
   428  		})
   429  
   430  		When("the PaC init branch is updated", Label("build-custom-branch"), func() {
   431  			var createdFileSHA string
   432  
   433  			BeforeAll(func() {
   434  				fileToCreatePath := fmt.Sprintf(".tekton/%s-readme.md", componentName)
   435  				createdFile, err := f.AsKubeAdmin.CommonController.Github.CreateFile(helloWorldComponentGitSourceRepoName, fileToCreatePath, fmt.Sprintf("test PaC branch %s update", pacBranchName), pacBranchName)
   436  				Expect(err).NotTo(HaveOccurred())
   437  
   438  				createdFileSHA = createdFile.GetSHA()
   439  				GinkgoWriter.Println("created file sha:", createdFileSHA)
   440  			})
   441  
   442  			It("eventually leads to triggering another PipelineRun", func() {
   443  				timeout = time.Minute * 5
   444  
   445  				Eventually(func() error {
   446  					pr, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, createdFileSHA)
   447  					if err != nil {
   448  						GinkgoWriter.Printf("PipelineRun has not been created yet for the component %s/%s\n", testNamespace, componentName)
   449  						return err
   450  					}
   451  					if !pr.HasStarted() {
   452  						return fmt.Errorf("pipelinerun %s/%s hasn't started yet", pr.GetNamespace(), pr.GetName())
   453  					}
   454  					return nil
   455  				}, timeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the PipelineRun to start for the component %s/%s", testNamespace, componentName))
   456  			})
   457  			It("should lead to a PaC init PR update", func() {
   458  				timeout = time.Second * 300
   459  				interval = time.Second * 1
   460  
   461  				Eventually(func() bool {
   462  					prs, err := f.AsKubeAdmin.CommonController.Github.ListPullRequests(helloWorldComponentGitSourceRepoName)
   463  					Expect(err).ShouldNot(HaveOccurred())
   464  
   465  					for _, pr := range prs {
   466  						if pr.Head.GetRef() == pacBranchName {
   467  							Expect(prHeadSha).NotTo(Equal(pr.Head.GetSHA()))
   468  							prNumber = pr.GetNumber()
   469  							prHeadSha = pr.Head.GetSHA()
   470  							return true
   471  						}
   472  					}
   473  					return false
   474  				}, timeout, interval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for init PaC PR (branch name '%s') to be created in %s repository", pacBranchName, helloWorldComponentGitSourceRepoName))
   475  			})
   476  			It("PipelineRun should eventually finish", func() {
   477  				pr := &pipeline.PipelineRun{}
   478  				Expect(f.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(component, createdFileSHA,
   479  					f.AsKubeAdmin.TektonController, &has.RetryOptions{Retries: 2, Always: true}, pr)).To(Succeed())
   480  				createdFileSHA = pr.Labels["pipelinesascode.tekton.dev/sha"]
   481  			})
   482  			It("eventually leads to another update of a PR about the PipelineRun status report at Checks tab", func() {
   483  				validateChecks()
   484  			})
   485  		})
   486  
   487  		When("the PaC init branch is merged", Label("build-custom-branch"), func() {
   488  			var mergeResult *github.PullRequestMergeResult
   489  			var mergeResultSha string
   490  			var pipelineRun *pipeline.PipelineRun
   491  
   492  			BeforeAll(func() {
   493  				Eventually(func() error {
   494  					mergeResult, err = f.AsKubeAdmin.CommonController.Github.MergePullRequest(helloWorldComponentGitSourceRepoName, prNumber)
   495  					return err
   496  				}, time.Minute).Should(BeNil(), fmt.Sprintf("error when merging PaC pull request #%d in repo %s", prNumber, helloWorldComponentGitSourceRepoName))
   497  
   498  				mergeResultSha = mergeResult.GetSHA()
   499  				GinkgoWriter.Println("merged result sha:", mergeResultSha)
   500  			})
   501  
   502  			It("eventually leads to triggering another PipelineRun", func() {
   503  				timeout = time.Minute * 10
   504  
   505  				Eventually(func() error {
   506  					pipelineRun, err = f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, mergeResultSha)
   507  					if err != nil {
   508  						GinkgoWriter.Printf("PipelineRun has not been created yet for the component %s/%s\n", testNamespace, componentName)
   509  						return err
   510  					}
   511  					if !pipelineRun.HasStarted() {
   512  						return fmt.Errorf("pipelinerun %s/%s hasn't started yet", pipelineRun.GetNamespace(), pipelineRun.GetName())
   513  					}
   514  					return nil
   515  				}, timeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the PipelineRun to start for the component %s/%s", testNamespace, componentName))
   516  			})
   517  
   518  			It("pipelineRun should eventually finish", func() {
   519  				Expect(f.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(component,
   520  					mergeResultSha, f.AsKubeAdmin.TektonController, &has.RetryOptions{Retries: 2, Always: true}, pipelineRun)).To(Succeed())
   521  				mergeResultSha = pipelineRun.Labels["pipelinesascode.tekton.dev/sha"]
   522  			})
   523  
   524  			It("does not have expiration set", func() {
   525  				image, err := build.ImageFromPipelineRun(pipelineRun)
   526  				Expect(err).ShouldNot(HaveOccurred())
   527  
   528  				labels := image.Config.Config.Labels
   529  				Expect(labels).ToNot(BeEmpty())
   530  
   531  				expiration, ok := labels["quay.expires-after"]
   532  				Expect(ok).To(BeFalse())
   533  				Expect(expiration).To(BeEmpty())
   534  			})
   535  
   536  			It("After updating image visibility to private, it should not trigger another PipelineRun", func() {
   537  				Expect(f.AsKubeAdmin.TektonController.DeleteAllPipelineRunsInASpecificNamespace(testNamespace)).To(Succeed())
   538  				Eventually(func() error {
   539  					err := f.AsKubeAdmin.HasController.SetComponentAnnotation(componentName, controllers.ImageRepoGenerateAnnotationName, constants.ImageControllerAnnotationRequestPrivateRepo[controllers.ImageRepoGenerateAnnotationName], testNamespace)
   540  					if err != nil {
   541  						GinkgoWriter.Printf("failed to update the component %s with error %v\n", componentName, err)
   542  						return err
   543  					}
   544  					return nil
   545  				}, time.Second*20, time.Second*1).Should(Succeed(), fmt.Sprintf("timed out when trying to update the component %s/%s", testNamespace, componentName))
   546  
   547  				Consistently(func() bool {
   548  					componentPipelineRun, _ := f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "")
   549  					return componentPipelineRun == nil
   550  				}, time.Minute, constants.PipelineRunPollingInterval).Should(BeTrue(), fmt.Sprintf("expected no PipelineRun to be triggered for the component %s in %s namespace", componentName, testNamespace))
   551  			})
   552  			It("check image repo status after switching to private", func() {
   553  				var imageStatus imagecontollers.ImageRepositoryStatus
   554  				Eventually(func() (bool, error) {
   555  					component, err := f.AsKubeAdmin.HasController.GetComponent(componentName, testNamespace)
   556  					if err != nil {
   557  						GinkgoWriter.Printf("error while getting component: %v\n", err)
   558  						return false, err
   559  					}
   560  
   561  					imageAnnotationValue := component.Annotations[controllers.ImageRepoAnnotationName]
   562  					GinkgoWriter.Printf("image annotation value: %s\n", imageAnnotationValue)
   563  					statusBytes := []byte(imageAnnotationValue)
   564  
   565  					err = json.Unmarshal(statusBytes, &imageStatus)
   566  					if err != nil {
   567  						GinkgoWriter.Printf("cannot unmarshal image status: %v\n", err)
   568  						return false, err
   569  					}
   570  					if imageStatus.Message != "" && strings.Contains(imageStatus.Message, "Quay organization plan doesn't allow private image repositories") {
   571  						return false, fmt.Errorf("failed to switch to private image")
   572  					}
   573  					return true, nil
   574  				}, time.Second*20, time.Second*2).Should(BeTrue(), "component image status annotation has unexpected content")
   575  			})
   576  			It("image repo is updated to private", func() {
   577  				isPublic, err := build.IsImageRepoPublic(imageRepoName)
   578  				Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("failed while checking if the image repo %s is private", imageRepoName))
   579  				Expect(isPublic).To(BeFalse(), "Expected image repo to changed to private, but it is public")
   580  			})
   581  
   582  		})
   583  
   584  		When("the component is removed and recreated (with the same name in the same namespace)", Label("build-custom-branch"), func() {
   585  			BeforeAll(func() {
   586  				Expect(f.AsKubeAdmin.HasController.DeleteComponent(componentName, testNamespace, true)).To(Succeed())
   587  
   588  				timeout = 1 * time.Minute
   589  				interval = 1 * time.Second
   590  				Eventually(func() bool {
   591  					_, err := f.AsKubeAdmin.HasController.GetComponent(componentName, testNamespace)
   592  					return k8sErrors.IsNotFound(err)
   593  				}, timeout, interval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for the app %s/%s to be deleted", testNamespace, applicationName))
   594  				// Check removal of image repo
   595  				Eventually(func() (bool, error) {
   596  					return build.DoesImageRepoExistInQuay(imageRepoName)
   597  				}, timeout, interval).Should(BeFalse(), fmt.Sprintf("timed out when waiting for image repo %s to be deleted", imageRepoName))
   598  				// Check removal of robot account
   599  				Eventually(func() (bool, error) {
   600  					return build.DoesRobotAccountExistInQuay(robotAccountName)
   601  				}, timeout, interval).Should(BeFalse(), fmt.Sprintf("timed out when waiting for robot account %s to be deleted", robotAccountName))
   602  
   603  				componentObj := appservice.ComponentSpec{
   604  					ComponentName: componentName,
   605  					Source: appservice.ComponentSource{
   606  						ComponentSourceUnion: appservice.ComponentSourceUnion{
   607  							GitSource: &appservice.GitSource{
   608  								URL:      helloWorldComponentGitSourceURL,
   609  								Revision: componentBaseBranchName,
   610  							},
   611  						},
   612  					},
   613  				}
   614  				_, err = f.AsKubeAdmin.HasController.CreateComponent(componentObj, testNamespace, "", "", applicationName, false, utils.MergeMaps(constants.ComponentPaCRequestAnnotation, constants.ImageControllerAnnotationRequestPublicRepo))
   615  				Expect(err).ShouldNot(HaveOccurred())
   616  			})
   617  
   618  			It("should no longer lead to a creation of a PaC PR", func() {
   619  				timeout = time.Second * 10
   620  				interval = time.Second * 2
   621  				Consistently(func() error {
   622  					prs, err := f.AsKubeAdmin.CommonController.Github.ListPullRequests(helloWorldComponentGitSourceRepoName)
   623  					Expect(err).ShouldNot(HaveOccurred())
   624  
   625  					for _, pr := range prs {
   626  						if pr.Head.GetRef() == pacBranchName {
   627  							return fmt.Errorf("did not expect a new PR created in %s repository after initial PaC configuration was already merged for the same component name and a namespace", helloWorldComponentGitSourceRepoName)
   628  						}
   629  					}
   630  					return nil
   631  				}, timeout, interval).Should(BeNil())
   632  			})
   633  		})
   634  	})
   635  
   636  	Describe("test pac with multiple components using same repository", Ordered, Label("pac-build", "multi-component"), func() {
   637  		var applicationName, testNamespace, multiComponentBaseBranchName, multiComponentPRBranchName, mergeResultSha string
   638  		var pacBranchNames []string
   639  		var prNumber int
   640  		var mergeResult *github.PullRequestMergeResult
   641  		var timeout time.Duration
   642  
   643  		BeforeAll(func() {
   644  			if os.Getenv(constants.SKIP_PAC_TESTS_ENV) == "true" {
   645  				Skip("Skipping this test due to configuration issue with Spray proxy")
   646  			}
   647  			f, err = framework.NewFramework(utils.GetGeneratedNamespace("build-e2e"))
   648  			Expect(err).NotTo(HaveOccurred())
   649  			testNamespace = f.UserNamespace
   650  
   651  			if utils.IsPrivateHostname(f.OpenshiftConsoleHost) {
   652  				Skip("Using private cluster (not reachable from Github), skipping...")
   653  			}
   654  
   655  			applicationName = fmt.Sprintf("build-suite-positive-mc-%s", util.GenerateRandomString(4))
   656  			_, err = f.AsKubeAdmin.HasController.CreateApplication(applicationName, testNamespace)
   657  			Expect(err).NotTo(HaveOccurred())
   658  
   659  			multiComponentBaseBranchName = fmt.Sprintf("multi-component-base-%s", util.GenerateRandomString(6))
   660  			err = f.AsKubeAdmin.CommonController.Github.CreateRef(multiComponentGitSourceRepoName, multiComponentDefaultBranch, multiComponentGitRevision, multiComponentBaseBranchName)
   661  			Expect(err).ShouldNot(HaveOccurred())
   662  
   663  			//Branch for creating pull request
   664  			multiComponentPRBranchName = fmt.Sprintf("%s-%s", "pr-branch", util.GenerateRandomString(6))
   665  
   666  		})
   667  
   668  		AfterAll(func() {
   669  			if !CurrentSpecReport().Failed() {
   670  				Expect(f.AsKubeAdmin.HasController.DeleteApplication(applicationName, testNamespace, false)).To(Succeed())
   671  				Expect(f.SandboxController.DeleteUserSignup(f.UserName)).To(BeTrue())
   672  			}
   673  
   674  			// Delete new branches created by PaC and a testing branch used as a component's base branch
   675  			for _, pacBranchName := range pacBranchNames {
   676  				err = f.AsKubeAdmin.CommonController.Github.DeleteRef(multiComponentGitSourceRepoName, pacBranchName)
   677  				if err != nil {
   678  					Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   679  				}
   680  			}
   681  			// Delete the created base branch
   682  			err = f.AsKubeAdmin.CommonController.Github.DeleteRef(multiComponentGitSourceRepoName, multiComponentBaseBranchName)
   683  			if err != nil {
   684  				Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   685  			}
   686  			// Delete the created pr branch
   687  			err = f.AsKubeAdmin.CommonController.Github.DeleteRef(multiComponentGitSourceRepoName, multiComponentPRBranchName)
   688  			if err != nil {
   689  				Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   690  			}
   691  		})
   692  
   693  		When("components are created in same namespace", func() {
   694  			var component *appservice.Component
   695  
   696  			for _, contextDir := range multiComponentContextDirs {
   697  				contextDir := contextDir
   698  				componentName := fmt.Sprintf("%s-%s", contextDir, util.GenerateRandomString(6))
   699  				pacBranchName := constants.PaCPullRequestBranchPrefix + componentName
   700  				pacBranchNames = append(pacBranchNames, pacBranchName)
   701  
   702  				It(fmt.Sprintf("creates component with context directory %s", contextDir), func() {
   703  					componentObj := appservice.ComponentSpec{
   704  						ComponentName: componentName,
   705  						Application:   applicationName,
   706  						Source: appservice.ComponentSource{
   707  							ComponentSourceUnion: appservice.ComponentSourceUnion{
   708  								GitSource: &appservice.GitSource{
   709  									URL:      multiComponentGitSourceURL,
   710  									Revision: multiComponentBaseBranchName,
   711  									Context:  contextDir,
   712  								},
   713  							},
   714  						},
   715  					}
   716  					component, err = f.AsKubeAdmin.HasController.CreateComponent(componentObj, testNamespace, "", "", applicationName, false, utils.MergeMaps(constants.ComponentPaCRequestAnnotation, constants.ImageControllerAnnotationRequestPublicRepo))
   717  					Expect(err).ShouldNot(HaveOccurred())
   718  				})
   719  
   720  				It(fmt.Sprintf("triggers a PipelineRun for component %s", componentName), func() {
   721  					timeout = time.Minute * 5
   722  					Eventually(func() error {
   723  						pr, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "")
   724  						if err != nil {
   725  							GinkgoWriter.Printf("PipelineRun has not been created yet for the component %s/%s\n", testNamespace, componentName)
   726  							return err
   727  						}
   728  						if !pr.HasStarted() {
   729  							return fmt.Errorf("pipelinerun %s/%s hasn't started yet", pr.GetNamespace(), pr.GetName())
   730  						}
   731  						return nil
   732  					}, timeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the PipelineRun to start for the component %s/%s", componentName, testNamespace))
   733  				})
   734  
   735  				It(fmt.Sprintf("should lead to a PaC PR creation for component %s", componentName), func() {
   736  					timeout = time.Second * 300
   737  					interval := time.Second * 1
   738  
   739  					Eventually(func() bool {
   740  						prs, err := f.AsKubeAdmin.CommonController.Github.ListPullRequests(multiComponentGitSourceRepoName)
   741  						Expect(err).ShouldNot(HaveOccurred())
   742  
   743  						for _, pr := range prs {
   744  							if pr.Head.GetRef() == pacBranchName {
   745  								prNumber = pr.GetNumber()
   746  								return true
   747  							}
   748  						}
   749  						return false
   750  					}, timeout, interval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for PaC PR (branch name '%s') to be created in %s repository", pacBranchName, multiComponentGitSourceRepoName))
   751  				})
   752  
   753  				It(fmt.Sprintf("the PipelineRun should eventually finish successfully for component %s", componentName), func() {
   754  					Expect(f.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(component, "",
   755  						f.AsKubeAdmin.TektonController, &has.RetryOptions{Retries: 2, Always: true}, nil)).To(Succeed())
   756  				})
   757  
   758  				It("merging the PR should be successful", func() {
   759  					Eventually(func() error {
   760  						mergeResult, err = f.AsKubeAdmin.CommonController.Github.MergePullRequest(multiComponentGitSourceRepoName, prNumber)
   761  						return err
   762  					}, time.Minute).Should(BeNil(), fmt.Sprintf("error when merging PaC pull request #%d in repo %s", prNumber, multiComponentGitSourceRepoName))
   763  
   764  					mergeResultSha = mergeResult.GetSHA()
   765  					GinkgoWriter.Printf("merged result sha: %s for PR #%d\n", mergeResultSha, prNumber)
   766  
   767  				})
   768  				It("leads to triggering on push PipelineRun", func() {
   769  					timeout = time.Minute * 5
   770  
   771  					Eventually(func() error {
   772  						pipelineRun, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, mergeResultSha)
   773  						if err != nil {
   774  							GinkgoWriter.Printf("Push PipelineRun has not been created yet for the component %s/%s\n", testNamespace, componentName)
   775  							return err
   776  						}
   777  						if !pipelineRun.HasStarted() {
   778  							return fmt.Errorf("push pipelinerun %s/%s hasn't started yet", pipelineRun.GetNamespace(), pipelineRun.GetName())
   779  						}
   780  						return nil
   781  					}, timeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the PipelineRun to start for the component %s/%s", testNamespace, componentName))
   782  				})
   783  			}
   784  			It("only one component is changed", func() {
   785  				//Delete all the pipelineruns in the namespace before sending PR
   786  				Expect(f.AsKubeAdmin.TektonController.DeleteAllPipelineRunsInASpecificNamespace(testNamespace)).To(Succeed())
   787  				//Create the ref, add the file and create the PR
   788  				err = f.AsKubeAdmin.CommonController.Github.CreateRef(multiComponentGitSourceRepoName, multiComponentDefaultBranch, mergeResultSha, multiComponentPRBranchName)
   789  				Expect(err).ShouldNot(HaveOccurred())
   790  				fileToCreatePath := fmt.Sprintf("%s/sample-file.txt", multiComponentContextDirs[0])
   791  				createdFileSha, err := f.AsKubeAdmin.CommonController.Github.CreateFile(multiComponentGitSourceRepoName, fileToCreatePath, fmt.Sprintf("sample test file inside %s", multiComponentContextDirs[0]), multiComponentPRBranchName)
   792  				Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("error while creating file: %s", fileToCreatePath))
   793  				pr, err := f.AsKubeAdmin.CommonController.Github.CreatePullRequest(multiComponentGitSourceRepoName, "sample pr title", "sample pr body", multiComponentPRBranchName, multiComponentBaseBranchName)
   794  				Expect(err).ShouldNot(HaveOccurred())
   795  				GinkgoWriter.Printf("PR #%d got created with sha %s\n", pr.GetNumber(), createdFileSha.GetSHA())
   796  			})
   797  			It("only related pipelinerun should be triggered", func() {
   798  				Eventually(func() error {
   799  					pipelineRuns, err := f.AsKubeAdmin.HasController.GetAllPipelineRunsForApplication(applicationName, testNamespace)
   800  					if err != nil {
   801  						GinkgoWriter.Println("on pull PiplelineRun has not been created yet for the PR")
   802  						return err
   803  					}
   804  					if len(pipelineRuns.Items) != 1 || !strings.HasPrefix(pipelineRuns.Items[0].Name, multiComponentContextDirs[0]) {
   805  						return fmt.Errorf("pipelinerun created in the namespace %s is not as expected, got pipelineruns %v", testNamespace, pipelineRuns.Items)
   806  					}
   807  					return nil
   808  				}, time.Minute*5, constants.PipelineRunPollingInterval).Should(Succeed(), "timeout while waiting for PR pipeline to start")
   809  			})
   810  		})
   811  		When("a components is created with same git url in different namespace", func() {
   812  			var namespace, appName, compName string
   813  			var fw *framework.Framework
   814  
   815  			BeforeAll(func() {
   816  				fw, err = framework.NewFramework(utils.GetGeneratedNamespace("build-e2e"))
   817  				Expect(err).NotTo(HaveOccurred())
   818  				namespace = fw.UserNamespace
   819  
   820  				appName = fmt.Sprintf("build-suite-negative-mc-%s", util.GenerateRandomString(4))
   821  				_, err = f.AsKubeAdmin.HasController.CreateApplication(appName, namespace)
   822  				Expect(err).NotTo(HaveOccurred())
   823  
   824  				compName = fmt.Sprintf("%s-%s", multiComponentContextDirs[0], util.GenerateRandomString(6))
   825  
   826  				componentObj := appservice.ComponentSpec{
   827  					ComponentName: compName,
   828  					Application:   appName,
   829  					Source: appservice.ComponentSource{
   830  						ComponentSourceUnion: appservice.ComponentSourceUnion{
   831  							GitSource: &appservice.GitSource{
   832  								URL:      multiComponentGitSourceURL,
   833  								Revision: multiComponentBaseBranchName,
   834  								Context:  multiComponentContextDirs[0],
   835  							},
   836  						},
   837  					},
   838  				}
   839  				_, err = fw.AsKubeAdmin.HasController.CreateComponent(componentObj, namespace, "", "", appName, false, utils.MergeMaps(constants.ComponentPaCRequestAnnotation, constants.ImageControllerAnnotationRequestPublicRepo))
   840  				Expect(err).ShouldNot(HaveOccurred())
   841  
   842  			})
   843  
   844  			AfterAll(func() {
   845  				if !CurrentSpecReport().Failed() {
   846  					Expect(fw.AsKubeAdmin.HasController.DeleteApplication(appName, namespace, false)).To(Succeed())
   847  					Expect(fw.SandboxController.DeleteUserSignup(fw.UserName)).To(BeTrue())
   848  				}
   849  			})
   850  
   851  			It("should fail to configure PaC for the component", func() {
   852  				var buildStatus *controllers.BuildStatus
   853  
   854  				Eventually(func() (bool, error) {
   855  					component, err := fw.AsKubeAdmin.HasController.GetComponent(compName, namespace)
   856  					if err != nil {
   857  						GinkgoWriter.Printf("error while getting the component: %v\n", err)
   858  						return false, err
   859  					}
   860  
   861  					buildStatusAnnotationValue := component.Annotations[controllers.BuildStatusAnnotationName]
   862  					GinkgoWriter.Printf(buildStatusAnnotationValueLoggingFormat, buildStatusAnnotationValue)
   863  					statusBytes := []byte(buildStatusAnnotationValue)
   864  
   865  					err = json.Unmarshal(statusBytes, &buildStatus)
   866  					if err != nil {
   867  						GinkgoWriter.Printf("cannot unmarshal build status from component annotation: %v\n", err)
   868  						return false, err
   869  					}
   870  
   871  					GinkgoWriter.Printf("build status: %+v\n", buildStatus.PaC)
   872  
   873  					return buildStatus.PaC != nil && buildStatus.PaC.State == "error" && strings.Contains(buildStatus.PaC.ErrMessage, "Git repository is already handled by Pipelines as Code"), nil
   874  				}, time.Minute*2, time.Second*2).Should(BeTrue(), "build status is unexpected")
   875  
   876  			})
   877  
   878  		})
   879  
   880  	})
   881  	Describe("test build secret lookup", Label("pac-build", "secret-lookup"), Ordered, func() {
   882  		var testNamespace, applicationName, firstComponentBaseBranchName, secondComponentBaseBranchName, firstComponentName, secondComponentName, firstPacBranchName, secondPacBranchName string
   883  		BeforeAll(func() {
   884  			if os.Getenv(constants.SKIP_PAC_TESTS_ENV) == "true" {
   885  				Skip("Skipping this test due to configuration issue with Spray proxy")
   886  			}
   887  			f, err = framework.NewFramework(utils.GetGeneratedNamespace("build-e2e"))
   888  			Expect(err).NotTo(HaveOccurred())
   889  			testNamespace = f.UserNamespace
   890  
   891  			applicationName = fmt.Sprintf("build-secret-lookup-%s", util.GenerateRandomString(4))
   892  			_, err = f.AsKubeAdmin.HasController.CreateApplication(applicationName, testNamespace)
   893  			Expect(err).NotTo(HaveOccurred())
   894  
   895  			firstComponentBaseBranchName = fmt.Sprintf("component-one-base-%s", util.GenerateRandomString(6))
   896  			err = f.AsKubeAdmin.CommonController.Github.CreateRef(secretLookupGitSourceRepoOneName, secretLookupDefaultBranchOne, secretLookupGitRevisionOne, firstComponentBaseBranchName)
   897  			Expect(err).ShouldNot(HaveOccurred())
   898  
   899  			secondComponentBaseBranchName = fmt.Sprintf("component-two-base-%s", util.GenerateRandomString(6))
   900  			err = f.AsKubeAdmin.CommonController.Github.CreateRef(secretLookupGitSourceRepoTwoName, secretLookupDefaultBranchTwo, secretLookupGitRevisionTwo, secondComponentBaseBranchName)
   901  			Expect(err).ShouldNot(HaveOccurred())
   902  
   903  		})
   904  
   905  		AfterAll(func() {
   906  			if !CurrentSpecReport().Failed() {
   907  				Expect(f.AsKubeAdmin.HasController.DeleteApplication(applicationName, testNamespace, false)).To(Succeed())
   908  				Expect(f.SandboxController.DeleteUserSignup(f.UserName)).To(BeTrue())
   909  			}
   910  
   911  			// Delete new branches created by PaC
   912  			err = f.AsKubeAdmin.CommonController.Github.DeleteRef(secretLookupGitSourceRepoOneName, firstPacBranchName)
   913  			if err != nil {
   914  				Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   915  			}
   916  			err = f.AsKubeAdmin.CommonController.Github.DeleteRef(secretLookupGitSourceRepoTwoName, secondPacBranchName)
   917  			if err != nil {
   918  				Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   919  			}
   920  
   921  			// Delete the created first component base branch
   922  			err = f.AsKubeAdmin.CommonController.Github.DeleteRef(secretLookupGitSourceRepoOneName, firstComponentBaseBranchName)
   923  			if err != nil {
   924  				Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   925  			}
   926  			// Delete the created second component base branch
   927  			err = f.AsKubeAdmin.CommonController.Github.DeleteRef(secretLookupGitSourceRepoTwoName, secondComponentBaseBranchName)
   928  			if err != nil {
   929  				Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   930  			}
   931  
   932  			// Delete created webhook from GitHub
   933  			cleanupWebhooks(f, secretLookupGitSourceRepoTwoName)
   934  
   935  		})
   936  		When("two secrets are created", func() {
   937  			BeforeAll(func() {
   938  				// create the correct build secret for second component
   939  				secretName1 := "build-secret-1"
   940  				secretAnnotations := map[string]string{
   941  					"appstudio.redhat.com/scm.repository": os.Getenv("MY_GITHUB_ORG") + "/" + secretLookupGitSourceRepoTwoName,
   942  				}
   943  				token := os.Getenv("GITHUB_TOKEN")
   944  				err = createBuildSecret(f, secretName1, secretAnnotations, token)
   945  				Expect(err).ShouldNot(HaveOccurred())
   946  
   947  				// create incorrect build-secret for the first component
   948  				secretName2 := "build-secret-2"
   949  				dummyToken := "ghp_dummy_secret"
   950  				err = createBuildSecret(f, secretName2, nil, dummyToken)
   951  				Expect(err).ShouldNot(HaveOccurred())
   952  
   953  				// component names and pac branch names
   954  				firstComponentName = fmt.Sprintf("%s-%s", "component-one", util.GenerateRandomString(4))
   955  				secondComponentName = fmt.Sprintf("%s-%s", "component-two", util.GenerateRandomString(4))
   956  				firstPacBranchName = constants.PaCPullRequestBranchPrefix + firstComponentName
   957  				secondPacBranchName = constants.PaCPullRequestBranchPrefix + secondComponentName
   958  			})
   959  
   960  			It("creates first component", func() {
   961  				componentObj1 := appservice.ComponentSpec{
   962  					ComponentName: firstComponentName,
   963  					Application:   applicationName,
   964  					Source: appservice.ComponentSource{
   965  						ComponentSourceUnion: appservice.ComponentSourceUnion{
   966  							GitSource: &appservice.GitSource{
   967  								URL:      secretLookupComponentOneGitSourceURL,
   968  								Revision: firstComponentBaseBranchName,
   969  							},
   970  						},
   971  					},
   972  				}
   973  				_, err := f.AsKubeAdmin.HasController.CreateComponent(componentObj1, testNamespace, "", "", applicationName, false, utils.MergeMaps(constants.ComponentPaCRequestAnnotation, constants.ImageControllerAnnotationRequestPublicRepo))
   974  				Expect(err).ShouldNot(HaveOccurred())
   975  			})
   976  			It("creates second component", func() {
   977  				componentObj2 := appservice.ComponentSpec{
   978  					ComponentName: secondComponentName,
   979  					Application:   applicationName,
   980  					Source: appservice.ComponentSource{
   981  						ComponentSourceUnion: appservice.ComponentSourceUnion{
   982  							GitSource: &appservice.GitSource{
   983  								URL:      secretLookupComponentTwoGitSourceURL,
   984  								Revision: secondComponentBaseBranchName,
   985  							},
   986  						},
   987  					},
   988  				}
   989  				_, err := f.AsKubeAdmin.HasController.CreateComponent(componentObj2, testNamespace, "", "", applicationName, false, utils.MergeMaps(constants.ComponentPaCRequestAnnotation, constants.ImageControllerAnnotationRequestPublicRepo))
   990  				Expect(err).ShouldNot(HaveOccurred())
   991  			})
   992  
   993  			It("check first component annotation has errors", func() {
   994  				buildStatus := &controllers.BuildStatus{}
   995  				Eventually(func() (bool, error) {
   996  					component, err := f.AsKubeAdmin.HasController.GetComponent(firstComponentName, testNamespace)
   997  					if err != nil {
   998  						return false, err
   999  					} else if component == nil {
  1000  						return false, fmt.Errorf("got component as nil after getting component %s in namespace %s", firstComponentName, testNamespace)
  1001  					}
  1002  					buildStatusAnnotationValue := component.Annotations[controllers.BuildStatusAnnotationName]
  1003  					GinkgoWriter.Printf(buildStatusAnnotationValueLoggingFormat, buildStatusAnnotationValue)
  1004  					statusBytes := []byte(buildStatusAnnotationValue)
  1005  					err = json.Unmarshal(statusBytes, buildStatus)
  1006  					if err != nil {
  1007  						return false, err
  1008  					}
  1009  					return buildStatus.PaC != nil && buildStatus.PaC.State == "error" && strings.Contains(buildStatus.PaC.ErrMessage, "Access token is unrecognizable by GitHub"), nil
  1010  				}, time.Minute*2, 5*time.Second).Should(BeTrue(), "failed while checking build status for component %q is correct", firstComponentName)
  1011  			})
  1012  
  1013  			It(fmt.Sprintf("triggered PipelineRun is for component %s", secondComponentName), func() {
  1014  				timeout = time.Minute * 5
  1015  				Eventually(func() error {
  1016  					pr, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(secondComponentName, applicationName, testNamespace, "")
  1017  					if err != nil {
  1018  						GinkgoWriter.Printf("PipelineRun has not been created yet for the component %s/%s\n", testNamespace, secondComponentName)
  1019  						return err
  1020  					}
  1021  					if !pr.HasStarted() {
  1022  						return fmt.Errorf("pipelinerun %s/%s hasn't started yet", pr.GetNamespace(), pr.GetName())
  1023  					}
  1024  					return nil
  1025  				}, timeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the PipelineRun to start for the component %s/%s", secondComponentName, testNamespace))
  1026  			})
  1027  
  1028  			It("check only one pipelinerun should be triggered", func() {
  1029  				// Waiting for 2 minute to see if only one pipelinerun is triggered
  1030  				Consistently(func() (bool, error) {
  1031  					pipelineRuns, err := f.AsKubeAdmin.HasController.GetAllPipelineRunsForApplication(applicationName, testNamespace)
  1032  					if err != nil {
  1033  						return false, err
  1034  					}
  1035  					if len(pipelineRuns.Items) != 1 {
  1036  						return false, fmt.Errorf("plr count in the namespace %s is not one, got pipelineruns %v", testNamespace, pipelineRuns.Items)
  1037  					}
  1038  					return true, nil
  1039  				}, time.Minute*2, constants.PipelineRunPollingInterval).Should(BeTrue(), "timeout while checking if any more pipelinerun is triggered")
  1040  			})
  1041  		})
  1042  	})
  1043  	Describe("test build annotations", Label("annotations"), Ordered, func() {
  1044  		var testNamespace, componentName, applicationName string
  1045  		var componentObj appservice.ComponentSpec
  1046  		var component *appservice.Component
  1047  
  1048  		var timeout, interval time.Duration
  1049  
  1050  		BeforeAll(func() {
  1051  			f, err = framework.NewFramework(utils.GetGeneratedNamespace("build-e2e"))
  1052  			Expect(err).ShouldNot(HaveOccurred())
  1053  			testNamespace = f.UserNamespace
  1054  
  1055  			timeout = 5 * time.Minute
  1056  			interval = 5 * time.Second
  1057  
  1058  			applicationName = fmt.Sprintf("build-suite-test-application-%s", util.GenerateRandomString(4))
  1059  			_, err = f.AsKubeAdmin.HasController.CreateApplication(applicationName, testNamespace)
  1060  			Expect(err).NotTo(HaveOccurred())
  1061  
  1062  			componentName = fmt.Sprintf("%s-%s", "test-annotations", util.GenerateRandomString(6))
  1063  
  1064  		})
  1065  
  1066  		AfterAll(func() {
  1067  			if !CurrentSpecReport().Failed() {
  1068  				Expect(f.AsKubeAdmin.HasController.DeleteApplication(applicationName, testNamespace, false)).To(Succeed())
  1069  				Expect(f.SandboxController.DeleteUserSignup(f.UserName)).To(BeTrue())
  1070  			}
  1071  
  1072  		})
  1073  
  1074  		When("component is created", func() {
  1075  			var lastBuildStartTime string
  1076  
  1077  			BeforeAll(func() {
  1078  				componentObj = appservice.ComponentSpec{
  1079  					ComponentName: componentName,
  1080  					Application:   applicationName,
  1081  					Source: appservice.ComponentSource{
  1082  						ComponentSourceUnion: appservice.ComponentSourceUnion{
  1083  							GitSource: &appservice.GitSource{
  1084  								URL:      annotationsTestGitSourceURL,
  1085  								Revision: annotationsTestRevision,
  1086  							},
  1087  						},
  1088  					},
  1089  				}
  1090  
  1091  				component, err = f.AsKubeAdmin.HasController.CreateComponent(componentObj, testNamespace, "", "", applicationName, false, nil)
  1092  				Expect(component).ToNot(BeNil())
  1093  				Expect(err).ShouldNot(HaveOccurred())
  1094  			})
  1095  
  1096  			It("triggers a pipeline run", func() {
  1097  				Eventually(func() error {
  1098  					pr, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "")
  1099  					if err != nil {
  1100  						GinkgoWriter.Printf("PipelineRun has not been created yet for the component %s/%s\n", testNamespace, componentName)
  1101  						return err
  1102  					}
  1103  					if !pr.HasStarted() {
  1104  						return fmt.Errorf("pipelinerun %s/%s hasn't started yet", pr.GetNamespace(), pr.GetName())
  1105  					}
  1106  					return nil
  1107  				}, time.Minute*5, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the PipelineRun to start for the component %s/%s", testNamespace, componentName))
  1108  			})
  1109  
  1110  			It("component build status annotation is set correctly", func() {
  1111  				var buildStatus *controllers.BuildStatus
  1112  
  1113  				Eventually(func() (bool, error) {
  1114  					component, err := f.AsKubeAdmin.HasController.GetComponent(componentName, testNamespace)
  1115  					if err != nil {
  1116  						GinkgoWriter.Printf("cannot get the component: %v\n", err)
  1117  						return false, err
  1118  					}
  1119  
  1120  					buildStatusAnnotationValue := component.Annotations[controllers.BuildStatusAnnotationName]
  1121  					GinkgoWriter.Printf(buildStatusAnnotationValueLoggingFormat, buildStatusAnnotationValue)
  1122  					statusBytes := []byte(buildStatusAnnotationValue)
  1123  
  1124  					err = json.Unmarshal(statusBytes, &buildStatus)
  1125  					if err != nil {
  1126  						GinkgoWriter.Printf("cannot unmarshal build status: %v\n", err)
  1127  						return false, err
  1128  					}
  1129  
  1130  					if buildStatus.Simple != nil {
  1131  						GinkgoWriter.Printf("buildStartTime: %s\n", buildStatus.Simple.BuildStartTime)
  1132  						lastBuildStartTime = buildStatus.Simple.BuildStartTime
  1133  					} else {
  1134  						GinkgoWriter.Println("build status does not have simple field")
  1135  					}
  1136  
  1137  					return buildStatus.Simple != nil && buildStatus.Simple.BuildStartTime != "", nil
  1138  				}, timeout, interval).Should(BeTrue(), "build status has unexpected content")
  1139  
  1140  				//Expect pipelinerun count to be 1
  1141  				Eventually(func() error {
  1142  					pipelineRuns, err := f.AsKubeAdmin.HasController.GetAllPipelineRunsForApplication(applicationName, testNamespace)
  1143  					if err != nil {
  1144  						GinkgoWriter.Println("PiplelineRun has not been created yet")
  1145  						return err
  1146  					}
  1147  					if len(pipelineRuns.Items) != 1 {
  1148  						return fmt.Errorf("pipelinerun count in the namespace %s is not one, got pipelineruns %v", testNamespace, pipelineRuns.Items)
  1149  					}
  1150  					return nil
  1151  				}, time.Minute*5, constants.PipelineRunPollingInterval).Should(Succeed(), "timeout while waiting for first pipelinerun to start")
  1152  			})
  1153  
  1154  			Specify("simple build can be triggered manually", func() {
  1155  				// Wait 1 second before sending the second build request, so that we get different buildStatus.Simple.BuildStartTime timestamp
  1156  				time.Sleep(1 * time.Second)
  1157  				Expect(f.AsKubeAdmin.HasController.SetComponentAnnotation(componentName, controllers.BuildRequestAnnotationName, controllers.BuildRequestTriggerSimpleBuildAnnotationValue, testNamespace)).To(Succeed())
  1158  			})
  1159  
  1160  			It("another pipelineRun is triggered", func() {
  1161  				//Expect pipelinerun count to be 2
  1162  				Eventually(func() error {
  1163  					pipelineRuns, err := f.AsKubeAdmin.HasController.GetAllPipelineRunsForApplication(applicationName, testNamespace)
  1164  					if err != nil {
  1165  						GinkgoWriter.Println("Second piplelineRun has not been created yet")
  1166  						return err
  1167  					}
  1168  					if len(pipelineRuns.Items) != 2 {
  1169  						return fmt.Errorf("pipelinerun count in the namespace %s is not two, got pipelineruns %v", testNamespace, pipelineRuns.Items)
  1170  					}
  1171  					return nil
  1172  				}, time.Minute*5, constants.PipelineRunPollingInterval).Should(Succeed(), "timeout while waiting for second pipelinerun to start")
  1173  			})
  1174  
  1175  			It("component build annotation is correct", func() {
  1176  				var buildStatus *controllers.BuildStatus
  1177  
  1178  				Eventually(func() (bool, error) {
  1179  					component, err := f.AsKubeAdmin.HasController.GetComponent(componentName, testNamespace)
  1180  					if err != nil {
  1181  						GinkgoWriter.Printf("cannot get the component: %v\n", err)
  1182  						return false, err
  1183  					}
  1184  
  1185  					buildStatusAnnotationValue := component.Annotations[controllers.BuildStatusAnnotationName]
  1186  					GinkgoWriter.Printf(buildStatusAnnotationValueLoggingFormat, buildStatusAnnotationValue)
  1187  					statusBytes := []byte(buildStatusAnnotationValue)
  1188  
  1189  					err = json.Unmarshal(statusBytes, &buildStatus)
  1190  					if err != nil {
  1191  						GinkgoWriter.Printf("cannot unmarshal build status: %v\n", err)
  1192  						return false, err
  1193  					}
  1194  
  1195  					if buildStatus.Simple != nil {
  1196  						GinkgoWriter.Printf("buildStartTime: %s\n", buildStatus.Simple.BuildStartTime)
  1197  					} else {
  1198  						GinkgoWriter.Println("build status does not have simple field")
  1199  					}
  1200  
  1201  					return buildStatus.Simple != nil && buildStatus.Simple.BuildStartTime != lastBuildStartTime, nil
  1202  				}, timeout, interval).Should(BeTrue(), "build status has unexpected content")
  1203  			})
  1204  
  1205  			It("handles invalid request annotation", func() {
  1206  
  1207  				invalidAnnotation := "foo"
  1208  				expectedInvalidAnnotationMessage := fmt.Sprintf("unexpected build request: %s", invalidAnnotation)
  1209  
  1210  				Expect(f.AsKubeAdmin.HasController.SetComponentAnnotation(componentName, controllers.BuildRequestAnnotationName, invalidAnnotation, testNamespace)).To(Succeed())
  1211  
  1212  				// Waiting for 2 minute to see if any more pipelinerun is triggered
  1213  				Consistently(func() (bool, error) {
  1214  					pipelineRuns, err := f.AsKubeAdmin.HasController.GetAllPipelineRunsForApplication(applicationName, testNamespace)
  1215  					if err != nil {
  1216  						return false, err
  1217  					}
  1218  					if len(pipelineRuns.Items) != 2 {
  1219  						return false, fmt.Errorf("pipelinerun count in the namespace %s is not two, got pipelineruns %v", testNamespace, pipelineRuns.Items)
  1220  					}
  1221  					return true, nil
  1222  				}, time.Minute*2, constants.PipelineRunPollingInterval).Should(BeTrue(), "timeout while checking if any more pipelinerun is triggered")
  1223  
  1224  				buildStatus := &controllers.BuildStatus{}
  1225  				Eventually(func() error {
  1226  					component, err = f.AsKubeAdmin.HasController.GetComponent(componentName, testNamespace)
  1227  					if err != nil {
  1228  						return err
  1229  					} else if component == nil {
  1230  						return fmt.Errorf("got component as nil after getting component %s in namespace %s", componentName, testNamespace)
  1231  					}
  1232  					buildStatusAnnotationValue := component.Annotations[controllers.BuildStatusAnnotationName]
  1233  					GinkgoWriter.Printf(buildStatusAnnotationValueLoggingFormat, buildStatusAnnotationValue)
  1234  					statusBytes := []byte(buildStatusAnnotationValue)
  1235  					err = json.Unmarshal(statusBytes, buildStatus)
  1236  					if err != nil {
  1237  						return err
  1238  					}
  1239  					if !strings.Contains(buildStatus.Message, expectedInvalidAnnotationMessage) {
  1240  						return fmt.Errorf("build status message is not as expected, got: %q, expected: %q", buildStatus.Message, expectedInvalidAnnotationMessage)
  1241  					}
  1242  					return nil
  1243  				}, time.Minute*2, 2*time.Second).Should(Succeed(), "failed while checking build status message for component %q is correct after setting invalid annotations", componentName)
  1244  			})
  1245  		})
  1246  	})
  1247  
  1248  	Describe("Creating component with container image source", Ordered, func() {
  1249  		var applicationName, componentName, testNamespace string
  1250  		var timeout time.Duration
  1251  
  1252  		BeforeAll(func() {
  1253  			applicationName = fmt.Sprintf("test-app-%s", util.GenerateRandomString(4))
  1254  			f, err = framework.NewFramework(utils.GetGeneratedNamespace("build-e2e"))
  1255  			Expect(err).NotTo(HaveOccurred())
  1256  			testNamespace = f.UserNamespace
  1257  
  1258  			_, err = f.AsKubeAdmin.HasController.CreateApplication(applicationName, testNamespace)
  1259  			Expect(err).NotTo(HaveOccurred())
  1260  
  1261  			componentName = fmt.Sprintf("build-suite-test-component-image-source-%s", util.GenerateRandomString(6))
  1262  			outputContainerImage := ""
  1263  			timeout = time.Second * 10
  1264  			// Create a component with containerImageSource being defined
  1265  			component := appservice.ComponentSpec{
  1266  				ComponentName:  fmt.Sprintf("build-suite-test-component-image-source-%s", util.GenerateRandomString(6)),
  1267  				ContainerImage: containerImageSource,
  1268  			}
  1269  			_, err = f.AsKubeAdmin.HasController.CreateComponent(component, testNamespace, outputContainerImage, "", applicationName, true, map[string]string{})
  1270  			Expect(err).ShouldNot(HaveOccurred())
  1271  
  1272  			// collect Build ResourceQuota metrics (temporary)
  1273  			err = f.AsKubeAdmin.CommonController.GetResourceQuotaInfo("build", testNamespace, appstudioCrdsBuild)
  1274  			Expect(err).NotTo(HaveOccurred())
  1275  			err = f.AsKubeAdmin.CommonController.GetResourceQuotaInfo("build", testNamespace, computeBuild)
  1276  			Expect(err).NotTo(HaveOccurred())
  1277  		})
  1278  
  1279  		AfterAll(func() {
  1280  			// collect Build ResourceQuota metrics (temporary)
  1281  			err = f.AsKubeAdmin.CommonController.GetResourceQuotaInfo("build", testNamespace, appstudioCrdsBuild)
  1282  			Expect(err).NotTo(HaveOccurred())
  1283  			err = f.AsKubeAdmin.CommonController.GetResourceQuotaInfo("build", testNamespace, computeBuild)
  1284  			Expect(err).NotTo(HaveOccurred())
  1285  			if !CurrentSpecReport().Failed() {
  1286  				Expect(f.AsKubeAdmin.HasController.DeleteApplication(applicationName, testNamespace, false)).To(Succeed())
  1287  				Expect(f.AsKubeAdmin.HasController.DeleteComponent(componentName, testNamespace, false)).To(Succeed())
  1288  				Expect(f.AsKubeAdmin.TektonController.DeleteAllPipelineRunsInASpecificNamespace(testNamespace)).To(Succeed())
  1289  				Expect(f.SandboxController.DeleteUserSignup(f.UserName)).To(BeTrue())
  1290  			}
  1291  		})
  1292  
  1293  		It("should not trigger a PipelineRun", func() {
  1294  			Consistently(func() bool {
  1295  				_, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "")
  1296  				Expect(err).To(HaveOccurred())
  1297  				return strings.Contains(err.Error(), "no pipelinerun found")
  1298  			}, timeout, constants.PipelineRunPollingInterval).Should(BeTrue(), fmt.Sprintf("expected no PipelineRun to be triggered for the component %s in %s namespace", componentName, testNamespace))
  1299  		})
  1300  	})
  1301  
  1302  	Describe("PLNSRVCE-799 - test pipeline selector", Label("pipeline-selector"), Ordered, func() {
  1303  		var timeout time.Duration
  1304  		var componentName, applicationName, testNamespace string
  1305  		var expectedAdditionalPipelineParam buildservice.PipelineParam
  1306  		var pr *pipeline.PipelineRun
  1307  
  1308  		BeforeAll(func() {
  1309  			f, err = framework.NewFramework(utils.GetGeneratedNamespace("build-e2e"))
  1310  			Expect(err).NotTo(HaveOccurred())
  1311  			testNamespace = f.UserNamespace
  1312  			applicationName = fmt.Sprintf("test-app-%s", util.GenerateRandomString(4))
  1313  
  1314  			_, err = f.AsKubeAdmin.HasController.CreateApplication(applicationName, testNamespace)
  1315  			Expect(err).NotTo(HaveOccurred())
  1316  
  1317  			componentName = "build-suite-test-bundle-overriding"
  1318  
  1319  			expectedAdditionalPipelineParam = buildservice.PipelineParam{
  1320  				Name:  "test-custom-param-name",
  1321  				Value: "test-custom-param-value",
  1322  			}
  1323  
  1324  			timeout = time.Second * 600
  1325  
  1326  			// collect Build ResourceQuota metrics (temporary)
  1327  			err = f.AsKubeAdmin.CommonController.GetResourceQuotaInfo("build", testNamespace, appstudioCrdsBuild)
  1328  			Expect(err).NotTo(HaveOccurred())
  1329  			err = f.AsKubeAdmin.CommonController.GetResourceQuotaInfo("build", testNamespace, computeBuild)
  1330  			Expect(err).NotTo(HaveOccurred())
  1331  		})
  1332  
  1333  		AfterAll(func() {
  1334  			// collect Build ResourceQuota metrics (temporary)
  1335  			err = f.AsKubeAdmin.CommonController.GetResourceQuotaInfo("build", testNamespace, appstudioCrdsBuild)
  1336  			Expect(err).NotTo(HaveOccurred())
  1337  			err = f.AsKubeAdmin.CommonController.GetResourceQuotaInfo("build", testNamespace, computeBuild)
  1338  			Expect(err).NotTo(HaveOccurred())
  1339  
  1340  			if !CurrentSpecReport().Failed() {
  1341  				Expect(f.AsKubeAdmin.HasController.DeleteApplication(applicationName, testNamespace, false)).To(Succeed())
  1342  				Expect(f.AsKubeAdmin.HasController.DeleteComponent(componentName, testNamespace, false)).To(Succeed())
  1343  				Expect(f.AsKubeAdmin.TektonController.DeleteAllPipelineRunsInASpecificNamespace(testNamespace)).To(Succeed())
  1344  				Expect(f.SandboxController.DeleteUserSignup(f.UserName)).To(BeTrue())
  1345  			}
  1346  		})
  1347  
  1348  		It("a specific Pipeline bundle should be used and additional pipeline params should be added to the PipelineRun if all WhenConditions match", func() {
  1349  			// using cdq since git ref is not known
  1350  			cdq, err := f.AsKubeAdmin.HasController.CreateComponentDetectionQuery(componentName, testNamespace, helloWorldComponentGitSourceURL, "", "", "", false)
  1351  			Expect(err).NotTo(HaveOccurred())
  1352  			Expect(cdq.Status.ComponentDetected).To(HaveLen(1), "Expected length of the detected Components was not 1")
  1353  
  1354  			for _, compDetected := range cdq.Status.ComponentDetected {
  1355  				// Since we only know the component name after cdq creation,
  1356  				// BuildPipelineSelector should be created before component creation and after cdq creation
  1357  				ps := &buildservice.BuildPipelineSelector{
  1358  					ObjectMeta: metav1.ObjectMeta{
  1359  						Name:      "build-pipeline-selector",
  1360  						Namespace: testNamespace,
  1361  					},
  1362  					Spec: buildservice.BuildPipelineSelectorSpec{Selectors: []buildservice.PipelineSelector{
  1363  						{
  1364  							Name:           "user-custom-selector",
  1365  							PipelineRef:    *tekton.NewBundleResolverPipelineRef("docker-build", dummyPipelineBundleRef),
  1366  							PipelineParams: []buildservice.PipelineParam{expectedAdditionalPipelineParam},
  1367  							WhenConditions: buildservice.WhenCondition{
  1368  								ProjectType:        "hello-world",
  1369  								DockerfileRequired: pointer.To[bool](true),
  1370  								ComponentName:      compDetected.ComponentStub.ComponentName,
  1371  								Annotations:        map[string]string{"skip-initial-checks": "true"},
  1372  								Labels:             constants.ComponentDefaultLabel,
  1373  							},
  1374  						},
  1375  					}},
  1376  				}
  1377  
  1378  				Expect(f.AsKubeAdmin.CommonController.KubeRest().Create(context.Background(), ps)).To(Succeed())
  1379  				c, err := f.AsKubeAdmin.HasController.CreateComponent(compDetected.ComponentStub, testNamespace, "", "", applicationName, true, map[string]string{})
  1380  				Expect(err).NotTo(HaveOccurred())
  1381  				componentName = c.Name
  1382  			}
  1383  
  1384  			Eventually(func() error {
  1385  				pr, err = f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "")
  1386  				if err != nil {
  1387  					GinkgoWriter.Printf("PipelineRun has not been created yet for the component %s/%s\n", testNamespace, componentName)
  1388  					return err
  1389  				}
  1390  				if !pr.HasStarted() {
  1391  					return fmt.Errorf("pipelinerun %s/%s hasn't started yet", pr.GetNamespace(), pr.GetName())
  1392  				}
  1393  				return nil
  1394  			}, timeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the PipelineRun to start for the component %s/%s", testNamespace, componentName))
  1395  
  1396  			pr, err = f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "")
  1397  			Expect(err).ShouldNot(HaveOccurred())
  1398  			Expect(pr.Spec.PipelineRef.Params).To(ContainElement(pipeline.Param{
  1399  				Name:  "bundle",
  1400  				Value: pipeline.ParamValue{StringVal: dummyPipelineBundleRef, Type: "string"}},
  1401  			))
  1402  			Expect(pr.Spec.Params).To(ContainElement(pipeline.Param{
  1403  				Name:  expectedAdditionalPipelineParam.Name,
  1404  				Value: pipeline.ParamValue{StringVal: expectedAdditionalPipelineParam.Value, Type: "string"}},
  1405  			))
  1406  		})
  1407  
  1408  		It("default Pipeline bundle should be used and no additional Pipeline params should be added to the PipelineRun if one of the WhenConditions does not match", func() {
  1409  			notMatchingComponentName := componentName + util.GenerateRandomString(6)
  1410  			// using cdq since git ref is not known
  1411  			cdq, err := f.AsKubeAdmin.HasController.CreateComponentDetectionQuery(notMatchingComponentName, testNamespace, helloWorldComponentGitSourceURL, "", "", "", false)
  1412  			Expect(err).NotTo(HaveOccurred())
  1413  			Expect(cdq.Status.ComponentDetected).To(HaveLen(1), "Expected length of the detected Components was not 1")
  1414  
  1415  			for _, compDetected := range cdq.Status.ComponentDetected {
  1416  				c, err := f.AsKubeAdmin.HasController.CreateComponent(compDetected.ComponentStub, testNamespace, "", "", applicationName, true, map[string]string{})
  1417  				Expect(err).NotTo(HaveOccurred())
  1418  				notMatchingComponentName = c.Name
  1419  			}
  1420  
  1421  			Eventually(func() error {
  1422  				pr, err = f.AsKubeAdmin.HasController.GetComponentPipelineRun(notMatchingComponentName, applicationName, testNamespace, "")
  1423  				if err != nil {
  1424  					GinkgoWriter.Printf("PipelineRun has not been created yet for the component %s/%s\n", testNamespace, notMatchingComponentName)
  1425  					return err
  1426  				}
  1427  				if !pr.HasStarted() {
  1428  					return fmt.Errorf("pipelinerun %s/%s hasn't started yet", pr.GetNamespace(), pr.GetName())
  1429  				}
  1430  				return err
  1431  			}, timeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the PipelineRun to start for the component %s/%s", testNamespace, notMatchingComponentName))
  1432  
  1433  			pr, err = f.AsKubeAdmin.HasController.GetComponentPipelineRun(notMatchingComponentName, applicationName, testNamespace, "")
  1434  			Expect(err).ShouldNot(HaveOccurred())
  1435  			Expect(tekton.GetBundleRef(pr.Spec.PipelineRef)).ToNot(Equal(dummyPipelineBundleRef)) //nolint:all
  1436  			Expect(pr.Spec.Params).ToNot(ContainElement(pipeline.Param{
  1437  				Name:  expectedAdditionalPipelineParam.Name,
  1438  				Value: pipeline.ParamValue{StringVal: expectedAdditionalPipelineParam.Value, Type: "string"}},
  1439  			))
  1440  		})
  1441  	})
  1442  
  1443  	Describe("A secret with dummy quay.io credentials is created in the testing namespace", Ordered, func() {
  1444  
  1445  		var applicationName, componentName, testNamespace string
  1446  		var timeout time.Duration
  1447  		var err error
  1448  		var pr *pipeline.PipelineRun
  1449  
  1450  		BeforeAll(func() {
  1451  
  1452  			f, err = framework.NewFramework(utils.GetGeneratedNamespace("build-e2e"))
  1453  			Expect(err).NotTo(HaveOccurred())
  1454  			testNamespace = f.UserNamespace
  1455  
  1456  			if err = f.AsKubeAdmin.CommonController.UnlinkSecretFromServiceAccount(testNamespace, constants.RegistryAuthSecretName, constants.DefaultPipelineServiceAccount, true); err != nil {
  1457  				GinkgoWriter.Println(fmt.Sprintf("Failed to unlink registry auth secret from service account: %v\n", err))
  1458  			}
  1459  
  1460  			if err = f.AsKubeAdmin.CommonController.DeleteSecret(testNamespace, constants.RegistryAuthSecretName); err != nil {
  1461  				GinkgoWriter.Println(fmt.Sprintf("Failed to delete regitry auth secret from namespace: %s\n", err))
  1462  			}
  1463  
  1464  			_, err := f.AsKubeAdmin.CommonController.GetSecret(testNamespace, constants.RegistryAuthSecretName)
  1465  			if err != nil {
  1466  				// If we have an error when getting RegistryAuthSecretName, it should be IsNotFound err
  1467  				Expect(k8sErrors.IsNotFound(err)).To(BeTrue())
  1468  			} else {
  1469  				Skip("a registry auth secret is already created in testing namespace - skipping....")
  1470  			}
  1471  
  1472  			applicationName = fmt.Sprintf("test-app-%s", util.GenerateRandomString(4))
  1473  
  1474  			_, err = f.AsKubeAdmin.HasController.CreateApplication(applicationName, testNamespace)
  1475  			Expect(err).NotTo(HaveOccurred())
  1476  
  1477  			timeout = time.Minute * 5
  1478  
  1479  			dummySecret := &v1.Secret{
  1480  				ObjectMeta: metav1.ObjectMeta{Name: constants.RegistryAuthSecretName},
  1481  				Type:       v1.SecretTypeDockerConfigJson,
  1482  				Data:       map[string][]byte{".dockerconfigjson": []byte("{\"auths\":{\"quay.io\":{\"username\":\"test\",\"password\":\"test\",\"auth\":\"dGVzdDp0ZXN0\",\"email\":\"\"}}}")},
  1483  			}
  1484  
  1485  			_, err = f.AsKubeAdmin.CommonController.CreateSecret(testNamespace, dummySecret)
  1486  			Expect(err).ToNot(HaveOccurred())
  1487  			err = f.AsKubeAdmin.CommonController.LinkSecretToServiceAccount(testNamespace, dummySecret.Name, constants.DefaultPipelineServiceAccount, false)
  1488  			Expect(err).ToNot(HaveOccurred())
  1489  
  1490  			componentName = "build-suite-test-secret-overriding"
  1491  			// using cdq since git ref is not known
  1492  			cdq, err := f.AsKubeAdmin.HasController.CreateComponentDetectionQuery(componentName, testNamespace, helloWorldComponentGitSourceURL, "", "", "", false)
  1493  			Expect(err).NotTo(HaveOccurred())
  1494  			Expect(cdq.Status.ComponentDetected).To(HaveLen(1), "Expected length of the detected Components was not 1")
  1495  
  1496  			for _, compDetected := range cdq.Status.ComponentDetected {
  1497  				c, err := f.AsKubeAdmin.HasController.CreateComponent(compDetected.ComponentStub, testNamespace, "", "", applicationName, true, map[string]string{})
  1498  				Expect(err).NotTo(HaveOccurred())
  1499  				componentName = c.Name
  1500  			}
  1501  
  1502  			// collect Build ResourceQuota metrics (temporary)
  1503  			err = f.AsKubeAdmin.CommonController.GetResourceQuotaInfo("build", testNamespace, appstudioCrdsBuild)
  1504  			Expect(err).NotTo(HaveOccurred())
  1505  			err = f.AsKubeAdmin.CommonController.GetResourceQuotaInfo("build", testNamespace, computeBuild)
  1506  			Expect(err).NotTo(HaveOccurred())
  1507  		})
  1508  
  1509  		AfterAll(func() {
  1510  			// collect Build ResourceQuota metrics (temporary)
  1511  			err = f.AsKubeAdmin.CommonController.GetResourceQuotaInfo("build", testNamespace, appstudioCrdsBuild)
  1512  			Expect(err).NotTo(HaveOccurred())
  1513  			err = f.AsKubeAdmin.CommonController.GetResourceQuotaInfo("build", testNamespace, computeBuild)
  1514  			Expect(err).NotTo(HaveOccurred())
  1515  
  1516  			if !CurrentSpecReport().Failed() {
  1517  				Expect(f.AsKubeAdmin.HasController.DeleteApplication(applicationName, testNamespace, false)).To(Succeed())
  1518  				Expect(f.AsKubeAdmin.HasController.DeleteComponent(componentName, testNamespace, false)).To(Succeed())
  1519  				Expect(f.AsKubeAdmin.TektonController.DeleteAllPipelineRunsInASpecificNamespace(testNamespace)).To(Succeed())
  1520  				Expect(f.SandboxController.DeleteUserSignup(f.UserName)).To(BeTrue())
  1521  			}
  1522  		})
  1523  
  1524  		It("should override the shared secret", func() {
  1525  			Eventually(func() error {
  1526  				pr, err = f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "")
  1527  				if err != nil {
  1528  					GinkgoWriter.Printf("PipelineRun has not been created yet for the component %s/%s\n", testNamespace, componentName)
  1529  					return err
  1530  				}
  1531  				if !pr.HasStarted() {
  1532  					return fmt.Errorf("pipelinerun %s/%s hasn't started yet", pr.GetNamespace(), pr.GetName())
  1533  				}
  1534  				return nil
  1535  			}, timeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the PipelineRun to start for the component %s/%s", testNamespace, componentName))
  1536  
  1537  			pr, err = f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "")
  1538  			Expect(err).ShouldNot(HaveOccurred())
  1539  			Expect(pr.Spec.Workspaces).To(HaveLen(1))
  1540  		})
  1541  
  1542  		It("should not be possible to push to quay.io repo (PipelineRun should fail)", func() {
  1543  			pipelineRunTimeout := int(time.Duration(20) * time.Minute)
  1544  
  1545  			Expect(f.AsKubeAdmin.TektonController.WatchPipelineRun(pr.Name, testNamespace, pipelineRunTimeout)).To(Succeed())
  1546  			pr, err = f.AsKubeAdmin.TektonController.GetPipelineRun(pr.GetName(), pr.GetNamespace())
  1547  			Expect(err).NotTo(HaveOccurred())
  1548  			tr, err := f.AsKubeAdmin.TektonController.GetTaskRunStatus(f.AsKubeAdmin.CommonController.KubeRest(), pr, constants.BuildTaskRunName)
  1549  			Expect(err).NotTo(HaveOccurred())
  1550  			Expect(tekton.DidTaskRunSucceed(tr)).To(BeFalse())
  1551  		})
  1552  	})
  1553  
  1554  	Describe("test of component update with renovate", Ordered, Label("renovate", "multi-component"), func() {
  1555  		type multiComponent struct {
  1556  			repoName        string
  1557  			baseBranch      string
  1558  			componentBranch string
  1559  			baseRevision    string
  1560  			componentName   string
  1561  			gitRepo         string
  1562  			pacBranchName   string
  1563  			component       *appservice.Component
  1564  		}
  1565  
  1566  		ChildComponentDef := multiComponent{repoName: componentDependenciesChildRepoName, baseRevision: componentDependenciesChildGitRevision, baseBranch: componentDependenciesChildDefaultBranch}
  1567  		ParentComponentDef := multiComponent{repoName: componentDependenciesParentRepoName, baseRevision: componentDependenciesParentGitRevision, baseBranch: componentDependenciesParentDefaultBranch}
  1568  		components := []*multiComponent{&ChildComponentDef, &ParentComponentDef}
  1569  		var applicationName, testNamespace, mergeResultSha string
  1570  		var prNumber int
  1571  		var mergeResult *github.PullRequestMergeResult
  1572  		var timeout time.Duration
  1573  		var parentFirstDigest string
  1574  		var parentPostPacMergeDigest string
  1575  		var parentImageNameWithNoDigest string
  1576  		const distributionRepository = "quay.io/redhat-appstudio-qe/release-repository"
  1577  		quayOrg := utils.GetEnv("DEFAULT_QUAY_ORG", "")
  1578  
  1579  		var managedNamespace string
  1580  		BeforeAll(func() {
  1581  			f, err = framework.NewFramework(utils.GetGeneratedNamespace("build-e2e"))
  1582  			Expect(err).NotTo(HaveOccurred())
  1583  			testNamespace = f.UserNamespace
  1584  
  1585  			applicationName = fmt.Sprintf("build-suite-component-update-%s", util.GenerateRandomString(4))
  1586  			_, err = f.AsKubeAdmin.HasController.CreateApplication(applicationName, testNamespace)
  1587  			Expect(err).NotTo(HaveOccurred())
  1588  			branchString := util.GenerateRandomString(4)
  1589  			ParentComponentDef.componentBranch = fmt.Sprintf("multi-component-parent-base-%s", branchString)
  1590  			ChildComponentDef.componentBranch = fmt.Sprintf("multi-component-child-base-%s", branchString)
  1591  			ParentComponentDef.gitRepo = fmt.Sprintf(githubUrlFormat, gihubOrg, ParentComponentDef.repoName)
  1592  			ChildComponentDef.gitRepo = fmt.Sprintf(githubUrlFormat, gihubOrg, ChildComponentDef.repoName)
  1593  			ParentComponentDef.componentName = fmt.Sprintf("multi-component-parent-%s", branchString)
  1594  			ChildComponentDef.componentName = fmt.Sprintf("multi-component-child-%s", branchString)
  1595  			ParentComponentDef.pacBranchName = constants.PaCPullRequestBranchPrefix + ParentComponentDef.componentName
  1596  			ChildComponentDef.pacBranchName = constants.PaCPullRequestBranchPrefix + ChildComponentDef.componentName
  1597  
  1598  			for _, i := range components {
  1599  				println("creating branch " + i.componentBranch)
  1600  				err = f.AsKubeAdmin.CommonController.Github.CreateRef(i.repoName, i.baseBranch, i.baseRevision, i.componentBranch)
  1601  				Expect(err).ShouldNot(HaveOccurred())
  1602  			}
  1603  			// Also setup a release namespace so we can test nudging of distribution repository images
  1604  			managedNamespace = testNamespace + "-managed"
  1605  			_, err = f.AsKubeAdmin.CommonController.CreateTestNamespace(managedNamespace)
  1606  			Expect(err).ShouldNot(HaveOccurred())
  1607  
  1608  			// We just need the ReleaseAdmissionPlan to contain a mapping between component and distribution repositories
  1609  			data := struct {
  1610  				Mapping struct {
  1611  					Components []struct {
  1612  						Name       string
  1613  						Repository string
  1614  					}
  1615  				}
  1616  			}{}
  1617  			data.Mapping.Components = append(data.Mapping.Components, struct {
  1618  				Name       string
  1619  				Repository string
  1620  			}{Name: ParentComponentDef.componentName, Repository: distributionRepository})
  1621  			rawData, err := json.Marshal(&data)
  1622  
  1623  			GinkgoWriter.Printf("ReleaseAdmissionPlan data: %s", string(rawData))
  1624  			Expect(err).NotTo(HaveOccurred())
  1625  			_, err = f.AsKubeAdmin.ReleaseController.CreateReleasePlanAdmission("demo", managedNamespace, "", f.UserNamespace, "demo", constants.DefaultPipelineServiceAccount, []string{applicationName}, false, &tektonutils.PipelineRef{
  1626  				Resolver: "git",
  1627  				Params: []tektonutils.Param{
  1628  					{Name: "url", Value: releasecommon.RelSvcCatalogURL},
  1629  					{Name: "revision", Value: releasecommon.RelSvcCatalogRevision},
  1630  					{Name: "pathInRepo", Value: "pipelines/e2e/e2e.yaml"},
  1631  				}}, &runtime.RawExtension{Raw: rawData})
  1632  			Expect(err).NotTo(HaveOccurred())
  1633  
  1634  		})
  1635  
  1636  		AfterAll(func() {
  1637  			if !CurrentSpecReport().Failed() {
  1638  				Expect(f.AsKubeAdmin.HasController.DeleteApplication(applicationName, testNamespace, false)).To(Succeed())
  1639  				Expect(f.SandboxController.DeleteUserSignup(f.UserName)).To(BeTrue())
  1640  			}
  1641  			Expect(f.AsKubeAdmin.CommonController.DeleteNamespace(managedNamespace)).ShouldNot(HaveOccurred())
  1642  
  1643  			// Delete new branches created by renovate and a testing branch used as a component's base branch
  1644  			for _, c := range components {
  1645  				println("deleting branch " + c.componentBranch)
  1646  				err = f.AsKubeAdmin.CommonController.Github.DeleteRef(c.repoName, c.componentBranch)
  1647  				if err != nil {
  1648  					Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
  1649  				}
  1650  				err = f.AsKubeAdmin.CommonController.Github.DeleteRef(c.repoName, c.pacBranchName)
  1651  				if err != nil {
  1652  					Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
  1653  				}
  1654  			}
  1655  		})
  1656  
  1657  		When("components are created in same namespace", func() {
  1658  
  1659  			It("creates component with nudges", func() {
  1660  				for _, comp := range components {
  1661  					componentObj := appservice.ComponentSpec{
  1662  						ComponentName: comp.componentName,
  1663  						Application:   applicationName,
  1664  						Source: appservice.ComponentSource{
  1665  							ComponentSourceUnion: appservice.ComponentSourceUnion{
  1666  								GitSource: &appservice.GitSource{
  1667  									URL:           comp.gitRepo,
  1668  									Revision:      comp.componentBranch,
  1669  									DockerfileURL: "Dockerfile",
  1670  								},
  1671  							},
  1672  						},
  1673  					}
  1674  					//make the parent repo nudge the child repo
  1675  					if comp.repoName == componentDependenciesParentRepoName {
  1676  						componentObj.BuildNudgesRef = []string{ChildComponentDef.componentName}
  1677  						comp.component, err = f.AsKubeAdmin.HasController.CreateComponent(componentObj, testNamespace, "", "", applicationName, true, utils.MergeMaps(constants.ComponentPaCRequestAnnotation, constants.ImageControllerAnnotationRequestPublicRepo))
  1678  					} else {
  1679  						comp.component, err = f.AsKubeAdmin.HasController.CreateComponent(componentObj, testNamespace, "", "", applicationName, true, constants.ImageControllerAnnotationRequestPublicRepo)
  1680  					}
  1681  					Expect(err).ShouldNot(HaveOccurred())
  1682  				}
  1683  			})
  1684  			// Initial pipeline run, we need this so we have an initial image that we can then update
  1685  			It(fmt.Sprintf("triggers a PipelineRun for parent component %s", ParentComponentDef.componentName), func() {
  1686  				timeout = time.Minute * 5
  1687  
  1688  				Eventually(func() error {
  1689  					pr, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(ParentComponentDef.componentName, applicationName, testNamespace, "")
  1690  					if err != nil {
  1691  						GinkgoWriter.Printf("PipelineRun has not been created yet for the component %s/%s\n", testNamespace, ParentComponentDef.componentName)
  1692  						return err
  1693  					}
  1694  					if !pr.HasStarted() {
  1695  						return fmt.Errorf("pipelinerun %s/%s hasn't started yet", pr.GetNamespace(), pr.GetName())
  1696  					}
  1697  					return nil
  1698  				}, timeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the PipelineRun to start for the component %s/%s", ParentComponentDef.componentName, testNamespace))
  1699  			})
  1700  			It(fmt.Sprintf("the PipelineRun should eventually finish successfully for parent component %s", ParentComponentDef.componentName), func() {
  1701  				Expect(f.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(ParentComponentDef.component, "", f.AsKubeAdmin.TektonController, &has.RetryOptions{Always: true, Retries: 2}, nil)).To(Succeed())
  1702  				pr, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(ParentComponentDef.component.GetName(), ParentComponentDef.component.Spec.Application, ParentComponentDef.component.GetNamespace(), "")
  1703  				Expect(err).ShouldNot(HaveOccurred())
  1704  				for _, result := range pr.Status.PipelineRunStatusFields.Results {
  1705  					if result.Name == "IMAGE_DIGEST" {
  1706  						parentFirstDigest = result.Value.StringVal
  1707  					}
  1708  				}
  1709  				Expect(parentFirstDigest).ShouldNot(BeEmpty())
  1710  			})
  1711  			// Now we have an initial image we create a dockerfile in the child that references this new image
  1712  			// This is the file that will be updated by the nudge
  1713  			It("create dockerfile and yaml manifest that references build and distribution repositorys", func() {
  1714  
  1715  				component, err := f.AsKubeAdmin.HasController.GetComponent(ParentComponentDef.componentName, testNamespace)
  1716  				Expect(err).ShouldNot(HaveOccurred(), "could not get component %s in the %s namespace", ParentComponentDef.componentName, testNamespace)
  1717  
  1718  				annotations := component.GetAnnotations()
  1719  				imageRepoName, err := build.GetQuayImageName(annotations)
  1720  				Expect(err).ShouldNot(HaveOccurred())
  1721  				err = f.AsKubeAdmin.CommonController.Github.CreateRef(ChildComponentDef.repoName, ChildComponentDef.baseBranch, ChildComponentDef.baseRevision, ChildComponentDef.pacBranchName)
  1722  				Expect(err).ShouldNot(HaveOccurred())
  1723  				parentImageNameWithNoDigest = "quay.io/" + quayOrg + "/" + imageRepoName
  1724  				_, err = f.AsKubeAdmin.CommonController.Github.CreateFile(ChildComponentDef.repoName, "Dockerfile.tmp", "FROM "+parentImageNameWithNoDigest+"@"+parentFirstDigest+"\nRUN echo hello\n", ChildComponentDef.pacBranchName)
  1725  				Expect(err).ShouldNot(HaveOccurred())
  1726  
  1727  				_, err = f.AsKubeAdmin.CommonController.Github.CreateFile(ChildComponentDef.repoName, "manifest.yaml", "image: "+distributionRepository+"@"+parentFirstDigest, ChildComponentDef.pacBranchName)
  1728  				Expect(err).ShouldNot(HaveOccurred())
  1729  
  1730  				_, err = f.AsKubeAdmin.CommonController.Github.CreatePullRequest(ChildComponentDef.repoName, "update to build repo image", "update to build repo image", ChildComponentDef.pacBranchName, ChildComponentDef.componentBranch)
  1731  				Expect(err).ShouldNot(HaveOccurred())
  1732  				prs, err := f.AsKubeAdmin.CommonController.Github.ListPullRequests(ChildComponentDef.repoName)
  1733  				Expect(err).ShouldNot(HaveOccurred())
  1734  
  1735  				prno := -1
  1736  				for _, pr := range prs {
  1737  					if pr.Head.GetRef() == ChildComponentDef.pacBranchName {
  1738  						prno = pr.GetNumber()
  1739  					}
  1740  				}
  1741  				Expect(prno).ShouldNot(Equal(-1))
  1742  				_, err = f.AsKubeAdmin.CommonController.Github.MergePullRequest(ChildComponentDef.repoName, prno)
  1743  				Expect(err).ShouldNot(HaveOccurred())
  1744  
  1745  			})
  1746  			// This actually happens immediately, but we only need the PR number now
  1747  			It(fmt.Sprintf("should lead to a PaC PR creation for parent component %s", ParentComponentDef.componentName), func() {
  1748  				timeout = time.Second * 300
  1749  				interval := time.Second * 1
  1750  
  1751  				Eventually(func() bool {
  1752  					prs, err := f.AsKubeAdmin.CommonController.Github.ListPullRequests(ParentComponentDef.repoName)
  1753  					Expect(err).ShouldNot(HaveOccurred())
  1754  
  1755  					for _, pr := range prs {
  1756  						if pr.Head.GetRef() == ParentComponentDef.pacBranchName {
  1757  							prNumber = pr.GetNumber()
  1758  							return true
  1759  						}
  1760  					}
  1761  					return false
  1762  				}, timeout, interval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for PaC PR (branch name '%s') to be created in %s repository", ParentComponentDef.pacBranchName, ParentComponentDef.repoName))
  1763  			})
  1764  			It(fmt.Sprintf("Merging the PaC PR should be successful for parent component %s", ParentComponentDef.componentName), func() {
  1765  				Eventually(func() error {
  1766  					mergeResult, err = f.AsKubeAdmin.CommonController.Github.MergePullRequest(ParentComponentDef.repoName, prNumber)
  1767  					return err
  1768  				}, time.Minute).Should(BeNil(), fmt.Sprintf("error when merging PaC pull request #%d in repo %s", prNumber, ParentComponentDef.repoName))
  1769  
  1770  				mergeResultSha = mergeResult.GetSHA()
  1771  				GinkgoWriter.Printf("merged result sha: %s for PR #%d\n", mergeResultSha, prNumber)
  1772  
  1773  			})
  1774  			// Now the PR is merged this will kick off another build. The result of this build is what we want to update in dockerfile we created
  1775  			It(fmt.Sprintf("PR merge triggers PAC PipelineRun for parent component %s", ParentComponentDef.componentName), func() {
  1776  				timeout = time.Minute * 5
  1777  
  1778  				Eventually(func() error {
  1779  					pipelineRun, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(ParentComponentDef.componentName, applicationName, testNamespace, mergeResultSha)
  1780  					if err != nil {
  1781  						GinkgoWriter.Printf("Push PipelineRun has not been created yet for the component %s/%s\n", testNamespace, ParentComponentDef.componentName)
  1782  						return err
  1783  					}
  1784  					if !pipelineRun.HasStarted() {
  1785  						return fmt.Errorf("push pipelinerun %s/%s hasn't started yet", pipelineRun.GetNamespace(), pipelineRun.GetName())
  1786  					}
  1787  					return nil
  1788  				}, timeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the PipelineRun to start for the component %s/%s", testNamespace, ParentComponentDef.componentName))
  1789  			})
  1790  			// Wait for this PR to be done and store the digest, we will need it to verify that the nudge was correct
  1791  			It(fmt.Sprintf("PAC PipelineRun for parent component %s is successful", ParentComponentDef.componentName), func() {
  1792  				pr := &pipeline.PipelineRun{}
  1793  				Expect(f.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(ParentComponentDef.component, mergeResultSha, f.AsKubeAdmin.TektonController, &has.RetryOptions{Always: true, Retries: 2}, pr)).To(Succeed())
  1794  
  1795  				for _, result := range pr.Status.PipelineRunStatusFields.Results {
  1796  					if result.Name == "IMAGE_DIGEST" {
  1797  						parentPostPacMergeDigest = result.Value.StringVal
  1798  					}
  1799  				}
  1800  				Expect(parentPostPacMergeDigest).ShouldNot(BeEmpty())
  1801  			})
  1802  			It(fmt.Sprintf("should lead to a nudge PR creation for child component %s", ChildComponentDef.componentName), func() {
  1803  				timeout = time.Minute * 20
  1804  				interval := time.Second * 1
  1805  
  1806  				Eventually(func() bool {
  1807  					prs, err := f.AsKubeAdmin.CommonController.Github.ListPullRequests(componentDependenciesChildRepoName)
  1808  					Expect(err).ShouldNot(HaveOccurred())
  1809  
  1810  					for _, pr := range prs {
  1811  						if strings.Contains(pr.Head.GetRef(), ParentComponentDef.componentName) {
  1812  							prNumber = pr.GetNumber()
  1813  							return true
  1814  						}
  1815  					}
  1816  					return false
  1817  				}, timeout, interval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for component nudge PR to be created in %s repository", componentDependenciesChildRepoName))
  1818  			})
  1819  			It(fmt.Sprintf("merging the PR should be successful for child component %s", ChildComponentDef.componentName), func() {
  1820  				Eventually(func() error {
  1821  					mergeResult, err = f.AsKubeAdmin.CommonController.Github.MergePullRequest(componentDependenciesChildRepoName, prNumber)
  1822  					return err
  1823  				}, time.Minute).Should(BeNil(), fmt.Sprintf("error when merging nudge pull request #%d in repo %s", prNumber, componentDependenciesChildRepoName))
  1824  
  1825  				mergeResultSha = mergeResult.GetSHA()
  1826  				GinkgoWriter.Printf("merged result sha: %s for PR #%d\n", mergeResultSha, prNumber)
  1827  
  1828  			})
  1829  			// Now the nudge has been merged we verify the dockerfile is what we expected
  1830  			It("Verify the nudge updated the contents", func() {
  1831  
  1832  				GinkgoWriter.Printf("Verifying Dockerfile.tmp updated to sha %s", parentPostPacMergeDigest)
  1833  				component, err := f.AsKubeAdmin.HasController.GetComponent(ParentComponentDef.componentName, testNamespace)
  1834  				Expect(err).ShouldNot(HaveOccurred(), "could not get component %s in the %s namespace", ParentComponentDef.componentName, testNamespace)
  1835  
  1836  				annotations := component.GetAnnotations()
  1837  				imageRepoName, err := build.GetQuayImageName(annotations)
  1838  				Expect(err).ShouldNot(HaveOccurred())
  1839  				contents, err := f.AsKubeAdmin.CommonController.Github.GetFile(ChildComponentDef.repoName, "Dockerfile.tmp", ChildComponentDef.componentBranch)
  1840  				Expect(err).ShouldNot(HaveOccurred())
  1841  				content, err := contents.GetContent()
  1842  				Expect(err).ShouldNot(HaveOccurred())
  1843  				Expect(content).Should(Equal("FROM quay.io/" + quayOrg + "/" + imageRepoName + "@" + parentPostPacMergeDigest + "\nRUN echo hello\n"))
  1844  
  1845  				contents, err = f.AsKubeAdmin.CommonController.Github.GetFile(ChildComponentDef.repoName, "manifest.yaml", ChildComponentDef.componentBranch)
  1846  				Expect(err).ShouldNot(HaveOccurred())
  1847  				content, err = contents.GetContent()
  1848  				Expect(err).ShouldNot(HaveOccurred())
  1849  				Expect(content).Should(Equal("image: " + distributionRepository + "@" + parentPostPacMergeDigest))
  1850  
  1851  			})
  1852  		})
  1853  
  1854  	})
  1855  
  1856  })
  1857  
  1858  func createBuildSecret(f *framework.Framework, secretName string, annotations map[string]string, token string) error {
  1859  	buildSecret := v1.Secret{}
  1860  	buildSecret.Name = secretName
  1861  	buildSecret.Labels = map[string]string{
  1862  		"appstudio.redhat.com/credentials": "scm",
  1863  		"appstudio.redhat.com/scm.host":    "github.com",
  1864  	}
  1865  	if annotations != nil {
  1866  		buildSecret.Annotations = annotations
  1867  	}
  1868  	buildSecret.Type = "kubernetes.io/basic-auth"
  1869  	buildSecret.StringData = map[string]string{
  1870  		"password": token,
  1871  	}
  1872  	_, err := f.AsKubeAdmin.CommonController.CreateSecret(f.UserNamespace, &buildSecret)
  1873  	if err != nil {
  1874  		return fmt.Errorf("error creating build secret: %v", err)
  1875  	}
  1876  	return nil
  1877  }
  1878  
  1879  func cleanupWebhooks(f *framework.Framework, repoName string) {
  1880  	hooks, err := f.AsKubeAdmin.CommonController.Github.ListRepoWebhooks(repoName)
  1881  	Expect(err).NotTo(HaveOccurred())
  1882  	for _, h := range hooks {
  1883  		hookUrl := h.Config["url"].(string)
  1884  		if strings.Contains(hookUrl, f.ClusterAppDomain) {
  1885  			GinkgoWriter.Printf("removing webhook URL: %s\n", hookUrl)
  1886  			Expect(f.AsKubeAdmin.CommonController.Github.DeleteWebhook(repoName, h.GetID())).To(Succeed())
  1887  			break
  1888  		}
  1889  	}
  1890  }