From df939a4334696f9fa4e2fc97089c221a19732fb8 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Mon, 14 Apr 2025 21:56:27 +0200 Subject: [PATCH 01/14] Add tests to build releases This adds a CI test for building releases so we know in advance if package versions are out-of-order. This also sets the primary project for CLI to the Server as that covers more than the CLI project. --- .github/workflows/build-packages.yml | 32 ++++++++++++++++++++++++++++ ReleaseBuilder/Build/Command.cs | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build-packages.yml diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml new file mode 100644 index 000000000..6633ea09c --- /dev/null +++ b/.github/workflows/build-packages.yml @@ -0,0 +1,32 @@ +name: Tests + +on: [pull_request, workflow_dispatch] + +jobs: + build_packages: + name: Build packages + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - name: Set up .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.x + + - name: Checkout source + uses: actions/checkout@v4 + + - name: Compile releases + run: dotnet run ReleaseBuilder/ReleaseBuilder.sln -- build debug --build-only=true --git-stash-push=false --disable-docker-push=true --keep-builds=true --disable-authenticode=true --disable-signcode=true --disable-notarize-signing=true --disable-gpg-signing=true --disable-s3-upload=true --disable-github-upload=true --disable-update-server-reload=true --disable-discourse-announce=true --disable-clean-source=true --password=test1234 --version=2.0.0.99 + + # Disabled, as a new test needs to be written for the new UI + # selenium: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + # - name: Selenium + # run: pipeline/selenium/test.sh diff --git a/ReleaseBuilder/Build/Command.cs b/ReleaseBuilder/Build/Command.cs index 6ec431a55..6d2a3cb35 100644 --- a/ReleaseBuilder/Build/Command.cs +++ b/ReleaseBuilder/Build/Command.cs @@ -41,7 +41,7 @@ public static partial class Command /// /// The primary project to build for CLI builds /// - private const string PrimaryCLIProject = "Duplicati.CommandLine.csproj"; + private const string PrimaryCLIProject = "Duplicati.Server.csproj"; /// /// The primary project to build for Agent builds From 512c109ed1c824f43a7bfb52a8b5d5c336a0c314 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Mon, 14 Apr 2025 21:59:51 +0200 Subject: [PATCH 02/14] Fixed path to project --- .github/workflows/build-packages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml index 6633ea09c..18671ba31 100644 --- a/.github/workflows/build-packages.yml +++ b/.github/workflows/build-packages.yml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v4 - name: Compile releases - run: dotnet run ReleaseBuilder/ReleaseBuilder.sln -- build debug --build-only=true --git-stash-push=false --disable-docker-push=true --keep-builds=true --disable-authenticode=true --disable-signcode=true --disable-notarize-signing=true --disable-gpg-signing=true --disable-s3-upload=true --disable-github-upload=true --disable-update-server-reload=true --disable-discourse-announce=true --disable-clean-source=true --password=test1234 --version=2.0.0.99 + run: dotnet run --project ReleaseBuilder/ReleaseBuilder.csproj -- build debug --build-only=true --git-stash-push=false --disable-docker-push=true --keep-builds=true --disable-authenticode=true --disable-signcode=true --disable-notarize-signing=true --disable-gpg-signing=true --disable-s3-upload=true --disable-github-upload=true --disable-update-server-reload=true --disable-discourse-announce=true --disable-clean-source=true --password=test1234 --version=2.0.0.99 # Disabled, as a new test needs to be written for the new UI # selenium: From 6c8a1cb4905cbcbc3d039121a948b756ac49146c Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Mon, 14 Apr 2025 22:03:23 +0200 Subject: [PATCH 03/14] Setting working folder --- .github/workflows/build-packages.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml index 18671ba31..669534145 100644 --- a/.github/workflows/build-packages.yml +++ b/.github/workflows/build-packages.yml @@ -21,7 +21,8 @@ jobs: uses: actions/checkout@v4 - name: Compile releases - run: dotnet run --project ReleaseBuilder/ReleaseBuilder.csproj -- build debug --build-only=true --git-stash-push=false --disable-docker-push=true --keep-builds=true --disable-authenticode=true --disable-signcode=true --disable-notarize-signing=true --disable-gpg-signing=true --disable-s3-upload=true --disable-github-upload=true --disable-update-server-reload=true --disable-discourse-announce=true --disable-clean-source=true --password=test1234 --version=2.0.0.99 + working-directory: ./ReleaseBuilder + run: dotnet run -- build debug --build-only=true --git-stash-push=false --disable-docker-push=true --keep-builds=true --disable-authenticode=true --disable-signcode=true --disable-notarize-signing=true --disable-gpg-signing=true --disable-s3-upload=true --disable-github-upload=true --disable-update-server-reload=true --disable-discourse-announce=true --disable-clean-source=true --password=test1234 --version=2.0.0.99 # Disabled, as a new test needs to be written for the new UI # selenium: From e30fbf56138e704c478ea4b5d8fb552df5e99b91 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Mon, 14 Apr 2025 22:14:06 +0200 Subject: [PATCH 04/14] Renamed `build-only` to `compile-only`. More flexible setup for compile-only runs. --- .github/workflows/build-packages.yml | 2 +- ReleaseBuilder/Build/Command.RuntimeConfig.cs | 8 +++++ ReleaseBuilder/Build/Command.cs | 35 +++++++++++-------- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml index 669534145..c1e452cef 100644 --- a/.github/workflows/build-packages.yml +++ b/.github/workflows/build-packages.yml @@ -22,7 +22,7 @@ jobs: - name: Compile releases working-directory: ./ReleaseBuilder - run: dotnet run -- build debug --build-only=true --git-stash-push=false --disable-docker-push=true --keep-builds=true --disable-authenticode=true --disable-signcode=true --disable-notarize-signing=true --disable-gpg-signing=true --disable-s3-upload=true --disable-github-upload=true --disable-update-server-reload=true --disable-discourse-announce=true --disable-clean-source=true --password=test1234 --version=2.0.0.99 + run: dotnet run -- build debug --compile-only=true --git-stash-push=false --disable-docker-push=true --keep-builds=true --disable-authenticode=true --disable-signcode=true --disable-notarize-signing=true --disable-gpg-signing=true --disable-s3-upload=true --disable-github-upload=true --disable-update-server-reload=true --disable-discourse-announce=true --disable-clean-source=true --password=test1234 --version=2.0.0.99 # Disabled, as a new test needs to be written for the new UI # selenium: diff --git a/ReleaseBuilder/Build/Command.RuntimeConfig.cs b/ReleaseBuilder/Build/Command.RuntimeConfig.cs index b78a40504..97f556936 100644 --- a/ReleaseBuilder/Build/Command.RuntimeConfig.cs +++ b/ReleaseBuilder/Build/Command.RuntimeConfig.cs @@ -211,6 +211,14 @@ public static partial class Command } } + /// + /// Disables docker builds + /// + public void DisableDockerBuilds() + { + _dockerBuild = false; + } + /// /// Cache value for checking if notarize is enabled /// diff --git a/ReleaseBuilder/Build/Command.cs b/ReleaseBuilder/Build/Command.cs index 6d2a3cb35..d9ee5c90e 100644 --- a/ReleaseBuilder/Build/Command.cs +++ b/ReleaseBuilder/Build/Command.cs @@ -191,8 +191,8 @@ public static partial class Command getDefaultValue: () => false ); - var buildOnlyOption = new Option( - name: "--build-only", + var compileOnlyOption = new Option( + name: "--compile-only", description: "Only build the binaries, do not create packages", getDefaultValue: () => false ); @@ -332,7 +332,7 @@ public static partial class Command buildTargetOption, solutionFileOption, keepBuildsOption, - buildOnlyOption, + compileOnlyOption, disableAuthenticodeOption, disableCodeSignOption, passwordOption, @@ -369,7 +369,7 @@ public static partial class Command /// The release channel /// The version override to use /// If the builds should be kept - /// If only the build should be performed + /// If only the build should be performed /// If authenticode signing should be disabled /// If signcode should be disabled /// The password to use for the keyfile @@ -397,7 +397,7 @@ public static partial class Command ReleaseChannel Channel, string? Version, bool KeepBuilds, - bool BuildOnly, + bool CompileOnly, bool DisableAuthenticode, bool DisableSignCode, string Password, @@ -433,7 +433,7 @@ public static partial class Command throw new FileNotFoundException($"Solution file not found: {input.SolutionFile.FullName}"); // This could be fixed, so we will throw an exception if the build is not possible - if (buildTargets.Any(x => x.Package == PackageType.MSI) && !configuration.IsMSIBuildPossible()) + if (buildTargets.Any(x => x.Package == PackageType.MSI) && !configuration.IsMSIBuildPossible() && !input.CompileOnly) throw new Exception("WiX toolset not configured, cannot build MSI files"); // This will be fixed in the future, but requires a new http-interface for Synology DSM @@ -441,7 +441,7 @@ public static partial class Command throw new Exception("Synology SPK files are currently not supported"); // This will not work, so to make it easier for non-MacOS developers, we will remove the MacOS packages - if (buildTargets.Any(x => x.Package == PackageType.MacPkg || x.Package == PackageType.DMG) && !configuration.IsMacPkgBuildPossible()) + if (buildTargets.Any(x => x.Package == PackageType.MacPkg || x.Package == PackageType.DMG) && !configuration.IsMacPkgBuildPossible() && !input.CompileOnly) { Console.WriteLine("MacOS packages requested but not running on MacOS, removing from build targets"); buildTargets = buildTargets.Where(x => x.Package != PackageType.MacPkg && x.Package != PackageType.DMG).ToArray(); @@ -532,13 +532,20 @@ public static partial class Command rtcfg.ToggleGithubUpload(rtcfg.ReleaseInfo.Channel); rtcfg.ToogleDiscourseAnnounce(rtcfg.ReleaseInfo.Channel); rtcfg.ToggleUpdateServerReload(); - await rtcfg.ToggleDockerBuild(); - - if (!rtcfg.UseDockerBuild) + if (input.CompileOnly) { - var unsupportedBuilds = buildTargets.Where(x => x.Package == PackageType.Docker || x.Package == PackageType.Deb || x.Package == PackageType.RPM).ToList(); - if (unsupportedBuilds.Any()) - throw new Exception($"The following packages cannot be built without Docker: {string.Join(", ", unsupportedBuilds.Select(x => x.PackageTargetString))}"); + rtcfg.DisableDockerBuilds(); + } + else + { + await rtcfg.ToggleDockerBuild(); + + if (!rtcfg.UseDockerBuild) + { + var unsupportedBuilds = buildTargets.Where(x => x.Package == PackageType.Docker || x.Package == PackageType.Deb || x.Package == PackageType.RPM).ToList(); + if (unsupportedBuilds.Any()) + throw new Exception($"The following packages cannot be built without Docker: {string.Join(", ", unsupportedBuilds.Select(x => x.PackageTargetString))}"); + } } // Prevent the system from going to sleep during the build @@ -588,7 +595,7 @@ public static partial class Command await Compile.BuildProjects(baseDir, input.BuildPath.FullName, sourceBuildMap, windowsOnly, buildTargets, releaseInfo, input.KeepBuilds, rtcfg, input.UseHostedBuilds, input.DisableCleanSource, input.AllowAssemblyMismatch); - if (input.BuildOnly) + if (input.CompileOnly) { Console.WriteLine("Build completed, skipping package creation ..."); return; From 2fb19b4e93e2a93a74869e5db30be219ddb42e2b Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Mon, 14 Apr 2025 22:18:14 +0200 Subject: [PATCH 05/14] Create dummy changelog file --- .github/workflows/build-packages.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml index c1e452cef..e41f44d27 100644 --- a/.github/workflows/build-packages.yml +++ b/.github/workflows/build-packages.yml @@ -20,6 +20,10 @@ jobs: - name: Checkout source uses: actions/checkout@v4 + - name: Create dummy changelog file + working-directory: ./ReleaseBuilder + run: echo "## Changed" > ./changelog-news.txt + - name: Compile releases working-directory: ./ReleaseBuilder run: dotnet run -- build debug --compile-only=true --git-stash-push=false --disable-docker-push=true --keep-builds=true --disable-authenticode=true --disable-signcode=true --disable-notarize-signing=true --disable-gpg-signing=true --disable-s3-upload=true --disable-github-upload=true --disable-update-server-reload=true --disable-discourse-announce=true --disable-clean-source=true --password=test1234 --version=2.0.0.99 From 8297df51fb94e1d773ba97c5aeaa29d83776138e Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Mon, 14 Apr 2025 22:24:23 +0200 Subject: [PATCH 06/14] Forced exit code --- ReleaseBuilder/Program.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/ReleaseBuilder/Program.cs b/ReleaseBuilder/Program.cs index 290476c2f..3349c6d62 100644 --- a/ReleaseBuilder/Program.cs +++ b/ReleaseBuilder/Program.cs @@ -102,12 +102,20 @@ class Program /// static async Task Main(string[] args) { - var r = await new RootCommand("Build tool for Duplicati") + try { - Build.Command.Create(), - CreateKey.Command.Create(), - }.InvokeAsync(args); + ReturnCode = await new RootCommand("Build tool for Duplicati") + { + Build.Command.Create(), + CreateKey.Command.Create(), + }.InvokeAsync(args); + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + ReturnCode = 1; + } - return ReturnCode ?? r; + return ReturnCode ?? 2; } } \ No newline at end of file From 27cec82aad957be98d76bff5cda9bdce5a3cb0a0 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Mon, 14 Apr 2025 22:24:31 +0200 Subject: [PATCH 07/14] Added keyfile to env --- .github/workflows/build-packages.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml index e41f44d27..2c2cebc53 100644 --- a/.github/workflows/build-packages.yml +++ b/.github/workflows/build-packages.yml @@ -26,6 +26,8 @@ jobs: - name: Compile releases working-directory: ./ReleaseBuilder + env: + UPDATER_KEYFILE: ./testfile.key1 run: dotnet run -- build debug --compile-only=true --git-stash-push=false --disable-docker-push=true --keep-builds=true --disable-authenticode=true --disable-signcode=true --disable-notarize-signing=true --disable-gpg-signing=true --disable-s3-upload=true --disable-github-upload=true --disable-update-server-reload=true --disable-discourse-announce=true --disable-clean-source=true --password=test1234 --version=2.0.0.99 # Disabled, as a new test needs to be written for the new UI From e3bc92b80d8fbd734f5750b182402b353c988038 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Mon, 14 Apr 2025 22:31:49 +0200 Subject: [PATCH 08/14] Make keep-alive optional --- ReleaseBuilder/KeepAliveAssertion.cs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/ReleaseBuilder/KeepAliveAssertion.cs b/ReleaseBuilder/KeepAliveAssertion.cs index 493db70b2..b2fd44d62 100644 --- a/ReleaseBuilder/KeepAliveAssertion.cs +++ b/ReleaseBuilder/KeepAliveAssertion.cs @@ -32,7 +32,7 @@ public class KeepAliveAssertion : IDisposable /// /// The previous state of the system, on Windows /// - private NativeMethods.EXECUTION_STATE _previousState; + private NativeMethods.EXECUTION_STATE? _previousState; /// /// The process that keeps the system awake, on Linux and MacOS /// @@ -45,17 +45,23 @@ public class KeepAliveAssertion : IDisposable { if (OperatingSystem.IsWindows()) { - _previousState = NativeMethods.SetThreadExecutionState(NativeMethods.EXECUTION_STATE.ES_CONTINUOUS | NativeMethods.EXECUTION_STATE.ES_SYSTEM_REQUIRED | NativeMethods.EXECUTION_STATE.ES_AWAYMODE_REQUIRED); + try { _previousState = NativeMethods.SetThreadExecutionState(NativeMethods.EXECUTION_STATE.ES_CONTINUOUS | NativeMethods.EXECUTION_STATE.ES_SYSTEM_REQUIRED | NativeMethods.EXECUTION_STATE.ES_AWAYMODE_REQUIRED); } + catch { } } else if (OperatingSystem.IsLinux()) { - _keepAliveProcess = Process.Start("xset", "s off -dpms"); + try { _keepAliveProcess = Process.Start("xset", "s off -dpms"); } + catch { } } else if (OperatingSystem.IsMacOS()) { - // Keep the display awake until this process exits - var selfProcessId = Process.GetCurrentProcess().Id; - _keepAliveProcess = Process.Start("caffeinate", ["-d", "-w", selfProcessId.ToString()]); + try + { + // Keep the display awake until this process exits + var selfProcessId = Process.GetCurrentProcess().Id; + _keepAliveProcess = Process.Start("caffeinate", ["-d", "-w", selfProcessId.ToString()]); + } + catch { } } } @@ -82,7 +88,8 @@ public class KeepAliveAssertion : IDisposable { if (OperatingSystem.IsWindows()) { - NativeMethods.SetThreadExecutionState(_previousState); + if (_previousState != null) + NativeMethods.SetThreadExecutionState(_previousState.Value); } else if (OperatingSystem.IsLinux()) { From 702804339c76d45c4bff631dbe1da1f2be6f91dc Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Mon, 14 Apr 2025 22:41:51 +0200 Subject: [PATCH 09/14] Removed unused using --- Duplicati/Agent/Program.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Duplicati/Agent/Program.cs b/Duplicati/Agent/Program.cs index a2dc73769..53df9f5c4 100644 --- a/Duplicati/Agent/Program.cs +++ b/Duplicati/Agent/Program.cs @@ -23,7 +23,6 @@ using System.CommandLine; using System.CommandLine.Builder; using System.CommandLine.NamingConventionBinder; using System.CommandLine.Parsing; -using System.Reactive.Linq; using System.Security.Cryptography; using Duplicati.Library.AutoUpdater; using Duplicati.Library.Encryption; From af61a62c5d3be6627af0be65adffc98fd64a40fd Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Mon, 14 Apr 2025 22:42:09 +0200 Subject: [PATCH 10/14] Don't fail-fast as we may need failed invokes --- .github/workflows/build-packages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml index 2c2cebc53..818f2cd50 100644 --- a/.github/workflows/build-packages.yml +++ b/.github/workflows/build-packages.yml @@ -7,7 +7,7 @@ jobs: name: Build packages runs-on: ${{ matrix.os }} strategy: - fail-fast: true + fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] From 8349c402fade47a8d8b846e9acf48c1d82031508 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Mon, 14 Apr 2025 22:53:15 +0200 Subject: [PATCH 11/14] No wix on Windows --- .github/workflows/build-packages.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml index 818f2cd50..15c781a29 100644 --- a/.github/workflows/build-packages.yml +++ b/.github/workflows/build-packages.yml @@ -28,6 +28,7 @@ jobs: working-directory: ./ReleaseBuilder env: UPDATER_KEYFILE: ./testfile.key1 + WIX: run: dotnet run -- build debug --compile-only=true --git-stash-push=false --disable-docker-push=true --keep-builds=true --disable-authenticode=true --disable-signcode=true --disable-notarize-signing=true --disable-gpg-signing=true --disable-s3-upload=true --disable-github-upload=true --disable-update-server-reload=true --disable-discourse-announce=true --disable-clean-source=true --password=test1234 --version=2.0.0.99 # Disabled, as a new test needs to be written for the new UI From 430e4a8b1b857a92238f5b844de3c92c152d3090 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Tue, 15 Apr 2025 00:05:20 +0200 Subject: [PATCH 12/14] Better Windows support --- ReleaseBuilder/Build/Command.Compile.Post.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ReleaseBuilder/Build/Command.Compile.Post.cs b/ReleaseBuilder/Build/Command.Compile.Post.cs index 07f430ea0..0383b4b75 100644 --- a/ReleaseBuilder/Build/Command.Compile.Post.cs +++ b/ReleaseBuilder/Build/Command.Compile.Post.cs @@ -242,7 +242,8 @@ public static partial class Command // Rename the executables, as symlinks are not supported in DMG files await PackageSupport.RenameExecutables(binDir); - await PackageSupport.SetPermissionFlags(binDir, rtcfg); + if (!OperatingSystem.IsWindows()) + await PackageSupport.SetPermissionFlags(binDir, rtcfg); // Move the licenses out of the code folder as the signing tool trips on it var licenseTarget = Path.Combine(tmpApp, "Contents", "Licenses"); From db872aa09ff6c4950241dddac86422ae7920d487 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Tue, 15 Apr 2025 10:22:30 +0200 Subject: [PATCH 13/14] Disabled ubuntu builds --- .github/workflows/build-packages.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml index 15c781a29..205bb3ab4 100644 --- a/.github/workflows/build-packages.yml +++ b/.github/workflows/build-packages.yml @@ -9,7 +9,9 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] + os: [macos-latest, windows-latest] + # Super slow on ubuntu-latest + # os: [ubuntu-latest, windows-latest, macos-latest] steps: - name: Set up .NET From 8fa68b75dcde6cb97e8763bbef9fa0b82101d3c9 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Tue, 15 Apr 2025 12:16:05 +0200 Subject: [PATCH 14/14] Added another Minio update fix --- Duplicati/Library/Backend/S3/S3MinioClient.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Duplicati/Library/Backend/S3/S3MinioClient.cs b/Duplicati/Library/Backend/S3/S3MinioClient.cs index d52a7b57c..a4d5b63fb 100644 --- a/Duplicati/Library/Backend/S3/S3MinioClient.cs +++ b/Duplicati/Library/Backend/S3/S3MinioClient.cs @@ -222,6 +222,11 @@ namespace Duplicati.Library.Backend { if (e.ServerResponse?.StatusCode == System.Net.HttpStatusCode.NotFound || e.Response?.Code == "NoSuchKey") throw new FileMissingException($"File {keyName} not found in bucket {bucketName}"); + + if (e is BucketNotFoundException) + throw new FolderMissingException($"Bucket {bucketName} not found"); + if (e is ObjectNotFoundException) + throw new FileMissingException($"File {keyName} not found in bucket {bucketName}"); } private Task ThrowExceptionIfBucketDoesNotExist(string bucketName, CancellationToken cancelToken)