Skip to content

Versioning and Release Process

Chiara Mooney edited this page Jul 14, 2021 · 5 revisions

Consumption of React Native Windows has not always been a pleasant experience. Consumers frequently experience undocumented breaking changes, trading regressions based on build, and the inability to use currently supported versions of React Native.

Engineers on RNW have faced their own set of issues such as painful integration with stock React Native (upstream) and high costs of breaking changes.

This document outlines how changes to our branch structure, versioning, integration, and release processes can help meet the needs of consumers and engineers.

Goals

  • Give our consumers high quality releases: We should provide customers with stable builds throughout the lifetime of them installing and upgrading a major version.
  • Don't burn out engineers: Our process shouldn't create unnecessary stress for engineers working on RNW.
  • Enable interactivity between us and stock RN: We should be able to quickly push changes to React Native and receive them in React Native Windows.
  • Allow agility to unblock customers: We should do our best to minimize the latency between customers discovering issues and our ability to fix them.
  • Lower the impact of breaking changes: We should dampen the effect of breaking changes to help both engineers and consumers.

Non-Goals

  • Full Feature Parity with the Corresponding React Native Release: We do not implement the entire React Native API surface, or its full feature set. We should strive to support as much functionality as possible but cannot hold ourselves to parity. Some features stock features may be implemented in later versions of RNW.
  • Isolation from upstream breaks during development: We need to catch upstream changes that break us quickly. This means integrating rawer code into our development branch, given it passes our automated coverage. These builds may not always be as stable as current the builds we use.

Isolating Instability from Consumers

Our drops previously corresponded directly to commits in our master branch. All package versions were marked using prerelease semver and breaking changes could come at any time without documentation. Show-stopping bugs within our development branch have been common, such as frequent crashes, inability to deploy apps, or the inability for users to build. Isolating consumers from our master branch gives us more control over release quality and breaking changes. This is achieved by regularly creating "stable branches" from our master branch which represent a user-visible version.

Release Distributions

This branching and stabilization process has led to three release distributions with corresponding npm package distribution tags:

  1. Canary (@canary)
  2. Preview (@preview)
  3. Latest (@latest)

canary builds are built directly from our master branch. These builds provide no guarantees around upstream React version, breaking changes, or overall stability. These builds should be used for development or to test bleeding edge functionality but should not be relied upon for production use. Master builds are versioned as 0.0.0-canary.x.

preview builds are the first released by stable branches. These builds aim to become increasingly polished over time and have fewer breaking changes than in canary. react-native-windows-init will work out of the box with preview builds when none else are available, but will warn users before installing them. Preview builds are versioned as 0.x.0-preview.y, where x matches the minor release of React Native.

latest builds corresponding to our "released" version. Breaking changes should not be made to stable branches after promotion to latest. Caution must be taken to not compromise the stability of our non-prerelease branches. Only low risk changes critical to customer scenarios should be backported. Released builds are versioned as 0.x.y where x matches the minor release of React Native.

Branch Cadence

Each stable RNW branch will correspond to a stable branch of React Native. Branching will occur at fixed points. When React Native Windows is aligned to Facebook's tip of master, our branch points will correspond to those used by Facebook for upstream stable branches.

Before React Native Windows is caught up to the tip of master we will set and communicate branch dates before the start of the major version. This date must be kept firm due to the large effect of branch time on catching up (see below).

After branching, a release is kept in preview for a targeted amount of time. That time may be extended if showstoppers are present but should optimally not overlap with another preview.

Communication of Lifecycle

The introduction of accurate, mutually understood dates gives predictability to engineers and partners a better ability to plan their work around us. This is especially important with our releases carrying fixes to unblock them.

We should communicate both the branch date and ship date to RNW engineers, partners, and the public at the start of a branch cycle.

Manual Validation

Our automated test coverage is currently limited. RNW must be manually validate in the meantime. This validation should happen before publishing the first preview to create an inventory of known issues, then again soon before final release.

