Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 60 additions & 18 deletions docs/community/contribute/faq.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -83,30 +83,60 @@ We cut a release every single merge to `master`.

## What is our versioning strategy?

We practice [`semver`](https://semver.org).
We practice [`semver`](https://semver.org). We cut a release for every merge to the default branch.

Our versioning strategy allows us to systematically and consistently increase patch, minor and major releases. When in doubt, bump the minor release.
Following this strategy allows us to move quickly, release often while enabling our community to version pin for stability, and still convey the *semantics* of the kind of change that happened.
The release automation reads a label on the Pull Request to select the version increment. Maintainers must apply exactly one of these labels before merge. If no label is applied, the automation uses `minor`.

1. **Patch Releases** We bump the patch release for bug fixes of *existing* functionality or small updates to documentation
2. **Minor Releases** Projects that are `< 1.x`, every merge to `master` else is a minor release. This is the proper [semver convention](https://semver.org/#spec-item-4) for `0.x.y` releases.
- While we always try to ensure the interfaces won't change radically, we cannot promise that will remain the case, especially when the tool (Terraform) itself is not yet `1.0`.
- Once the interface is more or less guaranteed to be stable we will release a 1.0.
3. **Major Releases** The major version is milestone-driven (e.g. `> 1.x`). The first milestone is always stability. A major release will correspond to the previous minor release that closes out that milestone.
- The 1.0 milestone doesn’t happen until we have had a very long burn-in period where it is stable and the interface works. For comparison, the `terraform` language had a `0.x` version from its initial release on July 28, 2014 until the `1.0` release on June 8, 2021.
- **After 1.0** all major releases are driven by achieving a particular feature set
| Label | Apply when |
| :----------- | :------------------------------------------------------------------------------------------ |
| `major` | The change can break an existing caller of a module at `1.0` or higher. See the rules below. |
| `minor` | The change adds a feature and does not change the plan for existing callers. Also, any change to a module that is still `0.x`. |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding any change - wouldn't patch releases still apply for the stated purposes, for pre 1.0 modules?

Perhaps that should be any major change if I'm understanding correctly?

| `patch` | The change fixes existing behavior or updates documentation, and does not change the plan for correct configurations. |
| `no-release` | The change touches only CI, tests, or repository files that are not part of the release. |

A common strategy practiced by other organizations is to bump the major release when there's a “known breaking change” and usually includes many changes all at once. This is typically practiced post-1.0 and it's still somewhat arbitrary and difficult to verify. Philosophically speaking, every change is breaking for somebody.
For example, if a project has a bug, chances are that someone has implemented a workaround for that bug. If we release a bug fix as a patch release, that could very well be a breaking change for anyone who had a workaround. By releasing frequently on every commit to `master`,
we allow the greatest number of users to benefit from the work we do. If we break something, no big deal. Users should always practice strict version pinning - never using `master` directly. That way, users can just pin to the previous release of of a module. As a small organization managing *hundreds* of projects, attempting a formal release schedule for each project is not feasible.
When in doubt between `minor` and `patch`, use `minor`. When in doubt between `major` and anything else, use `major`.

## What impact does raising the minimum Terraform or provider version have on a module?
Users must pin module versions. Never use the default branch directly.

We regularly need to bump these versions to take advantage of newer language features or resources. For modules at or above 1.0, raising the minimum required Terraform or provider version requires a major version bump of the module.
## Why do we release this way?

**Note:** this rule does not apply to modules that are still `0.x`, which follow our normal pre-1.0 versioning strategy.
We are a small organization that maintains *hundreds* of projects. A formal release schedule for each project is not possible. So we release on every merge. This lets the most users get fixes and features quickly. The version number still tells users what kind of change happened.

Generally speaking, these upgrades should be done to harness a specific improvement and not solely to use the latest versions.
Users pin versions for stability. If a release breaks something for you, pin to the previous release and open an issue.

Every change is breaking for somebody. For example, if a project has a bug, someone probably has a workaround for it. A fix for that bug can break their workaround. The rules below cover the breaking changes that a reviewer can find. They cannot promise that a `minor` or `patch` release breaks nobody.

## What is a breaking change?

For modules at `1.0` or higher, apply `major` if any of these is true:

1. A variable or output is removed or renamed, or its type changes in a way that existing values no longer satisfy.
2. A default value changes, and an existing caller gets a different plan. Examples: tighter IAM permissions, a different resource name, a new resource that is created by default.
3. A resource address changes without a `moved` block, or the change forces replacement of existing resources.
4. The minimum required Terraform version is raised.
5. The minimum required version of any provider is raised. This includes raises within the same major version, for example `>= 6.0.0` to `>= 6.22.0`.
6. A provider is upgraded to a new major version, for example `aws` `5.x` to `6.x`.
7. Behavior that callers depend on is removed, also when that behavior was a bug, if the plan changes for existing callers.

Before you accept a breaking change, look for a path that does not break callers:

- Keep the old variable in `variables-deprecated.tf` and use it as a fallback for the new variable.
- Add `moved` blocks for resource address changes.
- Add a new variable whose default keeps the old behavior.

A Pull Request with the `major` label must state what breaks and how callers migrate.

## How do we version modules that are still `0.x`?

Modules that are still `0.x` use `minor` for new features and for breaking changes. This is the [semver convention](https://semver.org/#spec-item-4) for `0.x.y` releases. The breaking change rules above do not apply.

We keep a module at `0.x` until its interface is stable after a long burn-in period. For comparison, Terraform itself was `0.x` from its first release on July 28, 2014 until `1.0` on June 8, 2021.

Only Cloud Posse engineers move a module from `0.x` to `1.0`. Usually `1.0` is the current release with a new version number, and it is not a breaking change.

## When should we raise the minimum Terraform or provider version?

Raise a minimum version only to use a specific feature or fix. Do not raise it only to use the latest version. For modules at `1.0` or higher, this is a `major` change (see above).

## How do we create a new release?

Expand Down Expand Up @@ -147,7 +177,19 @@ While we try to keep `master` stable, it's just a best-effort. If something goes

We recommend users version pin to releases for stability and never pin to master.

After merging a Pull Request to `master`, then cut a release. We cut a release for every merge to master. If it's a bug fix, bump the patch release (e.g. `0.0.x`). If it's a new feature, bump the minor (e.g. `0.x.0`). It's that easy! Review the rest of this FAQ for more details on our `semver` strategy.
The release automation cuts a release for every merge to `master`. The label on the Pull Request selects the version increment. See [What is our versioning strategy?](#what-is-our-versioning-strategy).

## How do modules and components merge differently?

Contributors rebase only when a Pull Request has merge conflicts. A Pull Request that is only behind the default branch does not need a rebase.

**Components** (`cloudposse-terraform-components/*`) use a GitHub merge queue. The queue tests each Pull Request against the latest default branch, so a Pull Request that is behind needs no update.

**Modules** (`cloudposse/terraform-*`) do not use a merge queue. The branch must be up to date with the default branch, and the required checks, including `test/terratest`, must pass on the updated branch. To merge a module Pull Request that is behind:

1. Click **Update branch**.
2. Comment `/terratest` to run the tests again.
3. Approve again if the update dismissed the earlier approval.

## What are the merge constraints?

Expand Down
Loading