diff --git a/.github/workflows/retry-test-jobs.yml b/.github/workflows/retry-test-jobs.yml index 4078b70b..fc7600b8 100644 --- a/.github/workflows/retry-test-jobs.yml +++ b/.github/workflows/retry-test-jobs.yml @@ -32,19 +32,18 @@ jobs: echo "Jobs and conclusions:" echo "$jobs_json" | jq '.jobs[] | {name: .name, conclusion: .conclusion}' - failed_matrix_jobs=$(echo "$jobs_json" | jq ' + failed_matrix_jobs=$(echo "$jobs_json" | jq -r ' [ .jobs[] | select(.conclusion == "failure" and (.name | contains(" API-"))) ] - | length + | length // 0 ') + failed_matrix_jobs=${failed_matrix_jobs:-0} - echo "Failed Integration Tests matrix jobs: $failed_matrix_jobs" - - if [ "$failed_matrix_jobs" -gt 0 ]; then + if [ "${failed_matrix_jobs}" -gt 0 ]; then echo "Detected failing Integration Tests jobs – re-running failed jobs for this run." - gh run rerun -R $REPO "$RUN_ID" --failed + gh run rerun -R "$REPO" "$RUN_ID" --failed else echo "Only non-matrix jobs (like Test Results) failed – not auto-rerunning." fi diff --git a/Changelog.md b/Changelog.md index b9df15c7..18871751 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,11 @@ +# 0.4.0 + +## ElectronNET.Core + +- Fixed ElectronSingleInstance handling (#996) @softworkz +- Fixed `PackageId` handling (#993) @softworkz +- Added cross-platform npm restore and check mismatch on publish (#988) @softworkz + # 0.3.1 ## ElectronNET.Core diff --git a/docs/GettingStarted/Console-App.md b/docs/GettingStarted/Console-App.md index bb59d64d..ec8a6043 100644 --- a/docs/GettingStarted/Console-App.md +++ b/docs/GettingStarted/Console-App.md @@ -54,7 +54,7 @@ Add the Electron.NET configuration to your `.csproj` file: - + ``` diff --git a/src/ElectronNET.API/Runtime/Data/BuildInfo.cs b/src/ElectronNET.API/Runtime/Data/BuildInfo.cs index cb71aa08..75febe06 100644 --- a/src/ElectronNET.API/Runtime/Data/BuildInfo.cs +++ b/src/ElectronNET.API/Runtime/Data/BuildInfo.cs @@ -8,7 +8,7 @@ public class BuildInfo public string RuntimeIdentifier { get; internal set; } - public string ElectronSingleInstance { get; internal set; } + public bool ElectronSingleInstance { get; internal set; } public string Title { get; internal set; } diff --git a/src/ElectronNET.API/Runtime/Services/ElectronProcess/ElectronProcessActive.cs b/src/ElectronNET.API/Runtime/Services/ElectronProcess/ElectronProcessActive.cs index 61cae062..b2d32a9e 100644 --- a/src/ElectronNET.API/Runtime/Services/ElectronProcess/ElectronProcessActive.cs +++ b/src/ElectronNET.API/Runtime/Services/ElectronProcess/ElectronProcessActive.cs @@ -1,12 +1,13 @@ namespace ElectronNET.Runtime.Services.ElectronProcess { - using ElectronNET.Common; - using ElectronNET.Runtime.Data; using System; using System.ComponentModel; using System.IO; + using System.Linq; using System.Runtime.InteropServices; using System.Threading.Tasks; + using ElectronNET.Common; + using ElectronNET.Runtime.Data; /// /// Launches and manages the Electron app process. @@ -33,14 +34,42 @@ public ElectronProcessActive(bool isUnpackaged, string electronBinaryName, strin this.socketPort = socketPort; } - protected override Task StartCore() + protected override async Task StartCore() { var dir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory); string startCmd, args, workingDir; if (this.isUnpackaged) { + this.CheckRuntimeIdentifier(); + var electrondir = Path.Combine(dir.FullName, ".electron"); + + ProcessRunner chmodRunner = null; + + try + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var distFolder = Path.Combine(electrondir, "node_modules", "electron", "dist"); + + chmodRunner = new ProcessRunner("ElectronRunner-Chmod"); + chmodRunner.Run("chmod", "-R +x " + distFolder, electrondir); + await chmodRunner.WaitForExitAsync().ConfigureAwait(true); + + if (chmodRunner.LastExitCode != 0) + { + throw new Exception("Failed to set executable permissions on Electron dist folder."); + } + } + } + catch (Exception ex) + { + Console.Error.WriteLine("[StartCore]: Exception: " + chmodRunner?.StandardError); + Console.Error.WriteLine("[StartCore]: Exception: " + chmodRunner?.StandardOutput); + Console.Error.WriteLine("[StartCore]: Exception: " + ex); + } + startCmd = Path.Combine(electrondir, "node_modules", "electron", "dist", "electron"); if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) @@ -53,17 +82,71 @@ protected override Task StartCore() } else { - dir = dir.Parent?.Parent; + dir = dir.Parent!.Parent!; startCmd = Path.Combine(dir.FullName, this.electronBinaryName); args = $"-dotnetpacked -electronforcedport={this.socketPort:D} " + this.extraArguments; workingDir = dir.FullName; } - // We don't await this in order to let the state transition to "Starting" Task.Run(async () => await this.StartInternal(startCmd, args, workingDir).ConfigureAwait(false)); + } - return Task.CompletedTask; + private void CheckRuntimeIdentifier() + { + var buildInfoRid = ElectronNetRuntime.BuildInfo.RuntimeIdentifier; + if (string.IsNullOrEmpty(buildInfoRid)) + { + return; + } + + var osPart = buildInfoRid.Split('-').First(); + + var mismatch = false; + + switch (osPart) + { + case "win": + + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + mismatch = true; + } + + break; + + case "linux": + + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + mismatch = true; + } + + break; + + case "osx": + + if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + mismatch = true; + } + + break; + + case "freebsd": + + if (!RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD)) + { + mismatch = true; + } + + break; + } + + if (mismatch) + { + throw new PlatformNotSupportedException($"This Electron.NET application was built for '{buildInfoRid}'. It cannot run on this platform."); + } } protected override Task StopCore() diff --git a/src/ElectronNET.API/Runtime/StartupManager.cs b/src/ElectronNET.API/Runtime/StartupManager.cs index 125b6dee..91fed9a2 100644 --- a/src/ElectronNET.API/Runtime/StartupManager.cs +++ b/src/ElectronNET.API/Runtime/StartupManager.cs @@ -165,13 +165,9 @@ private BuildInfo GatherBuildInfo() ElectronNetRuntime.DotnetAppType = DotnetAppType.AspNetCoreApp; } - if (isSingleInstance?.Length > 0 && bool.TryParse(isSingleInstance, out var isSingleInstanceActive) && isSingleInstanceActive) + if (bool.TryParse(isSingleInstance, out var parsedBool)) { - buildInfo.ElectronSingleInstance = "yes"; - } - else - { - buildInfo.ElectronSingleInstance = "no"; + buildInfo.ElectronSingleInstance = parsedBool; } if (httpPort?.Length > 0 && int.TryParse(httpPort, out var port)) diff --git a/src/ElectronNET.ConsoleApp/ElectronNET.ConsoleApp.csproj b/src/ElectronNET.ConsoleApp/ElectronNET.ConsoleApp.csproj index 5c48a427..f0cb290c 100644 --- a/src/ElectronNET.ConsoleApp/ElectronNET.ConsoleApp.csproj +++ b/src/ElectronNET.ConsoleApp/ElectronNET.ConsoleApp.csproj @@ -70,7 +70,7 @@ - + diff --git a/src/ElectronNET.Host/main.js b/src/ElectronNET.Host/main.js index 2562ca7b..9ea21ded 100644 --- a/src/ElectronNET.Host/main.js +++ b/src/ElectronNET.Host/main.js @@ -93,7 +93,7 @@ app.on('will-finish-launching', () => { const manifestJsonFile = require(manifestJsonFilePath); -if (manifestJsonFile.singleInstance === "yes") { +if (manifestJsonFile.singleInstance) { const mainInstance = app.requestSingleInstanceLock(); app.on('second-instance', (events, args = []) => { args.forEach((parameter) => { diff --git a/src/ElectronNET.WebApp/ElectronNET.WebApp.csproj b/src/ElectronNET.WebApp/ElectronNET.WebApp.csproj index 8a615e57..4d37bd91 100644 --- a/src/ElectronNET.WebApp/ElectronNET.WebApp.csproj +++ b/src/ElectronNET.WebApp/ElectronNET.WebApp.csproj @@ -76,8 +76,8 @@ - - + + diff --git a/src/ElectronNET/build/ElectronNET.Core.targets b/src/ElectronNET/build/ElectronNET.Core.targets index 9385fa54..962ed6fa 100644 --- a/src/ElectronNET/build/ElectronNET.Core.targets +++ b/src/ElectronNET/build/ElectronNET.Core.targets @@ -12,6 +12,10 @@ <_IsMsAspNetProject Condition="'$(UsingMicrosoftNETSdkWeb)' == 'true'">True + + $(ElectronPackageId) + + diff --git a/src/ElectronNET/build/ElectronNET.LateImport.targets b/src/ElectronNET/build/ElectronNET.LateImport.targets index 8e37a107..5adc6d64 100644 --- a/src/ElectronNET/build/ElectronNET.LateImport.targets +++ b/src/ElectronNET/build/ElectronNET.LateImport.targets @@ -135,7 +135,7 @@ - + @@ -297,12 +297,58 @@ + + + + x64 + ia32 + arm64 + x64 + armv7l + arm64 + x64 + arm64 + + win + linux + mac + + + win32 + linux + darwin + + + $(ElectronArch) + arm + + <_CurrentOSPlatform Condition="$([MSBuild]::IsOSPlatform('Windows'))">win + <_CurrentOSPlatform Condition="$([MSBuild]::IsOSPlatform('Linux'))">linux + <_CurrentOSPlatform Condition="$([MSBuild]::IsOSPlatform('OSX'))">mac + + + + + false + true + + <_IsCrossCompileAllowed>false + + <_IsCrossCompileAllowed Condition="'$(_CurrentOSPlatform)' == 'win' AND '$(ElectronPlatform)' == 'linux' AND '$(IsLinuxWsl)' == 'true'">true + + <_IsPlatformMismatch>false + <_IsPlatformMismatch Condition="'$(_CurrentOSPlatform)' != '$(ElectronPlatform)' AND '$(_IsCrossCompileAllowed)' != 'true'">true + + + + + @@ -316,10 +362,9 @@ $([System.IO.Path]::GetFullPath('$(ElectronOutDir)')) - linux - false - true <_NpmCmd>npm install --no-bin-links + + <_NpmCmd Condition="'$(_IsPlatformMismatch)' == 'true'">$(_NpmCmd) --os=$(NpmOs) --cpu=$(NpmCpu) --arch=$(NpmCpu) --platform=$(NpmOs) <_NpmCmd Condition="'$(IsLinuxWsl)' == 'true'">wsl bash -ic '$(_NpmCmd)' @@ -335,6 +380,23 @@ + + + <_ElectronFrameworksDir>$(ElectronOutDir)node_modules\electron\dist\Electron.app\Contents\Frameworks + + + + <_ElectronFrameworkDirs Include="$(_ElectronFrameworksDir)\Electron Framework.framework" /> + <_ElectronFrameworkDirs Include="$(_ElectronFrameworksDir)\Mantle.framework" /> + <_ElectronFrameworkDirs Include="$(_ElectronFrameworksDir)\ReactiveObjC.framework" /> + <_ElectronFrameworkDirs Include="$(_ElectronFrameworksDir)\Squirrel.framework" /> + + + + + + + @@ -367,7 +429,7 @@ <_ElectronPublishAppAfterTarget Condition="'$(UsingMicrosoftNETSdkWeb)' != 'true'">Publish - + $(_OriginalPublishDir) @@ -376,21 +438,18 @@ - - - x64 - ia32 - arm64 - x64 - armv7l - arm64 - x64 - arm64 + win - linux - mac - +Electron applications must be built on the target operating system: +- Windows targets (win-x64, win-x86, win-arm64) must be built on Windows +- Linux targets (linux-x64, linux-arm, linux-arm64) must be built on Linux (or Windows with WSL) +- macOS targets (osx-x64, osx-arm64) must be built on macOS + +EXCEPTION: Linux targets can be built on Windows using WSL (Windows Subsystem for Linux). + +For more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migration-Checks#8-cross-platform-build-validation" /> diff --git a/src/ElectronNET/build/package.template.json b/src/ElectronNET/build/package.template.json index 41837302..0f559489 100644 --- a/src/ElectronNET/build/package.template.json +++ b/src/ElectronNET/build/package.template.json @@ -23,7 +23,7 @@ }, "license": "$(License)", "executable": "$(TargetName)", - "singleInstance": "$(ElectronSingleInstance)", + "singleInstance": $(ElectronSingleInstance), "homepage": "$(ProjectUrl)", "splashscreen": { "imageFile": "$(ElectronSplashScreen)" diff --git a/src/common.props b/src/common.props index 047dfb8a..aaaae347 100644 --- a/src/common.props +++ b/src/common.props @@ -1,6 +1,6 @@ - 0.3.1 + 0.4.0 ElectronNET.Core Gregor Biswanger, Florian Rappl, softworkz Electron.NET