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