Back to Msbuild

What are Change Waves?

documentation/wiki/ChangeWaves-Dev.md

18.4.05.2 KB
Original Source

⚠ This doc is intended for internal teams. For information about how to deal with MSBuild Change Waves as an MSBuild user, see ChangeWaves.md.

What are Change Waves?

A Change Wave is a set of risky features developed under the same opt-out flag. The purpose of this is to warn developers of risky changes that will become standard functionality down the line. If there's something we think is worth the risk, we found that Change Waves were a good middle ground between making necessary changes and warning customers of what will soon be permanent.

Why Opt-Out vs. Opt-In?

Opt-out is a better approach for us because we'd likely get limited feedback when a feature impacts customer builds. When a feature does impact a customer negatively, it's a quick switch to disable and allows time to adapt. The key aspect to Change Waves is that it smooths the transition for customers adapting to risky changes that the MSBuild team feels strongly enough to take.

How do They Work?

The opt-out comes in the form of setting the environment variable MSBUILDDISABLEFEATURESFROMVERSION to the Change Wave (or version) that contains the feature you want disabled. This version happens to be the version of MSBuild that the features were developed for. See the mapping of change waves to features below.

Choosing a Change Wave for a New Feature

Use the change wave for the currently-in-development version of MSBuild, as specified in eng/Versions.props. This version corresponds to the latest version of Visual Studio. Create a new change wave if there isn't one for this version of MSBuild yet. For example, if you're developing a feature for MSBuild 18.6, you should use Wave18_6 or create it if it doesn't exist.

Developing With Change Waves in Mind

For the purpose of providing an example, the rest of this document assumes we're developing a feature for MSBuild version 17.3.

The Process:

  1. Develop your feature.
  2. Create the Change Wave (if necessary)
  3. Condition your feature on that Change Wave
  4. Test your feature
  5. Document it
  6. Delete the wave as it cycles out

Creating a Change Wave

  1. In the Microsoft.Build.Framework project, open ChangeWaves.cs.
  2. Add a static readonly Version to identify the new wave, following the format:
c#
public static readonly Version Wave17_4 = new Version(17, 4);
  1. Update the AllWaves array appropriately.
c#
public static readonly Version[] AllWaves = { Wave17_0, Wave17_2, Wave17_4 };

Condition Your Feature On A Change Wave

Surround your feature with the following:

c#
    // If you pass an incorrectly formatted change wave, this will throw.
    // Use the readonly Version that was created in the previous step.
    if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_4))
    {
        <your feature>
    }

If you need to condition a Task or Target, use the built in AreFeaturesEnabled function.

xml
<Target Name="SomeRiskyChange" Condition="$([MSBuild]::AreFeaturesEnabled('17.4'))">
<!-- Where '17.4' is the change wave assigned to your feature. -->

Test Your Feature

Create tests as you normally would. Include one test with environment variable MSBUILDDISABLEFEATURESFROMVERSION set to ChangeWaves.Wave17_4. Set this like so:

c#
using TestEnvironment env = TestEnvironment.Create();

ChangeWaves.ResetStateForTests();
// Important: use the version here
env.SetEnvironmentVariable("MSBUILDDISABLEFEATURESFROMVERSION", ChangeWaves.Wave17_4.ToString());
BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();

Important! If you need to build a project to test your feature (say, for tasks or targets), build via ProjectCollection in your test.

Example:

c#
using (TestEnvironment env = TestEnvironment.Create())
{
    ChangeWaves.ResetStateForTests();
    env.SetEnvironmentVariable("MSBUILDDISABLEFEATURESFROMVERSION", ChangeWaves.Wave17_4.ToString());
    BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();

    string projectFile = @"
        <Project>
            <Target Name='HelloWorld' Condition=""$([MSBuild]::AreFeaturesEnabled('17.4'))"">
                <Message Text='Hello World!'/>
            </Target>
        </Project>";

    TransientTestFile file = env.CreateFile("proj.csproj", projectFile);

    ProjectCollection collection = new ProjectCollection();
    MockLogger log = new MockLogger();
    collection.RegisterLogger(log);

    collection.LoadProject(file.Path).Build().ShouldBeTrue();
    log.AssertLogContains("Hello World!");
}

Change Wave 'End-of-Lifespan' Procedure

These features will eventually become standard functionality. When a change wave rotates out, do the following:

  1. Start by deleting the readonly Wave17_4 that was created in Creating a Change Wave.
  2. Remove ChangeWave.AreFeaturesEnabled or [MSBuild]::AreFeaturesEnabled conditions surrounding features that were assigned that change wave.
  3. Remove tests associated with ensuring features would not run if this wave were set.
  4. Clear all other issues that arose from deleting the version.
  5. Inspect for dead code that can be removed now that the change wave is deleted.