From 3075b2ed2daf058c955189f76c3d8fa113cecb41 Mon Sep 17 00:00:00 2001 From: tuti Date: Fri, 7 Feb 2025 13:52:14 -0800 Subject: [PATCH 1/4] check images promotion pipelines in hashrelease promotions --- release/cmd/flags.go | 7 +- release/cmd/hashrelease.go | 39 ++++++++++ release/internal/ci/semaphore.go | 128 +++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 release/internal/ci/semaphore.go diff --git a/release/cmd/flags.go b/release/cmd/flags.go index 744e576bc37..e18e8d1e8f7 100644 --- a/release/cmd/flags.go +++ b/release/cmd/flags.go @@ -258,7 +258,7 @@ var ( // External flags are flags used to interact with external services var ( // CI flags for interacting with CI services (Semaphore) - ciFlags = []cli.Flag{ciFlag, ciBaseURLFlag, ciJobIDFlag} + ciFlags = []cli.Flag{ciFlag, ciBaseURLFlag, ciJobIDFlag, ciTokenFlag} semaphoreCI = "semaphore" ciFlag = &cli.BoolFlag{ Name: "ci", @@ -282,6 +282,11 @@ var ( Usage: fmt.Sprintf("The job ID for the %s CI job", semaphoreCI), EnvVars: []string{"SEMAPHORE_JOB_ID"}, } + ciTokenFlag = &cli.StringFlag{ + Name: "ci-token", + Usage: fmt.Sprintf("The token for interacting with %s API", semaphoreCI), + EnvVars: []string{"SEMAPHORE_API_TOKEN"}, + } // Slack flags for posting messages to Slack slackFlags = []cli.Flag{slackTokenFlag, slackChannelFlag, notifyFlag} diff --git a/release/cmd/hashrelease.go b/release/cmd/hashrelease.go index 6622fc3d7ad..45a1ed7bfe2 100644 --- a/release/cmd/hashrelease.go +++ b/release/cmd/hashrelease.go @@ -16,11 +16,14 @@ package main import ( "fmt" + "os" "path/filepath" + "strconv" "github.com/sirupsen/logrus" cli "github.com/urfave/cli/v2" + "github.com/projectcalico/calico/release/internal/ci" "github.com/projectcalico/calico/release/internal/hashreleaseserver" "github.com/projectcalico/calico/release/internal/imagescanner" "github.com/projectcalico/calico/release/internal/outputs" @@ -64,6 +67,10 @@ func hashreleaseSubCommands(cfg *Config) []*cli.Command { return err } + if err := validateCIBuildRequirements(c, cfg.RepoRootDir); err != nil { + return err + } + // Clone the operator repository. operatorDir := filepath.Join(cfg.TmpDir, operator.DefaultRepoName) err := operator.Clone(c.String(operatorOrgFlag.Name), c.String(operatorRepoFlag.Name), c.String(operatorBranchFlag.Name), operatorDir) @@ -306,6 +313,9 @@ func validateHashreleaseBuildFlags(c *cli.Context) error { return fmt.Errorf("missing hashrelease server configuration, must set %s, %s, %s, %s, and %s", sshHostFlag, sshUserFlag, sshKeyFlag, sshPortFlag, sshKnownHostsFlag) } + if c.String(ciTokenFlag.Name) == "" { + return fmt.Errorf("%s API token must be set when running on CI, either set \"SEMAPHORE_API_TOKEN\" or use %s flag", semaphoreCI, ciTokenFlag.Name) + } } else { // If building images, log a warning if no registry is specified. if c.Bool(buildHashreleaseImageFlag.Name) && len(c.StringSlice(registryFlag.Name)) == 0 { @@ -381,3 +391,32 @@ func imageScanningAPIConfig(c *cli.Context) *imagescanner.Config { Scanner: c.String(imageScannerSelectFlag.Name), } } + +func validateCIBuildRequirements(c *cli.Context, repoRootDir string) error { + if !c.Bool(ciFlag.Name) { + return nil + } + if c.Bool(buildImagesFlag.Name) { + logrus.Debug("Building images, skipping images promotions check...") + return nil + } + orgURL := c.String(ciBaseURLFlag.Name) + token := c.String(ciTokenFlag.Name) + pipelineID := c.String(ciJobIDFlag.Name) + if promotion, err := strconv.ParseBool(os.Getenv("SEMAPHORE_PIPELINE_PROMOTION")); err != nil { + return fmt.Errorf("failed to parse promotion environment variable: %v", err) + } else if promotion { + logrus.Info("This is a promotion pipeline, checking if all images promotion pipelines have passed...") + pipelineID = os.Getenv("SEMAPHORE_PIPELINE_0_ARTEFACT_ID") + } else { + logrus.Info("This is a regular pipeline, skipping images promotions check...") + } + promotionsDone, err := ci.ImagePromotionsDone(repoRootDir, orgURL, pipelineID, token) + if err != nil { + return fmt.Errorf("failed to check if images promotions are done: %v", err) + } + if !promotionsDone { + return fmt.Errorf("images promotions are not done, wait for all images promotions to pass before publishing the hashrelease") + } + return nil +} diff --git a/release/internal/ci/semaphore.go b/release/internal/ci/semaphore.go new file mode 100644 index 00000000000..8ea0f62559d --- /dev/null +++ b/release/internal/ci/semaphore.go @@ -0,0 +1,128 @@ +package ci + +import ( + "encoding/json" + "fmt" + "net/http" + "strconv" + "strings" + + "github.com/sirupsen/logrus" + + "github.com/projectcalico/calico/release/internal/command" +) + +const passed = "passed" + +type promotion struct { + Status string `json:"status"` + Name string `json:"name"` + PipelineID string `json:"scheduled_pipeline_id"` +} + +type pipeline struct { + Result string `json:"result"` +} + +func apiURL(orgURL, path string) string { + orgURL = strings.TrimPrefix(orgURL, "/") + path = strings.TrimSuffix(path, "/") + return fmt.Sprintf("%s/api/v1alpha/%s", orgURL, path) +} + +func fetchPromotions(orgURL, pipelineID, token string) ([]promotion, error) { + url := apiURL(orgURL, "/promotions") + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, fmt.Errorf("failed to create %s request: %s", url, err.Error()) + } + req.Header.Set("Authorization", fmt.Sprintf("Token %s", token)) + q := req.URL.Query() + q.Add("pipeline_id", pipelineID) + req.URL.RawQuery = q.Encode() + + logrus.WithField("url", req.URL.String()).Debug("get pipeline promotions") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, fmt.Errorf("failed to request promotions: %s", err.Error()) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("failed to fetch promotions") + } + + var promotions []promotion + if err := json.NewDecoder(resp.Body).Decode(&promotions); err != nil { + return nil, fmt.Errorf("failed to parse promotions: %s", err.Error()) + } + + var imagesPromotions []promotion + for _, p := range promotions { + if strings.HasPrefix(strings.ToLower(p.Name), "push ") { + imagesPromotions = append(imagesPromotions, p) + } + } + return imagesPromotions, nil +} + +func getPipelineResult(orgURL, pipelineID, token string) (*pipeline, error) { + url := apiURL(orgURL, fmt.Sprintf("/pipeline/%s", pipelineID)) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, fmt.Errorf("failed to create %s request: %s", url, err.Error()) + } + req.Header.Set("Authorization", fmt.Sprintf("Token %s", token)) + + logrus.WithField("url", req.URL.String()).Debug("get pipeline details") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, fmt.Errorf("failed to request pipeline details: %s", err.Error()) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("failed to fetch pipeline details") + } + + var p pipeline + if err := json.NewDecoder(resp.Body).Decode(&p); err != nil { + return nil, fmt.Errorf("failed to parse pipeline: %s", err.Error()) + } + + return &p, err +} + +func ImagePromotionsDone(repoRootDir, orgURL, pipelineID, token string) (bool, error) { + expectPromotionCountStr, err := command.Run("grep", []string{"-c", `"name: Push "`, fmt.Sprintf("%s/.semaphore/semaphore.yml.d/03-promotions.yml")}) + if err != nil { + return false, fmt.Errorf("failed to get expected image promotions") + } + expectedPromotionCount, err := strconv.Atoi(expectPromotionCountStr) + if err != nil { + return false, fmt.Errorf("unable to convert expected promotions to int") + } + promotions, err := fetchPromotions(orgURL, pipelineID, token) + if err != nil { + return false, err + } + promotionsCount := len(promotions) + if promotionsCount < expectedPromotionCount { + return false, fmt.Errorf("number of promotions do not match: expected %d, got %d", expectedPromotionCount, promotionsCount) + } + for _, promotion := range promotions { + if promotion.Status != passed { + logrus.WithField("promotion", promotion.Name).Error("triggering promotion failed") + return false, fmt.Errorf("triggering %q promotion failed, cannot check pipeline result", promotion.Name) + } + pipeline, err := getPipelineResult(orgURL, promotion.PipelineID, token) + if err != nil { + return false, fmt.Errorf("unable to get %q pipeline details", promotion.Name) + } + if pipeline.Result != passed { + logrus.WithField("promotion", promotion.Name).Error("promotion failed") + return false, fmt.Errorf("%q promotion failed", promotion.Name) + } + } + return true, nil +} From 0f700bc7f8fa21bfb41d205810fefdada818f638 Mon Sep 17 00:00:00 2001 From: tuti Date: Fri, 7 Feb 2025 13:52:47 -0800 Subject: [PATCH 2/4] update hashrelease pipeline --- .semaphore/release/hashrelease.yml | 1 - .semaphore/semaphore-scheduled-builds.yml | 16 ++++++++++++++++ .semaphore/semaphore.yml | 16 ++++++++++++++++ .semaphore/semaphore.yml.d/03-promotions.yml | 16 ++++++++++++++++ release/internal/ci/semaphore.go | 2 +- 5 files changed, 49 insertions(+), 2 deletions(-) diff --git a/.semaphore/release/hashrelease.yml b/.semaphore/release/hashrelease.yml index 244f3f0c58e..62e99a2c8b4 100644 --- a/.semaphore/release/hashrelease.yml +++ b/.semaphore/release/hashrelease.yml @@ -47,7 +47,6 @@ blocks: jobs: - name: Build and publish hashrelease commands: - - if [[ ${SEMAPHORE_WORKFLOW_TRIGGERED_BY_SCHEDULE} == "true" ]]; then export BUILD_CONTAINER_IMAGES=true; export PUBLISH_IMAGES=true; fi - make hashrelease prologue: commands: diff --git a/.semaphore/semaphore-scheduled-builds.yml b/.semaphore/semaphore-scheduled-builds.yml index 5d74ea528ac..20834be74aa 100644 --- a/.semaphore/semaphore-scheduled-builds.yml +++ b/.semaphore/semaphore-scheduled-builds.yml @@ -33,6 +33,22 @@ promotions: # Manual promotion for publishing a hashrelease. - name: Publish hashrelease pipeline_file: release/hashrelease.yml + parameters: + env_vars: + - required: true + options: + - "true" + - "false" + default_value: "false" + description: "Set to 'true' to build images while building the hashrelease. Must set PUBLISH_IMAGES to 'true' to publish them." + name: BUILD_CONTAINER_IMAGES + - required: true + options: + - "true" + - "false" + default_value: "false" + description: "Set to 'true' to publish images built by the hashrelease. Requires BUILD_CONTAINER_IMAGES to be 'true'." + name: PUBLISH_IMAGES # Manual promotion for publishing a release. - name: Publish official release pipeline_file: release/release.yml diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml index c82e96dca00..dcadaf57b27 100644 --- a/.semaphore/semaphore.yml +++ b/.semaphore/semaphore.yml @@ -33,6 +33,22 @@ promotions: # Manual promotion for publishing a hashrelease. - name: Publish hashrelease pipeline_file: release/hashrelease.yml + parameters: + env_vars: + - required: true + options: + - "true" + - "false" + default_value: "false" + description: "Set to 'true' to build images while building the hashrelease. Must set PUBLISH_IMAGES to 'true' to publish them." + name: BUILD_CONTAINER_IMAGES + - required: true + options: + - "true" + - "false" + default_value: "false" + description: "Set to 'true' to publish images built by the hashrelease. Requires BUILD_CONTAINER_IMAGES to be 'true'." + name: PUBLISH_IMAGES # Manual promotion for publishing a release. - name: Publish official release pipeline_file: release/release.yml diff --git a/.semaphore/semaphore.yml.d/03-promotions.yml b/.semaphore/semaphore.yml.d/03-promotions.yml index dc902d1aeaa..afcc750f6e2 100644 --- a/.semaphore/semaphore.yml.d/03-promotions.yml +++ b/.semaphore/semaphore.yml.d/03-promotions.yml @@ -2,6 +2,22 @@ promotions: # Manual promotion for publishing a hashrelease. - name: Publish hashrelease pipeline_file: release/hashrelease.yml + parameters: + env_vars: + - required: true + options: + - "true" + - "false" + default_value: "false" + description: "Set to 'true' to build images while building the hashrelease. Must set PUBLISH_IMAGES to 'true' to publish them." + name: BUILD_CONTAINER_IMAGES + - required: true + options: + - "true" + - "false" + default_value: "false" + description: "Set to 'true' to publish images built by the hashrelease. Requires BUILD_CONTAINER_IMAGES to be 'true'." + name: PUBLISH_IMAGES # Manual promotion for publishing a release. - name: Publish official release pipeline_file: release/release.yml diff --git a/release/internal/ci/semaphore.go b/release/internal/ci/semaphore.go index 8ea0f62559d..55072e37af1 100644 --- a/release/internal/ci/semaphore.go +++ b/release/internal/ci/semaphore.go @@ -94,7 +94,7 @@ func getPipelineResult(orgURL, pipelineID, token string) (*pipeline, error) { } func ImagePromotionsDone(repoRootDir, orgURL, pipelineID, token string) (bool, error) { - expectPromotionCountStr, err := command.Run("grep", []string{"-c", `"name: Push "`, fmt.Sprintf("%s/.semaphore/semaphore.yml.d/03-promotions.yml")}) + expectPromotionCountStr, err := command.Run("grep", []string{"-c", `"name: Push "`, fmt.Sprintf("%s/.semaphore/semaphore.yml.d/03-promotions.yml", repoRootDir)}) if err != nil { return false, fmt.Errorf("failed to get expected image promotions") } From 6344a8ca9d8bf0b4c788f111a3db3aadbdfbf302 Mon Sep 17 00:00:00 2001 From: tuti Date: Wed, 12 Feb 2025 15:25:40 -0800 Subject: [PATCH 3/4] updates --- release/cmd/flags.go | 7 ++- release/cmd/hashrelease.go | 12 +---- release/internal/ci/semaphore.go | 85 +++++++++++++++++++++++++++++--- 3 files changed, 84 insertions(+), 20 deletions(-) diff --git a/release/cmd/flags.go b/release/cmd/flags.go index e18e8d1e8f7..8cdee4475b3 100644 --- a/release/cmd/flags.go +++ b/release/cmd/flags.go @@ -258,7 +258,7 @@ var ( // External flags are flags used to interact with external services var ( // CI flags for interacting with CI services (Semaphore) - ciFlags = []cli.Flag{ciFlag, ciBaseURLFlag, ciJobIDFlag, ciTokenFlag} + ciFlags = []cli.Flag{ciFlag, ciBaseURLFlag, ciJobIDFlag, ciPipelineIDFlag, ciTokenFlag} semaphoreCI = "semaphore" ciFlag = &cli.BoolFlag{ Name: "ci", @@ -282,6 +282,11 @@ var ( Usage: fmt.Sprintf("The job ID for the %s CI job", semaphoreCI), EnvVars: []string{"SEMAPHORE_JOB_ID"}, } + ciPipelineIDFlag = &cli.StringFlag{ + Name: "ci-pipeline-id", + Usage: fmt.Sprintf("The pipeline ID for the %s CI pipeline", semaphoreCI), + EnvVars: []string{"SEMAPHORE_PIPELINE_ID"}, + } ciTokenFlag = &cli.StringFlag{ Name: "ci-token", Usage: fmt.Sprintf("The token for interacting with %s API", semaphoreCI), diff --git a/release/cmd/hashrelease.go b/release/cmd/hashrelease.go index 45a1ed7bfe2..10d5d68f94f 100644 --- a/release/cmd/hashrelease.go +++ b/release/cmd/hashrelease.go @@ -16,9 +16,7 @@ package main import ( "fmt" - "os" "path/filepath" - "strconv" "github.com/sirupsen/logrus" cli "github.com/urfave/cli/v2" @@ -402,15 +400,7 @@ func validateCIBuildRequirements(c *cli.Context, repoRootDir string) error { } orgURL := c.String(ciBaseURLFlag.Name) token := c.String(ciTokenFlag.Name) - pipelineID := c.String(ciJobIDFlag.Name) - if promotion, err := strconv.ParseBool(os.Getenv("SEMAPHORE_PIPELINE_PROMOTION")); err != nil { - return fmt.Errorf("failed to parse promotion environment variable: %v", err) - } else if promotion { - logrus.Info("This is a promotion pipeline, checking if all images promotion pipelines have passed...") - pipelineID = os.Getenv("SEMAPHORE_PIPELINE_0_ARTEFACT_ID") - } else { - logrus.Info("This is a regular pipeline, skipping images promotions check...") - } + pipelineID := c.String(ciPipelineIDFlag.Name) promotionsDone, err := ci.ImagePromotionsDone(repoRootDir, orgURL, pipelineID, token) if err != nil { return fmt.Errorf("failed to check if images promotions are done: %v", err) diff --git a/release/internal/ci/semaphore.go b/release/internal/ci/semaphore.go index 55072e37af1..3eba72b0621 100644 --- a/release/internal/ci/semaphore.go +++ b/release/internal/ci/semaphore.go @@ -21,7 +21,12 @@ type promotion struct { } type pipeline struct { - Result string `json:"result"` + Result string `json:"result"` + PromotionOf string `json:"promotion_of"` +} + +type pipelineDetails struct { + Pipeline pipeline `json:"pipeline"` } func apiURL(orgURL, path string) string { @@ -30,7 +35,7 @@ func apiURL(orgURL, path string) string { return fmt.Sprintf("%s/api/v1alpha/%s", orgURL, path) } -func fetchPromotions(orgURL, pipelineID, token string) ([]promotion, error) { +func fetchImagePromotions(orgURL, pipelineID, token string) ([]promotion, error) { url := apiURL(orgURL, "/promotions") req, err := http.NewRequest("GET", url, nil) if err != nil { @@ -57,17 +62,30 @@ func fetchPromotions(orgURL, pipelineID, token string) ([]promotion, error) { return nil, fmt.Errorf("failed to parse promotions: %s", err.Error()) } - var imagesPromotions []promotion + imagesPromotionsMap := make(map[string]promotion) for _, p := range promotions { if strings.HasPrefix(strings.ToLower(p.Name), "push ") { - imagesPromotions = append(imagesPromotions, p) + if currentP, ok := imagesPromotionsMap[p.Name]; ok { + // If the promotion is already in the map, + // only if the staus for the promotion in the map is not passed. + if currentP.Status != passed { + imagesPromotionsMap[p.Name] = p + } + } else { + imagesPromotionsMap[p.Name] = p + } } } + + imagesPromotions := make([]promotion, 0, len(imagesPromotionsMap)) + for _, p := range imagesPromotionsMap { + imagesPromotions = append(imagesPromotions, p) + } return imagesPromotions, nil } func getPipelineResult(orgURL, pipelineID, token string) (*pipeline, error) { - url := apiURL(orgURL, fmt.Sprintf("/pipeline/%s", pipelineID)) + url := apiURL(orgURL, fmt.Sprintf("/pipelines/%s", pipelineID)) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, fmt.Errorf("failed to create %s request: %s", url, err.Error()) @@ -85,14 +103,51 @@ func getPipelineResult(orgURL, pipelineID, token string) (*pipeline, error) { return nil, fmt.Errorf("failed to fetch pipeline details") } - var p pipeline + var p pipelineDetails if err := json.NewDecoder(resp.Body).Decode(&p); err != nil { return nil, fmt.Errorf("failed to parse pipeline: %s", err.Error()) } - return &p, err + return &p.Pipeline, err } +func fetchParentPipelineID(orgURL, pipelineID, token string) (string, error) { + url := apiURL(orgURL, fmt.Sprintf("/pipelines/%s", pipelineID)) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return "", fmt.Errorf("failed to create %s request: %s", url, err.Error()) + } + req.Header.Set("Authorization", fmt.Sprintf("Token %s", token)) + + logrus.WithField("url", req.URL.String()).Debug("get pipeline details") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", fmt.Errorf("failed to request pipeline details: %s", err.Error()) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("failed to fetch pipeline details") + } + + var p pipelineDetails + if err := json.NewDecoder(resp.Body).Decode(&p); err != nil { + return "", fmt.Errorf("failed to parse pipeline: %s", err.Error()) + } + + return p.Pipeline.PromotionOf, err +} + +// ImagePromotionsDone checks if all the promotion pipelines have passed. +// +// As it is checking in the hashrelease pipeline, it tries to get the pipeline that triggered the hashrelease promotion. +// If the pipeline that triggered the hashrelease promotion is not found, +// this means that the hashrelease pipeline was not triggered by a promotion (likely triggered from a task). +// In this case, it skips the image promotions check. +// +// Once the pipeline that triggered the hashrelease promotion is found, it checks if all the expected image promotions have passed. +// Since the API only return promotions that have been triggered, it is possible that some promotions are not triggered. +// This is why it checks that the number of promotions is equal or greater than the expected number from the semaphore.yml. func ImagePromotionsDone(repoRootDir, orgURL, pipelineID, token string) (bool, error) { expectPromotionCountStr, err := command.Run("grep", []string{"-c", `"name: Push "`, fmt.Sprintf("%s/.semaphore/semaphore.yml.d/03-promotions.yml", repoRootDir)}) if err != nil { @@ -102,11 +157,25 @@ func ImagePromotionsDone(repoRootDir, orgURL, pipelineID, token string) (bool, e if err != nil { return false, fmt.Errorf("unable to convert expected promotions to int") } - promotions, err := fetchPromotions(orgURL, pipelineID, token) + logrus.WithField("count", expectedPromotionCount).Debug("expected number of image promotions") + parentPipelineID, err := fetchParentPipelineID(orgURL, pipelineID, token) + if err != nil { + return false, err + } + if parentPipelineID == "" { + logrus.Info("no parent pipeline found, skipping image promotions check") + return true, nil + } + logrus.WithField("pipeline_id", parentPipelineID).Debug("found pipeline that triggered image promotions") + promotions, err := fetchImagePromotions(orgURL, pipelineID, token) if err != nil { return false, err } promotionsCount := len(promotions) + logrus.WithFields(logrus.Fields{ + "expected": expectedPromotionCount, + "actual": promotionsCount, + }).Debug("number of image promotions") if promotionsCount < expectedPromotionCount { return false, fmt.Errorf("number of promotions do not match: expected %d, got %d", expectedPromotionCount, promotionsCount) } From c3329c4d8904d339bca35e3f048d9a2d0268f4c4 Mon Sep 17 00:00:00 2001 From: tuti Date: Wed, 12 Feb 2025 16:00:26 -0800 Subject: [PATCH 4/4] remove complexity with promotions --- .semaphore/semaphore-scheduled-builds.yml | 16 ---------------- .semaphore/semaphore.yml | 16 ---------------- .semaphore/semaphore.yml.d/03-promotions.yml | 16 ---------------- 3 files changed, 48 deletions(-) diff --git a/.semaphore/semaphore-scheduled-builds.yml b/.semaphore/semaphore-scheduled-builds.yml index 20834be74aa..5d74ea528ac 100644 --- a/.semaphore/semaphore-scheduled-builds.yml +++ b/.semaphore/semaphore-scheduled-builds.yml @@ -33,22 +33,6 @@ promotions: # Manual promotion for publishing a hashrelease. - name: Publish hashrelease pipeline_file: release/hashrelease.yml - parameters: - env_vars: - - required: true - options: - - "true" - - "false" - default_value: "false" - description: "Set to 'true' to build images while building the hashrelease. Must set PUBLISH_IMAGES to 'true' to publish them." - name: BUILD_CONTAINER_IMAGES - - required: true - options: - - "true" - - "false" - default_value: "false" - description: "Set to 'true' to publish images built by the hashrelease. Requires BUILD_CONTAINER_IMAGES to be 'true'." - name: PUBLISH_IMAGES # Manual promotion for publishing a release. - name: Publish official release pipeline_file: release/release.yml diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml index dcadaf57b27..c82e96dca00 100644 --- a/.semaphore/semaphore.yml +++ b/.semaphore/semaphore.yml @@ -33,22 +33,6 @@ promotions: # Manual promotion for publishing a hashrelease. - name: Publish hashrelease pipeline_file: release/hashrelease.yml - parameters: - env_vars: - - required: true - options: - - "true" - - "false" - default_value: "false" - description: "Set to 'true' to build images while building the hashrelease. Must set PUBLISH_IMAGES to 'true' to publish them." - name: BUILD_CONTAINER_IMAGES - - required: true - options: - - "true" - - "false" - default_value: "false" - description: "Set to 'true' to publish images built by the hashrelease. Requires BUILD_CONTAINER_IMAGES to be 'true'." - name: PUBLISH_IMAGES # Manual promotion for publishing a release. - name: Publish official release pipeline_file: release/release.yml diff --git a/.semaphore/semaphore.yml.d/03-promotions.yml b/.semaphore/semaphore.yml.d/03-promotions.yml index afcc750f6e2..dc902d1aeaa 100644 --- a/.semaphore/semaphore.yml.d/03-promotions.yml +++ b/.semaphore/semaphore.yml.d/03-promotions.yml @@ -2,22 +2,6 @@ promotions: # Manual promotion for publishing a hashrelease. - name: Publish hashrelease pipeline_file: release/hashrelease.yml - parameters: - env_vars: - - required: true - options: - - "true" - - "false" - default_value: "false" - description: "Set to 'true' to build images while building the hashrelease. Must set PUBLISH_IMAGES to 'true' to publish them." - name: BUILD_CONTAINER_IMAGES - - required: true - options: - - "true" - - "false" - default_value: "false" - description: "Set to 'true' to publish images built by the hashrelease. Requires BUILD_CONTAINER_IMAGES to be 'true'." - name: PUBLISH_IMAGES # Manual promotion for publishing a release. - name: Publish official release pipeline_file: release/release.yml