diff --git a/docs/content/contributing/releasing.md b/docs/content/contributing/releasing.md index 66c34782c..656387cb8 100644 --- a/docs/content/contributing/releasing.md +++ b/docs/content/contributing/releasing.md @@ -3,6 +3,8 @@ title = "Releasing" icon = "fa-solid fa-gift" +++ +## Creating a release PR + This project uses [release-please] to automate changelog updates per release. Due to security restrictions[^1] in the `nutanix-cloud-native` GitHub organization, the release process is a little more complex than just using the [release-please-action]. @@ -18,8 +20,10 @@ This will create the branch and release PR. From this point on until a release i will keep the PR up to date (GHA workflows are only not allowed to create the original PR, they can keep the PR up to date). -When a release is ready, the commits in the release PR will need to be signed (again, this is a security requirement). -To do this, check out the PR branch locally: +## Cutting a release + +When a release is ready, the commits in the release PR created above will need to be signed (again, this is a security +requirement). To do this, check out the PR branch locally: ```shell gh pr checkout @@ -31,6 +35,17 @@ Sign the previous commit: git commit --gpg-sign --amend --no-edit ``` +If you are releasing a new minor release, the update the `metadata.yaml`s so that the upcoming release version is used +for e.g. local development and e2e tests: + +1. Add the new release to the root level `metadata.yaml` release series. +1. Add the new release to the e2e configuration `test/e2e/data/shared/v1beta1-caren/metadata.yaml` release series. +1. Add the next release to the e2e configuration `test/e2e/data/shared/v1beta1-caren/metadata.yaml` (e.g. if release + `v0.6.0` then add release series for `v0.7`). +1. Update the `caren` provider configuration in `test/e2e/config/caren.yaml` with the new release (replacing the last + minor release with the new minor release version) and the next minor release configuration (replacing the `v0.x.99` + configuration). + And force push: ```shell diff --git a/metadata.yaml b/metadata.yaml index a975ca6fc..f54b4f923 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -25,3 +25,12 @@ releaseSeries: - contract: v1beta1 major: 0 minor: 8 + - contract: v1beta1 + major: 0 + minor: 9 + - contract: v1beta1 + major: 0 + minor: 10 + - contract: v1beta1 + major: 0 + minor: 11 diff --git a/test/e2e/config/caren.yaml b/test/e2e/config/caren.yaml index 4f108cd20..37aa6b7f7 100644 --- a/test/e2e/config/caren.yaml +++ b/test/e2e/config/caren.yaml @@ -134,8 +134,8 @@ providers: - name: caren type: RuntimeExtensionProvider versions: - - name: "{go://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix@v0.8}" - value: "https://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/releases/download/{go://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix@v0.8}/runtime-extension-components.yaml" + - name: "{go://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix@v0.11}" + value: "https://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/releases/download/{go://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix@v0.11}/runtime-extension-components.yaml" type: "url" contract: v1beta1 files: @@ -145,7 +145,7 @@ providers: new: "--v=8" - old: --metrics-addr=127.0.0.1:8080 new: --metrics-addr=:8080 - - name: v0.9.99 # "vNext"; use manifests from local source files + - name: v0.12.99 # "vNext"; use manifests from local source files value: "file://../../../runtime-extension-components.yaml" type: "url" contract: v1beta1 diff --git a/test/e2e/data/shared/v1beta1-caren/metadata.yaml b/test/e2e/data/shared/v1beta1-caren/metadata.yaml index 0da4642a0..9a958abe1 100644 --- a/test/e2e/data/shared/v1beta1-caren/metadata.yaml +++ b/test/e2e/data/shared/v1beta1-caren/metadata.yaml @@ -16,3 +16,12 @@ releaseSeries: - contract: v1beta1 major: 0 minor: 9 + - contract: v1beta1 + major: 0 + minor: 10 + - contract: v1beta1 + major: 0 + minor: 11 + - contract: v1beta1 + major: 0 + minor: 12 diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index f74486d40..9c45ba0e5 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -31,7 +31,6 @@ import ( helmaddonsv1 "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/test/e2e/framework" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/test/framework/bootstrap" - clusterctltemp "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/test/framework/clusterctl" ) //nolint:gochecknoinits // Idiomatically used to set up flags. @@ -174,7 +173,7 @@ var _ = SynchronizedAfterSuite(func() { }) func loadE2EConfig(configPath string) *clusterctl.E2EConfig { - config := clusterctltemp.LoadE2EConfig( + config := clusterctl.LoadE2EConfig( context.TODO(), clusterctl.LoadE2EConfigInput{ConfigPath: configPath}, ) diff --git a/test/framework/clusterctl/e2e_config.go b/test/framework/clusterctl/e2e_config.go deleted file mode 100644 index 2080ddb89..000000000 --- a/test/framework/clusterctl/e2e_config.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2023 Nutanix. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// This file is a copy of the original file from the cluster-api repository, to allow resolving latest patch releases -// versions. Once this is released upstream in CPAI v1.7, this file can be removed and code switched to use the upstream -// config loader. - -package clusterctl - -import ( - "context" - "errors" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/blang/semver/v4" - . "github.com/onsi/gomega" - "sigs.k8s.io/cluster-api/test/framework/clusterctl" - "sigs.k8s.io/yaml" - - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/test/framework/goproxy" -) - -// LoadE2EConfig loads the configuration for the e2e test environment. -func LoadE2EConfig(ctx context.Context, input clusterctl.LoadE2EConfigInput) *clusterctl.E2EConfig { - configData, err := os.ReadFile(input.ConfigPath) - Expect(err).ToNot(HaveOccurred(), "Failed to read the e2e test config file") - Expect(configData).ToNot(BeEmpty(), "The e2e test config file should not be empty") - - config := &clusterctl.E2EConfig{} - Expect( - yaml.Unmarshal(configData, config), - ).To(Succeed(), "Failed to convert the e2e test config file to yaml") - - Expect( - ResolveReleases(ctx, config), - ).To(Succeed(), "Failed to resolve release markers in e2e test config file") - config.Defaults() - config.AbsPaths(filepath.Dir(input.ConfigPath)) - - Expect(config.Validate()).To(Succeed(), "The e2e test config file is not valid") - - return config -} - -// ResolveReleases converts release markers to release version. -func ResolveReleases(ctx context.Context, config *clusterctl.E2EConfig) error { - for i := range config.Providers { - provider := &config.Providers[i] - for j := range provider.Versions { - version := &provider.Versions[j] - if version.Type != clusterctl.URLSource { - continue - } - // Skipping versions that are not a resolvable marker. Resolvable markers are surrounded by `{}` - if !strings.HasPrefix(version.Name, "{") || !strings.HasSuffix(version.Name, "}") { - continue - } - releaseMarker := strings.TrimLeft(strings.TrimRight(version.Name, "}"), "{") - ver, err := ResolveRelease(ctx, releaseMarker) - if err != nil { - return fmt.Errorf("failed resolving release url %q: %w", version.Name, err) - } - ver = "v" + ver - version.Value = strings.Replace(version.Value, version.Name, ver, 1) - version.Name = ver - } - } - return nil -} - -func ResolveRelease(ctx context.Context, releaseMarker string) (string, error) { - scheme, host, err := goproxy.GetSchemeAndHost(os.Getenv("GOPROXY")) - if err != nil { - return "", err - } - if scheme == "" || host == "" { - return "", fmt.Errorf( - "releasemarker does not support disabling the go proxy: GOPROXY=%q", - os.Getenv("GOPROXY"), - ) - } - goproxyClient := goproxy.NewClient(scheme, host) - return resolveReleaseMarker(ctx, releaseMarker, goproxyClient) -} - -// resolveReleaseMarker resolves releaseMarker string to verion string e.g. -// - Resolves "go://sigs.k8s.io/cluster-api@v1.0" to the latest stable patch release of v1.0. -// - Resolves "go://sigs.k8s.io/cluster-api@latest-v1.0" to the latest patch release of v1.0 including rc and -// pre releases. -func resolveReleaseMarker( - ctx context.Context, - releaseMarker string, - goproxyClient *goproxy.Client, -) (string, error) { - if !strings.HasPrefix(releaseMarker, "go://") { - return "", errors.New("unknown release marker scheme") - } - - releaseMarker = strings.TrimPrefix(releaseMarker, "go://") - if releaseMarker == "" { - return "", errors.New("empty release url") - } - - gomoduleParts := strings.Split(releaseMarker, "@") - if len(gomoduleParts) < 2 { - return "", errors.New("go module or version missing") - } - gomodule := gomoduleParts[0] - - includePrereleases := false - if strings.HasPrefix(gomoduleParts[1], "latest-") { - includePrereleases = true - } - version := strings.TrimPrefix(gomoduleParts[1], "latest-") + ".0" - version = strings.TrimPrefix(version, "v") - semVersion, err := semver.Parse(version) - if err != nil { - return "", fmt.Errorf("parsing semver for %s: %w", version, err) - } - - parsedTags, err := goproxyClient.GetVersions(ctx, gomodule) - if err != nil { - return "", err - } - - var picked semver.Version - for i, tag := range parsedTags { - if !includePrereleases && len(tag.Pre) > 0 { - continue - } - if tag.Major == semVersion.Major && tag.Minor == semVersion.Minor { - picked = parsedTags[i] - } - } - if picked.Major == 0 && picked.Minor == 0 && picked.Patch == 0 { - return "", fmt.Errorf( - "no suitable release available for release marker %s", - releaseMarker, - ) - } - return picked.String(), nil -}