diff --git a/.gitignore b/.gitignore index 2ca02fdd851..46c700445d8 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ node/windows-packaging/nssm.exe _output builder.coverprofile *.log +.release-*.* /* Created by local kind cluster */ hack/test/kind/kind diff --git a/.semaphore/release/hashrelease.yml b/.semaphore/release/hashrelease.yml index 9c9f5782bb9..a078605b896 100644 --- a/.semaphore/release/hashrelease.yml +++ b/.semaphore/release/hashrelease.yml @@ -40,6 +40,8 @@ blocks: jobs: - name: Build and publish hashrelease commands: + - | + if [[ ${SEMAPHORE_PIPELINE_PROMOTION} == "true" ]]; then export BUILD_IMAGES=true; export SKIP_PUBLISH_IMAGES=false; fi - make hashrelease prologue: commands: @@ -47,5 +49,5 @@ blocks: - cd release - make build env_vars: - - name: IS_HASHRELEASE - value: "true" + - name: REGISTRIES + value: docker.io/calico diff --git a/key-cert-provisioner/Makefile b/key-cert-provisioner/Makefile index 35846f4df44..68340db4ffe 100644 --- a/key-cert-provisioner/Makefile +++ b/key-cert-provisioner/Makefile @@ -30,6 +30,9 @@ KEY_CERT_PROVISIONER_CREATED=.key-cert-provisioner.created-$(ARCH)-fips VALIDARCHES=amd64 BINDIR=bin/$(ARCH)-fips LATEST_TAG=latest-fips +BUILD_IMAGES=$(KEY_CERT_PROVISIONER_IMAGE) +PUSH_IMAGES= $(foreach registry,$(DEV_REGISTRIES),$(addprefix $(registry)/,$(BUILD_IMAGES))) +RELEASE_IMAGES= $(foreach registry,$(RELEASE_REGISTRIES),$(addprefix $(registry)/,$(BUILD_IMAGES))) else KEY_CERT_PROVISIONER_CREATED=.key-cert-provisioner.created-$(ARCH) BINDIR=bin @@ -93,3 +96,21 @@ clean: -docker image rm -f $$(docker images $(KEY_CERT_PROVISIONER_IMAGE) -a -q) -docker image rm -f $$(docker images $(TEST_SIGNER_IMAGE) -a -q) +############################################################################### +# Release +############################################################################### +release-build: .release-$(VERSION).created +.release-$(VERSION).created: + $(MAKE) clean image-all RELEASE=true + $(MAKE) retag-build-images-with-registries RELEASE=true IMAGETAG=$(VERSION) + $(MAKE) retag-build-images-with-registries RELEASE=true IMAGETAG=latest + $(MAKE) FIPS=true retag-build-images-with-registries RELEASE=true IMAGETAG=$(VERSION)-fips LATEST_IMAGE_TAG=latest-fips + $(MAKE) FIPS=true retag-build-images-with-registries RELEASE=true IMAGETAG=latest-fips LATEST_IMAGE_TAG=latest-fips + touch $@ + +## Pushes a github release and release artifacts produced by `make release-build`. +release-publish: release-prereqs .release-$(VERSION).published +.release-$(VERSION).published: + $(MAKE) push-images-to-registries IMAGETAG=$(VERSION) RELEASE=$(RELEASE) CONFIRM=$(CONFIRM) + $(MAKE) FIPS=true push-images-to-registries IMAGETAG=$(VERSION)-fips RELEASE=$(RELEASE) CONFIRM=$(CONFIRM) + touch $@ diff --git a/release/build/main.go b/release/build/main.go index 76034008284..5fabb685d76 100644 --- a/release/build/main.go +++ b/release/build/main.go @@ -25,6 +25,7 @@ import ( "gopkg.in/natefinch/lumberjack.v2" "github.com/projectcalico/calico/release/internal/config" + "github.com/projectcalico/calico/release/internal/hashreleaseserver" "github.com/projectcalico/calico/release/internal/outputs" "github.com/projectcalico/calico/release/internal/pinnedversion" "github.com/projectcalico/calico/release/internal/registry" @@ -37,12 +38,13 @@ import ( ) const ( - latestFlag = "latest" - skipValidationFlag = "skip-validation" - skipImageScanFlag = "skip-image-scan" - skipBranchCheckFlag = "skip-branch-check" - publishBranchFlag = "git-publish" - buildImagesFlag = "build-images" + latestFlag = "latest" + skipValidationFlag = "skip-validation" + skipImageScanFlag = "skip-image-scan" + skipBranchCheckFlag = "skip-branch-check" + skipReleaseNotesFlag = "skip-release-notes" + publishBranchFlag = "git-publish" + buildImagesFlag = "build-images" orgFlag = "org" repoFlag = "repo" @@ -58,9 +60,10 @@ const ( newBranchFlag = "new-branch-version" // Configuration flags for the release publish command. - skipPublishImagesFlag = "skip-publish-images" - skipPublishGitTag = "skip-publish-git-tag" - skipPublishGithubRelease = "skip-publish-github-release" + skipPublishImagesFlag = "skip-publish-images" + skipPublishGitTagFlag = "skip-publish-git-tag" + skipPublishGithubReleaseFlag = "skip-publish-github-release" + skipPublishHashreleaseFlag = "skip-publish-hashrelease-server" ) var ( @@ -159,8 +162,9 @@ func hashreleaseSubCommands(cfg *config.Config) []*cli.Command { &cli.StringFlag{Name: repoFlag, Usage: "Git repository", EnvVars: []string{"GIT_REPO"}, Value: config.DefaultRepo}, &cli.BoolFlag{Name: skipValidationFlag, Usage: "Skip all pre-build validation", Value: false}, &cli.BoolFlag{Name: skipBranchCheckFlag, Usage: "Skip check that this is a valid release branch.", Value: false}, - &cli.BoolFlag{Name: buildImagesFlag, Usage: "Build images from local codebase. If false, will use images from CI instead.", Value: false}, - &cli.StringFlag{Name: imageRegistryFlag, Usage: "Specify image registry to use", Value: ""}, + &cli.BoolFlag{Name: skipReleaseNotesFlag, Usage: "Skip generating release notes. For dev, you want to set to true", Value: false}, + &cli.BoolFlag{Name: buildImagesFlag, Usage: "Build images from local codebase. If false, will use images from CI instead.", EnvVars: []string{"BUILD_IMAGES"}, Value: false}, + &cli.StringFlag{Name: imageRegistryFlag, Usage: "Specify image registry to use", EnvVars: []string{"REGISTRIES"}, Value: ""}, &cli.StringFlag{Name: operatorOrgFlag, Usage: "Operator git organization", EnvVars: []string{"OPERATOR_GIT_ORGANIZATION"}, Value: config.OperatorDefaultOrg}, &cli.StringFlag{Name: operatorRepoFlag, Usage: "Operator git repository", EnvVars: []string{"OPERATOR_GIT_REPO"}, Value: config.OperatorDefaultRepo}, &cli.StringFlag{Name: operatorImageFlag, Usage: "Specify the operator image to use", EnvVars: []string{"OPERATOR_IMAGE"}, Value: config.OperatorDefaultImage}, @@ -198,6 +202,7 @@ func hashreleaseSubCommands(cfg *config.Config) []*cli.Command { RootDir: cfg.RepoRootDir, ReleaseBranchPrefix: cfg.RepoReleaseBranchPrefix, Operator: cfg.Operator, + Registry: c.String(imageRegistryFlag), } if c.String(operatorImageFlag) != "" { pinnedCfg.Operator.Image = c.String(operatorImageFlag) @@ -268,10 +273,12 @@ func hashreleaseSubCommands(cfg *config.Config) []*cli.Command { return err } - // For real releases, release notes are generated prior to building the release. For hash releases, - // generate a set of release notes and add them to the hashrelease directory. - if _, err := outputs.ReleaseNotes(c.String(orgFlag), cfg.GithubToken, cfg.RepoRootDir, filepath.Join(dir, releaseNotesDir), versions.ProductVersion); err != nil { - return err + if !c.Bool(skipReleaseNotesFlag) { + // For real releases, release notes are generated prior to building the release. + // For hash releases, generate a set of release notes and add them to the hashrelease directory. + if _, err := outputs.ReleaseNotes(c.String(orgFlag), cfg.GithubToken, cfg.RepoRootDir, filepath.Join(dir, releaseNotesDir), versions.ProductVersion); err != nil { + return err + } } // Adjsut the formatting of the generated outputs to match the legacy hashrelease format. @@ -284,6 +291,11 @@ func hashreleaseSubCommands(cfg *config.Config) []*cli.Command { Name: "publish", Usage: "Publish hashrelease from _output/ to hashrelease server", Flags: []cli.Flag{ + &cli.StringFlag{Name: orgFlag, Usage: "Git organization", EnvVars: []string{"ORGANIZATION"}, Value: config.DefaultOrg}, + &cli.StringFlag{Name: repoFlag, Usage: "Git repository", EnvVars: []string{"GIT_REPO"}, Value: config.DefaultRepo}, + &cli.StringFlag{Name: imageRegistryFlag, Usage: "Specify image registry to use", EnvVars: []string{"REGISTRIES"}, Value: ""}, + &cli.BoolFlag{Name: skipPublishImagesFlag, Usage: "Skip publishing of container images to registry", EnvVars: []string{"SKIP_PUBLISH_IMAGES"}, Value: true}, + &cli.BoolFlag{Name: skipPublishHashreleaseFlag, Usage: "Skip publishing to hashrelease server", Value: false}, &cli.BoolFlag{Name: latestFlag, Usage: "Promote this release as the latest for this stream", Value: true}, &cli.BoolFlag{Name: skipValidationFlag, Usage: "Skip pre-build validation", Value: false}, &cli.BoolFlag{Name: skipImageScanFlag, Usage: "Skip sending images to image scan service.", Value: false}, @@ -297,17 +309,20 @@ func hashreleaseSubCommands(cfg *config.Config) []*cli.Command { return fmt.Errorf("%s must be set if %s is set", skipImageScanFlag, skipValidationFlag) } - // Extract the version from pinned-version.yaml. - hash, err := pinnedversion.RetrievePinnedVersionHash(cfg.TmpFolderPath()) + // Extract the pinned version as a hashrelease. + hashrel, err := pinnedversion.LoadHashrelease(cfg.RepoRootDir, cfg.TmpFolderPath(), dir) if err != nil { return err } + if c.Bool(latestFlag) { + hashrel.Latest = true + } // Check if the hashrelease has already been published. - if published, err := tasks.HashreleasePublished(cfg, hash); err != nil { + if published, err := tasks.HashreleasePublished(cfg, hashrel.Hash); err != nil { return err } else if published { - return fmt.Errorf("hashrelease %s has already been published", hash) + return fmt.Errorf("%s hashrelease (%s) has already been published", hashrel.Name, hashrel.Hash) } // Push the operator hashrelease first before validaion @@ -321,10 +336,38 @@ func hashreleaseSubCommands(cfg *config.Config) []*cli.Command { if err := o.Publish(cfg.TmpFolderPath()); err != nil { return err } - if !c.Bool(skipValidationFlag) { - tasks.HashreleaseValidate(cfg, c.Bool(skipImageScanFlag)) + + opts := []calico.Option{ + calico.WithRepoRoot(cfg.RepoRootDir), + calico.IsHashRelease(), + calico.WithVersions(&version.Data{ + ProductVersion: version.New(hashrel.ProductVersion), + OperatorVersion: version.New(hashrel.OperatorVersion), + }), + calico.WithGithubOrg(c.String(orgFlag)), + calico.WithRepoName(c.String(repoFlag)), + calico.WithRepoRemote(cfg.GitRemote), + calico.WithValidate(!c.Bool(skipValidationFlag)), + calico.WithTmpDir(cfg.TmpFolderPath()), + calico.WithHashrelease(*hashrel, cfg.HashreleaseServerConfig), + calico.WithPublishImages(!c.Bool(skipPublishImagesFlag)), + calico.WithPublishHashrelease(!c.Bool(skipPublishHashreleaseFlag)), + calico.WithImageScanning(!c.Bool(skipImageScanFlag), cfg.ImageScannerConfig), + } + if reg := c.String(imageRegistryFlag); reg != "" { + opts = append(opts, calico.WithImageRegistries([]string{reg})) + } + r := calico.NewManager(opts...) + if err := r.PublishRelease(); err != nil { + return err + } + + // Send a slack message to notify that the hashrelease has been published. + if !c.Bool(skipPublishHashreleaseFlag) { + if err := tasks.HashreleaseSlackMessage(cfg, hashrel); err != nil { + return err + } } - tasks.HashreleasePush(cfg, dir, c.Bool(latestFlag)) return nil }, }, @@ -336,8 +379,7 @@ func hashreleaseSubCommands(cfg *config.Config) []*cli.Command { Aliases: []string{"gc"}, Action: func(c *cli.Context) error { configureLogging("hashrelease-garbage-collect.log") - tasks.HashreleaseCleanRemote(cfg) - return nil + return hashreleaseserver.CleanOldHashreleases(&cfg.HashreleaseServerConfig) }, }, } @@ -379,6 +421,7 @@ func releaseSubCommands(cfg *config.Config) []*cli.Command { Flags: []cli.Flag{ &cli.StringFlag{Name: orgFlag, Usage: "Git organization", EnvVars: []string{"ORGANIZATION"}, Value: config.DefaultOrg}, &cli.StringFlag{Name: repoFlag, Usage: "Git repository", EnvVars: []string{"GIT_REPO"}, Value: config.DefaultRepo}, + &cli.BoolFlag{Name: buildImagesFlag, Usage: "Build images from local codebase. If false, will use images from CI instead.", EnvVars: []string{"BUILD_IMAGES"}, Value: true}, &cli.BoolFlag{Name: skipValidationFlag, Usage: "Skip pre-build validation", Value: false}, &cli.StringFlag{Name: imageRegistryFlag, Usage: "Specify image registry to use", Value: ""}, }, @@ -408,6 +451,7 @@ func releaseSubCommands(cfg *config.Config) []*cli.Command { calico.WithGithubOrg(c.String(orgFlag)), calico.WithRepoName(c.String(repoFlag)), calico.WithRepoRemote(cfg.GitRemote), + calico.WithBuildImages(c.Bool(buildImagesFlag)), } if c.Bool(skipValidationFlag) { opts = append(opts, calico.WithValidate(false)) @@ -427,9 +471,9 @@ func releaseSubCommands(cfg *config.Config) []*cli.Command { Flags: []cli.Flag{ &cli.StringFlag{Name: orgFlag, Usage: "Git organization", EnvVars: []string{"ORGANIZATION"}, Value: config.DefaultOrg}, &cli.StringFlag{Name: repoFlag, Usage: "Git repository", EnvVars: []string{"GIT_REPO"}, Value: config.DefaultRepo}, - &cli.BoolFlag{Name: skipPublishImagesFlag, Usage: "Skip publishing of container images to registry", Value: false}, - &cli.BoolFlag{Name: skipPublishGitTag, Usage: "Skip publishing of tag to git repository", Value: false}, - &cli.BoolFlag{Name: skipPublishGithubRelease, Usage: "Skip publishing of release to Github", Value: false}, + &cli.BoolFlag{Name: skipPublishImagesFlag, Usage: "Skip publishing of container images to registry", EnvVars: []string{"SKIP_PUBLISH_IMAGES"}, Value: false}, + &cli.BoolFlag{Name: skipPublishGitTagFlag, Usage: "Skip publishing of tag to git repository", Value: false}, + &cli.BoolFlag{Name: skipPublishGithubReleaseFlag, Usage: "Skip publishing of release to Github", Value: false}, &cli.StringFlag{Name: imageRegistryFlag, Usage: "Specify image registry to use", Value: ""}, }, Action: func(c *cli.Context) error { @@ -445,10 +489,12 @@ func releaseSubCommands(cfg *config.Config) []*cli.Command { OperatorVersion: operatorVer, }), calico.WithOutputDir(filepath.Join(baseUploadDir, ver.FormattedString())), - calico.WithPublishOptions(!c.Bool(skipPublishImagesFlag), !c.Bool(skipPublishGitTag), !c.Bool(skipPublishGithubRelease)), calico.WithGithubOrg(c.String(orgFlag)), calico.WithRepoName(c.String(repoFlag)), calico.WithRepoRemote(cfg.GitRemote), + calico.WithPublishImages(!c.Bool(skipPublishImagesFlag)), + calico.WithPublishGitTag(!c.Bool(skipPublishGitTagFlag)), + calico.WithPublishGithubRelease(!c.Bool(skipPublishGithubReleaseFlag)), } if reg := c.String(imageRegistryFlag); reg != "" { opts = append(opts, calico.WithImageRegistries([]string{reg})) diff --git a/release/internal/hashreleaseserver/config.go b/release/internal/hashreleaseserver/config.go index 28bf3da2167..0a1b3c81a30 100644 --- a/release/internal/hashreleaseserver/config.go +++ b/release/internal/hashreleaseserver/config.go @@ -38,8 +38,8 @@ type Config struct { KnownHosts string `envconfig:"DOCS_KNOWN_HOSTS"` } -// rshVars returns the ssh command for rsync to use for the connection -func (s *Config) rshVars() string { +// RSHVars returns the ssh command for rsync to use for the connection +func (s *Config) RSHVars() string { str := []string{"ssh", "-i", s.Key, "-p", s.Port, "-q", "-o StrictHostKeyChecking=yes"} if s.KnownHosts != "" { str = append(str, "-o UserKnownHostsFile="+s.KnownHosts) diff --git a/release/internal/hashreleaseserver/server.go b/release/internal/hashreleaseserver/server.go index 8e89c01a521..ece725d5dd4 100644 --- a/release/internal/hashreleaseserver/server.go +++ b/release/internal/hashreleaseserver/server.go @@ -25,8 +25,6 @@ import ( "time" "github.com/sirupsen/logrus" - - "github.com/projectcalico/calico/release/internal/command" ) const ( @@ -52,6 +50,12 @@ type Hashrelease struct { // Stream is the version the hashrelease is for (e.g master, v3.19) Stream string + // ProductVersion is the product version in the hashrelease + ProductVersion string + + // OperatorVersion is the operator version for the hashreleaseq + OperatorVersion string + // Source is the source of hashrelease content Source string @@ -62,11 +66,11 @@ type Hashrelease struct { Latest bool } -func (h Hashrelease) URL() string { +func (h *Hashrelease) URL() string { return fmt.Sprintf("https://%s.%s", h.Name, BaseDomain) } -func remoteDocsPath(user string) string { +func RemoteDocsPath(user string) string { path := "files" if user != "root" { path = filepath.Join("home", "core", "disk", "docs-preview", path) @@ -75,7 +79,7 @@ func remoteDocsPath(user string) string { } func remoteReleasesLibraryPath(user string) string { - return filepath.Join(remoteDocsPath(user), "all-releases") + return filepath.Join(RemoteDocsPath(user), "all-releases") } func HasHashrelease(hash string, cfg *Config) bool { @@ -86,25 +90,13 @@ func HasHashrelease(hash string, cfg *Config) bool { return false } -// PublishHashrelease publishes a hashrelease to the server -func PublishHashrelease(rel Hashrelease, cfg *Config) error { - logrus.WithFields(logrus.Fields{ - "hashrelease": rel.Name, - "hash": rel.Hash, - "source": rel.Source, - }).Debug("Publishing hashrelease") - dir := rel.Source + "/" - if _, err := command.Run("rsync", []string{"--stats", "-az", "--delete", fmt.Sprintf("--rsh=%s", cfg.rshVars()), dir, fmt.Sprintf("%s:%s/%s", cfg.HostString(), remoteDocsPath(cfg.User), rel.Name)}); err != nil { - logrus.WithError(err).Error("Failed to publish hashrelease") +// SetHashreleaseAsLatest sets the hashrelease as the latest for the stream +func SetHashreleaseAsLatest(rel Hashrelease, cfg *Config) error { + logrus.Debugf("Updating latest hashrelease for %s stream to %s", rel.Stream, rel.Name) + if _, err := runSSHCommand(cfg, fmt.Sprintf(`echo "%s/" > %s/latest-os/%s.txt && echo %s >> %s`, rel.URL(), RemoteDocsPath(cfg.User), rel.Stream, rel.Name, remoteReleasesLibraryPath(cfg.User))); err != nil { + logrus.WithError(err).Error("Failed to update latest hashrelease and hashrelease library") return err } - if rel.Latest { - logrus.Debugf("Updating latest hashrelease for %s stream to %s", rel.Stream, rel.Name) - if _, err := runSSHCommand(cfg, fmt.Sprintf(`echo "%s/" > %s/latest-os/%s.txt && echo %s >> %s`, rel.URL(), remoteDocsPath(cfg.User), rel.Stream, rel.Name, remoteReleasesLibraryPath(cfg.User))); err != nil { - logrus.WithError(err).Error("Failed to update latest hashrelease and hashrelease library") - return err - } - } return nil } @@ -136,7 +128,7 @@ func CleanOldHashreleases(cfg *Config) error { } func listHashreleases(cfg *Config) ([]Hashrelease, error) { - cmd := fmt.Sprintf("ls -lt --time-style=+'%%Y-%%m-%%d %%H:%%M:%%S' %s", remoteDocsPath(cfg.User)) + cmd := fmt.Sprintf("ls -lt --time-style=+'%%Y-%%m-%%d %%H:%%M:%%S' %s", RemoteDocsPath(cfg.User)) out, err := runSSHCommand(cfg, cmd) if err != nil { logrus.WithError(err).Error("Failed to get list of hashreleases") @@ -162,7 +154,7 @@ func listHashreleases(cfg *Config) ([]Hashrelease, error) { } if re.MatchString(name) { releases = append(releases, Hashrelease{ - Name: filepath.Join(remoteDocsPath(cfg.User), name), + Name: filepath.Join(RemoteDocsPath(cfg.User), name), Time: time, }) } diff --git a/release/internal/pinnedversion/pinnedversion.go b/release/internal/pinnedversion/pinnedversion.go index c742a6e0f04..a87e11531ab 100644 --- a/release/internal/pinnedversion/pinnedversion.go +++ b/release/internal/pinnedversion/pinnedversion.go @@ -51,6 +51,9 @@ type Config struct { // Operator is the configuration for the operator. Operator config.OperatorConfig + + // Registry is to override the default registry. + Registry string } // PinnedVersionData represents the data needed to generate the pinned version file from the template. @@ -75,6 +78,9 @@ type PinnedVersionData struct { // ReleaseBranch is the release branch of the release. ReleaseBranch string + + // Registry is to override the default registry. + Registry string } // PinnedVersion represents an entry in pinned version file. @@ -133,6 +139,7 @@ func GeneratePinnedVersionFile(cfg Config, outputDir string) (string, *PinnedVer Note: fmt.Sprintf("%s - generated at %s using %s release branch with %s operator branch", releaseName, time.Now().Format(time.RFC1123), productBranch, operatorBranch), ReleaseBranch: productVersion.ReleaseBranch(cfg.ReleaseBranchPrefix), + Registry: cfg.Registry, } logrus.WithField("file", pinnedVersionPath).Info("Generating pinned-version.yaml") pinnedVersionFile, err := os.Create(pinnedVersionPath) @@ -197,63 +204,6 @@ func RetrievePinnedOperator(outputDir string) (registry.OperatorComponent, error }, nil } -// RetrievePinnedOperatorVersion retrieves the operator version from the pinned version file. -func RetrievePinnedOperatorVersion(outputDir string) (string, error) { - operator, err := RetrievePinnedOperator(outputDir) - if err != nil { - return "", err - } - return operator.Version, nil -} - -// RetrieveReleaseName retrieves the release name from the pinned version file. -func RetrieveReleaseName(outputDir string) (string, error) { - pinnedVersionPath := pinnedVersionFilePath(outputDir) - var pinnedversion PinnedVersionFile - if pinnedVersionData, err := os.ReadFile(pinnedVersionPath); err != nil { - return "", err - } else if err := yaml.Unmarshal([]byte(pinnedVersionData), &pinnedversion); err != nil { - return "", err - } - return pinnedversion[0].ReleaseName, nil -} - -// RetrievePinnedProductVersion retrieves the product version from the pinned version file. -func RetrievePinnedProductVersion(outputDir string) (string, error) { - pinnedVersionPath := pinnedVersionFilePath(outputDir) - var pinnedversion PinnedVersionFile - if pinnedVersionData, err := os.ReadFile(pinnedVersionPath); err != nil { - return "", err - } else if err := yaml.Unmarshal([]byte(pinnedVersionData), &pinnedversion); err != nil { - return "", err - } - return pinnedversion[0].Title, nil -} - -// RetrievePinnedVersionNote retrieves the note from the pinned version file. -func RetrievePinnedVersionNote(outputDir string) (string, error) { - pinnedVersionPath := pinnedVersionFilePath(outputDir) - var pinnedversion PinnedVersionFile - if pinnedVersionData, err := os.ReadFile(pinnedVersionPath); err != nil { - return "", err - } else if err := yaml.Unmarshal([]byte(pinnedVersionData), &pinnedversion); err != nil { - return "", err - } - return pinnedversion[0].Note, nil -} - -// RetrievePinnedVersionHash retrieves the hash from the pinned version file. -func RetrievePinnedVersionHash(outputDir string) (string, error) { - pinnedVersionPath := pinnedVersionFilePath(outputDir) - var pinnedversion PinnedVersionFile - if pinnedVersionData, err := os.ReadFile(pinnedVersionPath); err != nil { - return "", err - } else if err := yaml.Unmarshal([]byte(pinnedVersionData), &pinnedversion); err != nil { - return "", err - } - return pinnedversion[0].Hash, nil -} - // RetrieveComponentsToValidate retrieves the components to validate from the pinned version file. func RetrieveComponentsToValidate(outputDir string) (map[string]registry.Component, error) { pinnedVersionPath := pinnedVersionFilePath(outputDir) @@ -284,3 +234,25 @@ func RetrieveComponentsToValidate(outputDir string) (map[string]registry.Compone } return components, nil } + +func LoadHashrelease(repoRootDir, tmpDir, srcDir string) (*hashreleaseserver.Hashrelease, error) { + productBranch, err := utils.GitBranch(repoRootDir) + if err != nil { + logrus.WithError(err).Errorf("Failed to get %s branch name", utils.ProductName) + return nil, err + } + pinnedVersion, err := RetrievePinnedVersion(tmpDir) + if err != nil { + logrus.WithError(err).Fatal("Failed to get pinned version") + } + return &hashreleaseserver.Hashrelease{ + Name: pinnedVersion.ReleaseName, + Hash: pinnedVersion.Hash, + Note: pinnedVersion.Note, + Stream: version.DeterminePublishStream(productBranch, pinnedVersion.Title), + ProductVersion: pinnedVersion.Title, + OperatorVersion: pinnedVersion.TigeraOperator.Version, + Source: srcDir, + Time: time.Now(), + }, nil +} diff --git a/release/internal/pinnedversion/templates/calico-version.yaml.gotmpl b/release/internal/pinnedversion/templates/calico-version.yaml.gotmpl index 5630171efb3..696975fd802 100644 --- a/release/internal/pinnedversion/templates/calico-version.yaml.gotmpl +++ b/release/internal/pinnedversion/templates/calico-version.yaml.gotmpl @@ -11,36 +11,50 @@ calico: version: {{.ProductVersion}} typha: - version: {{.ProductVersion}} + version: {{.ProductVersion}}{{if .Registry}} + registry: {{.Registry}}{{end}} calicoctl: - version: {{.ProductVersion}} + version: {{.ProductVersion}}{{if .Registry}} + registry: {{.Registry}}{{end}} calico/node: - version: {{.ProductVersion}} + version: {{.ProductVersion}}{{if .Registry}} + registry: {{.Registry}}{{end}} calico/cni: - version: {{.ProductVersion}} + version: {{.ProductVersion}}{{if .Registry}} + registry: {{.Registry}}{{end}} calico/apiserver: - version: {{.ProductVersion}} + version: {{.ProductVersion}}{{if .Registry}} + registry: {{.Registry}}{{end}} image: calico/apiserver calico/kube-controllers: - version: {{.ProductVersion}} + version: {{.ProductVersion}}{{if .Registry}} + registry: {{.Registry}}{{end}} calico/api: - version: {{.ProductVersion}} + version: {{.ProductVersion}}{{if .Registry}} + registry: {{.Registry}}{{end}} networking-calico: version: {{.ReleaseBranch}} flannel: version: v0.12.0 registry: quay.io calico/dikastes: - version: {{.ProductVersion}} + version: {{.ProductVersion}}{{if .Registry}} + registry: {{.Registry}}{{end}} flexvol: - version: {{.ProductVersion}} + version: {{.ProductVersion}}{{if .Registry}} + registry: {{.Registry}}{{end}} key-cert-provisioner: - version: {{.ProductVersion}} + version: {{.ProductVersion}}{{if .Registry}} + registry: {{.Registry}}{{end}} calico/csi: - version: {{.ProductVersion}} + version: {{.ProductVersion}}{{if .Registry}} + registry: {{.Registry}}{{end}} csi-node-driver-registrar: - version: {{.ProductVersion}} + version: {{.ProductVersion}}{{if .Registry}} + registry: {{.Registry}}{{end}} calico/cni-windows: - version: {{.ProductVersion}} + version: {{.ProductVersion}}{{if .Registry}} + registry: {{.Registry}}{{end}} calico/node-windows: - version: {{.ProductVersion}} + version: {{.ProductVersion}}{{if .Registry}} + registry: {{.Registry}}{{end}} diff --git a/release/pkg/manager/calico/manager.go b/release/pkg/manager/calico/manager.go index df04ba52da7..c54d8232ce6 100644 --- a/release/pkg/manager/calico/manager.go +++ b/release/pkg/manager/calico/manager.go @@ -27,6 +27,10 @@ import ( "gopkg.in/yaml.v2" "github.com/projectcalico/calico/release/internal/command" + "github.com/projectcalico/calico/release/internal/hashreleaseserver" + "github.com/projectcalico/calico/release/internal/imagescanner" + "github.com/projectcalico/calico/release/internal/pinnedversion" + "github.com/projectcalico/calico/release/internal/registry" "github.com/projectcalico/calico/release/internal/utils" ) @@ -48,10 +52,6 @@ func NewManager(opts ...Option) *CalicoManager { b := &CalicoManager{ runner: &command.RealCommandRunner{}, validate: true, - buildImages: true, - publishImages: true, - publishTag: true, - publishGithub: true, imageRegistries: defaultRegistries, } @@ -121,6 +121,9 @@ type CalicoManager struct { // which we should read them for publishing. outputDir string + // tmpDir is the directory to which we should write temporary files. + tmpDir string + // Fine-tuning configuration for publishing. publishImages bool publishTag bool @@ -144,6 +147,15 @@ type CalicoManager struct { // architectures is the list of architectures for which we should build images. // If empty, we build for all. architectures []string + + // hashrelease configuration. + publishHashrelease bool + hashrelease hashreleaseserver.Hashrelease + hashreleaseConfig hashreleaseserver.Config + + // image scanning configuration. + imageScanning bool + imageScanningConfig imagescanner.Config } // releaseImages returns the set of images that should be expected for a release. @@ -212,14 +224,8 @@ func (r *CalicoManager) Build() error { }() } - if r.buildImages { - // Build the container images for the release if configured to do so. - // - // If skipped, we expect that the images for this version have already - // been published as part of CI. - if err = r.BuildContainerImages(ver); err != nil { - return err - } + if err = r.buildContainerImages(); err != nil { + return err } // Build the helm chart. @@ -377,16 +383,6 @@ func (r *CalicoManager) TagRelease(ver string) error { return nil } -func (r *CalicoManager) BuildContainerImages(ver string) error { - // Build container images for the release. - if err := r.buildContainerImages(ver); err != nil { - return err - } - // TODO: Assert the produced images are OK. e.g., have correct - // commit and version information compiled in. - return nil -} - func (r *CalicoManager) BuildHelm() error { if r.isHashRelease { // We need to modify values.yaml to use the correct version. @@ -425,32 +421,51 @@ func (r *CalicoManager) buildOCPBundle() error { return nil } -func (r *CalicoManager) PublishRelease() error { - // Determine the currently checked-out tag. - ver, err := r.git("describe", "--exact-match", "--tags", "HEAD") - if err != nil { - return fmt.Errorf("failed to get tag for checked-out commit, is there one? %s", err) +func (r *CalicoManager) publishToHashreleaseServer() error { + if !r.publishHashrelease { + logrus.Info("Skipping publishing to hashrelease server") + return nil + } + logrus.WithField("note", r.hashrelease.Note).Info("Publishing hashrelease") + dir := r.hashrelease.Source + "/" + if _, err := r.runner.Run("rsync", + []string{ + "--stats", "-az", "--delete", + fmt.Sprintf("--rsh=%s", r.hashreleaseConfig.RSHVars()), dir, + fmt.Sprintf("%s:%s/%s", r.hashreleaseConfig.HostString(), hashreleaseserver.RemoteDocsPath(r.hashreleaseConfig.User), r.hashrelease.Name), + }, nil); err != nil { + logrus.WithError(err).Error("Failed to publish hashrelease") + return err + } + if r.hashrelease.Latest { + hashreleaseserver.SetHashreleaseAsLatest(r.hashrelease, &r.hashreleaseConfig) } + return nil +} +func (r *CalicoManager) PublishRelease() error { // Check that the environment has the necessary prereqs. - if err = r.publishPrereqs(); err != nil { + if err := r.publishPrereqs(); err != nil { return err } // Publish container images. - if err = r.publishContainerImages(ver); err != nil { + if err := r.publishContainerImages(); err != nil { return fmt.Errorf("failed to publish container images: %s", err) } - if r.publishTag { - // If all else is successful, push the git tag. - if _, err = r.git("push", r.remote, ver); err != nil { - return fmt.Errorf("failed to push git tag: %s", err) + if r.isHashRelease { + if err := r.publishToHashreleaseServer(); err != nil { + return fmt.Errorf("failed to publish hashrelease: %s", err) } } + if err := r.publishGitTag(); err != nil { + return fmt.Errorf("failed to publish git tag: %s", err) + } + // Publish the release to github. - if err = r.publishGithubRelease(ver); err != nil { + if err := r.publishGithubRelease(); err != nil { return fmt.Errorf("failed to publish github release: %s", err) } @@ -476,8 +491,88 @@ func (r *CalicoManager) releasePrereqs() error { return nil } +type imageExistsResult struct { + name string + image string + exists bool + err error +} + +func imgExists(name string, component registry.Component, ch chan imageExistsResult) { + r := imageExistsResult{ + name: name, + image: component.String(), + } + r.exists, r.err = registry.ImageExists(component.ImageRef()) + ch <- r +} + +// Check general prerequisites for publishing a hashrelease. +// This checks the following: +// - The hashrelease does not already exist. +// - All images for the hashrelease exist. +// - The images have been scanned (if required). +func (r *CalicoManager) hashreleasePrereqs() error { + // Publish images before checking if they exist. + if err := r.publishContainerImages(); err != nil { + return fmt.Errorf("failed to publish container images: %s", err) + } + images, err := pinnedversion.RetrieveComponentsToValidate(r.tmpDir) + if err != nil { + return fmt.Errorf("failed to get components to validate: %s", err) + } + results := make(map[string]imageExistsResult, len(images)) + + ch := make(chan imageExistsResult) + for name, component := range images { + go imgExists(name, component, ch) + } + for range images { + res := <-ch + results[res.name] = res + } + failedImageList := []string{} + for name, r := range results { + logrus.WithFields(logrus.Fields{ + "image": r.image, + "exists": r.exists, + }).Info("Validating image") + if r.err != nil || !r.exists { + logrus.WithError(r.err).WithField("image", name).Error("Error checking image") + failedImageList = append(failedImageList, images[name].String()) + } else { + logrus.WithField("image", name).Info("Image exists") + } + } + failedCount := len(failedImageList) + if failedCount > 0 { + return fmt.Errorf("failed to validate %d images: %s", failedCount, strings.Join(failedImageList, ", ")) + } + if r.imageScanning { + logrus.Info("Sending images to ISS") + imageList := []string{} + for _, component := range images { + imageList = append(imageList, component.String()) + } + imageScanner := imagescanner.New(r.imageScanningConfig) + err := imageScanner.Scan(imageList, r.hashrelease.Stream, false, r.tmpDir) + if err != nil { + // Error is logged and ignored as this is not considered a fatal error + logrus.WithError(err).Error("Failed to scan images") + } + } + return nil +} + // Prerequisites specific to publishing a release. func (r *CalicoManager) publishPrereqs() error { + if !r.validate { + logrus.Warn("Skipping pre-publish validation") + return nil + } + if r.isHashRelease { + return r.hashreleasePrereqs() + } // TODO: Verify all required artifacts are present. return r.releasePrereqs() } @@ -661,7 +756,11 @@ func (r *CalicoManager) buildReleaseTar(ver string, targetDir string) error { return nil } -func (r *CalicoManager) buildContainerImages(ver string) error { +func (r *CalicoManager) buildContainerImages() error { + if !r.buildImages { + logrus.Info("Skip building container images") + return nil + } releaseDirs := []string{ "node", "pod2daemon", @@ -680,9 +779,11 @@ func (r *CalicoManager) buildContainerImages(ver string) error { "cni-plugin", } + logrus.Info("Building container images") + // Build env. env := append(os.Environ(), - fmt.Sprintf("VERSION=%s", ver), + fmt.Sprintf("VERSION=%s", r.calicoVersion), fmt.Sprintf("DEV_REGISTRIES=%s", strings.Join(r.imageRegistries, " ")), ) @@ -711,7 +812,16 @@ func (r *CalicoManager) buildContainerImages(ver string) error { return nil } -func (r *CalicoManager) publishGithubRelease(ver string) error { +func (r *CalicoManager) publishGitTag() error { + if !r.publishTag { + logrus.Info("Skipping git tag") + return nil + } + _, err := r.git("push", r.remote, r.calicoVersion) + return err +} + +func (r *CalicoManager) publishGithubRelease() error { if !r.publishGithub { logrus.Info("Skipping github release") return nil @@ -732,19 +842,19 @@ Additional links: - [VPP data plane release information](https://github.com/projectcalico/vpp-dataplane/blob/master/RELEASE_NOTES.md) ` - sv, err := semver.NewVersion(strings.TrimPrefix(ver, "v")) + sv, err := semver.NewVersion(strings.TrimPrefix(r.calicoVersion, "v")) if err != nil { return err } formatters := []string{ // Alternating placeholder / filler. We can't use backticks in the multiline string above, // so we replace anything that needs to be backticked into it here. - "{version}", ver, + "{version}", r.calicoVersion, "{branch}", fmt.Sprintf("release-v%d.%d", sv.Major, sv.Minor), "{release_stream}", fmt.Sprintf("v%d.%d", sv.Major, sv.Minor), - "{release_tar}", fmt.Sprintf("`release-%s.tgz`", ver), - "{calico_windows_zip}", fmt.Sprintf("`calico-windows-%s.zip`", ver), - "{helm_chart}", fmt.Sprintf("`tigera-operator-%s.tgz`", ver), + "{release_tar}", fmt.Sprintf("`release-%s.tgz`", r.calicoVersion), + "{calico_windows_zip}", fmt.Sprintf("`calico-windows-%s.zip`", r.calicoVersion), + "{helm_chart}", fmt.Sprintf("`tigera-operator-%s.tgz`", r.calicoVersion), } replacer := strings.NewReplacer(formatters...) releaseNote := replacer.Replace(releaseNoteTemplate) @@ -752,16 +862,16 @@ Additional links: args := []string{ "-username", r.githubOrg, "-repository", r.repo, - "-name", ver, + "-name", r.calicoVersion, "-body", releaseNote, - ver, + r.calicoVersion, r.uploadDir(), } _, err = r.runner.RunInDir(r.repoRoot, "./bin/ghr", args, nil) return err } -func (r *CalicoManager) publishContainerImages(ver string) error { +func (r *CalicoManager) publishContainerImages() error { if !r.publishImages { logrus.Info("Skipping image publish") return nil @@ -785,8 +895,8 @@ func (r *CalicoManager) publishContainerImages(ver string) error { } env := append(os.Environ(), - fmt.Sprintf("IMAGETAG=%s", ver), - fmt.Sprintf("VERSION=%s", ver), + fmt.Sprintf("IMAGETAG=%s", r.calicoVersion), + fmt.Sprintf("VERSION=%s", r.calicoVersion), "RELEASE=true", "CONFIRM=true", fmt.Sprintf("DEV_REGISTRIES=%s", strings.Join(r.imageRegistries, " ")), diff --git a/release/pkg/manager/calico/options.go b/release/pkg/manager/calico/options.go index c2641474e59..bb43961a09f 100644 --- a/release/pkg/manager/calico/options.go +++ b/release/pkg/manager/calico/options.go @@ -15,6 +15,8 @@ package calico import ( + "github.com/projectcalico/calico/release/internal/hashreleaseserver" + "github.com/projectcalico/calico/release/internal/imagescanner" "github.com/projectcalico/calico/release/internal/version" ) @@ -63,11 +65,30 @@ func WithOutputDir(outputDir string) Option { } } -func WithPublishOptions(images, tag, github bool) Option { +func WithPublishImages(publish bool) Option { return func(r *CalicoManager) error { - r.publishImages = images - r.publishTag = tag - r.publishGithub = github + r.publishImages = publish + return nil + } +} + +func WithPublishGitTag(publish bool) Option { + return func(r *CalicoManager) error { + r.publishTag = publish + return nil + } +} + +func WithPublishGithubRelease(publish bool) Option { + return func(r *CalicoManager) error { + r.publishGithub = publish + return nil + } +} + +func WithPublishHashrelease(publish bool) Option { + return func(r *CalicoManager) error { + r.publishHashrelease = publish return nil } } @@ -120,3 +141,26 @@ func WithReleaseBranchPrefix(prefix string) Option { return nil } } + +func WithTmpDir(tmpDir string) Option { + return func(r *CalicoManager) error { + r.tmpDir = tmpDir + return nil + } +} + +func WithHashrelease(hashrelease hashreleaseserver.Hashrelease, cfg hashreleaseserver.Config) Option { + return func(r *CalicoManager) error { + r.hashrelease = hashrelease + r.hashreleaseConfig = cfg + return nil + } +} + +func WithImageScanning(scanning bool, cfg imagescanner.Config) Option { + return func(r *CalicoManager) error { + r.imageScanning = scanning + r.imageScanningConfig = cfg + return nil + } +} diff --git a/release/pkg/tasks/hashrelease.go b/release/pkg/tasks/hashrelease.go index d27b4d48611..f5b3f75f8a9 100644 --- a/release/pkg/tasks/hashrelease.go +++ b/release/pkg/tasks/hashrelease.go @@ -18,7 +18,6 @@ import ( "fmt" "os" "path/filepath" - "strings" "github.com/sirupsen/logrus" @@ -26,116 +25,10 @@ import ( "github.com/projectcalico/calico/release/internal/hashreleaseserver" "github.com/projectcalico/calico/release/internal/imagescanner" "github.com/projectcalico/calico/release/internal/pinnedversion" - "github.com/projectcalico/calico/release/internal/registry" "github.com/projectcalico/calico/release/internal/slack" "github.com/projectcalico/calico/release/internal/utils" - "github.com/projectcalico/calico/release/internal/version" ) -type imageExistsResult struct { - name string - image string - exists bool - err error -} - -func imgExists(name string, component registry.Component, ch chan imageExistsResult) { - r := imageExistsResult{ - name: name, - image: component.String(), - } - r.exists, r.err = registry.ImageExists(component.ImageRef()) - ch <- r -} - -// HashreleaseValidate validates the images in the hashrelease. -// These images are checked to ensure they exist in the registry -// as they should have been pushed in the standard build process. -func HashreleaseValidate(cfg *config.Config, skipISS bool) { - tmpDir := cfg.TmpFolderPath() - name, err := pinnedversion.RetrieveReleaseName(tmpDir) - if err != nil { - logrus.WithError(err).Fatal("Failed to get release name") - } - productBranch, err := utils.GitBranch(cfg.RepoRootDir) - if err != nil { - logrus.WithError(err).Fatalf("Failed to get %s branch name", utils.ProductName) - } - productVersion, err := pinnedversion.RetrievePinnedProductVersion(tmpDir) - if err != nil { - logrus.WithError(err).Fatal("Failed to get candidate name") - } - operatorVersion, err := pinnedversion.RetrievePinnedOperatorVersion(tmpDir) - if err != nil { - logrus.WithError(err).Fatal("Failed to get operator version") - } - images, err := pinnedversion.RetrieveComponentsToValidate(tmpDir) - if err != nil { - logrus.WithError(err).Fatal("Failed to get pinned version") - } - results := make(map[string]imageExistsResult, len(images)) - - ch := make(chan imageExistsResult) - for name, component := range images { - go imgExists(name, component, ch) - } - for range images { - res := <-ch - results[res.name] = res - } - failedImages := []registry.Component{} - failedImageNames := []string{} - for name, r := range results { - logrus.WithFields(logrus.Fields{ - "image": r.image, - "exists": r.exists, - }).Info("Validating image") - if r.err != nil || !r.exists { - logrus.WithError(r.err).WithField("image", name).Error("Error checking image") - failedImageNames = append(failedImageNames, name) - failedImages = append(failedImages, images[name]) - } else { - logrus.WithField("image", name).Info("Image exists") - } - } - failedCount := len(failedImageNames) - if failedCount > 0 { - // We only care to send failure messages if we are in CI - if cfg.CI.IsCI { - slackMsg := slack.Message{ - Config: cfg.SlackConfig, - Data: slack.MessageData{ - ReleaseName: name, - Product: utils.DisplayProductName(), - Stream: version.DeterminePublishStream(productBranch, productVersion), - Version: productVersion, - OperatorVersion: operatorVersion, - CIURL: cfg.CI.URL(), - FailedImages: failedImages, - }, - } - if err := slackMsg.SendFailure(logrus.IsLevelEnabled(logrus.DebugLevel)); err != nil { - logrus.WithError(err).Error("Failed to send slack message") - } - } - logrus.WithField("images", strings.Join(failedImageNames, ", ")). - Fatalf("Failed to validate %d images, see above for details", failedCount) - } - if !skipISS { - logrus.Info("Sending images to ISS") - imageList := []string{} - for _, component := range images { - imageList = append(imageList, component.String()) - } - imageScanner := imagescanner.New(cfg.ImageScannerConfig) - err := imageScanner.Scan(imageList, version.DeterminePublishStream(productBranch, productVersion), false, cfg.OutputDir) - if err != nil { - // Error is logged and ignored as this is not considered a fatal error - logrus.WithError(err).Error("Failed to scan images") - } - } -} - // HashreleasePublished checks if the hashrelease has already been published. // If it has, the process is halted. func HashreleasePublished(cfg *config.Config, hash string) (bool, error) { @@ -152,54 +45,20 @@ func HashreleasePublished(cfg *config.Config, hash string) (bool, error) { return hashreleaseserver.HasHashrelease(hash, &cfg.HashreleaseServerConfig), nil } -// HashreleaseValidate publishes the hashrelease -func HashreleasePush(cfg *config.Config, path string, setLatest bool) { - tmpDir := cfg.TmpFolderPath() - name, err := pinnedversion.RetrieveReleaseName(tmpDir) - if err != nil { - logrus.WithError(err).Fatal("Failed to get release name") - } - note, err := pinnedversion.RetrievePinnedVersionNote(tmpDir) - if err != nil { - logrus.WithError(err).Fatal("Failed to get pinned version note") - } - productBranch, err := utils.GitBranch(cfg.RepoRootDir) - if err != nil { - logrus.WithError(err).Fatalf("Failed to get %s branch name", utils.ProductName) - } - productVersion, err := pinnedversion.RetrievePinnedProductVersion(tmpDir) - if err != nil { - logrus.WithError(err).Fatal("Failed to get candidate name") - } - operatorVersion, err := pinnedversion.RetrievePinnedOperatorVersion(tmpDir) - if err != nil { - logrus.WithError(err).Fatal("Failed to get operator version") - } - releaseHash, err := pinnedversion.RetrievePinnedVersionHash(tmpDir) - if err != nil { - logrus.WithError(err).Fatal("Failed to get release hash") - } - hashrel := hashreleaseserver.Hashrelease{ - Name: name, - Hash: releaseHash, - Note: note, - Stream: version.DeterminePublishStream(productBranch, productVersion), - Source: path, - Latest: setLatest, +// HashreleaseSlackMessage sends a slack message to notify that a hashrelease has been published. +func HashreleaseSlackMessage(cfg *config.Config, hashrel *hashreleaseserver.Hashrelease) error { + scanResultURL := imagescanner.RetrieveResultURL(cfg.TmpFolderPath()) + if scanResultURL == "" { + logrus.Warn("No image scan result URL found") } - logrus.WithField("note", note).Info("Publishing hashrelease") - if err := hashreleaseserver.PublishHashrelease(hashrel, &cfg.HashreleaseServerConfig); err != nil { - logrus.WithError(err).Fatal("Failed to publish hashrelease") - } - scanResultURL := imagescanner.RetrieveResultURL(cfg.OutputDir) slackMsg := slack.Message{ Config: cfg.SlackConfig, Data: slack.MessageData{ - ReleaseName: name, + ReleaseName: hashrel.Name, Product: utils.DisplayProductName(), - Stream: version.DeterminePublishStream(productBranch, productVersion), - Version: productVersion, - OperatorVersion: operatorVersion, + Stream: hashrel.Stream, + Version: hashrel.ProductVersion, + OperatorVersion: hashrel.OperatorVersion, DocsURL: hashrel.URL(), CIURL: cfg.CI.URL(), ImageScanResultURL: scanResultURL, @@ -209,17 +68,10 @@ func HashreleasePush(cfg *config.Config, path string, setLatest bool) { logrus.WithError(err).Error("Failed to send slack message") } logrus.WithFields(logrus.Fields{ - "name": name, + "name": hashrel.Name, "URL": hashrel.URL(), - }).Info("Published hashrelease") -} - -// HashreleaseCleanRemote cleans up old hashreleases on the docs host -func HashreleaseCleanRemote(cfg *config.Config) { - logrus.Info("Cleaning up old hashreleases") - if err := hashreleaseserver.CleanOldHashreleases(&cfg.HashreleaseServerConfig); err != nil { - logrus.WithError(err).Fatal("Failed to delete old hashreleases") - } + }).Info("Sent hashrelease publish notification to slack") + return nil } // ReformatHashrelease modifies the generated release output to match