From a4d7e35cddab6350fce067bad959cf1878f51ba2 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Tue, 25 Oct 2022 14:52:33 +0300 Subject: [PATCH 01/15] Cleanup internal docs Signed-off-by: Stefan Prodan --- README.md | 2 +- docs/_files/gitops-toolkit.png | Bin 62459 -> 0 bytes docs/_redirects | 18 ----- docs/internal/diagrams.md | 83 -------------------- docs/internal/release.md | 139 --------------------------------- 5 files changed, 1 insertion(+), 241 deletions(-) delete mode 100644 docs/_files/gitops-toolkit.png delete mode 100644 docs/_redirects delete mode 100644 docs/internal/diagrams.md delete mode 100644 docs/internal/release.md diff --git a/README.md b/README.md index f0256ebb..b19f9b3f 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ runtime for Flux v2. The APIs comprise Kubernetes custom resources, which can be created and updated by a cluster user, or by other automation tooling. -![overview](docs/_files/gitops-toolkit.png) +![overview](https://fluxcd.io/img/diagrams/gitops-toolkit.png) You can use the toolkit to extend Flux, or to build your own systems for continuous delivery -- see [the developer diff --git a/docs/_files/gitops-toolkit.png b/docs/_files/gitops-toolkit.png deleted file mode 100644 index cc5447b6060c3efe81dfd44171aea608f56c0303..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62459 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
repository - participant sc as Flux

source-controller - participant kc as Flux

kustomize-controller - participant kube as Kubernetes

api-server - participant nc as Flux

notification-controller - me->>git: 1. git push - sc->>git: 2. git pull - sc->>sc: 3. build artifact for revision - sc->>kube: 4. update status for revision - sc-->>nc: 5. emit events - kube->>kc: 6. notify about new revision - kc->>sc: 7. fetch artifact for revision - kc->>kc: 8. build manifests to objects - kc-->>kc: 9. decrypt secrets - kc->>kube: 10. validate objects - kc->>kube: 11. apply objects - kc-->>kube: 12. delete objects - kc-->>kube: 13. wait for readiness - kc->>kube: 14. update status for revision - kc-->>nc: 15. emit events - nc-->>me: 16. send alerts for revision -``` - -## Helm release upgrade from Git - -```mermaid -sequenceDiagram - actor me - participant git as Git

repository - participant sc as Flux

source-controller - participant hc as Flux

helm-controller - participant kube as Kubernetes

api-server - participant nc as Flux

notification-controller - me->>git: 1. git push - sc->>git: 2. git pull - sc->>sc: 3. build chart for revision - sc->>kube: 4. update chart status - sc-->>nc: 5. emit events - kube->>hc: 6. notify about new revision - hc->>sc: 7. fetch chart - hc->>kube: 8. get values - hc->>hc: 9. render and customize manifests - hc-->>kube: 10. apply CRDs - hc->>kube: 11. upgrade release - hc-->>kube: 12. run tests - hc-->>kube: 13. wait for readiness - hc->>kube: 14. update status - hc-->>nc: 15. emit events - nc-->>me: 16. send alerts -``` - -## Image update to Git - -```mermaid -sequenceDiagram - actor me - participant oci as Image

repository - participant irc as Flux

image-reflector-controller - participant iac as Flux

image-automation-controller - participant kube as Kubernetes

api-server - participant nc as Flux

notification-controller - participant git as Git

repository - me->>oci: 1. docker push - irc->>oci: 2. list tags - irc->>irc: 3. match tags to policies - irc->>kube: 4. update status - irc-->>nc: 5. emit events - kube->>iac: 6. notify about new tags - iac->>git: 7. git clone - iac->>iac: 8. patch manifests with new tags - iac->>git: 9. git push - iac->>kube: 10. update status - iac-->>nc: 11. emit events - nc-->>me: 12. send alerts -``` - diff --git a/docs/internal/release.md b/docs/internal/release.md deleted file mode 100644 index 6fa08f03..00000000 --- a/docs/internal/release.md +++ /dev/null @@ -1,139 +0,0 @@ -# Flux release procedure - -The Flux Go modules and the GitOps Toolkit controllers are released by following the [semver](https://semver.org) conventions. - -Repositories subject to semver releases: - -1. [fluxcd/pkg](https://github.com/fluxcd/pkg) - - modules: `apis/meta`, `runtime`, various utilities - - dependencies: `k8s.io/*`, `sigs.k8s.io/controller-runtime` -1. [fluxcd/source-controller](https://github.com/fluxcd/source-controller) - - modules: `api` - - dependencies: `github.com/fluxcd/pkg/*` -1. [fluxcd/kustomize-controller](https://github.com/fluxcd/kustomize-controller) - - modules: `api` - - dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/pkg/*` -1. [fluxcd/helm-controller](https://github.com/fluxcd/helm-controller) - - modules: `api` - - dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/pkg/*` -1. [fluxcd/image-reflector-controller](https://github.com/fluxcd/image-reflector-controller) - - modules: `api` - - dependencies: `github.com/fluxcd/pkg/*` -1. [fluxcd/image-automation-controller](https://github.com/fluxcd/image-automation-controller) - - modules: `api` - - dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/image-reflector-controller/api`, `github.com/fluxcd/pkg/*` -1. [fluxcd/notification-controller](https://github.com/fluxcd/notification-controller) - - modules: `api` - - dependencies: `github.com/fluxcd/pkg/*` -1. [fluxcd/flux2](https://github.com/fluxcd/flux2) - - modules: `manifestgen` - - dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/kustomize-controller/api`, `github.com/fluxcd/helm-controller/api`, `github.com/fluxcd/image-reflector-controller/api`, `github.com/fluxcd/image-automation-controller/api`, `github.com/fluxcd/notification-controller/api`, `github.com/fluxcd/pkg/*` -1. [fluxcd/terraform-provider-flux](https://github.com/fluxcd/terraform-provider-flux) - - dependencies: `github.com/fluxcd/flux2/pkg/manifestgen` - -## Release procedure - -### Go packages - -The Go packages in [fluxcd/pkg](https://github.com/fluxcd/pkg) are dedicated modules, -each module has its own set of dependencies and release cycle. - -Release procedure for a package: - -1. Checkout the `main` branch and pull changes from remote. -1. Run `make release- VER=`. - -### Controllers - -A toolkit controller has a dedicated module for its API, the API module -has its own set of dependencies. - -Release procedure for a controller and its API: - -1. Checkout the `main` branch and pull changes from remote. -1. Create a `api/` tag and push it to remote. -1. Create a new branch from `main` i.e. `release-`. This - will function as your release preparation branch. -1. Update the `github.com/fluxcd/-controller/api` version in `go.mod` -1. Add an entry to the `CHANGELOG.md` for the new release and change the - `newTag` value in ` config/manager/kustomization.yaml` to that of the - semver release you are going to make. Commit and push your changes. -1. Create a PR for your release branch and get it merged into `main`. -1. Create a `` tag for the merge commit in `main` and - push it to remote. -1. Confirm CI builds and releases the newly tagged version. - -### Flux - -Release procedure for Flux: - -1. Checkout the `main` branch and pull changes from remote. -1. Create a `` tag form `main` and push it to remote. -1. Confirm CI builds and releases the newly tagged version. - -## Upgrade Kubernetes modules - -Flux has the following Kubernetes dependencies: - -- `k8s.io/api` -- `k8s.io/apiextensions-apiserver` -- `k8s.io/apimachinery` -- `k8s.io/cli-runtime` -- `k8s.io/client-go` -- `sigs.k8s.io/controller-runtime` - -**Note** that all `k8s.io/*` packages must have the same version in `go.mod` e.g.: - -``` - k8s.io/api v0.20.2 - k8s.io/apiextensions-apiserver v0.20.2 - k8s.io/apimachinery v0.20.2 - k8s.io/cli-runtime v0.20.2 - k8s.io/client-go v0.20.2 -``` - -The specialised reconcilers depend on: - -- kustomize-controller: `sigs.k8s.io/kustomize/api` -- image-automation-controller: `sigs.k8s.io/kustomize/kyaml` -- helm-controller: `helm.sh/helm/v3` - -**Note** that the `k8s.io/*` version must be compatible with both `kustomize/api` and `helm/v3`. -If there is a breaking change in `client-go` we have to wait for Kustomize and Helm to upgrade first. - -### Upgrade procedure: - -`fluxcd/pkg`: - -1. Update the `k8s.io/*` version in `pkg/apis/meta/go.mod` -1. Release the `apis/meta` package -1. Update `apis/meta` version in `pkg/runtime/go.mod` -1. Update the `k8s.io/*` version in `pkg/runtime/go.mod` -1. Update `sigs.k8s.io/controller-runtime` version in `pkg/runtime/go.mod` -1. Release the `runtime` package - -`fluxcd/source-controller`: - -1. Update the `github.com/fluxcd/pkg/apis/meta` version in `source-controller/api/go.mod` and `source-controller/go.mod` -1. Update the `k8s.io/*` version in `source-controller/api/go.mod` and `source-controller/go.mod` -1. Update the `sigs.k8s.io/controller-runtime` version in `source-controller/api/go.mod` and `source-controller/go.mod` -1. Update the `github.com/fluxcd/pkg/runtime` version in `source-controller/go.mod` -1. Release the `api` package - -`fluxcd/-controller`: - -1. Update the `github.com/fluxcd/source-controller/api` version in `-controller/api/go.mod` and `-controller/go.mod` -1. Update the `github.com/fluxcd/pkg/apis/meta` version in `-controller/api/go.mod` and `-controller/go.mod` -1. Update the `k8s.io/*` version in `-controller/api/go.mod` and `-controller/go.mod` -1. Update the `github.com/fluxcd/pkg/runtime` version in `-controller/go.mod` -1. Release the `api` package - -`fluxcd/flux2`: - -1. Update the `github.com/fluxcd/*-controller/api` version in `flux2/go.mod` (automated with [GitHub Actions](../../.github/workflows/update.yaml)) -1. Update the `github.com/fluxcd/pkg/*` version in `flux2/go.mod` -1. Update the `k8s.io/*` and `github.com/fluxcd/pkg/runtime` version in `flux2/go.mod` - -`fluxcd/terraform-provider-flux`: - -1. Update the `github.com/fluxcd/flux2` version in `terraform-provider-flux/go.mod` (automated with [GitHub Actions](https://github.com/fluxcd/terraform-provider-flux/blob/main/.github/workflows/update.yaml)) From f09616e780ad85196653dbe471818fec4178519e Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Tue, 25 Oct 2022 14:53:04 +0300 Subject: [PATCH 02/15] Add shared packages release spec Signed-off-by: Stefan Prodan --- docs/README.md | 17 ++------ docs/release/pkg.md | 99 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 docs/release/pkg.md diff --git a/docs/README.md b/docs/README.md index 5b1ab70e..472c337b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,17 +1,6 @@ -# Flux v2 Documentation +# Flux Development Documentation -The documentation for `flux2` has moved to this repository: . +## Release Engineering -[The Website's README](https://github.com/fluxcd/website/#readme) has information on how to +- [Shared packages release specifications](release/pkg.md) -- modify and extend documentation -- run the site locally -- publish changes - -and where all the individual pieces of content come from. - -It will be easier for us to maintain a coherent web presences (and merge all of Flux documentation) in one central repository. This was partly discussed in . - -## toolkit.fluxcd.io - -For historical reasons we are keeping a `_redirects` file in this directory. It defines how redirects from the old site `toolkit.fluxcd.io` to our new website work. Changes to this file need to be merged and a manual build triggered in the Netlify App. diff --git a/docs/release/pkg.md b/docs/release/pkg.md new file mode 100644 index 00000000..6a6d005e --- /dev/null +++ b/docs/release/pkg.md @@ -0,0 +1,99 @@ +# Flux shared packages release spec + +The Go packages in [github.com/fluxcd/pkg](https://github.com/fluxcd/pkg) are dedicated Go modules, +each module has its own set of dependencies and release cycle. + +These packages are primary meant for internal use in Flux controllers and +for projects which integrate and/or extend Flux. + +## Release versioning + +The Flux packages are released by following the +[Go module version numbering](https://go.dev/doc/modules/version-numbers) conventions: + +- `NAME/vX.Y.Z-RC.W` release candidates e.g. `runtime/v1.0.0-RC.1` +- `NAME/vX.Y.Z` stable releases e.g. `runtime/v1.0.0` + +To import or update a Flux package in a Go project: + +```shell +go get github.com/fluxcd/pkg/runtime@v1.0.0 +``` + +### Release candidates + +Release candidates are intended for testing new features or improvements. + +In most cases, a maintainer will cut a release candidate of a package to include it +in a Flux controller release candidate. + +Release candidates are not meant to be included in Flux stable releases. +Before cutting a stable release of a controller, all imported Flux packages must be pinned to a stable version. + +### Patch releases + +Patch releases are intended for critical bug fixes to the latest minor version, such as addressing security +vulnerabilities or fixes to severe problems with no workaround. + +Patch releases should not contain breaking changes, feature additions or any type of improvements. + +Patch releases should be used when updating dependencies such as `k8s.io/api` from one patch version to another. + +### Minor releases + +Minor releases are intended for backwards compatible feature additions and improvements. + +Minor releases should be used when updating dependencies such as `k8s.io/api` from one minor version to another. + +Given that Kubernetes does not follow semver, a Kubernetes package minor version bump may introduce breaking changes. +If a Kubernetes update requires a breaking change in a Flux package public API, then a major version release is necessary. + +### Major releases + +Major releases are intended for backwards incompatible feature additions and improvements. + +Any change to a package public API, such as a change to a Go function signature, requires a new major release. + +## Supported releases + +For Flux Go packages we only support the latest stable release. We expect for projects that depend on +Flux packages to stay up-to-date by automating the Go modules updates with tools like Dependabot. + +In effect, this means we'll not backport CVE fixes to an older minor or major version of a package. + +## Deprecation policy + +A Flux Go package can be deprecated at any time. Usually a deprecated package may be replaced a +different one, but there are no guarantees to always have a suitable replacement. + +A deprecated package is marked as so in its `go.mod` e.g. + +```go +// Deprecated: use github.com/fluxcd/pkg/tar instead. +module github.com/fluxcd/pkg/untar +``` + +## Release procedure + +As a project maintainer, to release a package, tag the `main` branch using semver, +and push the signed tag to upstream: + +```shell +git clone https://github.com/fluxcd/pkg.git +git switch main +git tag -s -m "runtime/v1.0.0" "runtime/v1.0.0" +git push origin "runtime/v1.0.0" +``` + +**Note** that the Git tags must be cryptographically signed with your private key +and your public key must be uploaded to GitHub. + +Release candidates of a specific package can be cut from the `main` branch or from an `dev-` branch: + +```shell +git switch dev-runtime +git tag -s -m "runtime/v1.1.0-RC.1" "runtime/v1.1.0-RC.1" +git push origin "runtime/v1.1.0-RC.1" +``` + +Before cutting a release candidate, make sure the tests are passing on the `dev` branch. From 41ba55634a24ed446a0f664ad2c4d109103dde5a Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Tue, 25 Oct 2022 18:21:59 +0300 Subject: [PATCH 03/15] Add controller release spec Signed-off-by: Stefan Prodan --- docs/README.md | 2 +- docs/release/controllers.md | 122 ++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 docs/release/controllers.md diff --git a/docs/README.md b/docs/README.md index 472c337b..f16c4016 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,4 +3,4 @@ ## Release Engineering - [Shared packages release specifications](release/pkg.md) - +- [Controllers release specifications](release/controllers.md) diff --git a/docs/release/controllers.md b/docs/release/controllers.md new file mode 100644 index 00000000..d3e20119 --- /dev/null +++ b/docs/release/controllers.md @@ -0,0 +1,122 @@ +# Flux controllers release spec + +The Flux controllers are +[Kubernetes operators](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/), +each controller has its own Git repository and release cycle. + +Controller repositories and their interdependencies: + +1. [fluxcd/source-controller](https://github.com/fluxcd/source-controller) + - dependencies: `github.com/fluxcd/pkg/runtime` +2. [fluxcd/kustomize-controller](https://github.com/fluxcd/kustomize-controller) + - dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/pkg/runtime` +3. [fluxcd/helm-controller](https://github.com/fluxcd/helm-controller) + - dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/pkg/runtime` +4. [fluxcd/notification-controller](https://github.com/fluxcd/notification-controller) + - dependencies: `github.com/fluxcd/pkg/runtime` +5. [fluxcd/image-reflector-controller](https://github.com/fluxcd/image-reflector-controller) + - dependencies: `github.com/fluxcd/pkg/runtime` +6. [fluxcd/image-automation-controller](https://github.com/fluxcd/image-automation-controller) + - dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/image-reflector-controller/api`, `github.com/fluxcd/pkg/runtime` + +## Release versioning + +The Flux controllers and their API packages are released by following the +[Go module version numbering](https://go.dev/doc/modules/version-numbers) conventions: + +- `vX.Y.Z-RC.W` release candidates e.g. `v1.0.0-RC.1` +- `vX.Y.Z` stable releases e.g. `v1.0.0` + +To import or update a controller API package in a Go project: + +```shell +go get github.com/fluxcd/source-controller/api@v1.0.0 +``` + +To pull a controller container image: + +```shell +docker pull ghcr.io/fluxcd/source-controller:v1.0.0 +``` + +A Flux controller's Kubernetes Custom Resource Definitions follow the +[Kubernetes API versioning](https://kubernetes.io/docs/reference/using-api/#api-versioning) scheme: + +- `v1apha1` experimental API +- `v1beta1` release candidate (supported while v1 is not released) +- `v1` stable release (supported) + +### Release candidates + +Release candidates are intended for testing new features or improvements before a final release. + +In most cases, a maintainer will publish a release candidate of a controller for Flux users +to tests it on their staging clusters. Release candidates are not meant to be deployed in production +unless advised to do so by a maintainer. + +### Patch releases + +Patch releases are intended for critical bug fixes to the latest minor version, such as addressing security +vulnerabilities or fixes to severe problems with no workaround. + +Patch releases do not contain breaking changes, feature additions or any type of user-facing changes. +If a CVE fix requires a breaking change, then a minor release will provide the fix. + +We expect users to be running the latest patch release of a given minor release as soon as the +controller release is included in a Flux patch release. + +### Minor releases + +Minor releases are intended for backwards compatible feature additions and improvements. +Note that breaking changes may occur if required by a security vulnerability fix. + +Minor releases are used when updating Kubernetes dependencies such as `k8s.io/api` from one minor version to another. + +In effect, this means a minor version will be released for all Flux controllers approximately every three months +after each Kubernetes minor version release. + +To properly validate the controllers against the latest Kubernetes version, we reserve a time window of at least +two weeks for Flux controllers end-to-end testing. + +### Major releases + +Major releases are intended for drastic changes in the controller behaviour or security stance. + +A controller major release will be announced ahead of time throughout all communication channels, +and a support window of one year will be provided for the previous major version. + +## Release Cadence + +Flux controllers follow Kubernetes three releases per year cadence. After each Kubernetes minor release, +all controllers are tested against the latest Kubernetes version and are released at approximately two +weeks after Kubernetes. The newly released controllers offer support for Kubernetes N-2 minor versions. + +A Flux controller may have more than three minor releases per year, if maintainers decide to ship a +new feature or optimisation ahead of schedule. + +## Supported releases + +For Flux controllers we support the last three minor releases. + +Security fixes, may be backported to those three minor versions as patch releases, +depending on severity and feasibility. + +## Release procedure + +As a project maintainer, to release a controller and its API: + +1. Checkout the `main` branch and pull changes from remote. +2. Create a `api/` tag and push it to remote. +3. Create a new branch from `main` i.e. `release-`. This + will function as your release preparation branch. +4. Update the `github.com/fluxcd/-controller/api` version in `go.mod` +5. Add an entry to the `CHANGELOG.md` for the new release and change the + `newTag` value in ` config/manager/kustomization.yaml` to that of the + semver release you are going to make. Commit and push your changes. +6. Create a PR for your release branch and get it merged into `main`. +7. Create a `` tag for the merge commit in `main` and + push it to remote. +8. Confirm CI builds and releases the newly tagged version. + +**Note** that the Git tags must be cryptographically signed with your private key +and your public key must be uploaded to GitHub. From ea06d9614fcaadfe08083b5796850d66df00631c Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Wed, 26 Oct 2022 01:16:49 +0300 Subject: [PATCH 04/15] Add API versioning spec Signed-off-by: Stefan Prodan --- docs/release/controllers.md | 78 ++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/docs/release/controllers.md b/docs/release/controllers.md index d3e20119..16820d93 100644 --- a/docs/release/controllers.md +++ b/docs/release/controllers.md @@ -7,44 +7,86 @@ each controller has its own Git repository and release cycle. Controller repositories and their interdependencies: 1. [fluxcd/source-controller](https://github.com/fluxcd/source-controller) - - dependencies: `github.com/fluxcd/pkg/runtime` -2. [fluxcd/kustomize-controller](https://github.com/fluxcd/kustomize-controller) - - dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/pkg/runtime` -3. [fluxcd/helm-controller](https://github.com/fluxcd/helm-controller) - - dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/pkg/runtime` +2. [fluxcd/kustomize-controller](https://github.com/fluxcd/kustomize-controller) (imports `fluxcd/source-controller/api`) +3. [fluxcd/helm-controller](https://github.com/fluxcd/helm-controller) (imports `fluxcd/source-controller/api`) 4. [fluxcd/notification-controller](https://github.com/fluxcd/notification-controller) - - dependencies: `github.com/fluxcd/pkg/runtime` 5. [fluxcd/image-reflector-controller](https://github.com/fluxcd/image-reflector-controller) - - dependencies: `github.com/fluxcd/pkg/runtime` -6. [fluxcd/image-automation-controller](https://github.com/fluxcd/image-automation-controller) - - dependencies: `github.com/fluxcd/source-controller/api`, `github.com/fluxcd/image-reflector-controller/api`, `github.com/fluxcd/pkg/runtime` +6. [fluxcd/image-automation-controller](https://github.com/fluxcd/image-automation-controller) (imports `fluxcd/source-controller/api` and `fluxcd/image-reflector-controller/api`) -## Release versioning +The API versioning and controller versioning are indirectly related. For example, +a source-controller minor release `v1.1.0` can introduce a new API version +`v1beta1` for a Kind `XRepository` in the `source.toolkit.fluxcd.io` group. -The Flux controllers and their API packages are released by following the +## API versioning + +The Flux APIs (Kubernetes CRDs) follow the +[Kubernetes API versioning](https://kubernetes.io/docs/reference/using-api/#api-versioning) scheme. + +### Alpha version + +An alpha version API e.g. `v1alpha1` is considered experiment and should be used on +test environments only. + +The schema of objects may change in incompatible ways in a later controller release. +The custom resources may require editing and re-creating after a CRD update. + +An alpha API is introduced after it reaches the `implementable` phase in the +[Flux RFC process](https://github.com/fluxcd/flux2/tree/main/rfcs). +We encourage users to try out the alpha APIs and provide feedback which is extremely +valuable during early stages of development. + +### Beta version + +A beta version API e.g. `v2beta1` is considered well tested and safe to be used. + +The schema of objects may change in incompatible ways in a subsequent beta or stable API version. +The custom resources may require editing after a CRD update for which migration instructions will be +provided as part of the controller changelog. + +A beta version API becomes deprecated once a subsequent beta or stable API version is released. +A deprecated beta version is subject to removal after a six months period. + +### Stable version + +A stable version API e.g. `v2` is considered feature complete. + +Any changes to the object schema do not require editing or re-creating of custom resources. +Schema fields can't be removed, only new fields can be added with a default value that +doesn't affect the controller's current behaviour. + +A stable version API becomes deprecated once a subsequent stable version is released. +Stable API versions are not subject to removal in any future release of a controller major version. + +In effect, this means that for as long as Flux `v2` is being maintained, all the stable API versions +will be supported. + +## Controller versioning + +The Flux controllers and their Go API packages are released by following the [Go module version numbering](https://go.dev/doc/modules/version-numbers) conventions: - `vX.Y.Z-RC.W` release candidates e.g. `v1.0.0-RC.1` - `vX.Y.Z` stable releases e.g. `v1.0.0` +The release artifacts can be accessed based on the controller name and version. + To import or update a controller API package in a Go project: ```shell -go get github.com/fluxcd/source-controller/api@v1.0.0 +go get github.com/fluxcd//api@ ``` To pull a controller container image: ```shell -docker pull ghcr.io/fluxcd/source-controller:v1.0.0 +docker pull ghcr.io/fluxcd/: ``` -A Flux controller's Kubernetes Custom Resource Definitions follow the -[Kubernetes API versioning](https://kubernetes.io/docs/reference/using-api/#api-versioning) scheme: +To download a controller's Kubernetes Custom resource definitions: -- `v1apha1` experimental API -- `v1beta1` release candidate (supported while v1 is not released) -- `v1` stable release (supported) +```shell +curl -sL https://github.com/fluxcd//releases/download//.crds.yaml +``` ### Release candidates From 590b7b7682dd10187ba2dd15fc2c0a76b99bc0db Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Wed, 26 Oct 2022 01:47:44 +0300 Subject: [PATCH 05/15] Add controller release artifacts spec Signed-off-by: Stefan Prodan --- docs/README.md | 2 +- docs/release/controllers.md | 76 ++++++++++++++++------------ docs/release/{pkg.md => packages.md} | 0 3 files changed, 46 insertions(+), 32 deletions(-) rename docs/release/{pkg.md => packages.md} (100%) diff --git a/docs/README.md b/docs/README.md index f16c4016..66c1fba9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,5 +2,5 @@ ## Release Engineering -- [Shared packages release specifications](release/pkg.md) +- [Shared packages release specifications](release/packages.md) - [Controllers release specifications](release/controllers.md) diff --git a/docs/release/controllers.md b/docs/release/controllers.md index 16820d93..a47427ed 100644 --- a/docs/release/controllers.md +++ b/docs/release/controllers.md @@ -13,10 +13,6 @@ Controller repositories and their interdependencies: 5. [fluxcd/image-reflector-controller](https://github.com/fluxcd/image-reflector-controller) 6. [fluxcd/image-automation-controller](https://github.com/fluxcd/image-automation-controller) (imports `fluxcd/source-controller/api` and `fluxcd/image-reflector-controller/api`) -The API versioning and controller versioning are indirectly related. For example, -a source-controller minor release `v1.1.0` can introduce a new API version -`v1beta1` for a Kind `XRepository` in the `source.toolkit.fluxcd.io` group. - ## API versioning The Flux APIs (Kubernetes CRDs) follow the @@ -30,7 +26,10 @@ test environments only. The schema of objects may change in incompatible ways in a later controller release. The custom resources may require editing and re-creating after a CRD update. -An alpha API is introduced after it reaches the `implementable` phase in the +An alpha version API becomes deprecated once a subsequent alpha or beta API version is released. +A deprecated alpha version is subject to removal after a three months period. + +An alpha API is introduced when its proposal reaches the `implementable` phase in the [Flux RFC process](https://github.com/fluxcd/flux2/tree/main/rfcs). We encourage users to try out the alpha APIs and provide feedback which is extremely valuable during early stages of development. @@ -68,25 +67,9 @@ The Flux controllers and their Go API packages are released by following the - `vX.Y.Z-RC.W` release candidates e.g. `v1.0.0-RC.1` - `vX.Y.Z` stable releases e.g. `v1.0.0` -The release artifacts can be accessed based on the controller name and version. - -To import or update a controller API package in a Go project: - -```shell -go get github.com/fluxcd//api@ -``` - -To pull a controller container image: - -```shell -docker pull ghcr.io/fluxcd/: -``` - -To download a controller's Kubernetes Custom resource definitions: - -```shell -curl -sL https://github.com/fluxcd//releases/download//.crds.yaml -``` +The API versioning and controller versioning are indirectly related. For example, +a source-controller minor release `v1.1.0` can introduce a new API version +`v1beta1` for a Kind `XRepository` in the `source.toolkit.fluxcd.io` group. ### Release candidates @@ -114,11 +97,9 @@ Note that breaking changes may occur if required by a security vulnerability fix Minor releases are used when updating Kubernetes dependencies such as `k8s.io/api` from one minor version to another. -In effect, this means a minor version will be released for all Flux controllers approximately every three months -after each Kubernetes minor version release. - -To properly validate the controllers against the latest Kubernetes version, we reserve a time window of at least -two weeks for Flux controllers end-to-end testing. +In effect, this means a minor version will be released for all Flux controllers approximately every four months +after each Kubernetes minor version release. To properly validate the controllers against the latest Kubernetes version, +we reserve a time window of at least two weeks for Flux controllers end-to-end testing. ### Major releases @@ -127,7 +108,7 @@ Major releases are intended for drastic changes in the controller behaviour or s A controller major release will be announced ahead of time throughout all communication channels, and a support window of one year will be provided for the previous major version. -## Release Cadence +## Release cadence Flux controllers follow Kubernetes three releases per year cadence. After each Kubernetes minor release, all controllers are tested against the latest Kubernetes version and are released at approximately two @@ -143,7 +124,40 @@ For Flux controllers we support the last three minor releases. Security fixes, may be backported to those three minor versions as patch releases, depending on severity and feasibility. -## Release procedure +## Release artifacts + +Each controller release produces the following artifacts: + +- Source code (GitHub Releases page) +- Software Bill of Materials in SPDX format (GitHub Releases page) +- Kubernetes manifests such as CRDs and Deployments (GitHub Releases page) +- Signed checksums of source code, SBOM and manifests (GitHub Releases page) +- Multi-arch container images (GitHub Container Registry and DockerHub) + +All the artifacts are cryptographically signed and can be verified with Cosign. + +The release artifacts can be accessed based on the controller name and version. + +To import or update a controller's API package in a Go project: + +```shell +go get github.com/fluxcd//api@ +``` + +To verify and pull a controller's container image: + +```shell +cosign verify ghcr.io/fluxcd/: +docker pull ghcr.io/fluxcd/: +``` + +To download a controller's Kubernetes Custom resource definitions: + +```shell +curl -sL https://github.com/fluxcd//releases/download//.crds.yaml +``` + +## Controller release procedure As a project maintainer, to release a controller and its API: diff --git a/docs/release/pkg.md b/docs/release/packages.md similarity index 100% rename from docs/release/pkg.md rename to docs/release/packages.md From 29ad52bb46f117a70b752137401927e48e8d3ed6 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Wed, 26 Oct 2022 10:15:37 +0300 Subject: [PATCH 06/15] Add Flux release spec Signed-off-by: Stefan Prodan --- docs/README.md | 6 -- docs/release/README.md | 7 ++ docs/release/controllers.md | 37 ++++---- docs/release/flux.md | 173 ++++++++++++++++++++++++++++++++++++ docs/release/packages.md | 6 +- 5 files changed, 203 insertions(+), 26 deletions(-) delete mode 100644 docs/README.md create mode 100644 docs/release/README.md create mode 100644 docs/release/flux.md diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 66c1fba9..00000000 --- a/docs/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Flux Development Documentation - -## Release Engineering - -- [Shared packages release specifications](release/packages.md) -- [Controllers release specifications](release/controllers.md) diff --git a/docs/release/README.md b/docs/release/README.md new file mode 100644 index 00000000..3920353a --- /dev/null +++ b/docs/release/README.md @@ -0,0 +1,7 @@ +# Flux Release Documentation + +## Release specifications + +- [Flux distribution](flux.md) +- [Flux APIs and controllers](controllers.md) +- [Flux shared libraries](packages.md) diff --git a/docs/release/controllers.md b/docs/release/controllers.md index a47427ed..68d9321c 100644 --- a/docs/release/controllers.md +++ b/docs/release/controllers.md @@ -20,26 +20,27 @@ The Flux APIs (Kubernetes CRDs) follow the ### Alpha version -An alpha version API e.g. `v1alpha1` is considered experiment and should be used on +An alpha version API e.g. `v1alpha1` is considered experimental and should be used on test environments only. The schema of objects may change in incompatible ways in a later controller release. -The custom resources may require editing and re-creating after a CRD update. +The Custom Resources may require editing and re-creating after a CRD update. An alpha version API becomes deprecated once a subsequent alpha or beta API version is released. A deprecated alpha version is subject to removal after a three months period. An alpha API is introduced when its proposal reaches the `implementable` phase in the [Flux RFC process](https://github.com/fluxcd/flux2/tree/main/rfcs). -We encourage users to try out the alpha APIs and provide feedback which is extremely -valuable during early stages of development. +We encourage users to try out the alpha APIs and provide feedback +(e.g. on CNCF Slack or in the form of GitHub issues/discussions) +which is extremely valuable during early stages of development. ### Beta version A beta version API e.g. `v2beta1` is considered well tested and safe to be used. The schema of objects may change in incompatible ways in a subsequent beta or stable API version. -The custom resources may require editing after a CRD update for which migration instructions will be +The Custom Resources may require editing after a CRD update for which migration instructions will be provided as part of the controller changelog. A beta version API becomes deprecated once a subsequent beta or stable API version is released. @@ -49,7 +50,7 @@ A deprecated beta version is subject to removal after a six months period. A stable version API e.g. `v2` is considered feature complete. -Any changes to the object schema do not require editing or re-creating of custom resources. +Any changes to the object schema do not require editing or re-creating of Custom Resources. Schema fields can't be removed, only new fields can be added with a default value that doesn't affect the controller's current behaviour. @@ -110,9 +111,10 @@ and a support window of one year will be provided for the previous major version ## Release cadence -Flux controllers follow Kubernetes three releases per year cadence. After each Kubernetes minor release, -all controllers are tested against the latest Kubernetes version and are released at approximately two -weeks after Kubernetes. The newly released controllers offer support for Kubernetes N-2 minor versions. +Flux controllers are at least released at the same rate as Kubernetes, following their cadence of three +minor releases per year. After each Kubernetes minor release, all controllers are tested against the latest +Kubernetes version and are released at approximately two weeks after Kubernetes. +The newly released controllers offer support for Kubernetes N-2 minor versions. A Flux controller may have more than three minor releases per year, if maintainers decide to ship a new feature or optimisation ahead of schedule. @@ -121,9 +123,11 @@ new feature or optimisation ahead of schedule. For Flux controllers we support the last three minor releases. -Security fixes, may be backported to those three minor versions as patch releases, +Security fixes, may be back-ported to those three minor versions as patch releases, depending on severity and feasibility. +Note that back-porting is provided by the community on a best-effort basis. + ## Release artifacts Each controller release produces the following artifacts: @@ -162,16 +166,15 @@ curl -sL https://github.com/fluxcd//releases/download/ As a project maintainer, to release a controller and its API: 1. Checkout the `main` branch and pull changes from remote. -2. Create a `api/` tag and push it to remote. -3. Create a new branch from `main` i.e. `release-`. This +2. Create a new branch from `main` i.e. `release-`. This will function as your release preparation branch. -4. Update the `github.com/fluxcd/-controller/api` version in `go.mod` -5. Add an entry to the `CHANGELOG.md` for the new release and change the +3. Update the `github.com/fluxcd/-controller/api` version in `go.mod` +4. Add an entry to the `CHANGELOG.md` for the new release and change the `newTag` value in ` config/manager/kustomization.yaml` to that of the semver release you are going to make. Commit and push your changes. -6. Create a PR for your release branch and get it merged into `main`. -7. Create a `` tag for the merge commit in `main` and - push it to remote. +5. Create a PR for your release branch and get it merged into `main`. +6. Create a `api/` tag for the merge commit in `main` and push it to remote. +7. Create a `` tag for the merge commit in `main` and push it to remote. 8. Confirm CI builds and releases the newly tagged version. **Note** that the Git tags must be cryptographically signed with your private key diff --git a/docs/release/flux.md b/docs/release/flux.md new file mode 100644 index 00000000..a5f8a3ab --- /dev/null +++ b/docs/release/flux.md @@ -0,0 +1,173 @@ +# Flux release spec + +The Flux project repository [fluxcd/flux2](https://github.com/fluxcd/flux2) contains +the Flux command-line tool source code and the Kubernetes manifests for +bundling the [Flux controllers](controllers.md) into a distributable package. + +## Release versioning + +Flux is released by following the [semver](https://semver.org/) conventions: + +- `vX.Y.Z-RC.W` release candidates e.g. `v2.0.0-RC.1` +- `vX.Y.Z` stable releases e.g. `v2.0.0` + +The Flux project maintains release branches for the most recent three minor releases +e.g. `release-2.0`, `release-2.1` and `release-2.2`. + +### Release candidates + +Release candidates are intended for testing new features or improvements before a final release. + +In most cases, a maintainer will publish a release candidate for Flux users to tests it on their +staging clusters. Release candidates are not meant to be deployed in production unless advised +to do so by a maintainer. + +Release candidates can be unstable and they are deprecated by subsequent RC or stable version. + +### Patch releases + +Patch releases are intended for critical bug fixes to the latest minor version, +such as addressing security vulnerabilities or fixes to severe problems with no workaround. + +Patch releases do not contain breaking changes, feature additions or any type of user-facing changes. +If a CVE fix requires a breaking change, then a minor release will provide the fix. + +We expect users to be running the latest patch release of a given minor release. + +### Minor releases + +Minor releases are intended for backwards compatible feature additions and improvements. +Note that breaking changes may occur if required by a security vulnerability fix. + +Minor releases are used when updating the Flux controllers or Kubernetes dependencies +from one minor version to another. + +In effect, this means a Flux minor version will be released at least every four months after each +Kubernetes minor version release. To properly validate the Flux CLI and controllers against +the latest Kubernetes version, we reserve a time window of at least two weeks for end-to-end testing. + +### Major releases + +Major releases are intended for drastic changes to the Flux behaviour or security stance. + +A Flux major release will be announced ahead of time throughout all communication channels, +and a support window of one year will be provided for the previous major version. + +## Release cadence + +Flux is at least released at the same rate as Kubernetes, following their cadence of three +minor releases per year. After each Kubernetes minor release, the CLI and all controllers are +tested against the latest Kubernetes version and are released at approximately two weeks after Kubernetes. +The newly released Flux version offers support for Kubernetes N-2 minor versions. + +Flux may have more than three minor releases per year, if maintainers decide to ship a +new feature or optimisation ahead of schedule. + +## Supported releases + +For Flux the CLI and its controllers we support the last three minor releases. +Critical bug fixes such as security fixes, may be back-ported to those three minor +versions as patch releases, depending on severity and feasibility. + +Note that back-porting is provided by the community on a best-effort basis. + +The Flux controllers are guaranteed to be compatible with each other +within one minor version (older or newer) of Flux. + +The `flux` command-line tool is supported within one minor version (older or newer) of Flux. + +## Supported upgrades + +Users can upgrade from any `v2.x` release to any other `v2.x` release (the latest patch version). + +After upgrade, [Flux Custom Resources](controllers.md#api-versioning) may require editing, +for which migration instructions are provided as part of the +[changelog](#release-changelog). + +We expect users to keep Flux up-to-date on their clusters using automation tools +such as [Flux GitHub Actions](../../action) and +[Renovatebot](https://docs.renovatebot.com/modules/manager/flux/). + +Various vendors such as Microsoft Azure, D2iQ, Weaveworks and others offer a managed Flux service, +and it's their responsibility to keep Flux up-to-date and free of CVEs. +The Flux team communicates security issues to vendors as described in the +[Coordinated Vulnerability Disclosure document](https://github.com/fluxcd/.github/blob/14b735cdb23ec80d528ff4f71e562405a2f00639/CVD_LIST.md). + +## Kubernetes supported versions + +The Flux CLI and controllers offer support for all Kubernetes versions supported upstream. + +Every Flux release undergoes a series of conformance and end-to-end tests for +the latest Kubernetes minor release. The test suite is run against +[Kubernetes Kind](https://kind.sigs.k8s.io/) for both AMD64 and ARM64 distributions. + +We expect users to keep Kubernetes up-to-date with the latest patch version of a +supported minor release. Once a Kubernetes version reaches [end-of-life](https://endoflife.date/kubernetes), +we can't guarantee the next Flux release will work with it, +as we don't run end-to-end testing for EOL Kubernetes versions. + +## Release artifacts + +Each Flux release produces the following artifacts: + +- Source code (GitHub Releases page) +- Software Bill of Materials in SPDX format (GitHub Releases page) +- Kubernetes manifests of all controllers (GitHub Releases page) +- CLI binaries for Linux, macOS and Windows (GitHub Releases page) +- Signed checksums of source code, SBOM and manifests (GitHub Releases page) +- Multi-arch container images of the CLI (GitHub Container Registry and DockerHub) +- OCI artifacts with the Kubernetes manifests (GitHub Container Registry and DockerHub) +- CLI [Homebrew](https://brew.sh/) formulas for Linux and macOS + +All the artifacts are cryptographically signed and can be verified with Cosign. + +The release artifacts can be accessed based on the Flux version. + +To verify and pull the Flux CLI container image: + +```shell +cosign verify ghcr.io/fluxcd/flux-cli: +docker pull ghcr.io/fluxcd/flux-cli: +``` + +To install the latest stable release of the Flux CLI with Homebrew: + +```shell +brew install fluxcd/tap/flux +``` + +To download the Kubernetes manifests: + +```shell +cosign verify ghcr.io/fluxcd/flux-manifests: +flux pull artifact oci://ghcr.io/fluxcd/flux-manifests: --output . +``` + +## Release changelog + +All released versions of Flux are published on [GitHub Releases page](https://github.com/fluxcd/flux2/releases) +along with a list of changes from the previous release. + +The changelog contains the following information: + +- Security vulnerabilities fixes (if any) +- Breaking changes and migration instructions (if any) +- A summary of new features and improvements for the Flux APIs and controllers +- Links to the changelog of each controller version included in a Flux release +- A list of new features, improvements and bug fixes for the Flux CLI +- A list of documentation additions + +**Note** that the vulnerability disclosure procedure is explained on the [security page](https://fluxcd.io/security/). + +## Release procedure + +- `v2.X.Y-RC.Z` (Branch: `release-2.X`) + - When the `main` branch is feature-complete for `v2.X`, we will cherrypick PRs essential to `v2.X` to the `release-2.X` branch. + - We will cut the first [release candidate](#release-candidates) by tagging the `release-2.X` as `v2.X.0-RC.0`. + - If we're not satisfied with `v2.X.0-RC.0`, we'll keep releasing RCs until all issues are solved. +- `v2.X.0` (Branch: `release-2.X`) + - The final release is cut from the `release-2.X` branch and tagged as `v2.X.0`. +- `v2.X.Y, Y > 0` (Branch: `release-2.X`) + - [Patch releases](#patch-releases) are released as we cherrypick commits from `main` into the `release-2.X` branch. + - Flux controller updates (patch versions of a controller minor release included in `v2.X.0`) PRs are merged directly into the `release-2.X` branch. + - A patch release is cut from the `release-2.X` branch and tagged as `v2.X.Y`. diff --git a/docs/release/packages.md b/docs/release/packages.md index 6a6d005e..0f8534c7 100644 --- a/docs/release/packages.md +++ b/docs/release/packages.md @@ -44,9 +44,9 @@ Patch releases should be used when updating dependencies such as `k8s.io/api` fr Minor releases are intended for backwards compatible feature additions and improvements. Minor releases should be used when updating dependencies such as `k8s.io/api` from one minor version to another. - -Given that Kubernetes does not follow semver, a Kubernetes package minor version bump may introduce breaking changes. -If a Kubernetes update requires a breaking change in a Flux package public API, then a major version release is necessary. +If a [Kubernetes minor version](https://github.com/kubernetes/sig-release/blob/master/release-engineering/versioning.md) +upgrade requires a breaking change (e.g. removal of an API such as `PodSecurityPolicy`) in a Flux package public API, +then a major version release is necessary. ### Major releases From 8d5c4492d8cb71bcfea9334410f5feb02e76b697 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Fri, 23 Jun 2023 12:31:04 +0300 Subject: [PATCH 07/15] Apply suggestions from code review Co-authored-by: Aurel Canciu Co-authored-by: Hidde Beydals Signed-off-by: Stefan Prodan --- docs/release/controllers.md | 12 ++++++------ docs/release/flux.md | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/release/controllers.md b/docs/release/controllers.md index 68d9321c..0058a2bf 100644 --- a/docs/release/controllers.md +++ b/docs/release/controllers.md @@ -37,7 +37,7 @@ which is extremely valuable during early stages of development. ### Beta version -A beta version API e.g. `v2beta1` is considered well tested and safe to be used. +A beta version API e.g. `v2beta1` is considered well-tested and safe to use in production. The schema of objects may change in incompatible ways in a subsequent beta or stable API version. The Custom Resources may require editing after a CRD update for which migration instructions will be @@ -96,11 +96,11 @@ controller release is included in a Flux patch release. Minor releases are intended for backwards compatible feature additions and improvements. Note that breaking changes may occur if required by a security vulnerability fix. -Minor releases are used when updating Kubernetes dependencies such as `k8s.io/api` from one minor version to another. +In addition, minor releases are used when updating Kubernetes dependencies such as `k8s.io/api` from one minor version to another. -In effect, this means a minor version will be released for all Flux controllers approximately every four months -after each Kubernetes minor version release. To properly validate the controllers against the latest Kubernetes version, -we reserve a time window of at least two weeks for Flux controllers end-to-end testing. +In effect, this means a new minor version will at least be released for all Flux controllers approximately every four months, following each Kubernetes minor version release. To properly validate the controllers against the latest Kubernetes version, we typically allocate a time window of at least two weeks for end-to-end testing of Flux controllers. + +It is worth noting that in certain scenarios where project dependencies are not in sync with the Kubernetes version or conflicts arise, this two-week timeframe may prove insufficient, requiring additional time to address the issues appropriately. ### Major releases @@ -123,7 +123,7 @@ new feature or optimisation ahead of schedule. For Flux controllers we support the last three minor releases. -Security fixes, may be back-ported to those three minor versions as patch releases, +Security fixes may be back-ported to those three minor versions as patch releases, depending on severity and feasibility. Note that back-porting is provided by the community on a best-effort basis. diff --git a/docs/release/flux.md b/docs/release/flux.md index a5f8a3ab..44c6cbbd 100644 --- a/docs/release/flux.md +++ b/docs/release/flux.md @@ -8,21 +8,21 @@ bundling the [Flux controllers](controllers.md) into a distributable package. Flux is released by following the [semver](https://semver.org/) conventions: -- `vX.Y.Z-RC.W` release candidates e.g. `v2.0.0-RC.1` +- `vX.Y.Z-RC.W` release candidates e.g. `v2.0.0-rc.1` - `vX.Y.Z` stable releases e.g. `v2.0.0` The Flux project maintains release branches for the most recent three minor releases -e.g. `release-2.0`, `release-2.1` and `release-2.2`. +e.g. `release/2.0.x`, `release/2.1.x` and `release/2.2.x`. ### Release candidates Release candidates are intended for testing new features or improvements before a final release. -In most cases, a maintainer will publish a release candidate for Flux users to tests it on their +In most cases, a maintainer will publish a release candidate for Flux users to test on their staging clusters. Release candidates are not meant to be deployed in production unless advised to do so by a maintainer. -Release candidates can be unstable and they are deprecated by subsequent RC or stable version. +Release candidates can be unstable and they are deprecated by subsequent RC or stable versions. ### Patch releases From 91660a98d5123c5ae0dbfb12ec771cf37a2b48c3 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Fri, 23 Jun 2023 12:45:52 +0300 Subject: [PATCH 08/15] Add SLSA provenance to release artifacts Signed-off-by: Stefan Prodan --- docs/release/controllers.md | 34 +++++++++++----------------------- docs/release/flux.md | 21 +-------------------- 2 files changed, 12 insertions(+), 43 deletions(-) diff --git a/docs/release/controllers.md b/docs/release/controllers.md index 0058a2bf..45db7280 100644 --- a/docs/release/controllers.md +++ b/docs/release/controllers.md @@ -96,11 +96,17 @@ controller release is included in a Flux patch release. Minor releases are intended for backwards compatible feature additions and improvements. Note that breaking changes may occur if required by a security vulnerability fix. -In addition, minor releases are used when updating Kubernetes dependencies such as `k8s.io/api` from one minor version to another. +In addition, minor releases are used when updating Kubernetes dependencies such +as `k8s.io/api` from one minor version to another. -In effect, this means a new minor version will at least be released for all Flux controllers approximately every four months, following each Kubernetes minor version release. To properly validate the controllers against the latest Kubernetes version, we typically allocate a time window of at least two weeks for end-to-end testing of Flux controllers. +In effect, this means a new minor version will at least be released for all Flux +controllers approximately every four months, following each Kubernetes minor version release. +To properly validate the controllers against the latest Kubernetes version, +we typically allocate a time window of around two weeks for end-to-end testing of Flux controllers. -It is worth noting that in certain scenarios where project dependencies are not in sync with the Kubernetes version or conflicts arise, this two-week timeframe may prove insufficient, requiring additional time to address the issues appropriately. +It is worth noting that in certain scenarios where project dependencies are not in sync with +the Kubernetes version or conflicts arise, this two-week timeframe may prove insufficient, +requiring additional time to address the issues appropriately. ### Major releases @@ -134,33 +140,15 @@ Each controller release produces the following artifacts: - Source code (GitHub Releases page) - Software Bill of Materials in SPDX format (GitHub Releases page) +- SLSA provenance attestations (GitHub Releases page) - Kubernetes manifests such as CRDs and Deployments (GitHub Releases page) - Signed checksums of source code, SBOM and manifests (GitHub Releases page) - Multi-arch container images (GitHub Container Registry and DockerHub) -All the artifacts are cryptographically signed and can be verified with Cosign. +All the artifacts are cryptographically signed and can be verified with Cosign and GitHub OIDC. The release artifacts can be accessed based on the controller name and version. -To import or update a controller's API package in a Go project: - -```shell -go get github.com/fluxcd//api@ -``` - -To verify and pull a controller's container image: - -```shell -cosign verify ghcr.io/fluxcd/: -docker pull ghcr.io/fluxcd/: -``` - -To download a controller's Kubernetes Custom resource definitions: - -```shell -curl -sL https://github.com/fluxcd//releases/download//.crds.yaml -``` - ## Controller release procedure As a project maintainer, to release a controller and its API: diff --git a/docs/release/flux.md b/docs/release/flux.md index 44c6cbbd..cae1bbb9 100644 --- a/docs/release/flux.md +++ b/docs/release/flux.md @@ -112,6 +112,7 @@ Each Flux release produces the following artifacts: - Source code (GitHub Releases page) - Software Bill of Materials in SPDX format (GitHub Releases page) +- SLSA provenance attestations (GitHub Releases page) - Kubernetes manifests of all controllers (GitHub Releases page) - CLI binaries for Linux, macOS and Windows (GitHub Releases page) - Signed checksums of source code, SBOM and manifests (GitHub Releases page) @@ -123,26 +124,6 @@ All the artifacts are cryptographically signed and can be verified with Cosign. The release artifacts can be accessed based on the Flux version. -To verify and pull the Flux CLI container image: - -```shell -cosign verify ghcr.io/fluxcd/flux-cli: -docker pull ghcr.io/fluxcd/flux-cli: -``` - -To install the latest stable release of the Flux CLI with Homebrew: - -```shell -brew install fluxcd/tap/flux -``` - -To download the Kubernetes manifests: - -```shell -cosign verify ghcr.io/fluxcd/flux-manifests: -flux pull artifact oci://ghcr.io/fluxcd/flux-manifests: --output . -``` - ## Release changelog All released versions of Flux are published on [GitHub Releases page](https://github.com/fluxcd/flux2/releases) From 33fdaee3999b8aef59a1f8b5b842b32ac50d2961 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Fri, 23 Jun 2023 12:57:48 +0300 Subject: [PATCH 09/15] Move the release procedures to dedicated doc Signed-off-by: Stefan Prodan --- docs/release/README.md | 1 + docs/release/controllers.md | 18 ----------- docs/release/flux.md | 12 -------- docs/release/packages.md | 24 --------------- docs/release/procedure.md | 60 +++++++++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 54 deletions(-) create mode 100644 docs/release/procedure.md diff --git a/docs/release/README.md b/docs/release/README.md index 3920353a..03df7d1b 100644 --- a/docs/release/README.md +++ b/docs/release/README.md @@ -5,3 +5,4 @@ - [Flux distribution](flux.md) - [Flux APIs and controllers](controllers.md) - [Flux shared libraries](packages.md) +- [Flux release procedure](procedure.md) \ No newline at end of file diff --git a/docs/release/controllers.md b/docs/release/controllers.md index 45db7280..eee134dd 100644 --- a/docs/release/controllers.md +++ b/docs/release/controllers.md @@ -149,21 +149,3 @@ All the artifacts are cryptographically signed and can be verified with Cosign a The release artifacts can be accessed based on the controller name and version. -## Controller release procedure - -As a project maintainer, to release a controller and its API: - -1. Checkout the `main` branch and pull changes from remote. -2. Create a new branch from `main` i.e. `release-`. This - will function as your release preparation branch. -3. Update the `github.com/fluxcd/-controller/api` version in `go.mod` -4. Add an entry to the `CHANGELOG.md` for the new release and change the - `newTag` value in ` config/manager/kustomization.yaml` to that of the - semver release you are going to make. Commit and push your changes. -5. Create a PR for your release branch and get it merged into `main`. -6. Create a `api/` tag for the merge commit in `main` and push it to remote. -7. Create a `` tag for the merge commit in `main` and push it to remote. -8. Confirm CI builds and releases the newly tagged version. - -**Note** that the Git tags must be cryptographically signed with your private key -and your public key must be uploaded to GitHub. diff --git a/docs/release/flux.md b/docs/release/flux.md index cae1bbb9..c4994411 100644 --- a/docs/release/flux.md +++ b/docs/release/flux.md @@ -140,15 +140,3 @@ The changelog contains the following information: **Note** that the vulnerability disclosure procedure is explained on the [security page](https://fluxcd.io/security/). -## Release procedure - -- `v2.X.Y-RC.Z` (Branch: `release-2.X`) - - When the `main` branch is feature-complete for `v2.X`, we will cherrypick PRs essential to `v2.X` to the `release-2.X` branch. - - We will cut the first [release candidate](#release-candidates) by tagging the `release-2.X` as `v2.X.0-RC.0`. - - If we're not satisfied with `v2.X.0-RC.0`, we'll keep releasing RCs until all issues are solved. -- `v2.X.0` (Branch: `release-2.X`) - - The final release is cut from the `release-2.X` branch and tagged as `v2.X.0`. -- `v2.X.Y, Y > 0` (Branch: `release-2.X`) - - [Patch releases](#patch-releases) are released as we cherrypick commits from `main` into the `release-2.X` branch. - - Flux controller updates (patch versions of a controller minor release included in `v2.X.0`) PRs are merged directly into the `release-2.X` branch. - - A patch release is cut from the `release-2.X` branch and tagged as `v2.X.Y`. diff --git a/docs/release/packages.md b/docs/release/packages.md index 0f8534c7..d61c5521 100644 --- a/docs/release/packages.md +++ b/docs/release/packages.md @@ -73,27 +73,3 @@ A deprecated package is marked as so in its `go.mod` e.g. module github.com/fluxcd/pkg/untar ``` -## Release procedure - -As a project maintainer, to release a package, tag the `main` branch using semver, -and push the signed tag to upstream: - -```shell -git clone https://github.com/fluxcd/pkg.git -git switch main -git tag -s -m "runtime/v1.0.0" "runtime/v1.0.0" -git push origin "runtime/v1.0.0" -``` - -**Note** that the Git tags must be cryptographically signed with your private key -and your public key must be uploaded to GitHub. - -Release candidates of a specific package can be cut from the `main` branch or from an `dev-` branch: - -```shell -git switch dev-runtime -git tag -s -m "runtime/v1.1.0-RC.1" "runtime/v1.1.0-RC.1" -git push origin "runtime/v1.1.0-RC.1" -``` - -Before cutting a release candidate, make sure the tests are passing on the `dev` branch. diff --git a/docs/release/procedure.md b/docs/release/procedure.md new file mode 100644 index 00000000..9ac03d36 --- /dev/null +++ b/docs/release/procedure.md @@ -0,0 +1,60 @@ +# Flux release procedure + +## Shared packages release procedure + +As a project maintainer, to release a package, tag the `main` branch using semver, +and push the signed tag to upstream: + +```shell +git clone https://github.com/fluxcd/pkg.git +git switch main +git tag -s -m "runtime/v1.0.0" "runtime/v1.0.0" +git push origin "runtime/v1.0.0" +``` + +**Note** that the Git tags must be cryptographically signed with your private key +and your public key must be uploaded to GitHub. + +Release candidates of a specific package can be cut from the `main` branch or from an `dev-` branch: + +```shell +git switch dev-runtime +git tag -s -m "runtime/v1.1.0-RC.1" "runtime/v1.1.0-RC.1" +git push origin "runtime/v1.1.0-RC.1" +``` + +Before cutting a release candidate, make sure the tests are passing on the `dev` branch. + +## Controllers release procedure + +As a project maintainer, to release a controller and its API: + +1. Checkout the `main` branch and pull changes from remote. +2. Create a new branch from `main` i.e. `release-`. This + will function as your release preparation branch. +3. Update the `github.com/fluxcd/-controller/api` version in `go.mod` +4. Add an entry to the `CHANGELOG.md` for the new release and change the + `newTag` value in ` config/manager/kustomization.yaml` to that of the + semver release you are going to make. Commit and push your changes. +5. Create a PR for your release branch and get it merged into `main`. +6. Create a `api/` tag for the merge commit in `main` and push it to remote. +7. Create a `` tag for the merge commit in `main` and push it to remote. +8. Confirm CI builds and releases the newly tagged version. + +**Note** that the Git tags must be cryptographically signed with your private key +and your public key must be uploaded to GitHub. + +## Distribution release procedure + +As a project maintainer, to release a new Flux version and its CLI: + +- `v2.X.Y-RC.Z` (Branch: `release-2.X`) + - When the `main` branch is feature-complete for `v2.X`, we will cherrypick PRs essential to `v2.X` to the `release-2.X` branch. + - We will cut the first [release candidate](#release-candidates) by tagging the `release-2.X` as `v2.X.0-RC.0`. + - If we're not satisfied with `v2.X.0-RC.0`, we'll keep releasing RCs until all issues are solved. +- `v2.X.0` (Branch: `release-2.X`) + - The final release is cut from the `release-2.X` branch and tagged as `v2.X.0`. +- `v2.X.Y, Y > 0` (Branch: `release-2.X`) + - [Patch releases](#patch-releases) are released as we cherrypick commits from `main` into the `release-2.X` branch. + - Flux controller updates (patch versions of a controller minor release included in `v2.X.0`) PRs are merged directly into the `release-2.X` branch. + - A patch release is cut from the `release-2.X` branch and tagged as `v2.X.Y`. From 33be9840f0ca615a6bc0b1eeb8b992b9de0c6fdf Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Tue, 27 Jun 2023 11:56:17 +0300 Subject: [PATCH 10/15] Apply suggestions from code review Co-authored-by: Max Jonas Werner Co-authored-by: Aurel Canciu Signed-off-by: Stefan Prodan --- docs/release/controllers.md | 30 +++++++++++++++--------------- docs/release/flux.md | 10 +++++----- docs/release/packages.md | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/release/controllers.md b/docs/release/controllers.md index eee134dd..07f9e780 100644 --- a/docs/release/controllers.md +++ b/docs/release/controllers.md @@ -2,16 +2,16 @@ The Flux controllers are [Kubernetes operators](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/), -each controller has its own Git repository and release cycle. +each controller has its own Git repository and release cycle (see below for details). Controller repositories and their interdependencies: -1. [fluxcd/source-controller](https://github.com/fluxcd/source-controller) -2. [fluxcd/kustomize-controller](https://github.com/fluxcd/kustomize-controller) (imports `fluxcd/source-controller/api`) -3. [fluxcd/helm-controller](https://github.com/fluxcd/helm-controller) (imports `fluxcd/source-controller/api`) -4. [fluxcd/notification-controller](https://github.com/fluxcd/notification-controller) -5. [fluxcd/image-reflector-controller](https://github.com/fluxcd/image-reflector-controller) -6. [fluxcd/image-automation-controller](https://github.com/fluxcd/image-automation-controller) (imports `fluxcd/source-controller/api` and `fluxcd/image-reflector-controller/api`) +1. [source-controller](https://github.com/fluxcd/source-controller) +2. [kustomize-controller](https://github.com/fluxcd/kustomize-controller) (imports `fluxcd/source-controller/api`) +3. [helm-controller](https://github.com/fluxcd/helm-controller) (imports `fluxcd/source-controller/api`) +4. [notification-controller](https://github.com/fluxcd/notification-controller) +5. [image-reflector-controller](https://github.com/fluxcd/image-reflector-controller) +6. [image-automation-controller](https://github.com/fluxcd/image-automation-controller) (imports `fluxcd/source-controller/api` and `fluxcd/image-reflector-controller/api`) ## API versioning @@ -23,11 +23,11 @@ The Flux APIs (Kubernetes CRDs) follow the An alpha version API e.g. `v1alpha1` is considered experimental and should be used on test environments only. -The schema of objects may change in incompatible ways in a later controller release. +The schema of objects may change in incompatible ways in a later API version. The Custom Resources may require editing and re-creating after a CRD update. An alpha version API becomes deprecated once a subsequent alpha or beta API version is released. -A deprecated alpha version is subject to removal after a three months period. +A deprecated alpha version is subject to removal after a three month period. An alpha API is introduced when its proposal reaches the `implementable` phase in the [Flux RFC process](https://github.com/fluxcd/flux2/tree/main/rfcs). @@ -48,14 +48,14 @@ A deprecated beta version is subject to removal after a six months period. ### Stable version -A stable version API e.g. `v2` is considered feature complete. +A stable API version, e.g. `v2`, is considered feature complete. Any changes to the object schema do not require editing or re-creating of Custom Resources. Schema fields can't be removed, only new fields can be added with a default value that doesn't affect the controller's current behaviour. -A stable version API becomes deprecated once a subsequent stable version is released. -Stable API versions are not subject to removal in any future release of a controller major version. +A stable API version becomes deprecated once a subsequent stable version is released. +Stable API versions are not subject to removal in any future release within a controller major version. In effect, this means that for as long as Flux `v2` is being maintained, all the stable API versions will be supported. @@ -65,7 +65,7 @@ will be supported. The Flux controllers and their Go API packages are released by following the [Go module version numbering](https://go.dev/doc/modules/version-numbers) conventions: -- `vX.Y.Z-RC.W` release candidates e.g. `v1.0.0-RC.1` +- `vX.Y.Z-rc.W` release candidates e.g. `v1.0.0-rc.1` - `vX.Y.Z` stable releases e.g. `v1.0.0` The API versioning and controller versioning are indirectly related. For example, @@ -86,7 +86,7 @@ Patch releases are intended for critical bug fixes to the latest minor version, vulnerabilities or fixes to severe problems with no workaround. Patch releases do not contain breaking changes, feature additions or any type of user-facing changes. -If a CVE fix requires a breaking change, then a minor release will provide the fix. +If a security fix requires a breaking change, then a minor release will provide the fix. We expect users to be running the latest patch release of a given minor release as soon as the controller release is included in a Flux patch release. @@ -119,7 +119,7 @@ and a support window of one year will be provided for the previous major version Flux controllers are at least released at the same rate as Kubernetes, following their cadence of three minor releases per year. After each Kubernetes minor release, all controllers are tested against the latest -Kubernetes version and are released at approximately two weeks after Kubernetes. +Kubernetes version and then released approximately two weeks after Kubernetes. The newly released controllers offer support for Kubernetes N-2 minor versions. A Flux controller may have more than three minor releases per year, if maintainers decide to ship a diff --git a/docs/release/flux.md b/docs/release/flux.md index c4994411..98b56da5 100644 --- a/docs/release/flux.md +++ b/docs/release/flux.md @@ -8,7 +8,7 @@ bundling the [Flux controllers](controllers.md) into a distributable package. Flux is released by following the [semver](https://semver.org/) conventions: -- `vX.Y.Z-RC.W` release candidates e.g. `v2.0.0-rc.1` +- `vX.Y.Z-rc.W` release candidates e.g. `v2.0.0-rc.1` - `vX.Y.Z` stable releases e.g. `v2.0.0` The Flux project maintains release branches for the most recent three minor releases @@ -36,7 +36,7 @@ We expect users to be running the latest patch release of a given minor release. ### Minor releases -Minor releases are intended for backwards compatible feature additions and improvements. +Minor releases are intended for backward-compatible feature additions and improvements. Note that breaking changes may occur if required by a security vulnerability fix. Minor releases are used when updating the Flux controllers or Kubernetes dependencies @@ -57,11 +57,11 @@ and a support window of one year will be provided for the previous major version Flux is at least released at the same rate as Kubernetes, following their cadence of three minor releases per year. After each Kubernetes minor release, the CLI and all controllers are -tested against the latest Kubernetes version and are released at approximately two weeks after Kubernetes. +tested against the latest Kubernetes version and are released approximately two weeks after Kubernetes. The newly released Flux version offers support for Kubernetes N-2 minor versions. -Flux may have more than three minor releases per year, if maintainers decide to ship a -new feature or optimisation ahead of schedule. +Flux may have more than three minor releases per year if maintainers decide to ship a +new feature or optimization ahead of schedule. ## Supported releases diff --git a/docs/release/packages.md b/docs/release/packages.md index d61c5521..ccd6417f 100644 --- a/docs/release/packages.md +++ b/docs/release/packages.md @@ -11,7 +11,7 @@ for projects which integrate and/or extend Flux. The Flux packages are released by following the [Go module version numbering](https://go.dev/doc/modules/version-numbers) conventions: -- `NAME/vX.Y.Z-RC.W` release candidates e.g. `runtime/v1.0.0-RC.1` +- `NAME/vX.Y.Z-rc.W` release candidates e.g. `runtime/v1.0.0-rc.1` - `NAME/vX.Y.Z` stable releases e.g. `runtime/v1.0.0` To import or update a Flux package in a Go project: From 4e78e806194a98aa0db32087841fff38584c557c Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Thu, 29 Jun 2023 18:57:51 +0200 Subject: [PATCH 11/15] Document various release procedures This lacks documentation for the Terraform provider repository, which is a higher level component than anything documented here. Signed-off-by: Hidde Beydals --- docs/release/procedure.md | 393 ++++++++++++++++++++++--- docs/release/release-notes-template.md | 72 +++++ 2 files changed, 425 insertions(+), 40 deletions(-) create mode 100644 docs/release/release-notes-template.md diff --git a/docs/release/procedure.md b/docs/release/procedure.md index 9ac03d36..1f586189 100644 --- a/docs/release/procedure.md +++ b/docs/release/procedure.md @@ -1,60 +1,373 @@ -# Flux release procedure +# Flux release procedures -## Shared packages release procedure +This document provides an overview of the release procedures for each component +type in the Flux project. It is intended for project maintainers, but may also +be useful for contributors who want to understand the release process. -As a project maintainer, to release a package, tag the `main` branch using semver, -and push the signed tag to upstream: +If you have any questions, please reach out to another maintainer for +clarification. + +## Table of contents + +- [General rules](#general-rules) + + [Signing releases](#signing-releases) +- [Component types](#component-types) + + [Shared packages](#shared-packages) + + [Controllers](#controllers) + * [Minor releases](#controller-minor-releases) + * [Patch releases](#controller-patch-releases) + * [Release candidates](#controller-release-candidates) + * [Preview releases](#controller-preview-releases) + + [Distribution](#distribution) + * [Minor releases](#distribution-minor-releases) + * [Patch releases](#distribution-patch-releases) + * [Release candidates](#distribution-release-candidates) +- [Backport changes for patch releases](#backport-changes-for-patch-releases) + +## General rules + +### Signing releases + +To ensure the integrity and authenticity of releases, all releases must be +signed with a GPG key. The public key must be uploaded to the GitHub account of +the maintainer, and the private key must be kept secure. + +In addition, we recommend the following practices: + +1. Safeguard your GPG private key, preferably using a hardware security key + like a YubiKey. +2. Use a subkey dedicated to signing releases, set an expiration date for + added security, and keep the master key offline. Refer to + [this guide](https://riseup.net/en/security/message-security/openpgp/best-practices#key-configuration) + for detailed instructions. + +We understand that this may seem overwhelming. If you are not comfortable with +the process, don't hesitate to seek assistance from another maintainer who has +experience with signing releases. + +Please note that SSH signatures are not supported at this time due to limited +availability of SSH signature verification outside the `git` CLI. + +## Component types + +### Shared packages + +To release a [package](packages.md) as a project maintainer, follow these steps: + +1. Tag the `main` branch using SemVer. +2. Sign the tag according to the [general rules](#general-rules). +3. Push the signed tag to the upstream repository. + +Use the following commands as an example: ```shell git clone https://github.com/fluxcd/pkg.git git switch main -git tag -s -m "runtime/v1.0.0" "runtime/v1.0.0" -git push origin "runtime/v1.0.0" +git tag -s -m "/" "/" +git push origin "/" ``` -**Note** that the Git tags must be cryptographically signed with your private key -and your public key must be uploaded to GitHub. +In the commands above, `` represents the relative path to the directory +containing the `go.mod` file, and `` refers to the SemVer version of the +release. For instance, `runtime/v1.0.0` for [`fluxcd/pkg/runtime`](https://github.com/fluxcd/pkg/tree/main/runtime), +or `http/fetch/v0.1.0` for [`fluxcd/pkg/http/fetch`](https://github.com/fluxcd/pkg/tree/main/http/fetch). -Release candidates of a specific package can be cut from the `main` branch or from an `dev-` branch: +Before cutting a release candidate, ensure that the package's tests pass +successfully. + +Here's an example of releasing a candidate from a feature branch: ```shell -git switch dev-runtime -git tag -s -m "runtime/v1.1.0-RC.1" "runtime/v1.1.0-RC.1" -git push origin "runtime/v1.1.0-RC.1" +git switch +git tag -s -m "/-.1" "/-.1" +git push origin "/-.1" ``` -Before cutting a release candidate, make sure the tests are passing on the `dev` branch. +### Controllers -## Controllers release procedure +To release a [controller](controllers.md) as a project maintainer, follow the +steps below. Note that the release procedure differs depending on the type of +release. -As a project maintainer, to release a controller and its API: +##### Controller minor releases -1. Checkout the `main` branch and pull changes from remote. -2. Create a new branch from `main` i.e. `release-`. This - will function as your release preparation branch. -3. Update the `github.com/fluxcd/-controller/api` version in `go.mod` -4. Add an entry to the `CHANGELOG.md` for the new release and change the - `newTag` value in ` config/manager/kustomization.yaml` to that of the - semver release you are going to make. Commit and push your changes. -5. Create a PR for your release branch and get it merged into `main`. -6. Create a `api/` tag for the merge commit in `main` and push it to remote. -7. Create a `` tag for the merge commit in `main` and push it to remote. -8. Confirm CI builds and releases the newly tagged version. +1. Checkout the `main` branch and pull changes from the remote repository. -**Note** that the Git tags must be cryptographically signed with your private key -and your public key must be uploaded to GitHub. +2. Create a "release series" branch for the next minor SemVer range, e.g., + `release/v1.2.x`, and push it to the remote repository. -## Distribution release procedure + ```shell + git switch -c release/v1.2.x main + ``` -As a project maintainer, to release a new Flux version and its CLI: +3. From the release series branch, create a release preparation branch for the + specific release. -- `v2.X.Y-RC.Z` (Branch: `release-2.X`) - - When the `main` branch is feature-complete for `v2.X`, we will cherrypick PRs essential to `v2.X` to the `release-2.X` branch. - - We will cut the first [release candidate](#release-candidates) by tagging the `release-2.X` as `v2.X.0-RC.0`. - - If we're not satisfied with `v2.X.0-RC.0`, we'll keep releasing RCs until all issues are solved. -- `v2.X.0` (Branch: `release-2.X`) - - The final release is cut from the `release-2.X` branch and tagged as `v2.X.0`. -- `v2.X.Y, Y > 0` (Branch: `release-2.X`) - - [Patch releases](#patch-releases) are released as we cherrypick commits from `main` into the `release-2.X` branch. - - Flux controller updates (patch versions of a controller minor release included in `v2.X.0`) PRs are merged directly into the `release-2.X` branch. - - A patch release is cut from the `release-2.X` branch and tagged as `v2.X.Y`. + ```shell + git switch -c release-v1.2.0 release/v1.2.x + ``` + +4. Add an entry to `CHANGELOG.md` for the new release and commit the changes. + + ```shell + vim CHANGELOG.md + git add CHANGELOG.md + git commit -s -m "Add changelog entry for v1.2.0" + ``` + +5. Update `github.com/fluxcd/-controller/api` version in `go.mod` and + `newTag` value in `config/manager/kustomization.yaml` to the target SemVer + (e.g., `v1.2.0`). Commit and push the changes. + + ```shell + vim go.mod + vim config/manager/kustomization.yaml + git add go.mod config/manager/kustomization.yaml + git commit -s -m "Release v1.2.0" + git push origin release-v1.2.0 + ``` + +6. Create a pull request for the release branch and merge it into the release + series branch (e.g., `release/v1.2.x`). + +7. Create `api/` and `` tags for the merge commit in + `release/v1.2.x`. Ensure the tags are signed according to the [general + rules](#general-rules)., and push them to the remote repository. + + ```shell + git switch release/v1.2.x + git pull origin release/v1.2.x + git tag -s -m "api/v1.2.0" api/v1.2.0 + git push origin api/v1.2.0 + git tag -s -m "v1.2.0" v1.2.0 + git push origin v1.2.0 + ``` + +8. Confirm that the CI builds and releases the newly tagged version. + +9. Create a pull request for the release series branch and merge it into `main`. + +##### Controller patch releases + +1. Ensure everything to be included in the release is backported to the + "release series" branch (e.g., `release/v1.2.x`). If not, refer to the + [backporting](#backport-changes-for-patch-releases) section. + +2. From the release series branch, create a release preparation branch for the + specific patch release. + + ```shell + git pull origin release/v1.2.x + git switch -c release-v1.2.1 release/v1.2.1 + ``` + +3. Add an entry to `CHANGELOG.md` for the new release and commit the changes. + + ```shell + vim CHANGELOG.md + git add CHANGELOG.md + git commit -s -m "Add changelog entry for v1.2.1" + ``` + +4. Update `github.com/fluxcd/-controller/api` version in `go.mod` and + `newTag` value in `config/manager/kustomization.yaml` to the target SemVer + (e.g., `v1.2.1`). Commit and push the changes. + + ```shell + vim go.mod + vim config/manager/kustomization.yaml + git add go.mod config/manager/kustomization.yaml + git commit -s -m "Release v1.2.1" + git push origin release-v1.2.1 + ``` + +5. Create a pull request for the release branch and merge it into the release + series branch (e.g., `release/v1.2.x`). + +6. Create `api/` and `` tags for the merge commit in + `release/v1.2.x`. Ensure the tags are signed according to the [general + rules](#general-rules)., and push them to the remote repository. + + ```shell + git switch release/v1.2.x + git pull origin release/v1.2.x + git tag -s -m "api/v1.2.1" api/v1.2.1 + git push origin api/v1.2.1 + git tag -s -m "v1.2.1" v1.2.1 + git push origin v1.2.1 + ``` + +7. Confirm that the CI builds and releases the newly tagged version. + +8. Cherry-pick the changelog entry from the release series branch and create a + pull request to merge it into `main`. + + ```shell + git pull origin main + git switch -c pick-changelog-v1.2.1 main + git cherry-pick -x + git push origin pick-changelog-v1.2.1 + ``` + +#### Controller release candidates + +In some cases, it may be necessary to release a [release +candidate](controllers.md#release-candidates) of a controller. + +To create a first release candidate, follow the steps to create a [minor +release](#controller-minor-releases), but use the `rc.X` suffix for SemVer +version to release (e.g., `v1.2.0-rc.1`). + +Once the release series branch is created, subsequent release candidates and +the final (non-RC) release should follow the procedure for [patch controller +releases](#controller-patch-releases). + +#### Controller preview releases + +In some cases, it may be necessary to release a preview of a controller. +A preview release is a release that is not intended for production use, but +rather to allow users to quickly test new features or an intended bug fix, and +provide feedback. + +Preview releases are made by triggering the release GitHub Actions workflow on +a specific Git branch. This workflow will build the container image, sign it +using Cosign, and push it to the registry. But does not require a Git tag, +GitHub release, or a changelog entry. + +To create a preview release, follow the steps below. + +1. Navigate to `https://github.com/fluxcd/-controller/actions/workflows/release.yml`. +2. Click the `Run workflow` button. +3. Select the branch to release from the `Branch` dropdown. +4. The default values for the `image tag` (`preview`) should be correct, but can + be changed if necessary. +5. Click the green `Run workflow` button. +6. The workflow will now run, and the container image will be pushed to the + registry. Once the workflow has completed, the image reference will be + available in the logs, and can be shared in the relevant issue or pull + request. + +### Distribution + +To release a [Flux distribution](flux.md) as a project maintainer, follow the +steps below. + +Note that the Flux distribution contains multiple components, and you may need +to release [controllers](#controllers) before releasing the distribution. +Automation is in place to automatically create a pull request to update the +version in the `main` branch when a new controller version is released. + +#### Distribution minor releases + +1. Ensure everything to be included in the release is merged into the `main` + branch, including any controller releases you wish to include in the + release. + +2. Create a "release series" branch for the next minor SemVer range, e.g., + `release/v1.2.x`, and push it to the remote repository. + + ```shell + git switch -c release/v1.2.x main + ``` + +3. Prepare the required release notes for this release, see [release + notes](#distribution-release-notes) for more information. + +4. Tag the release series branch with the SemVer version of the release, e.g., + `v1.2.0`. Ensure the tag is signed according to the [general + rules](#general-rules), and push it to the remote repository. + + ```shell + git tag -s -m "v1.2.0" v1.2.0 + git push origin v1.2.0 + ``` + +5. Confirm that the CI builds and releases the newly tagged version. + +6. Once the release is complete, update the release notes on GitHub with the + release notes prepared in step 3. + +7. Post a message in the [`#flux` CNCF Slack channel](https://cloud-native.slack.com/archives/CLAJ40HV3) + announcing the release, and pin it. + +#### Distribution patch releases + +1. Ensure everything to be included in the release is backported to the + "release series" branch (e.g., `release/v1.2.x`). If not, refer to the + [backporting](#backport-changes-for-patch-releases) section. + +2. Prepare the required release notes for this release, see [release + notes](#distribution-release-notes) for more information. + +3. Tag the release series branch with the SemVer version of the release, e.g., + `v1.2.1`. Ensure the tag is signed according to the [general + rules](#general-rules), and push it to the remote repository. + + ```shell + git tag -s -m "v1.2.1" v1.2.1 + git push origin v1.2.1 + ``` + +4. Confirm that the CI builds and releases the newly tagged version. + +5. Once the release is complete, update the release notes on GitHub with the + release notes prepared in step 2. + +6. Post a message in the [`#flux` CNCF Slack channel](https://cloud-native.slack.com/archives/CLAJ40HV3) + +#### Distribution release candidates + +In some cases, it may be necessary to release a [release candidate](flux.md#release-candidates) +of the distribution. + +To create a first release candidate, follow the steps to create a [minor +release](#distribution-minor-releases), but use the `rc.X` suffix for SemVer +version to release (e.g., `v1.2.0-rc.1`). + +Once the release series branch is created, subsequent release candidates and +the final (non-RC) release should follow the procedure for [patch controller +releases](#controller-patch-releases). + +#### Distribution release notes + +The release notes template for Flux distributions is available in the +[release-notes-template.md](release-notes-template.md) file. + +## Backport changes for patch releases + +The Flux projects have a backport bot that automates the process of backporting +changes from `main` to the release series branches. The bot is configured to +backport pull requests that are labeled with `backport:` (e.g., +`backport:release/v2.1.x`) and have been merged into `main`. + +The label(s) are preferably added to the pull request before it is merged into +`main`. If the pull request is merged into `main` without labeling, they can +still be added to the pull request after it has been merged. + +The backport bot will automatically backport the pull request to the release +series branch and create a pull request for the backport. It will comment on +the pull request with a link to the backport pull request. + +If the backport bot is unable to backport a pull request automatically (for +example, due to conflicts), it will comment on the pull request with +instructions on how to backport the pull request manually. + +### Manual backporting + +In some cases, the backport bot may not be suitable for backporting a pull +request. For example, if the pull request contains a series of changes of which +a subset should be backported. In these cases, the pull request should be +backported manually. + +To backport a pull request manually, create a new branch from the release +series branch (e.g., `release/v2.1.x`) and cherry-pick the commits from the +pull request into the new branch. Push the new branch to the remote repository +and create a pull request to merge it into the release series branch. + +```shell +git pull origin release/v2.1.x +git switch -c backport--to-v2.1.x release/v2.1.x +git cherry-pick -x +# Repeat the cherry-pick command for each commit to backport +git push origin backport--to-v2.1.x +``` diff --git a/docs/release/release-notes-template.md b/docs/release/release-notes-template.md new file mode 100644 index 00000000..b64d769b --- /dev/null +++ b/docs/release/release-notes-template.md @@ -0,0 +1,72 @@ +# Release notes template + +This is a template for release notes. It is intended to be used as a +starting point for writing release notes for a new release. It should be copied +to a temporary file, and then edited to reflect the changes in the release. + +Once the release notes are complete, you can tag the release and push it to +GitHub. + +After the release is tagged, the CI will build the release artifacts and upload +them to the GitHub release page. The release notes can then be copied from the +temporary file to the GitHub release page. + +The release notes should be formatted using [Markdown](https://guides.github.com/features/mastering-markdown/), +and not make use of line breaks unless they function as paragraph breaks. + +For examples of release notes, including language and formatting of the release +highlights, see the [Flux release notes](https://github.com/fluxcd/flux2/releases). + +## GitHub release template + +The following template can be used for the GitHub release page: + +```markdown +## Highlights + + + +### Fixes and improvements + + + +## New documentation + + + +## Components changelog + +- -controller [v](https://github.com/fluxcd/-controller/blob//CHANGELOG.md + +## CLI changelog + + +``` + +In some scenarios, you may want to include specific information about API +changes and/or upgrade procedures. Consult [the formatting of +`v2.0.0-rc.1`](https://github.com/fluxcd/flux2/releases/tag/v2.0.0-rc.1) for +such an example. + +## Slack message template + +The following template can be used for the Slack release message: + +```markdown +:sparkles: *We are pleased to announce the release of Flux [](https://github.com/fluxcd/flux2/releases/tag//)!* + + + +:hammer_and_pick: *Fixes and improvements* + + + +:books: Documentation + + + +:heart: Big thanks to all the Flux contributors that helped us with this release! +``` + +For more concrete examples, see the pinned messages in the [Flux Slack +channel](https://cloud-native.slack.com/archives/CLAJ40HV3). \ No newline at end of file From 5abf1ee8175af87a7da94ef113bd23fcbc6bf65c Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Thu, 29 Jun 2023 19:00:19 +0200 Subject: [PATCH 12/15] Address various nits Signed-off-by: Hidde Beydals --- docs/release/README.md | 2 +- docs/release/controllers.md | 7 +++---- docs/release/flux.md | 7 +++---- docs/release/packages.md | 5 ++--- docs/release/release-notes-template.md | 2 +- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/docs/release/README.md b/docs/release/README.md index 03df7d1b..cfc6dac4 100644 --- a/docs/release/README.md +++ b/docs/release/README.md @@ -5,4 +5,4 @@ - [Flux distribution](flux.md) - [Flux APIs and controllers](controllers.md) - [Flux shared libraries](packages.md) -- [Flux release procedure](procedure.md) \ No newline at end of file +- [Flux release procedures](procedure.md) diff --git a/docs/release/controllers.md b/docs/release/controllers.md index 07f9e780..cfcccf18 100644 --- a/docs/release/controllers.md +++ b/docs/release/controllers.md @@ -1,4 +1,4 @@ -# Flux controllers release spec +# Flux controller releases The Flux controllers are [Kubernetes operators](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/), @@ -13,7 +13,7 @@ Controller repositories and their interdependencies: 5. [image-reflector-controller](https://github.com/fluxcd/image-reflector-controller) 6. [image-automation-controller](https://github.com/fluxcd/image-automation-controller) (imports `fluxcd/source-controller/api` and `fluxcd/image-reflector-controller/api`) -## API versioning +## API versioning The Flux APIs (Kubernetes CRDs) follow the [Kubernetes API versioning](https://kubernetes.io/docs/reference/using-api/#api-versioning) scheme. @@ -44,7 +44,7 @@ The Custom Resources may require editing after a CRD update for which migration provided as part of the controller changelog. A beta version API becomes deprecated once a subsequent beta or stable API version is released. -A deprecated beta version is subject to removal after a six months period. +A deprecated beta version is subject to removal after a six-months period. ### Stable version @@ -148,4 +148,3 @@ Each controller release produces the following artifacts: All the artifacts are cryptographically signed and can be verified with Cosign and GitHub OIDC. The release artifacts can be accessed based on the controller name and version. - diff --git a/docs/release/flux.md b/docs/release/flux.md index 98b56da5..508f75a5 100644 --- a/docs/release/flux.md +++ b/docs/release/flux.md @@ -1,4 +1,4 @@ -# Flux release spec +# Flux releases The Flux project repository [fluxcd/flux2](https://github.com/fluxcd/flux2) contains the Flux command-line tool source code and the Kubernetes manifests for @@ -65,8 +65,8 @@ new feature or optimization ahead of schedule. ## Supported releases -For Flux the CLI and its controllers we support the last three minor releases. -Critical bug fixes such as security fixes, may be back-ported to those three minor +For Flux the CLI and its controllers, we support the last three minor releases. +Critical bug fixes, such as security fixes, may be back-ported to those three minor versions as patch releases, depending on severity and feasibility. Note that back-porting is provided by the community on a best-effort basis. @@ -139,4 +139,3 @@ The changelog contains the following information: - A list of documentation additions **Note** that the vulnerability disclosure procedure is explained on the [security page](https://fluxcd.io/security/). - diff --git a/docs/release/packages.md b/docs/release/packages.md index ccd6417f..66354d13 100644 --- a/docs/release/packages.md +++ b/docs/release/packages.md @@ -1,9 +1,9 @@ -# Flux shared packages release spec +# Flux shared package releases The Go packages in [github.com/fluxcd/pkg](https://github.com/fluxcd/pkg) are dedicated Go modules, each module has its own set of dependencies and release cycle. -These packages are primary meant for internal use in Flux controllers and +These packages are primarily meant for internal use in Flux controllers and for projects which integrate and/or extend Flux. ## Release versioning @@ -72,4 +72,3 @@ A deprecated package is marked as so in its `go.mod` e.g. // Deprecated: use github.com/fluxcd/pkg/tar instead. module github.com/fluxcd/pkg/untar ``` - diff --git a/docs/release/release-notes-template.md b/docs/release/release-notes-template.md index b64d769b..0b3a41de 100644 --- a/docs/release/release-notes-template.md +++ b/docs/release/release-notes-template.md @@ -1,4 +1,4 @@ -# Release notes template +# Flux release note template This is a template for release notes. It is intended to be used as a starting point for writing release notes for a new release. It should be copied From 9e11b860ec0c7a78edddb65704a61229317fbbb8 Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Sat, 1 Jul 2023 00:05:36 +0200 Subject: [PATCH 13/15] Address release procedure review nits Signed-off-by: Hidde Beydals --- docs/release/procedure.md | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/docs/release/procedure.md b/docs/release/procedure.md index 1f586189..603ce785 100644 --- a/docs/release/procedure.md +++ b/docs/release/procedure.md @@ -23,6 +23,7 @@ clarification. * [Patch releases](#distribution-patch-releases) * [Release candidates](#distribution-release-candidates) - [Backport changes for patch releases](#backport-changes-for-patch-releases) + + [Manual backporting](#manual-backporting) ## General rules @@ -132,7 +133,7 @@ release. 7. Create `api/` and `` tags for the merge commit in `release/v1.2.x`. Ensure the tags are signed according to the [general - rules](#general-rules)., and push them to the remote repository. + rules](#general-rules), and push them to the remote repository. ```shell git switch release/v1.2.x @@ -186,7 +187,7 @@ release. 6. Create `api/` and `` tags for the merge commit in `release/v1.2.x`. Ensure the tags are signed according to the [general - rules](#general-rules)., and push them to the remote repository. + rules](#general-rules), and push them to the remote repository. ```shell git switch release/v1.2.x @@ -229,19 +230,24 @@ A preview release is a release that is not intended for production use, but rather to allow users to quickly test new features or an intended bug fix, and provide feedback. -Preview releases are made by triggering the release GitHub Actions workflow on +Preview releases are made by triggering the `release` GitHub Actions workflow on a specific Git branch. This workflow will build the container image, sign it -using Cosign, and push it to the registry. But does not require a Git tag, +using Cosign, and push it to the registry. But it does not require a Git tag, GitHub release, or a changelog entry. To create a preview release, follow the steps below. 1. Navigate to `https://github.com/fluxcd/-controller/actions/workflows/release.yml`. + 2. Click the `Run workflow` button. + 3. Select the branch to release from the `Branch` dropdown. + 4. The default values for the `image tag` (`preview`) should be correct, but can be changed if necessary. + 5. Click the green `Run workflow` button. + 6. The workflow will now run, and the container image will be pushed to the registry. Once the workflow has completed, the image reference will be available in the logs, and can be shared in the relevant issue or pull @@ -264,10 +270,10 @@ version in the `main` branch when a new controller version is released. release. 2. Create a "release series" branch for the next minor SemVer range, e.g., - `release/v1.2.x`, and push it to the remote repository. + `release/v2.2.x`, and push it to the remote repository. ```shell - git switch -c release/v1.2.x main + git switch -c release/v2.2.x main ``` 3. Prepare the required release notes for this release, see [release @@ -278,8 +284,8 @@ version in the `main` branch when a new controller version is released. rules](#general-rules), and push it to the remote repository. ```shell - git tag -s -m "v1.2.0" v1.2.0 - git push origin v1.2.0 + git tag -s -m "v2.2.0" v2.2.0 + git push origin v2.2.0 ``` 5. Confirm that the CI builds and releases the newly tagged version. @@ -293,19 +299,19 @@ version in the `main` branch when a new controller version is released. #### Distribution patch releases 1. Ensure everything to be included in the release is backported to the - "release series" branch (e.g., `release/v1.2.x`). If not, refer to the + "release series" branch (e.g., `release/v2.2.x`). If not, refer to the [backporting](#backport-changes-for-patch-releases) section. 2. Prepare the required release notes for this release, see [release notes](#distribution-release-notes) for more information. 3. Tag the release series branch with the SemVer version of the release, e.g., - `v1.2.1`. Ensure the tag is signed according to the [general + `v2.2.1`. Ensure the tag is signed according to the [general rules](#general-rules), and push it to the remote repository. ```shell - git tag -s -m "v1.2.1" v1.2.1 - git push origin v1.2.1 + git tag -s -m "v2.2.1" v2.2.1 + git push origin v2.2.1 ``` 4. Confirm that the CI builds and releases the newly tagged version. @@ -322,7 +328,7 @@ of the distribution. To create a first release candidate, follow the steps to create a [minor release](#distribution-minor-releases), but use the `rc.X` suffix for SemVer -version to release (e.g., `v1.2.0-rc.1`). +version to release (e.g., `v2.2.0-rc.1`). Once the release series branch is created, subsequent release candidates and the final (non-RC) release should follow the procedure for [patch controller From 926842a21688dc07fe9f8fbd33b5e5ed0dbb75e1 Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Mon, 3 Jul 2023 11:12:01 +0200 Subject: [PATCH 14/15] Address review comment section titles Signed-off-by: Hidde Beydals --- docs/release/procedure.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/release/procedure.md b/docs/release/procedure.md index 603ce785..b9b2f07b 100644 --- a/docs/release/procedure.md +++ b/docs/release/procedure.md @@ -14,10 +14,10 @@ clarification. - [Component types](#component-types) + [Shared packages](#shared-packages) + [Controllers](#controllers) - * [Minor releases](#controller-minor-releases) - * [Patch releases](#controller-patch-releases) - * [Release candidates](#controller-release-candidates) - * [Preview releases](#controller-preview-releases) + * [Minor releases](#controllers-minor-releases) + * [Patch releases](#controllers-patch-releases) + * [Release candidates](#controllers-release-candidates) + * [Preview releases](#controllers-preview-releases) + [Distribution](#distribution) * [Minor releases](#distribution-minor-releases) * [Patch releases](#distribution-patch-releases) @@ -90,7 +90,7 @@ To release a [controller](controllers.md) as a project maintainer, follow the steps below. Note that the release procedure differs depending on the type of release. -##### Controller minor releases +##### Controllers: minor releases 1. Checkout the `main` branch and pull changes from the remote repository. @@ -148,7 +148,7 @@ release. 9. Create a pull request for the release series branch and merge it into `main`. -##### Controller patch releases +##### Controllers: patch releases 1. Ensure everything to be included in the release is backported to the "release series" branch (e.g., `release/v1.2.x`). If not, refer to the @@ -210,7 +210,7 @@ release. git push origin pick-changelog-v1.2.1 ``` -#### Controller release candidates +#### Controllers: release candidates In some cases, it may be necessary to release a [release candidate](controllers.md#release-candidates) of a controller. @@ -223,7 +223,7 @@ Once the release series branch is created, subsequent release candidates and the final (non-RC) release should follow the procedure for [patch controller releases](#controller-patch-releases). -#### Controller preview releases +#### Controllers: preview releases In some cases, it may be necessary to release a preview of a controller. A preview release is a release that is not intended for production use, but @@ -263,7 +263,7 @@ to release [controllers](#controllers) before releasing the distribution. Automation is in place to automatically create a pull request to update the version in the `main` branch when a new controller version is released. -#### Distribution minor releases +#### Distribution: minor releases 1. Ensure everything to be included in the release is merged into the `main` branch, including any controller releases you wish to include in the @@ -296,7 +296,7 @@ version in the `main` branch when a new controller version is released. 7. Post a message in the [`#flux` CNCF Slack channel](https://cloud-native.slack.com/archives/CLAJ40HV3) announcing the release, and pin it. -#### Distribution patch releases +#### Distribution: patch releases 1. Ensure everything to be included in the release is backported to the "release series" branch (e.g., `release/v2.2.x`). If not, refer to the @@ -321,7 +321,7 @@ version in the `main` branch when a new controller version is released. 6. Post a message in the [`#flux` CNCF Slack channel](https://cloud-native.slack.com/archives/CLAJ40HV3) -#### Distribution release candidates +#### Distribution: release candidates In some cases, it may be necessary to release a [release candidate](flux.md#release-candidates) of the distribution. @@ -334,7 +334,7 @@ Once the release series branch is created, subsequent release candidates and the final (non-RC) release should follow the procedure for [patch controller releases](#controller-patch-releases). -#### Distribution release notes +#### Distribution: release notes The release notes template for Flux distributions is available in the [release-notes-template.md](release-notes-template.md) file. From 1a8798a5d43657977b553091976d03b58dea9046 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Mon, 3 Jul 2023 14:58:01 +0300 Subject: [PATCH 15/15] Link to release cadence from minor section Signed-off-by: Stefan Prodan --- docs/release/controllers.md | 23 ++++++++++++----------- docs/release/flux.md | 12 ++++++++---- docs/release/procedure.md | 9 ++++----- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/docs/release/controllers.md b/docs/release/controllers.md index cfcccf18..1459fa22 100644 --- a/docs/release/controllers.md +++ b/docs/release/controllers.md @@ -99,14 +99,9 @@ Note that breaking changes may occur if required by a security vulnerability fix In addition, minor releases are used when updating Kubernetes dependencies such as `k8s.io/api` from one minor version to another. -In effect, this means a new minor version will at least be released for all Flux -controllers approximately every four months, following each Kubernetes minor version release. -To properly validate the controllers against the latest Kubernetes version, -we typically allocate a time window of around two weeks for end-to-end testing of Flux controllers. - -It is worth noting that in certain scenarios where project dependencies are not in sync with -the Kubernetes version or conflicts arise, this two-week timeframe may prove insufficient, -requiring additional time to address the issues appropriately. +In effect, this means a controller minor version will be released at least every four months, after each +Kubernetes minor version release. For in-depth information about this, please refer to the +[release cadence](#release-cadence) section of this document. ### Major releases @@ -117,11 +112,17 @@ and a support window of one year will be provided for the previous major version ## Release cadence -Flux controllers are at least released at the same rate as Kubernetes, following their cadence of three -minor releases per year. After each Kubernetes minor release, all controllers are tested against the latest -Kubernetes version and then released approximately two weeks after Kubernetes. +Flux controllers are _at least_ released at the same rate as Kubernetes, following their cadence of three +minor releases per year. + +To properly validate the controllers against the latest Kubernetes version, +we typically allocate a time window of around two weeks for end-to-end testing of Flux controllers. The newly released controllers offer support for Kubernetes N-2 minor versions. +It is worth noting that in certain scenarios where project dependencies are not in sync with +the Kubernetes version or conflicts arise, this two-week timeframe may prove insufficient, +requiring additional time to address the issues appropriately. + A Flux controller may have more than three minor releases per year, if maintainers decide to ship a new feature or optimisation ahead of schedule. diff --git a/docs/release/flux.md b/docs/release/flux.md index 508f75a5..c030392d 100644 --- a/docs/release/flux.md +++ b/docs/release/flux.md @@ -42,9 +42,9 @@ Note that breaking changes may occur if required by a security vulnerability fix Minor releases are used when updating the Flux controllers or Kubernetes dependencies from one minor version to another. -In effect, this means a Flux minor version will be released at least every four months after each -Kubernetes minor version release. To properly validate the Flux CLI and controllers against -the latest Kubernetes version, we reserve a time window of at least two weeks for end-to-end testing. +In effect, this means a Flux minor version will be released at least every four months, after each +Kubernetes minor version release. For in-depth information about this, please refer to the +[release cadence](#release-cadence) section of this document. ### Major releases @@ -55,11 +55,15 @@ and a support window of one year will be provided for the previous major version ## Release cadence -Flux is at least released at the same rate as Kubernetes, following their cadence of three +Flux is _at least_ released at the same rate as Kubernetes, following their cadence of three minor releases per year. After each Kubernetes minor release, the CLI and all controllers are tested against the latest Kubernetes version and are released approximately two weeks after Kubernetes. The newly released Flux version offers support for Kubernetes N-2 minor versions. +It is worth noting that in certain scenarios where project dependencies are not in sync with +the Kubernetes version or conflicts arise, this two-week timeframe may prove insufficient, +requiring additional time to address the issues appropriately. + Flux may have more than three minor releases per year if maintainers decide to ship a new feature or optimization ahead of schedule. diff --git a/docs/release/procedure.md b/docs/release/procedure.md index b9b2f07b..084340e6 100644 --- a/docs/release/procedure.md +++ b/docs/release/procedure.md @@ -216,12 +216,12 @@ In some cases, it may be necessary to release a [release candidate](controllers.md#release-candidates) of a controller. To create a first release candidate, follow the steps to create a [minor -release](#controller-minor-releases), but use the `rc.X` suffix for SemVer +release](#controllers-minor-releases), but use the `rc.X` suffix for SemVer version to release (e.g., `v1.2.0-rc.1`). Once the release series branch is created, subsequent release candidates and the final (non-RC) release should follow the procedure for [patch controller -releases](#controller-patch-releases). +releases](#controllers-patch-releases). #### Controllers: preview releases @@ -331,13 +331,12 @@ release](#distribution-minor-releases), but use the `rc.X` suffix for SemVer version to release (e.g., `v2.2.0-rc.1`). Once the release series branch is created, subsequent release candidates and -the final (non-RC) release should follow the procedure for [patch controller -releases](#controller-patch-releases). +the final (non-RC) release should follow the procedure for [patch releases](#distribution-patch-releases). #### Distribution: release notes The release notes template for Flux distributions is available in the -[release-notes-template.md](release-notes-template.md) file. +[release-notes-template.md](https://github.com/fluxcd/flux2/blob/main/docs/release/release-notes-template.md) file. ## Backport changes for patch releases