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

     1  package pipelines
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/devfile/library/v2/pkg/util"
    10  	ecp "github.com/enterprise-contract/enterprise-contract-controller/api/v1alpha1"
    11  	. "github.com/onsi/ginkgo/v2"
    12  	. "github.com/onsi/gomega"
    13  	appservice "github.com/redhat-appstudio/application-api/api/v1alpha1"
    14  	"github.com/redhat-appstudio/e2e-tests/pkg/clients/github"
    15  	"github.com/redhat-appstudio/e2e-tests/pkg/clients/has"
    16  	"github.com/redhat-appstudio/e2e-tests/pkg/constants"
    17  	"github.com/redhat-appstudio/e2e-tests/pkg/framework"
    18  	"github.com/redhat-appstudio/e2e-tests/pkg/utils"
    19  	"github.com/redhat-appstudio/e2e-tests/pkg/utils/tekton"
    20  	releasecommon "github.com/redhat-appstudio/e2e-tests/tests/release"
    21  	releaseapi "github.com/redhat-appstudio/release-service/api/v1alpha1"
    22  	tektonutils "github.com/redhat-appstudio/release-service/tekton/utils"
    23  	tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
    24  	corev1 "k8s.io/api/core/v1"
    25  	"k8s.io/apimachinery/pkg/api/errors"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  )
    29  
    30  const (
    31  	sampServiceAccountName = "release-service-account"
    32  	sampSourceGitURL       = "https://github.com/redhat-appstudio-qe/devfile-sample-go-basic"
    33  	sampReleaseURL         = "https://github.com/redhat-appstudio-qe/devfile-sample-go-basic/releases/tag/v2.1"
    34  	sampRepoOwner          = "redhat-appstudio-qe"
    35  	sampRepo               = "devfile-sample-go-basic"
    36  	sampCatalogPathInRepo  = "pipelines/release-to-github/release-to-github.yaml"
    37  )
    38  
    39  var _ = framework.ReleasePipelinesSuiteDescribe("e2e tests for release-to-github pipeline", Label("release-pipelines", "release-to-github"), func() {
    40  	defer GinkgoRecover()
    41  
    42  	var devWorkspace = utils.GetEnv(constants.RELEASE_DEV_WORKSPACE_ENV, constants.DevReleaseTeam)
    43  	var managedWorkspace = utils.GetEnv(constants.RELEASE_MANAGED_WORKSPACE_ENV, constants.ManagedReleaseTeam)
    44  
    45  	var devNamespace = devWorkspace + "-tenant"
    46  	var managedNamespace = managedWorkspace + "-tenant"
    47  
    48  	var err error
    49  	var devFw *framework.Framework
    50  	var managedFw *framework.Framework
    51  	var sampApplicationName = "samp-app-" + util.GenerateRandomString(4)
    52  	var sampComponentName = "samp-comp-" + util.GenerateRandomString(4)
    53  	var sampReleasePlanName = "samp-rp-" + util.GenerateRandomString(4)
    54  	var sampReleasePlanAdmissionName = "samp-rpa-" + util.GenerateRandomString(4)
    55  	var sampEnterpriseContractPolicyName = "samp-policy-" + util.GenerateRandomString(4)
    56  
    57  	var snapshot *appservice.Snapshot
    58  	var releaseCR *releaseapi.Release
    59  	var releasePR, buildPR *tektonv1.PipelineRun
    60  	var gh *github.Github
    61  
    62  	AfterEach(framework.ReportFailure(&devFw))
    63  
    64  	Describe("Release-to-github happy path", Label("releaseToGithub"), func() {
    65  		var component *appservice.Component
    66  		BeforeAll(func() {
    67  			devFw = releasecommon.NewFramework(devWorkspace)
    68  			managedFw = releasecommon.NewFramework(managedWorkspace)
    69  
    70  			managedNamespace = managedFw.UserNamespace
    71  
    72  			// Linking the build secret to the pipeline service account in dev namespace.
    73  			err = devFw.AsKubeAdmin.CommonController.LinkSecretToServiceAccount(devNamespace, releasecommon.HacbsReleaseTestsTokenSecret, constants.DefaultPipelineServiceAccount, true)
    74  			Expect(err).ToNot(HaveOccurred())
    75  
    76  			githubUser := utils.GetEnv("GITHUB_USER", "redhat-appstudio-qe-bot")
    77  			githubToken := utils.GetEnv(constants.GITHUB_TOKEN_ENV, "")
    78  			gh, err = github.NewGithubClient(githubToken, githubUser)
    79  			Expect(githubToken).ToNot(BeEmpty())
    80  
    81  			// Remove the release if the release exists
    82  			if gh.CheckIfReleaseExist(sampRepoOwner, sampRepo, sampReleaseURL) {
    83  				gh.DeleteRelease(sampRepoOwner, sampRepo, sampReleaseURL)
    84  			}
    85  
    86  			_, err = managedFw.AsKubeAdmin.CommonController.GetSecret(managedNamespace, releasecommon.RedhatAppstudioQESecret)
    87  			if errors.IsNotFound(err) {
    88  				githubSecret := &corev1.Secret{
    89  					ObjectMeta: metav1.ObjectMeta{
    90  						Name:      releasecommon.RedhatAppstudioQESecret,
    91  						Namespace: managedNamespace,
    92  					},
    93  					Type: corev1.SecretTypeOpaque,
    94  					Data: map[string][]byte{
    95  						"token": []byte(githubToken),
    96  					},
    97  				}
    98  				_, err = managedFw.AsKubeAdmin.CommonController.CreateSecret(managedNamespace, githubSecret)
    99  				Expect(err).ToNot(HaveOccurred())
   100  			}
   101  			Expect(err).ToNot(HaveOccurred())
   102  
   103  			err = managedFw.AsKubeAdmin.CommonController.LinkSecretToServiceAccount(managedNamespace, releasecommon.RedhatAppstudioQESecret, constants.DefaultPipelineServiceAccount, true)
   104  			Expect(err).ToNot(HaveOccurred())
   105  
   106  			_, err = devFw.AsKubeDeveloper.HasController.CreateApplication(sampApplicationName, devNamespace)
   107  			Expect(err).NotTo(HaveOccurred())
   108  
   109  			_, err = devFw.AsKubeDeveloper.ReleaseController.CreateReleasePlan(sampReleasePlanName, devNamespace, sampApplicationName, managedNamespace, "true", nil)
   110  			Expect(err).NotTo(HaveOccurred())
   111  
   112  			createGHReleasePlanAdmission(sampReleasePlanAdmissionName, *managedFw, devNamespace, managedNamespace, sampApplicationName, sampEnterpriseContractPolicyName, sampCatalogPathInRepo, "false", "", "", "", "")
   113  			component = releasecommon.CreateComponentByCDQ(*devFw, devNamespace, managedNamespace, sampApplicationName, sampComponentName, sampSourceGitURL)
   114  			createGHEnterpriseContractPolicy(sampEnterpriseContractPolicyName, *managedFw, devNamespace, managedNamespace)
   115  		})
   116  
   117  		AfterAll(func() {
   118  			devFw = releasecommon.NewFramework(devWorkspace)
   119  			managedFw = releasecommon.NewFramework(managedWorkspace)
   120  			Expect(devFw.AsKubeDeveloper.HasController.DeleteApplication(sampApplicationName, devNamespace, false)).NotTo(HaveOccurred())
   121  			Expect(managedFw.AsKubeDeveloper.TektonController.DeleteEnterpriseContractPolicy(sampEnterpriseContractPolicyName, managedNamespace, false)).NotTo(HaveOccurred())
   122  			Expect(managedFw.AsKubeDeveloper.ReleaseController.DeleteReleasePlanAdmission(sampReleasePlanAdmissionName, managedNamespace, false)).NotTo(HaveOccurred())
   123  		})
   124  
   125  		var _ = Describe("Post-release verification", func() {
   126  			It("verifies that a build PipelineRun is created in dev namespace and succeeds", func() {
   127  				devFw = releasecommon.NewFramework(devWorkspace)
   128  				managedFw = releasecommon.NewFramework(managedWorkspace)
   129  				// Create a ticker that ticks every 3 minutes
   130  				ticker := time.NewTicker(3 * time.Minute)
   131  				// Schedule the stop of the ticker after 15 minutes
   132  				time.AfterFunc(15*time.Minute, func() {
   133  					ticker.Stop()
   134  					fmt.Println("Stopped executing every 3 minutes.")
   135  				})
   136  				// Run a goroutine to handle the ticker ticks
   137  				go func() {
   138  					for range ticker.C {
   139  						devFw = releasecommon.NewFramework(devWorkspace)
   140  						managedFw = releasecommon.NewFramework(managedWorkspace)
   141  					}
   142  				}()
   143  				Eventually(func() error {
   144  					buildPR, err = devFw.AsKubeDeveloper.HasController.GetComponentPipelineRun(component.Name, sampApplicationName, devNamespace, "")
   145  					if err != nil {
   146  						return err
   147  					}
   148  					if !buildPR.IsDone() {
   149  						return fmt.Errorf("build pipelinerun %s in namespace %s did not finish yet", buildPR.Name, buildPR.Namespace)
   150  					}
   151  					Expect(tekton.HasPipelineRunSucceeded(buildPR)).To(BeTrue(), fmt.Sprintf("build pipelinerun %s/%s did not succeed", buildPR.GetNamespace(), buildPR.GetName()))
   152  					snapshot, err = devFw.AsKubeDeveloper.IntegrationController.GetSnapshot("", buildPR.Name, "", devNamespace)
   153  					if err != nil {
   154  						return err
   155  					}
   156  					return nil
   157  				}, releasecommon.BuildPipelineRunCompletionTimeout, releasecommon.DefaultInterval).Should(Succeed(), "timed out when waiting for build pipelinerun to be created")
   158  				Expect(devFw.AsKubeDeveloper.HasController.WaitForComponentPipelineToBeFinished(component, "", devFw.AsKubeDeveloper.TektonController, &has.RetryOptions{Retries: 3, Always: true}, nil)).To(Succeed())
   159  			})
   160  			It("verifies release pipelinerun is running and succeeds", func() {
   161  				devFw = releasecommon.NewFramework(devWorkspace)
   162  				managedFw = releasecommon.NewFramework(managedWorkspace)
   163  
   164  				releaseCR, err = devFw.AsKubeDeveloper.ReleaseController.GetRelease("", snapshot.Name, devNamespace)
   165  				Expect(err).ShouldNot(HaveOccurred())
   166  				Eventually(func() error {
   167  					releasePR, err = managedFw.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedFw.UserNamespace, releaseCR.GetName(), releaseCR.GetNamespace())
   168  					if err != nil {
   169  						return err
   170  					}
   171  					GinkgoWriter.Println("Release PR: ", releasePR.Name)
   172  					if !releasePR.IsDone() {
   173  						return fmt.Errorf("release pipelinerun %s in namespace %s did not finished yet", releasePR.Name, releasePR.Namespace)
   174  					}
   175  					return nil
   176  				}, releasecommon.ReleasePipelineRunCompletionTimeout, releasecommon.DefaultInterval).Should(Succeed(), "timed out when waiting for release pipelinerun to succeed")
   177  				Expect(tekton.HasPipelineRunSucceeded(releasePR)).To(BeTrue(), fmt.Sprintf("release pipelinerun %s/%s did not succeed", releasePR.GetNamespace(), releasePR.GetName()))
   178  			})
   179  
   180  			It("verifies release CR completed and set succeeded.", func() {
   181  				devFw = releasecommon.NewFramework(devWorkspace)
   182  				Eventually(func() error {
   183  					releaseCr, err := devFw.AsKubeDeveloper.ReleaseController.GetRelease("", snapshot.Name, devNamespace)
   184  					if err != nil {
   185  						return err
   186  					}
   187  					GinkgoWriter.Println("Release CR: ", releaseCr.Name)
   188  					if !releaseCr.IsReleased() {
   189  						return fmt.Errorf("release %s/%s is not marked as finished yet", releaseCR.GetNamespace(), releaseCR.GetName())
   190  					}
   191  					return nil
   192  				}, 10*time.Minute, releasecommon.DefaultInterval).Should(Succeed())
   193  			})
   194  
   195  			It("verifies if the Release exists in github repo", func() {
   196  				managedFw = releasecommon.NewFramework(managedWorkspace)
   197  				trReleasePr, err := managedFw.AsKubeAdmin.TektonController.GetTaskRunStatus(managedFw.AsKubeAdmin.CommonController.KubeRest(), releasePR, "create-github-release")
   198  				Expect(err).NotTo(HaveOccurred())
   199  				trReleaseURL := trReleasePr.Status.TaskRunStatusFields.Results[0].Value.StringVal
   200  				releaseURL := strings.Replace(trReleaseURL, "\n", "", -1)
   201  				Expect(gh.CheckIfReleaseExist(sampRepoOwner, sampRepo, releaseURL)).To(BeTrue(), fmt.Sprintf("release %s doesn't exist", releaseURL))
   202  			})
   203  		})
   204  	})
   205  })
   206  
   207  func createGHEnterpriseContractPolicy(sampECPName string, managedFw framework.Framework, devNamespace, managedNamespace string) {
   208  	defaultEcPolicySpec := ecp.EnterpriseContractPolicySpec{
   209  		Description: "Red Hat's enterprise requirements",
   210  		PublicKey:   "k8s://openshift-pipelines/public-key",
   211  		Sources: []ecp.Source{{
   212  			Name:   "Default",
   213  			Policy: []string{releasecommon.EcPolicyLibPath, releasecommon.EcPolicyReleasePath},
   214  			Data:   []string{releasecommon.EcPolicyDataBundle, releasecommon.EcPolicyDataPath},
   215  		}},
   216  		Configuration: &ecp.EnterpriseContractPolicyConfiguration{
   217  			Exclude: []string{"cve", "step_image_registries", "tasks.required_tasks_found:prefetch-dependencies"},
   218  			Include: []string{"minimal", "slsa3"},
   219  		},
   220  	}
   221  
   222  	_, err := managedFw.AsKubeDeveloper.TektonController.CreateEnterpriseContractPolicy(sampECPName, managedNamespace, defaultEcPolicySpec)
   223  	Expect(err).NotTo(HaveOccurred())
   224  
   225  }
   226  
   227  func createGHReleasePlanAdmission(sampRPAName string, managedFw framework.Framework, devNamespace, managedNamespace, sampAppName, sampECPName, pathInRepoValue, hotfix, issueId, preGA, productName, productVersion string) {
   228  	var err error
   229  
   230  	data, err := json.Marshal(map[string]interface{}{
   231  		"github": map[string]interface{}{
   232  			"githubSecret": releasecommon.RedhatAppstudioQESecret,
   233  		},
   234  		"sign": map[string]interface{}{
   235  			"configMapName": "hacbs-signing-pipeline-config-redhatbeta2",
   236  		},
   237  	})
   238  	Expect(err).NotTo(HaveOccurred())
   239  
   240  	_, err = managedFw.AsKubeAdmin.ReleaseController.CreateReleasePlanAdmission(sampRPAName, managedNamespace, "", devNamespace, sampECPName, sampServiceAccountName, []string{sampAppName}, true, &tektonutils.PipelineRef{
   241  		Resolver: "git",
   242  		Params: []tektonutils.Param{
   243  			{Name: "url", Value: releasecommon.RelSvcCatalogURL},
   244  			{Name: "revision", Value: releasecommon.RelSvcCatalogRevision},
   245  			{Name: "pathInRepo", Value: pathInRepoValue},
   246  		},
   247  	}, &runtime.RawExtension{
   248  		Raw: data,
   249  	})
   250  	Expect(err).NotTo(HaveOccurred())
   251  }