diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml new file mode 100644 index 000000000..205bb3ab4 --- /dev/null +++ b/.github/workflows/build-packages.yml @@ -0,0 +1,42 @@ +name: Tests + +on: [pull_request, workflow_dispatch] + +jobs: + build_packages: + name: Build packages + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [macos-latest, windows-latest] + # Super slow on ubuntu-latest + # 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: Create dummy changelog file + working-directory: ./ReleaseBuilder + run: echo "## Changed" > ./changelog-news.txt + + - name: Compile releases + 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 + # selenium: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + # - name: Selenium + # run: pipeline/selenium/test.sh 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; 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"); 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 6ec431a55..d9ee5c90e 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 @@ -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; 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()) { 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