From 019e0d411de667dff6952852e03b4a38b0a689c3 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Thu, 19 Oct 2023 13:52:45 +0200 Subject: [PATCH] Added commit ID and tags to promote job and job models (#550) * Added commit ID and tags to promote job and job models * Cleanup * Cleanup * Renamed swagger endpoint restart to rerun * remove log.Print(err) with require.NoError(t, err) --------- Co-authored-by: Richard Hagen --- .../applications_controller_test.go | 44 ++++++++---- api/applications/applications_handler.go | 33 ++++++--- api/buildstatus/models/buildstatus.go | 8 ++- .../environment_controller_secrets_test.go | 9 ++- .../environment_controller_test.go | 68 ++++++++++++------- api/events/event_handler_test.go | 18 ++--- api/jobs/job_controller.go | 2 +- api/jobs/models/job.go | 34 +++++++--- api/jobs/models/job_summary.go | 42 ++++++++++-- api/jobs/start_job_handler.go | 1 + api/kubequery/deployment.go | 12 +++- api/secrets/models/tls_certificate_test.go | 4 +- go.mod | 2 +- go.sum | 4 +- swaggerui_src/swagger.json | 44 +++++++++++- 15 files changed, 240 insertions(+), 85 deletions(-) diff --git a/api/applications/applications_controller_test.go b/api/applications/applications_controller_test.go index 3601224f..fe1483a5 100644 --- a/api/applications/applications_controller_test.go +++ b/api/applications/applications_controller_test.go @@ -12,18 +12,18 @@ import ( "testing" "time" - "github.com/equinor/radix-api/models" - "github.com/equinor/radix-common/utils/pointers" - applicationModels "github.com/equinor/radix-api/api/applications/models" environmentModels "github.com/equinor/radix-api/api/environments/models" jobModels "github.com/equinor/radix-api/api/jobs/models" controllertest "github.com/equinor/radix-api/api/test" "github.com/equinor/radix-api/api/utils" + "github.com/equinor/radix-api/models" radixhttp "github.com/equinor/radix-common/net/http" radixutils "github.com/equinor/radix-common/utils" + "github.com/equinor/radix-common/utils/pointers" "github.com/equinor/radix-operator/pkg/apis/applicationconfig" "github.com/equinor/radix-operator/pkg/apis/defaults" + "github.com/equinor/radix-operator/pkg/apis/kube" jobPipeline "github.com/equinor/radix-operator/pkg/apis/pipeline" v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" "github.com/equinor/radix-operator/pkg/apis/radixvalidators" @@ -1393,26 +1393,44 @@ func TestHandleTriggerPipeline_Deploy_JobHasCorrectParameters(t *testing.T) { } func TestHandleTriggerPipeline_Promote_JobHasCorrectParameters(t *testing.T) { - _, controllerTestUtils, _, radixclient, _, _ := setupTest(true, true) - - appName := "an-app" + commonTestUtils, controllerTestUtils, _, radixclient, _, _ := setupTest(true, true) + + const ( + appName = "an-app" + commitId = "475f241c-478b-49da-adfb-3c336aaab8d2" + deploymentName = "a-deployment" + fromEnvironment = "origin" + toEnvironment = "target" + ) parameters := applicationModels.PipelineParametersPromote{ - FromEnvironment: "origin", - ToEnvironment: "target", - DeploymentName: "a-deployment", + FromEnvironment: fromEnvironment, + ToEnvironment: toEnvironment, + DeploymentName: deploymentName, } + _, err := commonTestUtils.ApplyDeployment(builders. + ARadixDeployment(). + WithAppName(appName). + WithDeploymentName(deploymentName). + WithEnvironment(fromEnvironment). + WithLabel(kube.RadixCommitLabel, commitId). + WithCondition(v1.DeploymentInactive)) + require.NoError(t, err) + registerAppParam := buildApplicationRegistrationRequest(anApplicationRegistration().WithName(appName).Build(), false) <-controllerTestUtils.ExecuteRequestWithParameters("POST", "/api/v1/applications", registerAppParam) responseChannel := controllerTestUtils.ExecuteRequestWithParameters("POST", fmt.Sprintf("/api/v1/applications/%s/pipelines/%s", appName, v1.Promote), parameters) <-responseChannel appNamespace := fmt.Sprintf("%s-app", appName) - jobs, _ := getJobsInNamespace(radixclient, appNamespace) + jobs, err := getJobsInNamespace(radixclient, appNamespace) + require.NoError(t, err) - assert.Equal(t, jobs[0].Spec.Promote.FromEnvironment, "origin") - assert.Equal(t, jobs[0].Spec.Promote.ToEnvironment, "target") - assert.Equal(t, jobs[0].Spec.Promote.DeploymentName, "a-deployment") + require.Len(t, jobs, 1) + assert.Equal(t, jobs[0].Spec.Promote.FromEnvironment, fromEnvironment) + assert.Equal(t, jobs[0].Spec.Promote.ToEnvironment, toEnvironment) + assert.Equal(t, jobs[0].Spec.Promote.DeploymentName, deploymentName) + assert.Equal(t, jobs[0].Spec.Promote.CommitID, commitId) } func TestIsDeployKeyValid(t *testing.T) { diff --git a/api/applications/applications_handler.go b/api/applications/applications_handler.go index b7a4d460..037d62da 100644 --- a/api/applications/applications_handler.go +++ b/api/applications/applications_handler.go @@ -4,6 +4,9 @@ import ( "context" "encoding/json" "fmt" + "net/http" + "strings" + applicationModels "github.com/equinor/radix-api/api/applications/models" "github.com/equinor/radix-api/api/deployments" "github.com/equinor/radix-api/api/environments" @@ -19,10 +22,11 @@ import ( "github.com/equinor/radix-operator/pkg/apis/applicationconfig" "github.com/equinor/radix-operator/pkg/apis/defaults" "github.com/equinor/radix-operator/pkg/apis/defaults/k8s" + "github.com/equinor/radix-operator/pkg/apis/kube" jobPipeline "github.com/equinor/radix-operator/pkg/apis/pipeline" v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" "github.com/equinor/radix-operator/pkg/apis/radixvalidators" - crdUtils "github.com/equinor/radix-operator/pkg/apis/utils" + operatorUtils "github.com/equinor/radix-operator/pkg/apis/utils" log "github.com/sirupsen/logrus" authorizationapi "k8s.io/api/authorization/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -31,8 +35,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/fake" - "net/http" - "strings" ) type patch struct { @@ -66,7 +68,7 @@ func NewApplicationHandler(accounts models.Accounts, config ApplicationHandlerCo } func getApiNamespace(config ApplicationHandlerConfig) string { - if namespace := crdUtils.GetEnvironmentNamespace(config.AppName, config.EnvironmentName); len(namespace) > 0 { + if namespace := operatorUtils.GetEnvironmentNamespace(config.AppName, config.EnvironmentName); len(namespace) > 0 { return namespace } panic("missing RADIX_APP or RADIX_ENVIRONMENT environment variables") @@ -288,7 +290,7 @@ func (ah *ApplicationHandler) ModifyRegistrationDetails(ctx context.Context, app } if patchRequest.Repository != nil && *patchRequest.Repository != "" { - cloneURL := crdUtils.GetGithubCloneURLFromRepo(*patchRequest.Repository) + cloneURL := operatorUtils.GetGithubCloneURLFromRepo(*patchRequest.Repository) updatedRegistration.Spec.CloneURL = cloneURL payload = append(payload, patch{Op: "replace", Path: "/spec/cloneURL", Value: cloneURL}) runUpdate = true @@ -433,6 +435,15 @@ func (ah *ApplicationHandler) TriggerPipelinePromote(ctx context.Context, appNam return nil, err } + radixDeployment, err := kubequery.GetRadixDeploymentByName(ctx, ah.accounts.UserAccount.RadixClient, appName, fromEnvironment, deploymentName) + if err != nil { + if k8serrors.IsNotFound(err) { + return nil, fmt.Errorf("deployment %s not found in the app %s, environment %s", deploymentName, appName, fromEnvironment) + } + return nil, fmt.Errorf("failed to get deployment %s for the app %s, environment %s: %v", deploymentName, appName, fromEnvironment, err) + } + + jobParameters.CommitID = radixDeployment.GetLabels()[kube.RadixCommitLabel] jobSummary, err := ah.jobHandler.HandleStartPipelineJob(ctx, appName, pipeline, jobParameters) if err != nil { return nil, err @@ -601,23 +612,23 @@ func (ah *ApplicationHandler) RegenerateDeployKey(ctx context.Context, appName s if regenerateDeployKeyAndSecretData.PrivateKey != "" { // Deriving the public key from the private key in order to test it for validity - _, err := crdUtils.DeriveDeployKeyFromPrivateKey(regenerateDeployKeyAndSecretData.PrivateKey) + _, err := operatorUtils.DeriveDeployKeyFromPrivateKey(regenerateDeployKeyAndSecretData.PrivateKey) if err != nil { return fmt.Errorf("failed to derive public key from private key: %v", err) } - existingSecret, err := ah.getUserAccount().Client.CoreV1().Secrets(crdUtils.GetAppNamespace(appName)).Get(ctx, defaults.GitPrivateKeySecretName, metav1.GetOptions{}) + existingSecret, err := ah.getUserAccount().Client.CoreV1().Secrets(operatorUtils.GetAppNamespace(appName)).Get(ctx, defaults.GitPrivateKeySecretName, metav1.GetOptions{}) if err != nil { return err } newSecret := existingSecret.DeepCopy() newSecret.Data[defaults.GitPrivateKeySecretKey] = []byte(regenerateDeployKeyAndSecretData.PrivateKey) - _, err = ah.getUserAccount().Client.CoreV1().Secrets(crdUtils.GetAppNamespace(appName)).Update(ctx, newSecret, metav1.UpdateOptions{}) + _, err = ah.getUserAccount().Client.CoreV1().Secrets(operatorUtils.GetAppNamespace(appName)).Update(ctx, newSecret, metav1.UpdateOptions{}) if err != nil { return err } } else { // Deleting the secret with the private key. This triggers the RR to be reconciled and the new key to be generated - err = ah.getUserAccount().Client.CoreV1().Secrets(crdUtils.GetAppNamespace(appName)).Delete(ctx, defaults.GitPrivateKeySecretName, metav1.DeleteOptions{}) + err = ah.getUserAccount().Client.CoreV1().Secrets(operatorUtils.GetAppNamespace(appName)).Delete(ctx, defaults.GitPrivateKeySecretName, metav1.DeleteOptions{}) if err != nil { return err } @@ -627,7 +638,7 @@ func (ah *ApplicationHandler) RegenerateDeployKey(ctx context.Context, appName s } func (ah *ApplicationHandler) GetDeployKeyAndSecret(ctx context.Context, appName string) (*applicationModels.DeployKeyAndSecret, error) { - cm, err := ah.getUserAccount().Client.CoreV1().ConfigMaps(crdUtils.GetAppNamespace(appName)).Get(ctx, defaults.GitPublicKeyConfigMapName, metav1.GetOptions{}) + cm, err := ah.getUserAccount().Client.CoreV1().ConfigMaps(operatorUtils.GetAppNamespace(appName)).Get(ctx, defaults.GitPublicKeyConfigMapName, metav1.GetOptions{}) if err != nil && !k8serrors.IsNotFound(err) { return nil, err } @@ -674,7 +685,7 @@ func (ah *ApplicationHandler) validateUserIsMemberOfAdGroups(ctx context.Context } name := fmt.Sprintf("access-validation-%s", appName) labels := map[string]string{"radix-access-validation": "true"} - configMapName := fmt.Sprintf("%s-%s", name, strings.ToLower(crdUtils.RandString(6))) + configMapName := fmt.Sprintf("%s-%s", name, strings.ToLower(operatorUtils.RandString(6))) role, err := createRoleToGetConfigMap(ctx, ah.accounts.ServiceAccount.Client, ah.namespace, name, labels, configMapName) if err != nil { return err diff --git a/api/buildstatus/models/buildstatus.go b/api/buildstatus/models/buildstatus.go index b629d513..36ed3a43 100644 --- a/api/buildstatus/models/buildstatus.go +++ b/api/buildstatus/models/buildstatus.go @@ -12,6 +12,7 @@ import ( ) // embed https://golang.org/pkg/embed/ - For embedding a single file, a variable of type []byte or string is often best +// //go:embed badges/build-status.svg var defaultBadgeTemplate string @@ -86,9 +87,12 @@ func (rbs *pipelineBadge) getBadge(condition v1.RadixJobCondition, pipeline v1.R } svgTemplate := template.New("status-badge.svg") - svgTemplate.Parse(rbs.badgeTemplate) + _, err := svgTemplate.Parse(rbs.badgeTemplate) + if err != nil { + return nil, err + } var buff bytes.Buffer - err := svgTemplate.Execute(&buff, &badgeData) + err = svgTemplate.Execute(&buff, &badgeData) if err != nil { return nil, errors.New("failed to create SVG template") } diff --git a/api/environments/environment_controller_secrets_test.go b/api/environments/environment_controller_secrets_test.go index f8da71ea..85765186 100644 --- a/api/environments/environment_controller_secrets_test.go +++ b/api/environments/environment_controller_secrets_test.go @@ -28,6 +28,7 @@ import ( operatorutils "github.com/equinor/radix-operator/pkg/apis/utils" radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned" "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" @@ -872,12 +873,14 @@ func (s *externalDnsAliasSecretTestSuite) SetupTest() { s.appName, s.componentName, s.environmentName, s.alias = "any-app", "backend", "dev", "cdn.myalias.com" - s.deployment, _ = s.commonTestUtils.ApplyDeployment(operatorutils. + deployment, err := s.commonTestUtils.ApplyDeployment(operatorutils. ARadixDeployment(). WithAppName(s.appName). WithEnvironment(s.environmentName). WithComponents(operatorutils.NewDeployComponentBuilder().WithName(s.componentName).WithDNSExternalAlias(s.alias)). WithImageTag("master")) + require.NoError(s.T(), err) + s.deployment = deployment s.commonTestUtils.ApplyApplication(operatorutils. ARadixApplication(). @@ -1232,7 +1235,9 @@ func (s *secretHandlerTestSuite) prepareTestRun(scenario *getSecretScenario, app ObjectMeta: metav1.ObjectMeta{Name: envNamespace}, Spec: v1.RadixEnvironmentSpec{AppName: appName, EnvName: envName}, } - radixClient.RadixV1().RadixEnvironments().Create(context.Background(), re, metav1.CreateOptions{}) + _, err := radixClient.RadixV1().RadixEnvironments().Create(context.Background(), re, metav1.CreateOptions{}) + require.NoError(s.T(), err) + radixDeployment := v1.RadixDeployment{ ObjectMeta: metav1.ObjectMeta{Name: deploymentName}, Spec: v1.RadixDeploymentSpec{ diff --git a/api/environments/environment_controller_test.go b/api/environments/environment_controller_test.go index 6d0f988d..d1766feb 100644 --- a/api/environments/environment_controller_test.go +++ b/api/environments/environment_controller_test.go @@ -91,7 +91,7 @@ func TestGetEnvironmentDeployments_SortedWithFromTo(t *testing.T) { // Setup commonTestUtils, environmentControllerTestUtils, _, _, _, _, _ := setupTest(nil) - setupGetDeploymentsTest(commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, anyEnvironment) + setupGetDeploymentsTest(t, commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, anyEnvironment) responseChannel := environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments/%s/deployments", anyAppName, anyEnvironment)) response := <-responseChannel @@ -124,7 +124,7 @@ func TestGetEnvironmentDeployments_Latest(t *testing.T) { // Setup commonTestUtils, environmentControllerTestUtils, _, _, _, _, _ := setupTest(nil) - setupGetDeploymentsTest(commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, anyEnvironment) + setupGetDeploymentsTest(t, commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, anyEnvironment) responseChannel := environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments/%s/deployments?latest=true", anyAppName, anyEnvironment)) response := <-responseChannel @@ -178,7 +178,8 @@ func TestGetEnvironmentSummary_ApplicationWithDeployment_EnvironmentConsistent(t re, err := radixClient.RadixV1().RadixEnvironments().Get(context.Background(), operatorutils.GetEnvironmentNamespace(anyAppName, anyEnvironment), metav1.GetOptions{}) require.NoError(t, err) re.Status.Reconciled = metav1.Now() - radixClient.RadixV1().RadixEnvironments().UpdateStatus(context.Background(), re, metav1.UpdateOptions{}) + _, err = radixClient.RadixV1().RadixEnvironments().UpdateStatus(context.Background(), re, metav1.UpdateOptions{}) + require.NoError(t, err) // Test responseChannel := environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments", anyAppName)) @@ -240,26 +241,30 @@ func TestGetEnvironmentSummary_OrphanedEnvironmentWithDash_OrphanedEnvironmentIs // Setup commonTestUtils, environmentControllerTestUtils, _, _, _, _, _ := setupTest(nil) - rr, _ := commonTestUtils.ApplyRegistration(operatorutils. + rr, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) - commonTestUtils.ApplyApplication(operatorutils. + require.NoError(t, err) + _, err = commonTestUtils.ApplyApplication(operatorutils. NewRadixApplicationBuilder(). WithAppName(anyAppName). WithEnvironment(anyEnvironment, "master")) - commonTestUtils.ApplyEnvironment(operatorutils. + require.NoError(t, err) + _, err = commonTestUtils.ApplyEnvironment(operatorutils. NewEnvironmentBuilder(). WithAppLabel(). WithAppName(anyAppName). WithEnvironmentName(anyOrphanedEnvironment). WithRegistrationOwner(rr). WithOrphaned(true)) + require.NoError(t, err) // Test responseChannel := environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments", anyAppName)) response := <-responseChannel environments := make([]*environmentModels.EnvironmentSummary, 0) - controllertest.GetResponseBody(response, &environments) + err = controllertest.GetResponseBody(response, &environments) + require.NoError(t, err) environmentListed := false for _, environment := range environments { @@ -278,25 +283,28 @@ func TestDeleteEnvironment_OneOrphanedEnvironment_OnlyOrphanedCanBeDeleted(t *te // Setup commonTestUtils, environmentControllerTestUtils, _, _, _, _, _ := setupTest(nil) - commonTestUtils.ApplyApplication(operatorutils. + _, err := commonTestUtils.ApplyApplication(operatorutils. NewRadixApplicationBuilder(). WithAppName(anyAppName). WithEnvironment(anyNonOrphanedEnvironment, "master"). WithRadixRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName))) - commonTestUtils.ApplyEnvironment(operatorutils. + require.NoError(t, err) + _, err = commonTestUtils.ApplyEnvironment(operatorutils. NewEnvironmentBuilder(). WithAppLabel(). WithAppName(anyAppName). WithEnvironmentName(anyOrphanedEnvironment)) + require.NoError(t, err) // Test // Start with two environments responseChannel := environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments", anyAppName)) response := <-responseChannel environments := make([]*environmentModels.EnvironmentSummary, 0) - controllertest.GetResponseBody(response, &environments) + err = controllertest.GetResponseBody(response, &environments) + require.NoError(t, err) assert.Equal(t, 2, len(environments)) // Orphaned environment can be deleted @@ -316,7 +324,8 @@ func TestDeleteEnvironment_OneOrphanedEnvironment_OnlyOrphanedCanBeDeleted(t *te responseChannel = environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments", anyAppName)) response = <-responseChannel environments = make([]*environmentModels.EnvironmentSummary, 0) - controllertest.GetResponseBody(response, &environments) + err = controllertest.GetResponseBody(response, &environments) + require.NoError(t, err) assert.Equal(t, 1, len(environments)) } @@ -325,10 +334,11 @@ func TestGetEnvironment_NoExistingEnvironment_ReturnsAnError(t *testing.T) { // Setup commonTestUtils, environmentControllerTestUtils, _, _, _, _, _ := setupTest(nil) - commonTestUtils.ApplyApplication(operatorutils. + _, err := commonTestUtils.ApplyApplication(operatorutils. ARadixApplication(). WithAppName(anyAppName). WithEnvironment(anyEnvironment, "master")) + require.NoError(t, err) // Test responseChannel := environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments/%s", anyAppName, anyNonExistingEnvironment)) @@ -343,10 +353,11 @@ func TestGetEnvironment_NoExistingEnvironment_ReturnsAnError(t *testing.T) { func TestGetEnvironment_ExistingEnvironmentInConfig_ReturnsAPendingEnvironment(t *testing.T) { // Setup commonTestUtils, environmentControllerTestUtils, _, _, _, _, _ := setupTest(nil) - commonTestUtils.ApplyApplication(operatorutils. + _, err := commonTestUtils.ApplyApplication(operatorutils. ARadixApplication(). WithAppName(anyAppName). WithEnvironment(anyEnvironment, "master")) + require.NoError(t, err) // Test responseChannel := environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments/%s", anyAppName, anyEnvironment)) @@ -354,14 +365,14 @@ func TestGetEnvironment_ExistingEnvironmentInConfig_ReturnsAPendingEnvironment(t assert.Equal(t, http.StatusOK, response.Code) environment := environmentModels.Environment{} - err := controllertest.GetResponseBody(response, &environment) - assert.Nil(t, err) + err = controllertest.GetResponseBody(response, &environment) + require.NoError(t, err) assert.Equal(t, anyEnvironment, environment.Name) assert.Equal(t, environmentModels.Pending.String(), environment.Status) } -func setupGetDeploymentsTest(commonTestUtils *commontest.Utils, appName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage string, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated time.Time, environment string) { - commonTestUtils.ApplyDeployment(operatorutils. +func setupGetDeploymentsTest(t *testing.T, commonTestUtils *commontest.Utils, appName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage string, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated time.Time, environment string) { + _, err := commonTestUtils.ApplyDeployment(operatorutils. ARadixDeployment(). WithDeploymentName(deploymentOneImage). WithAppName(appName). @@ -371,8 +382,9 @@ func setupGetDeploymentsTest(commonTestUtils *commontest.Utils, appName, deploym WithCondition(v1.DeploymentInactive). WithActiveFrom(deploymentOneCreated). WithActiveTo(deploymentTwoCreated)) + require.NoError(t, err) - commonTestUtils.ApplyDeployment(operatorutils. + _, err = commonTestUtils.ApplyDeployment(operatorutils. ARadixDeployment(). WithDeploymentName(deploymentTwoImage). WithAppName(appName). @@ -382,8 +394,9 @@ func setupGetDeploymentsTest(commonTestUtils *commontest.Utils, appName, deploym WithCondition(v1.DeploymentInactive). WithActiveFrom(deploymentTwoCreated). WithActiveTo(deploymentThreeCreated)) + require.NoError(t, err) - commonTestUtils.ApplyDeployment(operatorutils. + _, err = commonTestUtils.ApplyDeployment(operatorutils. ARadixDeployment(). WithDeploymentName(deploymentThreeImage). WithAppName(appName). @@ -392,6 +405,7 @@ func setupGetDeploymentsTest(commonTestUtils *commontest.Utils, appName, deploym WithCreated(deploymentThreeCreated). WithCondition(v1.DeploymentActive). WithActiveFrom(deploymentThreeCreated)) + require.NoError(t, err) } func TestRestartComponent_ApplicationWithDeployment_EnvironmentConsistent(t *testing.T) { @@ -724,11 +738,12 @@ func Test_GetEnvironmentEvents_Controller(t *testing.T) { // Setup commonTestUtils, environmentControllerTestUtils, _, kubeClient, _, _, _ := setupTest(nil) createEvent := func(namespace, eventName string) { - kubeClient.CoreV1().Events(namespace).CreateWithEventNamespace(&corev1.Event{ + _, err := kubeClient.CoreV1().Events(namespace).CreateWithEventNamespace(&corev1.Event{ ObjectMeta: metav1.ObjectMeta{ Name: eventName, }, }) + require.NoError(t, err) } createEvent(operatorutils.GetEnvironmentNamespace(anyAppName, envName), "ev1") createEvent(operatorutils.GetEnvironmentNamespace(anyAppName, envName), "ev2") @@ -973,7 +988,7 @@ func TestGetSecretDeployments_SortedWithFromTo(t *testing.T) { // Setup commonTestUtils, environmentControllerTestUtils, _, _, _, _, _ := setupTest(nil) - setupGetDeploymentsTest(commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, anyEnvironment) + setupGetDeploymentsTest(t, commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, anyEnvironment) responseChannel := environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments/%s/deployments", anyAppName, anyEnvironment)) response := <-responseChannel @@ -1006,7 +1021,7 @@ func TestGetSecretDeployments_Latest(t *testing.T) { // Setup commonTestUtils, environmentControllerTestUtils, _, _, _, _, _ := setupTest(nil) - setupGetDeploymentsTest(commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, anyEnvironment) + setupGetDeploymentsTest(t, commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, anyEnvironment) responseChannel := environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments/%s/deployments?latest=true", anyAppName, anyEnvironment)) response := <-responseChannel @@ -1094,20 +1109,23 @@ func TestGetEnvironmentSummary_OrphanedSecretWithDash_OrphanedSecretIsListedOk(t // Setup commonTestUtils, environmentControllerTestUtils, _, _, _, _, _ := setupTest(nil) - rr, _ := commonTestUtils.ApplyRegistration(operatorutils. + rr, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) - commonTestUtils.ApplyApplication(operatorutils. + require.NoError(t, err) + _, err = commonTestUtils.ApplyApplication(operatorutils. NewRadixApplicationBuilder(). WithAppName(anyAppName). WithEnvironment(anyEnvironment, "master")) - commonTestUtils.ApplyEnvironment(operatorutils. + require.NoError(t, err) + _, err = commonTestUtils.ApplyEnvironment(operatorutils. NewEnvironmentBuilder(). WithAppLabel(). WithAppName(anyAppName). WithEnvironmentName(orphanedEnvironment). WithRegistrationOwner(rr). WithOrphaned(true)) + require.NoError(t, err) // Test responseChannel := environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments", anyAppName)) diff --git a/api/events/event_handler_test.go b/api/events/event_handler_test.go index 75a552fc..d75b7bfd 100644 --- a/api/events/event_handler_test.go +++ b/api/events/event_handler_test.go @@ -5,6 +5,7 @@ import ( "testing" operatorutils "github.com/equinor/radix-operator/pkg/apis/utils" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/assert" v1 "k8s.io/api/core/v1" @@ -32,9 +33,9 @@ func Test_EventHandler_GetEventsForRadixApplication(t *testing.T) { appNamespace := operatorutils.GetEnvironmentNamespace(appName, envName) kubeClient := kubefake.NewSimpleClientset() - createKubernetesEvent(kubeClient, appNamespace, "ev1", "Normal", "pod1", "Pod") - createKubernetesEvent(kubeClient, appNamespace, "ev2", "Normal", "pod2", "Pod") - createKubernetesEvent(kubeClient, "app2-env", "ev3", "Normal", "pod3", "Pod") + createKubernetesEvent(t, kubeClient, appNamespace, "ev1", "Normal", "pod1", "Pod") + createKubernetesEvent(t, kubeClient, appNamespace, "ev2", "Normal", "pod2", "Pod") + createKubernetesEvent(t, kubeClient, "app2-env", "ev3", "Normal", "pod3", "Pod") ra := operatorutils.NewRadixApplicationBuilder().WithAppName(appName).BuildRA() eventHandler := Init(kubeClient) @@ -55,7 +56,7 @@ func Test_EventHandler_GetEvents_PodState(t *testing.T) { t.Run("ObjectState is nil for normal event type", func(t *testing.T) { kubeClient := kubefake.NewSimpleClientset() - createKubernetesEvent(kubeClient, appNamespace, "ev1", "Normal", "pod1", "Pod") + createKubernetesEvent(t, kubeClient, appNamespace, "ev1", "Normal", "pod1", "Pod") createKubernetesPod(kubeClient, "pod1", appNamespace, true, true, 0) eventHandler := Init(kubeClient) events, _ := eventHandler.GetEvents(context.Background(), RadixEnvironmentNamespace(ra, envName)) @@ -65,7 +66,7 @@ func Test_EventHandler_GetEvents_PodState(t *testing.T) { t.Run("ObjectState has Pod state for warning event type", func(t *testing.T) { kubeClient := kubefake.NewSimpleClientset() - createKubernetesEvent(kubeClient, appNamespace, "ev1", "Warning", "pod1", "Pod") + createKubernetesEvent(t, kubeClient, appNamespace, "ev1", "Warning", "pod1", "Pod") createKubernetesPod(kubeClient, "pod1", appNamespace, true, false, 0) eventHandler := Init(kubeClient) events, _ := eventHandler.GetEvents(context.Background(), RadixEnvironmentNamespace(ra, envName)) @@ -76,7 +77,7 @@ func Test_EventHandler_GetEvents_PodState(t *testing.T) { t.Run("ObjectState is nil for warning event type when pod not exist", func(t *testing.T) { kubeClient := kubefake.NewSimpleClientset() - createKubernetesEvent(kubeClient, appNamespace, "ev1", "Normal", "pod1", "Pod") + createKubernetesEvent(t, kubeClient, appNamespace, "ev1", "Normal", "pod1", "Pod") eventHandler := Init(kubeClient) events, _ := eventHandler.GetEvents(context.Background(), RadixEnvironmentNamespace(ra, envName)) assert.Len(t, events, 1) @@ -84,9 +85,9 @@ func Test_EventHandler_GetEvents_PodState(t *testing.T) { }) } -func createKubernetesEvent(client *kubefake.Clientset, namespace, +func createKubernetesEvent(t *testing.T, client *kubefake.Clientset, namespace, name, eventType, involvedObjectName, involvedObjectKind string) { - client.CoreV1().Events(namespace).CreateWithEventNamespace(&v1.Event{ + _, err := client.CoreV1().Events(namespace).CreateWithEventNamespace(&v1.Event{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, @@ -97,6 +98,7 @@ func createKubernetesEvent(client *kubefake.Clientset, namespace, }, Type: eventType, }) + require.NoError(t, err) } func createKubernetesPod(client *kubefake.Clientset, name, namespace string, diff --git a/api/jobs/job_controller.go b/api/jobs/job_controller.go index 64a6d8b8..f3b6a966 100644 --- a/api/jobs/job_controller.go +++ b/api/jobs/job_controller.go @@ -235,7 +235,7 @@ func StopApplicationJob(accounts models.Accounts, w http.ResponseWriter, r *http // RerunApplicationJob Reruns the pipeline job func RerunApplicationJob(accounts models.Accounts, w http.ResponseWriter, r *http.Request) { - // swagger:operation POST /applications/{appName}/jobs/{jobName}/restart pipeline-job rerunApplicationJob + // swagger:operation POST /applications/{appName}/jobs/{jobName}/rerun pipeline-job rerunApplicationJob // --- // summary: Reruns the pipeline job // parameters: diff --git a/api/jobs/models/job.go b/api/jobs/models/job.go index 446a2c86..073dc802 100644 --- a/api/jobs/models/job.go +++ b/api/jobs/models/job.go @@ -3,7 +3,7 @@ package models import ( deploymentModels "github.com/equinor/radix-api/api/deployments/models" radixutils "github.com/equinor/radix-common/utils" - v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" + radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" ) const ( @@ -19,7 +19,7 @@ type Job struct { // example: radix-pipeline-20181029135644-algpv-6hznh Name string `json:"name"` - // Branch branch to build from + // Branch to build from // // required: false // example: master @@ -31,6 +31,12 @@ type Job struct { // example: 4faca8595c5283a9d0f17a623b9255a0d9866a2e CommitID string `json:"commitID"` + // Image tags names for components - if empty will use default logic + // + // required: false + // Example: component1: tag1,component2: tag2 + ImageTagNames map[string]string `json:"imageTagNames,omitempty"` + // Created timestamp // // required: false @@ -75,6 +81,11 @@ type Job struct { // example: build-deploy Pipeline string `json:"pipeline"` + // RadixDeployment name, which is promoted + // + // required: false + PromotedFromDeployment string `json:"promotedFromDeployment,omitempty"` + // PromotedDeploymentName the name of the deployment that was promoted // // required: false @@ -121,7 +132,7 @@ type Job struct { } // GetJobFromRadixJob Gets job from a radix job -func GetJobFromRadixJob(job *v1.RadixJob, jobDeployments []*deploymentModels.DeploymentSummary) *Job { +func GetJobFromRadixJob(job *radixv1.RadixJob, jobDeployments []*deploymentModels.DeploymentSummary) *Job { steps := GetJobStepsFromRadixJob(job) created := radixutils.FormatTime(&job.CreationTimestamp) @@ -138,8 +149,6 @@ func GetJobFromRadixJob(job *v1.RadixJob, jobDeployments []*deploymentModels.Dep jobModel := Job{ Name: job.GetName(), - Branch: job.Spec.Build.Branch, - CommitID: job.Spec.Build.CommitID, Created: created, Started: radixutils.FormatTime(job.Status.Started), Ended: radixutils.FormatTime(job.Status.Ended), @@ -151,17 +160,24 @@ func GetJobFromRadixJob(job *v1.RadixJob, jobDeployments []*deploymentModels.Dep TriggeredBy: job.Spec.TriggeredBy, RerunFromJob: job.Annotations[RadixPipelineJobRerunAnnotation], } - if job.Spec.PipeLineType == v1.Promote { + switch job.Spec.PipeLineType { + case radixv1.Build, radixv1.BuildDeploy: + jobModel.Branch = job.Spec.Build.Branch + jobModel.CommitID = job.Spec.Build.CommitID + case radixv1.Deploy: + jobModel.ImageTagNames = job.Spec.Deploy.ImageTagNames + jobModel.CommitID = job.Spec.Deploy.CommitID + case radixv1.Promote: + jobModel.PromotedFromDeployment = job.Spec.Promote.DeploymentName jobModel.PromotedFromEnvironment = job.Spec.Promote.FromEnvironment jobModel.PromotedToEnvironment = job.Spec.Promote.ToEnvironment - jobModel.PromotedDeploymentName = job.Spec.Promote.DeploymentName + jobModel.CommitID = job.Spec.Promote.CommitID } - return &jobModel } // GetJobStepsFromRadixJob Gets the steps from a Radix job -func GetJobStepsFromRadixJob(job *v1.RadixJob) []Step { +func GetJobStepsFromRadixJob(job *radixv1.RadixJob) []Step { var steps []Step for _, jobStep := range job.Status.Steps { step := Step{ diff --git a/api/jobs/models/job_summary.go b/api/jobs/models/job_summary.go index dc938518..788f1866 100644 --- a/api/jobs/models/job_summary.go +++ b/api/jobs/models/job_summary.go @@ -2,7 +2,7 @@ package models import ( radixutils "github.com/equinor/radix-common/utils" - v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" + radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" ) // JobSummary holds general information about job @@ -20,7 +20,7 @@ type JobSummary struct { // example: radix-pipeline-20181029135644-algpv-6hznh AppName string `json:"appName"` - // Branch branch to build from + // Branch to build from // // required: false // example: master @@ -32,6 +32,12 @@ type JobSummary struct { // example: 4faca8595c5283a9d0f17a623b9255a0d9866a2e CommitID string `json:"commitID"` + // Image tags names for components - if empty will use default logic + // + // required: false + // Example: component1: tag1,component2: tag2 + ImageTagNames map[string]string `json:"imageTagNames,omitempty"` + // Created timestamp // // required: false @@ -75,10 +81,25 @@ type JobSummary struct { // required: false // example: ["dev", "qa"] Environments []string `json:"environments,omitempty"` + + // RadixDeployment name, which is promoted + // + // required: false + PromotedFromDeployment string `json:"promotedFromDeployment,omitempty"` + + // Environment name, from which the Radix deployment is promoted + // + // required: false + PromotedFromEnvironment string `json:"promotedFromEnvironment,omitempty"` + + // Environment name, to which the Radix deployment is promoted + // + // required: false + PromotedToEnvironment string `json:"promotedToEnvironment,omitempty"` } // GetSummaryFromRadixJob Used to get job summary from a radix job -func GetSummaryFromRadixJob(job *v1.RadixJob) *JobSummary { +func GetSummaryFromRadixJob(job *radixv1.RadixJob) *JobSummary { status := job.Status ended := radixutils.FormatTime(status.Ended) created := radixutils.FormatTime(&job.CreationTimestamp) @@ -91,8 +112,6 @@ func GetSummaryFromRadixJob(job *v1.RadixJob) *JobSummary { pipelineJob := &JobSummary{ Name: job.Name, AppName: job.Spec.AppName, - Branch: job.Spec.Build.Branch, - CommitID: job.Spec.Build.CommitID, Status: GetStatusFromRadixJobStatus(status, job.Spec.Stop), Created: created, Started: radixutils.FormatTime(status.Started), @@ -101,6 +120,19 @@ func GetSummaryFromRadixJob(job *v1.RadixJob) *JobSummary { Environments: job.Status.TargetEnvs, TriggeredBy: job.Spec.TriggeredBy, } + switch job.Spec.PipeLineType { + case radixv1.Build, radixv1.BuildDeploy: + pipelineJob.Branch = job.Spec.Build.Branch + pipelineJob.CommitID = job.Spec.Build.CommitID + case radixv1.Deploy: + pipelineJob.ImageTagNames = job.Spec.Deploy.ImageTagNames + pipelineJob.CommitID = job.Spec.Deploy.CommitID + case radixv1.Promote: + pipelineJob.PromotedFromDeployment = job.Spec.Promote.DeploymentName + pipelineJob.PromotedFromEnvironment = job.Spec.Promote.FromEnvironment + pipelineJob.PromotedToEnvironment = job.Spec.Promote.ToEnvironment + pipelineJob.CommitID = job.Spec.Promote.CommitID + } return pipelineJob } diff --git a/api/jobs/start_job_handler.go b/api/jobs/start_job_handler.go index a5515a4c..cd6f4137 100644 --- a/api/jobs/start_job_handler.go +++ b/api/jobs/start_job_handler.go @@ -90,6 +90,7 @@ func (jh JobHandler) buildPipelineJob(appName, cloneURL, radixConfigFullName str DeploymentName: jobSpec.DeploymentName, FromEnvironment: jobSpec.FromEnvironment, ToEnvironment: jobSpec.ToEnvironment, + CommitID: jobSpec.CommitID, } case v1.Deploy: deploySpec = v1.RadixDeploySpec{ diff --git a/api/kubequery/deployment.go b/api/kubequery/deployment.go index 61b2dbea..801fc57a 100644 --- a/api/kubequery/deployment.go +++ b/api/kubequery/deployment.go @@ -3,19 +3,27 @@ package kubequery import ( "context" + radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" operatorUtils "github.com/equinor/radix-operator/pkg/apis/utils" "github.com/equinor/radix-operator/pkg/apis/utils/labels" + radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned" appsv1 "k8s.io/api/apps/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" ) // GetDeploymentsForEnvironment returns all Deployments for the specified application and environment. func GetDeploymentsForEnvironment(ctx context.Context, client kubernetes.Interface, appName, envName string) ([]appsv1.Deployment, error) { ns := operatorUtils.GetEnvironmentNamespace(appName, envName) - deployments, err := client.AppsV1().Deployments(ns).List(ctx, v1.ListOptions{LabelSelector: labels.ForApplicationName(appName).String()}) + deployments, err := client.AppsV1().Deployments(ns).List(ctx, metav1.ListOptions{LabelSelector: labels.ForApplicationName(appName).String()}) if err != nil { return nil, err } return deployments.Items, nil } + +// GetRadixDeploymentByName returns a RadixDeployment for an application and namespace +func GetRadixDeploymentByName(ctx context.Context, radixClient radixclient.Interface, appName, envName, deploymentName string) (*radixv1.RadixDeployment, error) { + ns := operatorUtils.GetEnvironmentNamespace(appName, envName) + return radixClient.RadixV1().RadixDeployments(ns).Get(ctx, deploymentName, metav1.GetOptions{}) +} diff --git a/api/secrets/models/tls_certificate_test.go b/api/secrets/models/tls_certificate_test.go index 3174318d..68a61159 100644 --- a/api/secrets/models/tls_certificate_test.go +++ b/api/secrets/models/tls_certificate_test.go @@ -11,6 +11,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" ) @@ -118,9 +119,10 @@ func (s *tlsCertificateTestSuite) buildCert(certCN, issuerCN string, notBefore, certPrivKey, _ := rsa.GenerateKey(rand.Reader, 4096) certBytes, _ := x509.CreateCertificate(rand.Reader, cert, ca, &certPrivKey.PublicKey, caPrivKey) certPEM := new(bytes.Buffer) - pem.Encode(certPEM, &pem.Block{ + err := pem.Encode(certPEM, &pem.Block{ Type: "CERTIFICATE", Bytes: certBytes, }) + require.NoError(s.T(), err) return certPEM.Bytes() } diff --git a/go.mod b/go.mod index 74ed1f48..616edc57 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.21 require ( github.com/equinor/radix-common v1.5.0 github.com/equinor/radix-job-scheduler v1.8.3 - github.com/equinor/radix-operator v1.43.9 + github.com/equinor/radix-operator v1.43.10 github.com/evanphx/json-patch/v5 v5.6.0 github.com/go-openapi/strfmt v0.21.7 github.com/golang-jwt/jwt/v4 v4.5.0 diff --git a/go.sum b/go.sum index 47b8bdad..7dc1636d 100644 --- a/go.sum +++ b/go.sum @@ -97,8 +97,8 @@ github.com/equinor/radix-common v1.5.0 h1:z5hQHlKG2x16/NnV4b9ynf9n5ZageYUewE4MAN github.com/equinor/radix-common v1.5.0/go.mod h1:UZ69U56VFtTxABi5JjGdaqn9Df5ilfTTqzUQ0riofVM= github.com/equinor/radix-job-scheduler v1.8.3 h1:SqxbLD3vfwQXlxr6U6R9odeonu5uTKLoBVv9P6Tqins= github.com/equinor/radix-job-scheduler v1.8.3/go.mod h1:r71td0yDeDixdiMtq5TuCpCICD3lMHR8d1o5rSgTrTo= -github.com/equinor/radix-operator v1.43.9 h1:+B6IqCgVFWOvvfiouNvBpNJ4yTvER2b60t0Mpvd1CAk= -github.com/equinor/radix-operator v1.43.9/go.mod h1:j/Lb9bcof4L+KjtHVv5GD6MqYVsxHSGsliIP6C2F8YU= +github.com/equinor/radix-operator v1.43.10 h1:EuLrUZZurXKqdWF23t/XjYDSjhjHfUVR5qPU6xLWU3E= +github.com/equinor/radix-operator v1.43.10/go.mod h1:j/Lb9bcof4L+KjtHVv5GD6MqYVsxHSGsliIP6C2F8YU= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= diff --git a/swaggerui_src/swagger.json b/swaggerui_src/swagger.json index 3c9b7ba8..f95f30c9 100644 --- a/swaggerui_src/swagger.json +++ b/swaggerui_src/swagger.json @@ -4364,7 +4364,7 @@ } } }, - "/applications/{appName}/jobs/{jobName}/restart": { + "/applications/{appName}/jobs/{jobName}/rerun": { "post": { "tags": [ "pipeline-job" @@ -6217,7 +6217,7 @@ "type": "object", "properties": { "branch": { - "description": "Branch branch to build from", + "description": "Branch to build from", "type": "string", "x-go-name": "Branch", "example": "master" @@ -6256,6 +6256,15 @@ "x-go-name": "Ended", "example": "2006-01-02T15:04:05Z" }, + "imageTagNames": { + "description": "Image tags names for components - if empty will use default logic", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-go-name": "ImageTagNames", + "example": "component1: tag1,component2: tag2" + }, "name": { "description": "Name of the job", "type": "string", @@ -6277,6 +6286,11 @@ "x-go-name": "PromotedDeploymentName", "example": "component-6hznh" }, + "promotedFromDeployment": { + "description": "RadixDeployment name, which is promoted", + "type": "string", + "x-go-name": "PromotedFromDeployment" + }, "promotedFromEnvironment": { "description": "PromotedFromEnvironment the name of the environment that was promoted from", "type": "string", @@ -6344,7 +6358,7 @@ "example": "radix-pipeline-20181029135644-algpv-6hznh" }, "branch": { - "description": "Branch branch to build from", + "description": "Branch to build from", "type": "string", "x-go-name": "Branch", "example": "master" @@ -6379,6 +6393,15 @@ "qa" ] }, + "imageTagNames": { + "description": "Image tags names for components - if empty will use default logic", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-go-name": "ImageTagNames", + "example": "component1: tag1,component2: tag2" + }, "name": { "description": "Name of the job", "type": "string", @@ -6395,6 +6418,21 @@ "x-go-name": "Pipeline", "example": "build-deploy" }, + "promotedFromDeployment": { + "description": "RadixDeployment name, which is promoted", + "type": "string", + "x-go-name": "PromotedFromDeployment" + }, + "promotedFromEnvironment": { + "description": "Environment name, from which the Radix deployment is promoted", + "type": "string", + "x-go-name": "PromotedFromEnvironment" + }, + "promotedToEnvironment": { + "description": "Environment name, to which the Radix deployment is promoted", + "type": "string", + "x-go-name": "PromotedToEnvironment" + }, "started": { "description": "Started timestamp", "type": "string",