Skip to content
Merged
6 changes: 6 additions & 0 deletions .azure-pipelines/.vsts.release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ parameters:
displayName: Dry Run (no push, no PR, no feed publish)
type: boolean
default: false
- name: useSemverBuildConfig
displayName: Use Semver Build Config to support canary rollout
type: boolean
default: false

variables:
- name: currentDate
Expand Down Expand Up @@ -134,6 +138,7 @@ extends:
- template: /ci/build-all-steps.yml@self
parameters:
os: Windows_NT
useSemverBuildConfig: ${{ parameters.useSemverBuildConfig }}

# Publish
- job: publish
Expand Down Expand Up @@ -217,4 +222,5 @@ extends:
- template: /ci/build-all-tasks.yml@self
parameters:
deploy_all_tasks: ${{ eq(parameters.task_deployment, 'Deploy all Tasks') }}
useSemverBuildConfig: ${{ parameters.useSemverBuildConfig }}

3 changes: 2 additions & 1 deletion BuildConfigGen/Debugging/VsCodeLaunchConfigGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ public void AddForTask(string taskConfigPath)
int major = versionNode["Major"]!.GetValue<int>();
int minor = versionNode["Minor"]!.GetValue<int>();
int patch = versionNode["Patch"]!.GetValue<int>();
string? build = versionNode["Build"]?.GetValue<string>() ?? null;

var version = new TaskVersion(major, minor, patch);
var version = new TaskVersion(major, minor, patch, build);

