diff --git a/public/docs/i/1000/deployments/patterns/images/branching-diagram-with-ephemeral-environments.webp b/public/docs/i/1000/deployments/patterns/images/branching-diagram-with-ephemeral-environments.webp new file mode 100644 index 0000000000..1447571a21 Binary files /dev/null and b/public/docs/i/1000/deployments/patterns/images/branching-diagram-with-ephemeral-environments.webp differ diff --git a/public/docs/i/1000/deployments/patterns/images/recommended-octopus-channels.webp b/public/docs/i/1000/deployments/patterns/images/recommended-octopus-channels.webp new file mode 100644 index 0000000000..cd8ae89e71 Binary files /dev/null and b/public/docs/i/1000/deployments/patterns/images/recommended-octopus-channels.webp differ diff --git a/public/docs/i/1000/deployments/patterns/images/recommended-octopus-lifecycles.webp b/public/docs/i/1000/deployments/patterns/images/recommended-octopus-lifecycles.webp new file mode 100644 index 0000000000..ce3f697609 Binary files /dev/null and b/public/docs/i/1000/deployments/patterns/images/recommended-octopus-lifecycles.webp differ diff --git a/public/docs/i/2000/deployments/patterns/images/branching-diagram-with-ephemeral-environments.webp b/public/docs/i/2000/deployments/patterns/images/branching-diagram-with-ephemeral-environments.webp new file mode 100644 index 0000000000..4e9131bd9f Binary files /dev/null and b/public/docs/i/2000/deployments/patterns/images/branching-diagram-with-ephemeral-environments.webp differ diff --git a/public/docs/i/2000/deployments/patterns/images/recommended-octopus-channels.webp b/public/docs/i/2000/deployments/patterns/images/recommended-octopus-channels.webp new file mode 100644 index 0000000000..a116a1f248 Binary files /dev/null and b/public/docs/i/2000/deployments/patterns/images/recommended-octopus-channels.webp differ diff --git a/public/docs/i/2000/deployments/patterns/images/recommended-octopus-lifecycles.webp b/public/docs/i/2000/deployments/patterns/images/recommended-octopus-lifecycles.webp new file mode 100644 index 0000000000..a34819837a Binary files /dev/null and b/public/docs/i/2000/deployments/patterns/images/recommended-octopus-lifecycles.webp differ diff --git a/public/docs/i/600/deployments/patterns/images/branching-diagram-with-ephemeral-environments.webp b/public/docs/i/600/deployments/patterns/images/branching-diagram-with-ephemeral-environments.webp new file mode 100644 index 0000000000..42cb750213 Binary files /dev/null and b/public/docs/i/600/deployments/patterns/images/branching-diagram-with-ephemeral-environments.webp differ diff --git a/public/docs/i/600/deployments/patterns/images/recommended-octopus-channels.webp b/public/docs/i/600/deployments/patterns/images/recommended-octopus-channels.webp new file mode 100644 index 0000000000..51fbcdc7ef Binary files /dev/null and b/public/docs/i/600/deployments/patterns/images/recommended-octopus-channels.webp differ diff --git a/public/docs/i/600/deployments/patterns/images/recommended-octopus-lifecycles.webp b/public/docs/i/600/deployments/patterns/images/recommended-octopus-lifecycles.webp new file mode 100644 index 0000000000..438d7a123b Binary files /dev/null and b/public/docs/i/600/deployments/patterns/images/recommended-octopus-lifecycles.webp differ diff --git a/public/docs/i/x/deployments/patterns/images/branching-diagram-with-ephemeral-environments.png b/public/docs/i/x/deployments/patterns/images/branching-diagram-with-ephemeral-environments.png new file mode 100644 index 0000000000..c730eeaabb Binary files /dev/null and b/public/docs/i/x/deployments/patterns/images/branching-diagram-with-ephemeral-environments.png differ diff --git a/public/docs/i/x/deployments/patterns/images/recommended-octopus-channels.png b/public/docs/i/x/deployments/patterns/images/recommended-octopus-channels.png new file mode 100644 index 0000000000..3b315fe4e4 Binary files /dev/null and b/public/docs/i/x/deployments/patterns/images/recommended-octopus-channels.png differ diff --git a/public/docs/i/x/deployments/patterns/images/recommended-octopus-lifecycles.png b/public/docs/i/x/deployments/patterns/images/recommended-octopus-lifecycles.png new file mode 100644 index 0000000000..dd1e92c030 Binary files /dev/null and b/public/docs/i/x/deployments/patterns/images/recommended-octopus-lifecycles.png differ diff --git a/public/docs/img/deployments/patterns/images/3278438.png b/public/docs/img/deployments/patterns/images/3278438.png deleted file mode 100644 index 33997f7c4e..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278438.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278439.png b/public/docs/img/deployments/patterns/images/3278439.png deleted file mode 100644 index ff4dbde5b4..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278439.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278440.png b/public/docs/img/deployments/patterns/images/3278440.png deleted file mode 100644 index 29fb84b1dd..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278440.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278442.png b/public/docs/img/deployments/patterns/images/3278442.png deleted file mode 100644 index bf1cdc7091..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278442.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278443.png b/public/docs/img/deployments/patterns/images/3278443.png deleted file mode 100644 index 7f915e779d..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278443.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278444.png b/public/docs/img/deployments/patterns/images/3278444.png deleted file mode 100644 index 2be71c6dd6..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278444.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278468.png b/public/docs/img/deployments/patterns/images/3278468.png deleted file mode 100644 index 199e73bb8f..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278468.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278469.png b/public/docs/img/deployments/patterns/images/3278469.png deleted file mode 100644 index b073faba15..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278469.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278470.png b/public/docs/img/deployments/patterns/images/3278470.png deleted file mode 100644 index e0c9a20e5b..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278470.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278471.png b/public/docs/img/deployments/patterns/images/3278471.png deleted file mode 100644 index cdfbab5ea7..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278471.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278472.png b/public/docs/img/deployments/patterns/images/3278472.png deleted file mode 100644 index 8e9fef425c..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278472.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278473.png b/public/docs/img/deployments/patterns/images/3278473.png deleted file mode 100644 index 9987e8e7c8..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278473.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278474.png b/public/docs/img/deployments/patterns/images/3278474.png deleted file mode 100644 index 0223bceb45..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278474.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278475.png b/public/docs/img/deployments/patterns/images/3278475.png deleted file mode 100644 index 68ad04363e..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278475.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278476.png b/public/docs/img/deployments/patterns/images/3278476.png deleted file mode 100644 index 7455e5724b..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278476.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278477.png b/public/docs/img/deployments/patterns/images/3278477.png deleted file mode 100644 index 5730f9fe49..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278477.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278478.png b/public/docs/img/deployments/patterns/images/3278478.png deleted file mode 100644 index 5201ee6ded..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278478.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278479.png b/public/docs/img/deployments/patterns/images/3278479.png deleted file mode 100644 index 495af0d532..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278479.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/3278480.png b/public/docs/img/deployments/patterns/images/3278480.png deleted file mode 100644 index 9eb674a6e9..0000000000 Binary files a/public/docs/img/deployments/patterns/images/3278480.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/branching-diagram-with-ephemeral-environments.png b/public/docs/img/deployments/patterns/images/branching-diagram-with-ephemeral-environments.png new file mode 100644 index 0000000000..dc8d8c52f9 Binary files /dev/null and b/public/docs/img/deployments/patterns/images/branching-diagram-with-ephemeral-environments.png differ diff --git a/public/docs/img/deployments/patterns/images/branching-diagram-with-ephemeral-environments.png.json b/public/docs/img/deployments/patterns/images/branching-diagram-with-ephemeral-environments.png.json new file mode 100644 index 0000000000..41567454b7 --- /dev/null +++ b/public/docs/img/deployments/patterns/images/branching-diagram-with-ephemeral-environments.png.json @@ -0,0 +1 @@ +{"width":2219,"height":1091} \ No newline at end of file diff --git a/public/docs/img/deployments/patterns/images/discrete-channel-release.png b/public/docs/img/deployments/patterns/images/discrete-channel-release.png deleted file mode 100644 index 5e4000ef16..0000000000 Binary files a/public/docs/img/deployments/patterns/images/discrete-channel-release.png and /dev/null differ diff --git a/public/docs/img/deployments/patterns/images/recommended-octopus-channels.png b/public/docs/img/deployments/patterns/images/recommended-octopus-channels.png new file mode 100644 index 0000000000..90d1d35671 Binary files /dev/null and b/public/docs/img/deployments/patterns/images/recommended-octopus-channels.png differ diff --git a/public/docs/img/deployments/patterns/images/recommended-octopus-channels.png.json b/public/docs/img/deployments/patterns/images/recommended-octopus-channels.png.json new file mode 100644 index 0000000000..a109173837 --- /dev/null +++ b/public/docs/img/deployments/patterns/images/recommended-octopus-channels.png.json @@ -0,0 +1 @@ +{"width":2033,"height":1055} \ No newline at end of file diff --git a/public/docs/img/deployments/patterns/images/recommended-octopus-lifecycles.png b/public/docs/img/deployments/patterns/images/recommended-octopus-lifecycles.png new file mode 100644 index 0000000000..f223d34b68 Binary files /dev/null and b/public/docs/img/deployments/patterns/images/recommended-octopus-lifecycles.png differ diff --git a/public/docs/img/deployments/patterns/images/recommended-octopus-lifecycles.png.json b/public/docs/img/deployments/patterns/images/recommended-octopus-lifecycles.png.json new file mode 100644 index 0000000000..d669e8cc45 --- /dev/null +++ b/public/docs/img/deployments/patterns/images/recommended-octopus-lifecycles.png.json @@ -0,0 +1 @@ +{"width":1951,"height":558} \ No newline at end of file diff --git a/public/docs/img/releases/lifecycles/images/hotfix-lifecycle.png b/public/docs/img/releases/lifecycles/images/hotfix-lifecycle.png deleted file mode 100644 index b36a9c35df..0000000000 Binary files a/public/docs/img/releases/lifecycles/images/hotfix-lifecycle.png and /dev/null differ diff --git a/src/pages/docs/deployments/patterns/branching.md b/src/pages/docs/deployments/patterns/branching.md index 705687af78..f54ce54210 100644 --- a/src/pages/docs/deployments/patterns/branching.md +++ b/src/pages/docs/deployments/patterns/branching.md @@ -1,211 +1,189 @@ --- layout: src/layouts/Default.astro pubDate: 2023-01-01 -modDate: 2023-01-01 +modDate: 2026-08-25 title: Branching -description: Implementing different branching strategies with Octopus Deploy. +description: Implementing branching strategies with Octopus Deploy. navOrder: 60 --- -This section describes how different branching strategies can be modeled in Octopus Deploy. +This section describes how to best model branching strategies for Octopus Deploy. ## Branching strategies -When thinking about branching and Octopus, keep this rule in mind: +When thinking about branching and Octopus Deploy, keep these rules in mind: -> Octopus doesn't care about branches. It cares about NuGet packages. +1. The main or primary branch must always be in a production deployable state. +2. Make any changes in a short-lived branch. Merge those changes into the main or primary branch using a pull request (PR). +3. Only the main or primary branch can deploy to production. +4. Verify changes in short-lived branches and PRs by deploying them to development or ephemeral environments. +5. Build artifacts from the main or primary branch once; promote them through testing environments (QA, test, staging) until production. -Your build server cares about source code and branches, and uses them to compile and [package your application](/docs/packaging-applications). +### Recommended branching strategies -Octopus, on the other hand, only sees packages. It doesn't particularly care which branch they came from, or how they were built, or which source control system you used. +The recommended branching strategies for Octopus Deploy are: -The section below describes some common branching strategies, and what they mean in terms of NuGet packages and releases in Octopus. +- [Trunk Based Development](https://trunkbaseddevelopment.com) +- [GitHub Flow](https://docs.github.com/en/get-started/using-github/github-flow) -### No branches +Both encourage short-lived branches, a single primary or main branch, and pull requests into that single primary or main branch. -The simplest branching workflow is, of course, no branches - all developers work directly on `trunk` or the `main` (default) branch. For small projects with few developers, and when the project isn't really in "production" yet, this strategy can work well. - -:::figure -![A single trunk branch with no branching](/docs/img/deployments/patterns/images/3278438.png) +:::div{.hint} +Don't confuse GitHub Flow with [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/). GitFlow is significantly more complex. It requires multiple primary branches (develop and main), long-running feature branches, and complex merging strategies. While possible to use GitFlow with Octopus Deploy, it is not recommended nor encouraged. ::: -Builds from this single branch will produce a NuGet package, and that package goes into a release which is deployed by Octopus. +### Feature flags for unfinished changes -:::figure -![Builds from a single branch feeding releases in Octopus](/docs/img/deployments/patterns/images/3278468.png) -::: +Short-lived branches should live for no more than one or two days before being merged. Long-lived branches increase merge conflicts and bugs. However, very few features can be completed in one or two days. Hide unfinished changes from users behind feature flags. That separates deploying a new version of code from releasing new functionality to users. -### Release branches +Feature flags also enable the incremental building of new features. Each incremental addition can be deployed to production. Once the feature reaches an appropriate stage, a subset of users can try it out. That subset can be internal users, alpha customers, or beta customers. -Sometimes developers work on new features that aren't quite ready to ship, while also maintaining a current production release. Bugs can be fixed on the release branch, and deployed, without needing to also ship the half-baked features. +## Lifecycles and environments -:::figure -![A release branch alongside the main branch](/docs/img/deployments/patterns/images/3278439.png) -::: +This example uses four environments, development, test, staging, and production. The development environment is for applications who cannot use the ephemeral environments feature. -So long as one release branch never overlaps another, from an Octopus point of view, the process is similar to the "no branches" scenario above - new NuGet packages are built, and those packages go into a release, which is deployed. Octopus doesn't care that they came from a branch; to Octopus, there's just a stream of new, incrementing package versions. +The overall workflow of the build server and Octopus Deploy is: -### Multiple active release branches +:::figure -Multiple release branches may be supported over a period of time. For example, you may have customers who are using your 2.x versions of your software in production, and early adopters testing your 3.x versions while you work to make it stable. You'll need to fix bugs in the 2.x version as well as the 3.x version, and deploy them both. +:img{ src="/docs/img/deployments/patterns/images/branching-diagram-with-ephemeral-environments.png" alt="Diagram demonstrating when ephemeral environments will be used in a trunk-based or GitHub Flow based branching strategy" loading="lazy" } -:::figure -![Multiple release branches supported at the same time](/docs/img/deployments/patterns/images/3278440.png) ::: -To prevent [retention policies](/docs/administration/retention-policies) for one channel from impacting deployments for another channel, version `3.12.2` introduces the [Discrete Channel Releases setting](/docs/releases/channels/#discrete-channel-releases). Enabling this feature will also ensure that your project overview dashboard correctly shows which releases are current for each environment *in each channel*. Without this set, the default behavior is for releases across channels to supersede each other (for example, in a hotfix scenario where the `3.2.2-bugfix` is expected to override the `3.2.2` release, allowing `3.2.2` to be considered for retention policy cleanup). +To accomplish that, first create two [lifecycles](/docs/releases/lifecycles/): - ![Discrete channel release](/docs/img/deployments/patterns/images/discrete-channel-release.png) +- **Default:** development Only +- **Release:** test → staging → production -Modeling this in Octopus is a little more complicated than the scenarios above, but still easy to achieve. If the only thing that changes between branches is the NuGet package version numbers, and you create releases infrequently, then you can simply choose the correct package versions when creating a release via the release creation page: +**Disclaimer:** Include all static testing environments in the Release lifecycle required to reach production. If only test → production are required, then only include two environments. Never include the development environment. development is for testing changes from branches. :::figure -![Releases created from two branches without channels](/docs/img/deployments/patterns/images/3278469.png) -::: -If you plan to create many releases from both branches, or your deployment process is different between branches, then you will need to use channels. [Channels](/docs/releases/channels) are a feature in Octopus that lets you model differences in releases: +:img{ src="/docs/img/deployments/patterns/images/recommended-octopus-lifecycles.png" alt="Screenshot of Octopus Deploy interface showing the recommended lifecycles of default and release." loading="lazy" } -:::figure -![Channels separating 2.x and 3.x packages](/docs/img/deployments/patterns/images/3278470.png) ::: -In this example, packages that start with 2.x go to the "Stable" channel, while packages that start with 3.x go to the "Early Adopter" channel. - -:::div{.hint} -**Tip: Channels aren't branches** -When designing channels in Octopus, don't think about channels as another name for branches: - -- **Branches** can be short-lived and tend to get merged, and model the way code changes in the system. -- **Channels** are often long-lived, and model your release process. +The subsequent [channels](/docs/releases/channels) are: -For example, [Google Chrome have four different channels](https://www.chromium.org/getting-involved/dev-channel) (Stable, Beta, Dev, and Canary). Their channels are designed around user's tolerance for bleeding edge features vs. stability. Underneath, they may have many release branches contributing to those channels. +- **Default:** (uses the default lifecycle or an ephemeral environment): build artifacts require a [pre-release tag](https://docs.nuget.org/create/versioning#really-brief-introduction-to-semver). +- **Release:** (uses release lifecycle): build artifacts cannot have a pre-release tag and can only come from the main branch. -It's important to realize that **branches will map to different channels over time**. For example, right now, packages from the `release/v2` branch might map to your "Stable" channel in Octopus, while packages from `release/v3` go to your "Early Adopter" channel. - -Eventually, `release/v3` will become more and more stable, and packages from it will eventually go to your Stable channel, while `release/v4` packages will begin to go to your Early Adopter channel. -::: - -### Feature branches - -Feature branches are usually short-lived, and allow developers to work on a new feature in isolation. When the feature is complete, it is merged back to the `trunk` or the `main` (default) branch. Often, feature branches are not deployed, and so don't need to be mapped in Octopus. +The screenshot below uses ephemeral environments instead of the default lifecycle. If the project cannot support ephemeral environments, then use the default lifecycle. :::figure -![Short-lived feature branches merged back to the main branch](/docs/img/deployments/patterns/images/3278442.png) -::: -If feature branches do need to be deployed, then you can create NuGet packages from them, and then release them with Octopus as per normal. To keep feature branch packages separate from release-ready packages, [we recommend using SemVer tags](https://docs.nuget.org/create/versioning#really-brief-introduction-to-semver) in the NuGet package version. You should be able to [configure your build server to generate version numbers based on the feature branch](https://octopus.com/blog/teamcity-version-numbers-based-on-branches). +:img{ src="/docs/img/deployments/patterns/images/recommended-octopus-channels.png" alt="Screenshot of Octopus Deploy interface showing the recommended default and release channels for a specific project." loading="lazy" } -:::figure -![Feature branch packages kept separate from release-ready packages](/docs/img/deployments/patterns/images/3278443.png) ::: -Again, channels can be used to make it easier to create releases for feature branches: +## Running multiple versions in production -:::figure -![A channel used for feature branch releases](/docs/img/deployments/patterns/images/3278471.png) -::: +Some applications host multiple versions (v1.x, v2.x, v3.x, etc.) in production for backward compatibility. Deviation from the standard trunk-based development or GitHub flow is expected. -### Environment branches +- The main branch represents the latest version (v3.x) +- Separate long-lived branches for earlier versions (v1.x and v2.x) +- Each version branch is treated like a "trunk" + - Changes are made in short-lived branches that were branched off the version branch. + - Merging into those version branches requires a pull request. -A final branching strategy that we see is to use a branch per environment that gets deployed to. Code is promoted from one environment to another by merging code between branches. +Create a single [lifecycle](/docs/releases/lifecycles/): -:::figure -![A branch per environment, with code promoted by merging](/docs/img/deployments/patterns/images/3278444.png) -::: +- **Release:** test → staging → production -We do not like or recommend this strategy, as it violates the principle of [Build your Binaries Once](https://octopus.com/blog/build-your-binaries-once). +The project will have four [channels](/docs/releases/channels): -- The code that will eventually run in production may not match 100% the code run during testing. -- It's easy for a merge to go wrong and result in different code than you expected running in production. -- Packages have to be rebuilt, and different dependencies might be used. +- Default + - Uses an ephemeral environment + - Build artifacts require a pre-release tag and can only come from non-version or main branches. +- vCurrent + - Uses release lifecycle + - Build artifacts cannot have a pre-release tag + - Build artifacts must come from the main branch + - Build artifacts version must be \<= 3.x +- V2 + - Uses release lifecycle + - Build artifacts cannot have a pre-release tag + - Build artifacts must come from the v2 branch + - Build artifacts version must be between 2 and 2.999999 +- V1 + - Uses release lifecycle + - Build artifacts cannot have a pre-release tag + - Build artifacts must come from the v1 branch + - Build artifacts version must be between 1 and 1.999999 -You can make this work in Octopus, by creating a package for each environment and pushing them to environment-specific [feeds](/docs/packaging-applications/package-repositories), and then binding the NuGet feed selector in your package steps to an environment-scoped variable: +When ephemeral environments cannot be used then setup multiple static development environments. -However, on the whole, this isn't a scenario we've set out to support in Octopus, and we don't believe it's a good idea in general. +To prevent [retention policies](/docs/administration/retention-policies) for one channel from impacting deployments for another channel use the [Discrete Channel Releases setting](/docs/releases/channels/#discrete-channel-releases). Enabling this feature will also ensure that your project overview dashboard correctly shows which releases are current for each environment *in each channel*. Without this set, the default behavior is for releases across channels to supersede each other (for example, in a scenario where the `3.2.2-bugfix` is expected to override the `3.2.2` release, allowing `3.2.2` to be considered for retention policy cleanup). ## Other considerations -The above section describes common branching strategies and how they map to NuGet packages, releases and channels in Octopus. However, depending on your release process, there may be other things to consider. Below are some issues that often come up in relation to branching and Octopus. +The above section describes common branching strategies and how to configure [lifecycles](/docs/releases/lifecycles/) and [Channels](/docs/releases/channels) in Octopus. However, depending on your release process, there may be other things to consider. Below are some questions that often come up in relation to branching and Octopus. -### multiple branches can be "currently deployed" at the same time +### Different deployment process per branch -Normally in Octopus, a single release for a project is deployed to a single environment at a time - for example, only one release is "currently" in Production. When you have multiple active release branches, or sometimes even feature branches, it might be that you actually have more than one "current" release. +Sometimes a new feature introduces a new component requiring a change to the deployment process. All projects should use project [config-as-code](/docs/projects/version-control) feature. That stores the deployment process, runbooks, variables, and deployment settings in a git repo. -For example: +1. Make all the necessary changes to the deployment process, variables, and runbooks in a branch. +2. Create test releases and deploy them to an ephemeral environment or static development environment. +3. Merge those changes into the main or primary branch via a pull request. -- The stable channel is deployed to the same web servers as the Early Adopter channel, but each goes to a different IIS website. -- The stable channel and Early Adopter channels go to different web servers. -- Each feature branch goes to its own virtual directory. +Store the Octopus Deploy configuration in the same repository as the source code. Often a change to the deployment process has a corresponding code change. By using project config-as-code, both code and deployment changes are made in a branch and merged in the same pull request. -Your dashboard in Octopus should reflect this reality by displaying each channel individually: +### Hotfix lifecycles -:::figure -![A dashboard displaying each channel individually](/docs/img/deployments/patterns/images/3278472.png) -::: - -### My branches are very different, and i need my deployment process to work differently between them - -Sometimes a new branch might introduce a new component that needs to be deployed, which doesn't exist in the old branch. If you use channels, you can scope deployment steps and variables to channels to support this. +Hotfix lifecycles are often created to skip lower environments (development and test) and deploy straight to upper environments (staging and production). Often they are created because there is one lifecycle development → test → staging → production. -For example, the Rate Service package was added as part of v3, so currently only applies to the Early Adopter channel: +Do not create hotfix lifecycles. That only causes more problems. -:::figure -![The Rate Service package scoped to the Early Adopter channel](/docs/img/deployments/patterns/images/3278473.png) -::: +- Branching and Deploying + - Will the hotfix branch use an ephemeral environment for testing before going to staging? + - What will the version number be for the hotfix release? If production is 2026.8.1, does that mean the hotfix is 2026.8.1-Hotfix, 2026.8.1.1, or 2026.8.1.1-hotfix? + - The main branch is supposed to represent production. How will the appropriate hotfix be communicated to the rest of the engineering team? + - When will the hotfix changes merge into the main branch? How much of a delta is there between what is in the main branch and production? Can the fix even be merged into the main branch without serious modifications? +- testing and Risk + - What is preventing the main branch from being deployed to production? + - Were there changes already in staging that were overwritten by the hotfix? Will that impact other teams or applications? + - What steps and tests are being skipped in the test environment? + - How much time is really being saved by skipping the test environment? + - What if the hotfix requires a hotfix? How long is it acceptable to block the normal pipeline from deploying to staging → production? + - How often is the hotfix pipeline tested and verified? -Likewise, it has variables that only apply on Early Adopter: +Instead, follow the recommendation from above and create two lifecycles: -:::figure -![Variables scoped to the Early Adopter channel](/docs/img/deployments/patterns/images/3278474.png) -::: +- **Default:** development only +- **Release:** test → staging → production -For more advanced uses, you may need to clone your project. +The **Default** lifecycle represents pending work in short-lived branches. The **Release** lifecycle represents the main or primary branch. -### We sometimes need to make hotfixes that are deployed straight to staging/production - -Hotfixes are a special kind of release branch, but typically have a shorter lifecycle - they may need to go directly to production to fix a critical issue, and might skip certain deployment steps. - -Again, channels can handle this by creating a Hotfix channel, and assigning the Hotfix channel a different lifecycle: - -:::figure -![A Hotfix channel with its own lifecycle](/docs/img/deployments/patterns/images/3278475.png) -::: +### Release branches -Likewise, steps can be defined that apply to the Stable channel, but not to the Hotfix channel: +Some branching strategies recommend a long-lived release branch. -When releases are created for the Hotfix channel, they can then be deployed straight to production: +Do not use release branches unless multiple versions of the application must run in production. When that occurs, follow the recommendation below for running multiple versions in production. Otherwise, when main is always in a production deployable state, there is no need for release branches. -:::figure -![A hotfix release deployed straight to production](/docs/img/deployments/patterns/images/3278476.png) -::: +### Environment branches -While stable releases still follow the usual testing lifecycle: +Some branching strategies opt for a branch per environment strategy. -:::figure -![A stable release following the usual testing lifecycle](/docs/img/deployments/patterns/images/3278477.png) -::: +Do not use the branch per environment strategy. -### We need to deploy different components depending on whether it's a "full" release or a "partial" release - -You might have a large project with many components. Sometimes you only need to deploy a single component, while other times you may need to deploy all components together. +- The code that will eventually run in production may not match 100% the code run during testing. +- It's easy for a merge to go wrong and result in different code than you expected running in production. +- Packages have to be rebuilt, and different dependencies might be used. -This can be modeled by creating a channel per component, plus a channel for a release of all components. +### Full vs. partial releases -:::figure -![A channel per component plus a channel for a combined release](/docs/img/deployments/patterns/images/3278478.png) -::: +Often, applications have multiple components. For example, an application may have a web front-end, a API back-end, a database, and a backend service. It is unlikely every pull request into main will includes changes for all components. -Steps can then be scoped to their individual channel as well as the major release channel: +There are three options when this happens. -:::figure -![Steps scoped to their component channel and the major release channel](/docs/img/deployments/patterns/images/3278479.png) -::: +1. Create a channel for each possible combination of components. One channel for web front-end and API back-end, another channel for API back-end and database, another for the backend service and database. Scope appropriate steps to each channel. +2. Create a project for each component and a orchestration project. The orchestration project skips component unchanged component projects. +3. Have a single deployment process, but use [script steps](/docs/deployments/custom-scripts), [output variables](/docs/projects/variables/output-variables), and [variable run conditions](/docs/projects/steps/conditions/#variable-expressions) to skip unnecessary steps. The script steps run on the deployment targets and pre-check for version differences. -When creating the release, you can then choose whether the release is for an individual component or all components: +There are pros and cons with each approach. For example, a channel component allows for a single deployment process. With four components, that means 16 channels for all the possible component combinations. The build server will need extremely complex scripts to pick the right channel. A project eliminates the need for 16 channels, but introduces complexity when orchestrating each of the component's projects. Permissions and approvals become more complex. Both of those approaches assume Octopus Deploy is the truth center for what is running in production. But the actual truth center are the application hosts themselves. -:::figure -![Choosing a component channel when creating a release](/docs/img/deployments/patterns/images/3278480.png) -::: +The recommended approach is a single deployment process using [script steps](/docs/deployments/custom-scripts), [output variables](/docs/projects/variables/output-variables) and [variable run conditions](/docs/projects/steps/conditions/#variable-expressions) to skip unneeded steps. For example, have a step create a delta script for all the database changes. If no database changes are discovered then skip the database deployment step. ## Learn more diff --git a/src/pages/docs/releases/lifecycles/index.mdx b/src/pages/docs/releases/lifecycles/index.mdx index 907a7a6988..422a416d0a 100644 --- a/src/pages/docs/releases/lifecycles/index.mdx +++ b/src/pages/docs/releases/lifecycles/index.mdx @@ -46,7 +46,7 @@ When adding an environment to a phase, you can choose whether you want deploymen 1. If tenanted deployments are allowed, attempt to enqueue a new deployment for each tenant connected to the automatic-environment(s), taking the following into consideration: 1. Filter the tenants by any Tenant filter defined on the Channel for the Release being considered for deployment. - 2. Further, filter the tenants based on promotion rules (e.g. deploy to UAT before Production for this tenant) + 2. Further, filter the tenants based on promotion rules (e.g. deploy to UAT before production for this tenant) 2. If untenanted deployments are allowed, attempt to enqueue the untenanted deployment to the automatic-environment(s). ### Phases without environments @@ -150,7 +150,7 @@ This phase has the default option to manually deploy to the environment set. The Phase names usually match the environment it contains. While this is a good practice, it's not a rule. ::: -You can repeat this process to create extra phases. In this example, we are creating a phase for Testing, Staging, and Production. +You can repeat this process to create extra phases. In this example, we are creating a phase for testing, staging, and production. :::figure ![Default lifecycle phases added](/docs/img/releases/lifecycles/images/default-lifecycle-phases-added.png) @@ -162,15 +162,18 @@ This allows you to explicitly configure the default lifecycle for deploying your In this section, we cover some lifecycle examples and their included phases. -### Hotfix lifecycle +### Default and release lifecycle -A hotfix lifecycle is useful when you have a critical bug-fix that needs to be deployed quickly. In this scenario, lower environments such as Development and Testing are skipped. +By default, Octopus Deploy will include all environments in the default lifecycle, for example, development → test → staging → production. That only works if all changes are made directly on the main or primary branch and there are no other branches. -It's recommended to follow good deployment practices and validate any changes before pushing them to production. To match this, a hotfix lifecycle usually has just two phases, Staging and Production. Software with the bug fix is validated in Staging and then promoted to Production. Your lifecycle may be different to reflect how you decide to handle hotfixes. +However, most developers do their work in a branch and then merge those changes in via a pull request. For that workflow, create two [lifecycles](/docs/releases/lifecycles/): -:::figure -![Hotfix lifecycle](/docs/img/releases/lifecycles/images/hotfix-lifecycle.png) -::: +- **Default:** development only +- **Release:** test → staging → production + +**Disclaimer:** Include all static testing environments in the Release lifecycle required to reach production. If only test → production are required, then only include two environments. Never include the development environment. Development is for testing changes from branches. + +The **Default** lifecycle represents unfinished work in a branch. The **Release** lifecycle represents the main or primary branch. Unfinished work should never have a path to production. For more information please see [branching in Octopus Deploy](/docs/deployments/patterns/branching). ### Maintenance lifecycle @@ -180,7 +183,7 @@ It's recommended to follow good deployment practices and validate any changes be A Maintenance lifecycle can be used for projects that run maintenance tasks such as backups or software upgrades. This lifecycle can be used for any tasks that you want to run regularly with the same benefits that Octopus provides for your application deployments. -It typically consists of just one phase and one environment, also called Maintenance. You can include this environment in all deployment targets you want to run these tasks against. You can also split them up into the Development, Testing, Staging, and Production environments if you want to run the tasks for targets in those environments at different times. +It typically consists of just one phase and one environment, also called Maintenance. You can include this environment in all deployment targets you want to run these tasks against. You can also split them up into the development, testing, staging, and production environments if you want to run the tasks for targets in those environments at different times. :::figure ![Maintenance lifecycle](/docs/img/releases/lifecycles/images/maintenance-lifecycle.png)