From c584611959a78f05f1fe3cf674d79044be973279 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 22 Feb 2026 20:57:20 +0900 Subject: [PATCH 1/5] improve error message when edge is already installed --- src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 6054c04..9260082 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,7 +31,8 @@ async function run(): Promise { const result = await (async () => { const installed = await installer.checkInstalled(version); if (installed) { - core.info(`Edge ${version} is already installed @ ${installed.root}`); + const bin = path.join(installed.root, installed.bin); + core.info(`Edge ${version} is already installed @ ${bin}`); return installed; } From e7d479eec15d1b049e9a9c1c99c53ea57dc55117 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 22 Feb 2026 21:13:34 +0900 Subject: [PATCH 2/5] ignore dist directory from biome --- biome.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biome.json b/biome.json index 96e61d4..5720642 100644 --- a/biome.json +++ b/biome.json @@ -1,6 +1,6 @@ { "files": { - "ignore": ["package.json", "__test__/*.json"] + "ignore": ["package.json", "__test__/*.json", "dist"] }, "linter": { "enabled": true, From 905205821145e9f54a30c9bfeac3ee236c58c828 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 22 Feb 2026 21:38:44 +0900 Subject: [PATCH 3/5] Call Get-Item instead of wmic to get the version --- src/installer_windows.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/installer_windows.ts b/src/installer_windows.ts index d28499a..52585c8 100644 --- a/src/installer_windows.ts +++ b/src/installer_windows.ts @@ -101,12 +101,11 @@ export class WindowsInstaller implements Installer { async test(_version: versions.Version): Promise { const msedgeBin = await io.which("msedge", true); - await exec.exec("wmic", [ - "datafile", - "where", - `name="${msedgeBin.replace(/\\/g, "\\\\")}"`, - "get", - "version", + await exec.exec("powershell", [ + "-NoProfile", + "-NonInteractive", + "-Command", + `(Get-Item (Get-Command '${msedgeBin}').Source).VersionInfo.ProductVersion`, ]); } } From 1028c6b499018a6f3fe5a357bf38ba5d62656371 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Wed, 29 Apr 2026 15:00:31 +0900 Subject: [PATCH 4/5] debug: add diagnostic logging for macOS Edge install - Log extracted pkg directory tree (3 levels) after xar -xf - Check codesign, xattr, and spctl on app before caching - Log cached binary path and existence after tc.cacheDir - Capture stdout/stderr/exitCode in test() for diagnosis Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/installer_mac.ts | 45 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/installer_mac.ts b/src/installer_mac.ts index ef348de..a24fd6c 100644 --- a/src/installer_mac.ts +++ b/src/installer_mac.ts @@ -60,6 +60,20 @@ export class MacInstaller implements Installer { await exec.exec("xar", ["-xf", archive], { cwd: extdir }); + // Log directory tree to diagnose where the .app bundle is located + const walk = async (dir: string, depth = 0): Promise => { + if (depth > 3) return; + for (const e of await fs.promises.readdir(dir)) { + core.info(`${" ".repeat(depth)}${e}`); + const full = path.join(dir, e); + if ((await fs.promises.stat(full)).isDirectory()) { + await walk(full, depth + 1); + } + } + }; + core.info(`Extracted pkg structure under ${extdir}:`); + await walk(extdir); + const pkgdir = (await fs.promises.readdir(extdir)).filter( (e) => e.startsWith("MicrosoftEdge") && e.endsWith(".pkg"), )[0]; @@ -76,8 +90,26 @@ export class MacInstaller implements Installer { await exec.exec("cpio", ["--extract", "--file", "App"], { cwd: pkgroot }); const app = path.join(pkgroot, this.appName(version)); + + // Diagnose codesign and quarantine attributes before caching + core.info(`App path: ${app}`); + core.info(`App exists: ${fs.existsSync(app)}`); + await exec.exec("codesign", ["--verify", "--verbose=4", app], { + ignoreReturnCode: true, + }); + await exec.exec("xattr", ["-l", app], { ignoreReturnCode: true }); + await exec.exec("spctl", ["-a", "-v", app], { ignoreReturnCode: true }); + const root = await tc.cacheDir(app, "msedge", version); + // Diagnose cached binary + const cachedBin = path.join(root, this.binPath(version)); + core.info(`Cached binary: ${cachedBin}`); + core.info(`Cached binary exists: ${fs.existsSync(cachedBin)}`); + await exec.exec("ls", ["-la", path.dirname(cachedBin)], { + ignoreReturnCode: true, + }); + return { root, bin: this.binPath(version) }; } @@ -110,6 +142,17 @@ export class MacInstaller implements Installer { async test(version: versions.Version): Promise { const bin = path.basename(this.binPath(version)); const msedgeBin = await io.which(bin, true); - await exec.exec(`"${msedgeBin}"`, ["--version"]); + core.info(`Testing binary: ${msedgeBin}`); + const output = await exec.getExecOutput(`"${msedgeBin}"`, ["--version"], { + ignoreReturnCode: true, + }); + core.info(`stdout: ${output.stdout}`); + core.info(`stderr: ${output.stderr}`); + core.info(`exit code: ${output.exitCode}`); + if (output.exitCode !== 0) { + throw new Error( + `Edge binary test failed with exit code ${output.exitCode}\nstderr: ${output.stderr}`, + ); + } } } From 937caeb09989667b885252f4995995ee08e06828 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Wed, 29 Apr 2026 15:08:37 +0900 Subject: [PATCH 5/5] fix: preserve .app bundle name in tool cache on macOS tc.cacheDir copies the *contents* of the source directory into the cache root (copySourceDirectory: false), stripping the .app name. The cached binary ends up at: hostedtoolcache/msedge/stable/arm64/Contents/MacOS/Microsoft Edge The Edge binary looks for its bundle root two levels up, finding 'arm64/' which has no .app extension. On macOS 15, Edge validates the bundle path and exits immediately (null exit code). Fix: wrap the .app in a plain directory before caching so the .app name is preserved in the cache: hostedtoolcache/msedge/stable/arm64/Microsoft Edge.app/Contents/MacOS/Microsoft Edge Update binPath to include the .app directory name accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/installer_mac.ts | 65 +++++++++++--------------------------------- 1 file changed, 16 insertions(+), 49 deletions(-) diff --git a/src/installer_mac.ts b/src/installer_mac.ts index a24fd6c..4b99bdc 100644 --- a/src/installer_mac.ts +++ b/src/installer_mac.ts @@ -60,20 +60,6 @@ export class MacInstaller implements Installer { await exec.exec("xar", ["-xf", archive], { cwd: extdir }); - // Log directory tree to diagnose where the .app bundle is located - const walk = async (dir: string, depth = 0): Promise => { - if (depth > 3) return; - for (const e of await fs.promises.readdir(dir)) { - core.info(`${" ".repeat(depth)}${e}`); - const full = path.join(dir, e); - if ((await fs.promises.stat(full)).isDirectory()) { - await walk(full, depth + 1); - } - } - }; - core.info(`Extracted pkg structure under ${extdir}:`); - await walk(extdir); - const pkgdir = (await fs.promises.readdir(extdir)).filter( (e) => e.startsWith("MicrosoftEdge") && e.endsWith(".pkg"), )[0]; @@ -89,26 +75,18 @@ export class MacInstaller implements Installer { await exec.exec("gzip", ["--decompress", "App.gz"], { cwd: pkgroot }); await exec.exec("cpio", ["--extract", "--file", "App"], { cwd: pkgroot }); - const app = path.join(pkgroot, this.appName(version)); - - // Diagnose codesign and quarantine attributes before caching - core.info(`App path: ${app}`); - core.info(`App exists: ${fs.existsSync(app)}`); - await exec.exec("codesign", ["--verify", "--verbose=4", app], { - ignoreReturnCode: true, - }); - await exec.exec("xattr", ["-l", app], { ignoreReturnCode: true }); - await exec.exec("spctl", ["-a", "-v", app], { ignoreReturnCode: true }); - - const root = await tc.cacheDir(app, "msedge", version); + // tc.cacheDir copies the *contents* of the source dir into the cache root, + // so we wrap the .app inside a subdirectory to preserve the .app name and + // extension. Without this, the bundle root in the cache lacks the .app + // suffix and Edge refuses to launch (exits with null on macOS 15+). + const wrapperDir = path.join(extdir, "wrapper"); + await fs.promises.mkdir(wrapperDir); + await fs.promises.rename( + path.join(pkgroot, this.appName(version)), + path.join(wrapperDir, this.appName(version)), + ); - // Diagnose cached binary - const cachedBin = path.join(root, this.binPath(version)); - core.info(`Cached binary: ${cachedBin}`); - core.info(`Cached binary exists: ${fs.existsSync(cachedBin)}`); - await exec.exec("ls", ["-la", path.dirname(cachedBin)], { - ignoreReturnCode: true, - }); + const root = await tc.cacheDir(wrapperDir, "msedge", version); return { root, bin: this.binPath(version) }; } @@ -116,13 +94,13 @@ export class MacInstaller implements Installer { private binPath(version: versions.Version): string { switch (version) { case versions.StableVersion: - return "Contents/MacOS/Microsoft Edge"; + return "Microsoft Edge.app/Contents/MacOS/Microsoft Edge"; case versions.BetaVersion: - return "Contents/MacOS/Microsoft Edge Beta"; + return "Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta"; case versions.DevVersion: - return "Contents/MacOS/Microsoft Edge Dev"; + return "Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev"; case versions.CanaryVersion: - return "Contents/MacOS/Microsoft Edge Canary"; + return "Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary"; } } @@ -142,17 +120,6 @@ export class MacInstaller implements Installer { async test(version: versions.Version): Promise { const bin = path.basename(this.binPath(version)); const msedgeBin = await io.which(bin, true); - core.info(`Testing binary: ${msedgeBin}`); - const output = await exec.getExecOutput(`"${msedgeBin}"`, ["--version"], { - ignoreReturnCode: true, - }); - core.info(`stdout: ${output.stdout}`); - core.info(`stderr: ${output.stderr}`); - core.info(`exit code: ${output.exitCode}`); - if (output.exitCode !== 0) { - throw new Error( - `Edge binary test failed with exit code ${output.exitCode}\nstderr: ${output.stderr}`, - ); - } + await exec.exec(`"${msedgeBin}"`, ["--version"]); } }