diff --git a/ReleaseBuilder/Build/Command.Upload.cs b/ReleaseBuilder/Build/Command.Upload.cs index d75cc2af8..c311f5bbb 100644 --- a/ReleaseBuilder/Build/Command.Upload.cs +++ b/ReleaseBuilder/Build/Command.Upload.cs @@ -106,8 +106,9 @@ public static partial class Command /// /// The files to upload /// The runtime configuration + /// The release channels to propagate to /// An awaitable task - public static async Task UploadToS3(IEnumerable files, RuntimeConfig rtcfg) + public static async Task UploadToS3(IEnumerable files, RuntimeConfig rtcfg, IEnumerable propagateTo) { var totalSize = files.Sum(f => new FileInfo(f.Path).Length); Console.WriteLine($"Uploading {files.Count()} files ({Duplicati.Library.Utility.Utility.FormatSizeString(totalSize)}) to S3..."); @@ -141,6 +142,22 @@ public static partial class Command size += filesize; Console.WriteLine($"{size / (double)totalSize * 100:F1}% - Uploaded {file.Name} ({Duplicati.Library.Utility.Utility.FormatSizeString(filesize)})"); } + + foreach (var channel in propagateTo) + { + if (channel == rtcfg.ReleaseInfo.Channel) + continue; + + var target = $"{channel.ToString().ToLowerInvariant()}/latest-v2.manifest"; + var source = $"{rtcfg.ReleaseInfo.Channel.ToString().ToLowerInvariant()}/latest-v2.manifest"; + await Duplicati.Library.Utility.RetryHelper.Retry(() => + client.CopyObjectAsync( + Program.Configuration.ConfigFiles.AwsUploadBucket, + source, + Program.Configuration.ConfigFiles.AwsUploadBucket, + target + ), 3, TimeSpan.FromSeconds(1), CancellationToken.None); + } } /// @@ -214,7 +231,7 @@ public static partial class Command /// /// The runtime configuration /// An awaitable task - public static async Task ReloadUpdateServer(RuntimeConfig rtcfg) + public static async Task ReloadUpdateServer(RuntimeConfig rtcfg, IEnumerable propagateTo) { using var client = new HttpClient(); var req = new HttpRequestMessage(HttpMethod.Post, "https://updates.duplicati.com/reload"); @@ -225,7 +242,7 @@ public static partial class Command $"{rtcfg.ReleaseInfo.Channel.ToString().ToLowerInvariant()}/latest-v2.json", $"{rtcfg.ReleaseInfo.Channel.ToString().ToLowerInvariant()}/latest-v2.js", $"{rtcfg.ReleaseInfo.Channel.ToString().ToLowerInvariant()}/latest-v2.manifest", - }); + }.Concat(propagateTo.Select(c => $"{c.ToString().ToLowerInvariant()}/latest-v2.manifest"))); var response = await client.SendAsync(req); response.EnsureSuccessStatusCode(); diff --git a/ReleaseBuilder/Build/Command.cs b/ReleaseBuilder/Build/Command.cs index 84c25fb60..d0de3a4b9 100644 --- a/ReleaseBuilder/Build/Command.cs +++ b/ReleaseBuilder/Build/Command.cs @@ -299,6 +299,12 @@ public static partial class Command getDefaultValue: () => false ); + var propagateReleaseOption = new Option( + name: "--propagate-release", + description: "Propagate the release to the next channel", + getDefaultValue: () => false + ); + var command = new System.CommandLine.Command("build", "Builds the packages for a release") { gitStashPushOption, releaseChannelArgument, @@ -322,7 +328,8 @@ public static partial class Command disableUpdateServerReloadOption, disableDiscordAnnounceOption, useHostedBuildsOption, - resumeFromUploadOption + resumeFromUploadOption, + propagateReleaseOption }; command.Handler = CommandHandler.Create(DoBuild); @@ -355,6 +362,7 @@ public static partial class Command /// If forum posting should be disabled /// If hosted builds should be used /// If the process should resume from the upload step + /// If the release should be propagated to the next channel record CommandInput( PackageTarget[] Targets, DirectoryInfo BuildPath, @@ -378,7 +386,8 @@ public static partial class Command bool DisableUpdateServerReload, bool DisableDiscordAnnounce, bool UseHostedBuilds, - bool ResumeFromUpload + bool ResumeFromUpload, + bool PropagateRelease ); static async Task DoBuild(CommandInput input) @@ -619,6 +628,13 @@ public static partial class Command if (input.GitStashPush && !input.ResumeFromUpload) await GitPush.TagAndPush(baseDir, releaseInfo); + // Propagate the release to the next channel, if selected + var nextChannels = new[] { ReleaseChannel.Experimental, ReleaseChannel.Beta, ReleaseChannel.Stable } + .Where(x => x > releaseInfo.Channel) + .Where(x => rtcfg.ReleaseInfo.Channel != ReleaseChannel.Canary) + .Where(x => input.PropagateRelease) + .ToArray(); + if (rtcfg.UseS3Upload || rtcfg.UseGithubUpload) { Console.WriteLine("Build completed, uploading packages ..."); @@ -636,7 +652,7 @@ public static partial class Command .Append(new Upload.UploadFile(packageJson, Path.GetFileName(packageJson))) .Append(new Upload.UploadFile(packageJson, $"latest-v2-{releaseInfo.Version}.json")); - await Upload.UploadToS3(uploads, rtcfg); + await Upload.UploadToS3(uploads, rtcfg, nextChannels); } if (rtcfg.UseGithubUpload) @@ -657,7 +673,7 @@ public static partial class Command if (rtcfg.UseUpdateServerReload) { Console.WriteLine("Release completed, reloading update server ..."); - await Upload.ReloadUpdateServer(rtcfg); + await Upload.ReloadUpdateServer(rtcfg, nextChannels); } if (rtcfg.UseForumPosting)