Examples of Scenarios and Test Collateral:

  • Playground and Playground Win32 as Native Bits
  • Interaction with RNTester Controls Gallery
  • C++ and C# Sample apps
  • OSS RNW Projects
  • Upgrading from a previous version
  • Sample apps in the samples repo (see upgrade procedure)
  • React Native Gallery

We should consider doing group test passes to gain extra coverage and expand engineer understanding of customer scenarios.

Backporting Policy Throughout Release

Backporting policy needs to balance the needs of stability and feature completeness. Policy must become increasingly strict throughout the life of a version.

Engineers can request backporting a change by adding the “Request Backport” to their PRs. A “Backported to 0.xx” label will be added if the change is backported. Some changes may not be backported depending on the described criteria:

Phase 1 (First two weeks into preview)

  • All changes will be accepted for backport
  • Breaking changes are allowed, but discouraged

Phase 2 (Rest of preview)

  • Changes will go through a triage process which becomes increasingly strict
  • Only changes critical to customer scenarios will be accepted
  • Breaking changes may still be allowed depending on severity

Stable Releases

  • Triage increases in strictness
  • Breaking changes may only be made to APIs clearly documented as experimental

Breaking Changes and Release Notes

PRs with breaking changes should have the “Breaking Change” label. This includes anything that modifies public APIs, changes requirements, or changes the template project. These changes will be scrubbed at release time to create a consumer-readable list of changes.

We currently automatically generate daily changelogs in markdown. These are generally based on commit names and are not high enough quality to serve as primary documentation. We should scrub through this changelog to pick out consumer readable notes to be published. These should be shared at the time of first preview, and after release. These changes should be reflected in the public React Native at Microsoft documentation site and announced internally.

Documentation

With each new React Native Windows release, should also come a new update of the documentation found on the React Native for Windows + MacOS website. Instructions for how to update the documentation following the cut of a new React Native Windows version can be found by following these steps: Cutting Documentation for New React Native Windows Release.

Integration with Upstream

Facebook started publishing nightly builds of the React Native master branch starting slightly before 0.63. Our master branch will integrate against these daily builds instead of Facebook stable releases. This integration will be tool-assisted before we catch up to Facebook master, and largely automatic after. Metrics will be collected during tool-assisted daily upgrades to inform us of the types of issues we should address before automatic integration. Our stable branches use Facebook stable releases instead of nightly builds.

Once targeting master, we will want to keep our branch relatively in sync with Facebook’s master branch. This is not always possible, such as cases where breaking API changes are made. As a north star we should aim to not ever be more than a week behind Facebook’s master. This may sometimes mean temporary solutions to unblock integration, with longer-term solutions scheduled out.

Catching up to Facebook Master

We need to create branches for new versions of React Native Windows faster than upstream spent on developing the branch.

Using 4 month upstream releases as a basis:

  • Branching every 4 months: Impossible to catch up to master
  • Branching every 3 months: 15 months to catch up to master
  • Branching every 2 months: 5 months to catch up to master

Special consideration must be taken combining short release cycles with the above goal of "Don't burn out engineers". We will not be able to accomplish as much as previously in a shorter period, and it is likely not all goals will make our initial target. We must be liberal in delaying incomplete work to the next release. Shorter upstream release cycles can minimize the latency of these changes.

Refining the Process

This process is non-final, and we should continually iterate to balance the conflicting needs of stability, feature completeness, agility, and engineering effort.

There are multiple signals to watch for during the process:

  1. Users seeing breaks mid-release
  2. Taking unreasonably long to unblock customers
  3. Our master branch being too unstable for development
  4. Overlapping previews
  5. Excess intervention required for integration
  6. Integration lags too far behind expectations within a cycle
  7. Increased time to complete feature work
  8. Engineer confusion on release timelines, triage bar
  9. Lack of partner validation of previews

These signals can help inform release cadence, direction of tooling, communication practices, and CI investment. These should be reviewed in a retrospective at the conclusion of a branch cycle to better inform the process when planning for the next version.