LaunchConfig.AddConfigForTask(
taskId: taskConfig["id"]!.GetValue<string>(),
Expand Down
93 changes: 81 additions & 12 deletions BuildConfigGen/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ internal static class Config
{
public static readonly string[] ExtensionsToPreprocess = new[] { ".ts", ".json" };

public record ConfigRecord(string name, string constMappingKey, bool isDefault, bool isNode, string nodePackageVersion, bool isWif, string nodeHandler, string preprocessorVariableName, bool enableBuildConfigOverrides, bool deprecated, bool shouldUpdateTypescript, bool writeNpmrc, string? overriddenDirectoryName = null, bool shouldUpdateLocalPkgs = false, bool useGlobalVersion = false, bool useAltGeneratedPath = false, bool mergeToBase = false);
public record ConfigRecord(string name, string constMappingKey, bool isDefault, bool isNode, string nodePackageVersion, bool isWif, string nodeHandler, string preprocessorVariableName, bool enableBuildConfigOverrides, bool deprecated, bool shouldUpdateTypescript, bool writeNpmrc, string? overriddenDirectoryName = null, bool shouldUpdateLocalPkgs = false, bool useGlobalVersion = false, bool useAltGeneratedPath = false, bool mergeToBase = false, bool abTaskReleases = true);

public static readonly ConfigRecord Default = new ConfigRecord(name: nameof(Default), constMappingKey: "Default", isDefault: true, isNode: false, nodePackageVersion: "", isWif: false, nodeHandler: "", preprocessorVariableName: "DEFAULT", enableBuildConfigOverrides: false, deprecated: false, shouldUpdateTypescript: false, writeNpmrc: false);
public static readonly ConfigRecord Node16 = new ConfigRecord(name: nameof(Node16), constMappingKey: "Node16-219", isDefault: false, isNode: true, nodePackageVersion: "^16.11.39", isWif: false, nodeHandler: "Node16", preprocessorVariableName: "NODE16", enableBuildConfigOverrides: true, deprecated: true, shouldUpdateTypescript: false, writeNpmrc: false);
Expand Down Expand Up @@ -86,12 +86,22 @@ public record ConfigRecord(string name, string constMappingKey, bool isDefault,
/// <param name="getTaskVersionTable"></param>
/// <param name="debugAgentDir">When set to the local pipeline agent directory, this tool will produce tasks in debug mode with the corresponding visual studio launch configurations that can be used to attach to built tasks running on this agent</param>
/// <param name="includeLocalPackagesBuildConfig">Include LocalPackagesBuildConfig</param>
static void Main(string? task = null, string? configs = null, int? currentSprint = null, bool writeUpdates = false, bool allTasks = false, bool getTaskVersionTable = false, string? debugAgentDir = null, bool includeLocalPackagesBuildConfig = false)
/// <param name="useSemverBuildConfig">If true, the semver "build" (suffix) will be generated for each task configuration produced, but all tasks configurations will have the same version (for example '1.2.3-node20' and 1.2.3-wif). The default configuration gets no build suffix (e.g. 1.2.3).</param>
static void Main(
string? task = null,
string? configs = null,
int? currentSprint = null,
bool writeUpdates = false,
bool allTasks = false,
bool getTaskVersionTable = false,
string? debugAgentDir = null,
bool includeLocalPackagesBuildConfig = false,
bool useSemverBuildConfig = false)
{
try
{
ensureUpdateModeVerifier = new EnsureUpdateModeVerifier(!writeUpdates);
MainInner(task, configs, currentSprint, writeUpdates, allTasks, getTaskVersionTable, debugAgentDir, includeLocalPackagesBuildConfig);
MainInner(task, configs, currentSprint, writeUpdates, allTasks, getTaskVersionTable, debugAgentDir, includeLocalPackagesBuildConfig, useSemverBuildConfig);
}
catch (Exception e2)
{
Expand All @@ -113,7 +123,16 @@ static void Main(string? task = null, string? configs = null, int? currentSprint
}
}

private static void MainInner(string? task, string? configs, int? currentSprintNullable, bool writeUpdates, bool allTasks, bool getTaskVersionTable, string? debugAgentDir, bool includeLocalPackagesBuildConfig)
private static void MainInner(
string? task,
string? configs,
int? currentSprintNullable,
bool writeUpdates,
bool allTasks,
bool getTaskVersionTable,
string? debugAgentDir,
bool includeLocalPackagesBuildConfig,
bool useSemverBuildConfig)
{
if (allTasks)
{
Expand Down Expand Up @@ -313,7 +332,18 @@ private static void MainInner(string? task, string? configs, int? currentSprintN
{
IEnumerable<string> configsList = FilterConfigsForTask(configs, t);

MainUpdateTask(taskVersionInfo[t.Value.Name], t.Value.Name, configsList, writeUpdates, currentSprint, debugConfGen, includeLocalPackagesBuildConfig, hasGlobalVersion: globalVersion is not null, generatedFolder: generatedFolder, altGeneratedFolder: altGeneratedFolder);
MainUpdateTask(
taskVersionInfo[t.Value.Name],
t.Value.Name,
configsList,
writeUpdates,
currentSprint,
debugConfGen,
includeLocalPackagesBuildConfig,
hasGlobalVersion: globalVersion is not null,
generatedFolder: generatedFolder,
altGeneratedFolder: altGeneratedFolder,
useSemverBuildConfig: useSemverBuildConfig);
}

debugConfGen.WriteLaunchConfigurations();
Expand Down Expand Up @@ -464,6 +494,7 @@ private static void GetVersions(string task, string configsString, out List<(str
string gitRootPath = GetTasksRootPath(currentDir);

string taskTargetPath = Path.Combine(gitRootPath, "Tasks", task);

if (!Directory.Exists(taskTargetPath))
{
throw new Exception($"expected {taskTargetPath} to exist!");
Expand Down Expand Up @@ -572,7 +603,8 @@ private static void MainUpdateTask(
bool includeLocalPackagesBuildConfig,
bool hasGlobalVersion,
string generatedFolder,
string altGeneratedFolder)
string altGeneratedFolder,
bool useSemverBuildConfig)
{
if (string.IsNullOrEmpty(task))
{
Expand Down Expand Up @@ -717,7 +749,18 @@ private static void MainUpdateTask(
WriteWIFInputTaskJson(taskOutput, config, "task.json", isLoc: false);
WriteWIFInputTaskJson(taskOutput, config, "task.loc.json", isLoc: true);

if (!config.mergeToBase)
if (useSemverBuildConfig && !config.mergeToBase)
{
var defaultConfig = targetConfigs.FirstOrDefault(x => x.isDefault);
if (defaultConfig == null)
{
throw new Exception($"There is no default config for task {task}");
}

WriteTaskJson(taskOutput, taskVersionState, config, "task.json", existingLocalPackageVersion, useSemverBuildConfig: true, defaultConfig: defaultConfig);
WriteTaskJson(taskOutput, taskVersionState, config, "task.loc.json", existingLocalPackageVersion, useSemverBuildConfig: true, defaultConfig: defaultConfig);
}
else if (!config.mergeToBase)
{
WriteTaskJson(taskOutput, taskVersionState, config, "task.json", existingLocalPackageVersion);
WriteTaskJson(taskOutput, taskVersionState, config, "task.loc.json", existingLocalPackageVersion);
Expand Down Expand Up @@ -1048,7 +1091,12 @@ private static void PreprocessIfExtensionEnabledInConfig(string file, Config.Con
return outputTaskNodeObject["_buildConfigMapping"]?.AsObject()?[Config.LocalPackages.constMappingKey]?.GetValue<string>();
}

private static void WriteTaskJson(string taskPath, TaskStateStruct taskState, Config.ConfigRecord config, string fileName, string? existingLocalPackageVersion)
/// <summary>
/// Writes task.json with version information and build config mapping.
/// When useSemverBuildConfig is true, uses the same major.minor.patch for all build configuration tasks,
/// but the "build" suffix of semver is different and directly corresponds to the config name.
/// </summary>
private static void WriteTaskJson(string taskPath, TaskStateStruct taskState, Config.ConfigRecord config, string fileName, string? existingLocalPackageVersion, bool useSemverBuildConfig = false, Config.ConfigRecord? defaultConfig = null)
{
string outputTaskPath = Path.Combine(taskPath, fileName);
JsonNode outputTaskNode = JsonNode.Parse(ensureUpdateModeVerifier!.FileReadAllText(outputTaskPath))!;
Expand All @@ -1057,6 +1105,12 @@ private static void WriteTaskJson(string taskPath, TaskStateStruct taskState, Co
outputTaskNode["version"]!["Minor"] = taskState.configTaskVersionMapping[config].Minor;
outputTaskNode["version"]!["Patch"] = taskState.configTaskVersionMapping[config].Patch;

// Add semver build suffix if using semver config and not the default config
if (useSemverBuildConfig && defaultConfig != null && defaultConfig != config)
{
outputTaskNode["version"]!["Build"] = config.constMappingKey;
}

var outputTaskNodeObject = outputTaskNode.AsObject();
outputTaskNodeObject.Remove("_buildConfigMapping");

Expand Down Expand Up @@ -1305,7 +1359,6 @@ private static void UpdateVersionsForTask(string task, TaskStateStruct taskState
string currentDir = Environment.CurrentDirectory;
string gitRootPath = GetTasksRootPath(currentDir);
string taskTargetPath = Path.Combine(gitRootPath, "Tasks", task);

if (!Directory.Exists(taskTargetPath))
{
throw new Exception($"expected {taskTargetPath} to exist!");
Expand Down Expand Up @@ -1481,6 +1534,13 @@ private static void UpdateVersionsForTask(string task, TaskStateStruct taskState
}
while (taskState.configTaskVersionMapping.Values.Contains(targetVersion));

if (config.abTaskReleases)
{
// In the first stage of refactoring, we keep different version numbers to retain the ability to rollback.
// In the second stage of refactoring, we are going to use the same version, which is going to significantly reduce complexity of all this.
targetVersion = targetVersion.CloneWithBuild(config.constMappingKey);
}

taskState.configTaskVersionMapping.Add(config, targetVersion);

if (!taskState.versionsUpdated.Contains(config))
Expand Down Expand Up @@ -1555,11 +1615,20 @@ private static void UpdateVersionsGlobal(string task, TaskStateStruct taskState,
{
if (config.useGlobalVersion)
{
TaskVersion versionToUse = globalVersion;

if (config.abTaskReleases)
{
// In the first stage of refactoring, we keep different version numbers to retain the ability to rollback.
// In the second stage of refactoring, we are going to use the same version, which is going to significantly reduce complexity of all this.
versionToUse = globalVersion.CloneWithBuild(config.constMappingKey);
}

if (taskState.configTaskVersionMapping.ContainsKey(config))
{
if (taskState.configTaskVersionMapping[config] != globalVersion)
if (taskState.configTaskVersionMapping[config] != versionToUse)
{
taskState.configTaskVersionMapping[config] = globalVersion;
taskState.configTaskVersionMapping[config] = versionToUse;

if (!taskState.versionsUpdated.Contains(config))
{
Expand All @@ -1569,7 +1638,7 @@ private static void UpdateVersionsGlobal(string task, TaskStateStruct taskState,
}
else
{
taskState.configTaskVersionMapping.Add(config, globalVersion);
taskState.configTaskVersionMapping.Add(config, versionToUse);

if (!taskState.versionsUpdated.Contains(config))
{
Expand Down
4 changes: 4 additions & 0 deletions BuildConfigGen/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
"BuildConfigGen": {
"commandName": "Project",
"commandLineArgs": "--all-tasks --write-updates"
},
"BuildConfigGenNew": {
"commandName": "Project",
"commandLineArgs": "--use-semver-build-config --all-tasks --write-updates"
}
}
}
Loading