documentation/wiki/ChangeWaves-Dev.md
⚠ This doc is intended for internal teams. For information about how to deal with MSBuild Change Waves as an MSBuild user, see ChangeWaves.md.
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.
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.
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.
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.
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:
Microsoft.Build.Framework project, open ChangeWaves.cs.public static readonly Version Wave17_4 = new Version(17, 4);
public static readonly Version[] AllWaves = { Wave17_0, Wave17_2, Wave17_4 };
Surround your feature with the following:
// 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.
<Target Name="SomeRiskyChange" Condition="$([MSBuild]::AreFeaturesEnabled('17.4'))">
<!-- Where '17.4' is the change wave assigned to your feature. -->
Create tests as you normally would. Include one test with environment variable MSBUILDDISABLEFEATURESFROMVERSION set to ChangeWaves.Wave17_4. Set this like so:
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:
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!");
}
These features will eventually become standard functionality. When a change wave rotates out, do the following:
Wave17_4 that was created in Creating a Change Wave.ChangeWave.AreFeaturesEnabled or [MSBuild]::AreFeaturesEnabled conditions surrounding features that were assigned that change wave.