From 6f021b1835307c60bd70ae8e3f793d28274354c8 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 21 Jul 2025 12:03:35 +0900 Subject: [PATCH 1/5] move installer classes to separate files and rename tests --- ...llerFactory.test.ts => installers.test.ts} | 10 +- src/Installer.ts | 190 ------------------ src/InstallerFactory.ts | 16 -- src/LinuxInstaller.ts | 59 ++++++ src/MacOSInstaller.ts | 67 ++++++ src/WindowsInstaller.ts | 59 ++++++ src/firefoxUtils.ts | 14 ++ src/index.ts | 2 +- src/installers.ts | 29 +++ 9 files changed, 233 insertions(+), 213 deletions(-) rename __test__/{InstallerFactory.test.ts => installers.test.ts} (68%) delete mode 100644 src/Installer.ts delete mode 100644 src/InstallerFactory.ts create mode 100644 src/LinuxInstaller.ts create mode 100644 src/MacOSInstaller.ts create mode 100644 src/WindowsInstaller.ts create mode 100644 src/firefoxUtils.ts create mode 100644 src/installers.ts diff --git a/__test__/InstallerFactory.test.ts b/__test__/installers.test.ts similarity index 68% rename from __test__/InstallerFactory.test.ts rename to __test__/installers.test.ts index 2664f61..b4bc2cd 100644 --- a/__test__/InstallerFactory.test.ts +++ b/__test__/installers.test.ts @@ -1,10 +1,8 @@ import { describe, expect, test } from "vitest"; -import { - LinuxInstaller, - MacOSInstaller, - WindowsInstaller, -} from "../src/Installer"; -import InstallerFactory from "../src/InstallerFactory"; +import { LinuxInstaller } from "../src/LinuxInstaller"; +import { MacOSInstaller } from "../src/MacOSInstaller"; +import { WindowsInstaller } from "../src/WindowsInstaller"; +import { InstallerFactory } from "../src/installers"; import { Arch, OS } from "../src/platform"; describe("InstallerFactory", () => { diff --git a/src/Installer.ts b/src/Installer.ts deleted file mode 100644 index 79f901b..0000000 --- a/src/Installer.ts +++ /dev/null @@ -1,190 +0,0 @@ -import fs from "node:fs"; -import path from "node:path"; -import * as core from "@actions/core"; -import * as exec from "@actions/exec"; -import * as io from "@actions/io"; -import * as tc from "@actions/tool-cache"; -import { DownloadURLFactory } from "./DownloadURLFactory"; -import type { Platform } from "./platform"; -import { LatestVersion } from "./versions"; - -export type InstallSpec = { - version: string; - platform: Platform; - language: string; -}; - -export default interface Installer { - install(spec: InstallSpec): Promise; - - testVersion(bin: string): Promise; -} - -const commonTestVersion = async (bin: string): Promise => { - const output = await exec.getExecOutput(`"${bin}"`, ["--version"]); - if (output.exitCode !== 0) { - throw new Error( - `firefox exits with status ${output.exitCode}: ${output.stderr}`, - ); - } - if (!output.stdout.startsWith("Mozilla Firefox ")) { - throw new Error(`firefox outputs unexpected results: ${output.stdout}`); - } - return output.stdout.trimEnd().replace("Mozilla Firefox ", ""); -}; - -export class LinuxInstaller implements Installer { - async install(spec: InstallSpec): Promise { - return this.download(spec); - } - - private async download({ - version, - platform, - language, - }: InstallSpec): Promise { - const toolPath = tc.find("firefox", version); - if (toolPath) { - core.info(`Found in cache @ ${toolPath}`); - return toolPath; - } - core.info(`Attempting to download firefox ${version}...`); - - const url = new DownloadURLFactory(version, platform, language) - .create() - .getURL(); - core.info(`Acquiring ${version} from ${url}`); - - const archivePath = await tc.downloadTool(url); - core.info("Extracting Firefox..."); - const handle = await fs.promises.open(archivePath, "r"); - const firstBytes = new Int8Array(3); - if (handle !== null) { - await handle.read(firstBytes, 0, 3, null); - core.debug( - `Extracted ${firstBytes[0]}, ${firstBytes[1]} and ${firstBytes[2]}`, - ); - } - const options = - firstBytes[0] === 66 && firstBytes[1] === 90 && firstBytes[2] === 104 - ? "xj" - : "xJ"; - const extPath = await tc.extractTar(archivePath, "", [ - options, - "--strip-components=1", - ]); - core.info(`Successfully extracted firefox ${version} to ${extPath}`); - - core.info("Adding to the cache ..."); - const cachedDir = await tc.cacheDir(extPath, "firefox", version); - core.info(`Successfully cached firefox ${version} to ${cachedDir}`); - return cachedDir; - } - - testVersion = commonTestVersion; -} - -export class MacOSInstaller implements Installer { - async install(spec: InstallSpec): Promise { - const installPath = await this.download(spec); - return path.join(installPath, "Contents", "MacOS"); - } - - async download({ - version, - platform, - language, - }: InstallSpec): Promise { - const toolPath = tc.find("firefox", version); - if (toolPath) { - core.info(`Found in cache @ ${toolPath}`); - return toolPath; - } - core.info(`Attempting to download firefox ${version}...`); - - const url = new DownloadURLFactory(version, platform, language) - .create() - .getURL(); - core.info(`Acquiring ${version} from ${url}`); - - const archivePath = await tc.downloadTool(url); - core.info("Extracting Firefox..."); - - const mountpoint = path.join("/Volumes", path.basename(archivePath)); - const appPath = (() => { - if (version === LatestVersion.LATEST_NIGHTLY) { - return path.join(mountpoint, "Firefox Nightly.app"); - } else if (version.includes("devedition")) { - return path.join(mountpoint, "Firefox Developer Edition.app"); - } else { - return path.join(mountpoint, "Firefox.app"); - } - })(); - - await exec.exec("hdiutil", [ - "attach", - "-quiet", - "-noautofsck", - "-noautoopen", - "-mountpoint", - mountpoint, - archivePath, - ]); - core.info(`Successfully extracted firefox ${version} to ${appPath}`); - - core.info("Adding to the cache ..."); - const cachedDir = await tc.cacheDir(appPath, "firefox", version); - core.info(`Successfully cached firefox ${version} to ${cachedDir}`); - return cachedDir; - } - - testVersion = commonTestVersion; -} - -export class WindowsInstaller implements Installer { - install(spec: InstallSpec): Promise { - return this.download(spec); - } - - async download({ - version, - platform, - language, - }: InstallSpec): Promise { - const installPath = `C:\\Program Files\\Firefox_${version}`; - if (await this.checkInstall(installPath)) { - core.info(`Already installed @ ${installPath}`); - return installPath; - } - - core.info(`Attempting to download firefox ${version}...`); - - const url = new DownloadURLFactory(version, platform, language) - .create() - .getURL(); - core.info(`Acquiring ${version} from ${url}`); - - const installerPath = await tc.downloadTool(url); - await io.mv(installerPath, `${installerPath}.exe`); - core.info("Extracting Firefox..."); - - await exec.exec(installerPath, [ - "/S", - `/InstallDirectoryName=${path.basename(installPath)}`, - ]); - core.info(`Successfully installed firefox ${version} to ${installPath}`); - - return installPath; - } - - private async checkInstall(dir: string): Promise { - try { - await fs.promises.access(dir, fs.constants.F_OK); - } catch (err) { - return false; - } - return true; - } - - testVersion = commonTestVersion; -} diff --git a/src/InstallerFactory.ts b/src/InstallerFactory.ts deleted file mode 100644 index 64a1c4f..0000000 --- a/src/InstallerFactory.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type Installer from "./Installer"; -import { LinuxInstaller, MacOSInstaller, WindowsInstaller } from "./Installer"; -import { OS, type Platform } from "./platform"; - -export default class InstallerFactory { - create(platform: Platform): Installer { - switch (platform.os) { - case OS.LINUX: - return new LinuxInstaller(); - case OS.MACOS: - return new MacOSInstaller(); - case OS.WINDOWS: - return new WindowsInstaller(); - } - } -} diff --git a/src/LinuxInstaller.ts b/src/LinuxInstaller.ts new file mode 100644 index 0000000..e8f2d1f --- /dev/null +++ b/src/LinuxInstaller.ts @@ -0,0 +1,59 @@ +import fs from "node:fs"; +import * as core from "@actions/core"; +import * as tc from "@actions/tool-cache"; +import { DownloadURLFactory } from "./DownloadURLFactory"; +import { testBinaryVersion } from "./firefoxUtils"; +import type { InstallSpec, Installer } from "./installers"; + +export class LinuxInstaller implements Installer { + async install(spec: InstallSpec): Promise { + return this.download(spec); + } + + private async download({ + version, + platform, + language, + }: InstallSpec): Promise { + const toolPath = tc.find("firefox", version); + if (toolPath) { + core.info(`Found in cache @ ${toolPath}`); + return toolPath; + } + core.info(`Attempting to download firefox ${version}...`); + + const url = new DownloadURLFactory(version, platform, language) + .create() + .getURL(); + core.info(`Acquiring ${version} from ${url}`); + + const archivePath = await tc.downloadTool(url); + core.info("Extracting Firefox..."); + const handle = await fs.promises.open(archivePath, "r"); + const firstBytes = new Int8Array(3); + if (handle !== null) { + await handle.read(firstBytes, 0, 3, null); + core.debug( + `Extracted ${firstBytes[0]}, ${firstBytes[1]} and ${firstBytes[2]}`, + ); + } + const options = + firstBytes[0] === 66 && firstBytes[1] === 90 && firstBytes[2] === 104 + ? "xj" + : "xJ"; + const extPath = await tc.extractTar(archivePath, "", [ + options, + "--strip-components=1", + ]); + core.info(`Successfully extracted firefox ${version} to ${extPath}`); + + core.info("Adding to the cache ..."); + const cachedDir = await tc.cacheDir(extPath, "firefox", version); + core.info(`Successfully cached firefox ${version} to ${cachedDir}`); + return cachedDir; + } + + async testVersion(bin: string): Promise { + return testBinaryVersion(bin); + } +} diff --git a/src/MacOSInstaller.ts b/src/MacOSInstaller.ts new file mode 100644 index 0000000..ff1ba6e --- /dev/null +++ b/src/MacOSInstaller.ts @@ -0,0 +1,67 @@ +import path from "node:path"; +import * as core from "@actions/core"; +import * as exec from "@actions/exec"; +import * as tc from "@actions/tool-cache"; +import { DownloadURLFactory } from "./DownloadURLFactory"; +import { testBinaryVersion } from "./firefoxUtils"; +import type { InstallSpec, Installer } from "./installers"; +import { LatestVersion } from "./versions"; + +export class MacOSInstaller implements Installer { + async install(spec: InstallSpec): Promise { + const installPath = await this.download(spec); + return path.join(installPath, "Contents", "MacOS"); + } + + async download({ + version, + platform, + language, + }: InstallSpec): Promise { + const toolPath = tc.find("firefox", version); + if (toolPath) { + core.info(`Found in cache @ ${toolPath}`); + return toolPath; + } + core.info(`Attempting to download firefox ${version}...`); + + const url = new DownloadURLFactory(version, platform, language) + .create() + .getURL(); + core.info(`Acquiring ${version} from ${url}`); + + const archivePath = await tc.downloadTool(url); + core.info("Extracting Firefox..."); + + const mountpoint = path.join("/Volumes", path.basename(archivePath)); + const appPath = (() => { + if (version === LatestVersion.LATEST_NIGHTLY) { + return path.join(mountpoint, "Firefox Nightly.app"); + } else if (version.includes("devedition")) { + return path.join(mountpoint, "Firefox Developer Edition.app"); + } else { + return path.join(mountpoint, "Firefox.app"); + } + })(); + + await exec.exec("hdiutil", [ + "attach", + "-quiet", + "-noautofsck", + "-noautoopen", + "-mountpoint", + mountpoint, + archivePath, + ]); + core.info(`Successfully extracted firefox ${version} to ${appPath}`); + + core.info("Adding to the cache ..."); + const cachedDir = await tc.cacheDir(appPath, "firefox", version); + core.info(`Successfully cached firefox ${version} to ${cachedDir}`); + return cachedDir; + } + + async testVersion(bin: string): Promise { + return testBinaryVersion(bin); + } +} diff --git a/src/WindowsInstaller.ts b/src/WindowsInstaller.ts new file mode 100644 index 0000000..bd85ea8 --- /dev/null +++ b/src/WindowsInstaller.ts @@ -0,0 +1,59 @@ +import fs from "node:fs"; +import path from "node:path"; +import * as core from "@actions/core"; +import * as exec from "@actions/exec"; +import * as io from "@actions/io"; +import * as tc from "@actions/tool-cache"; +import { DownloadURLFactory } from "./DownloadURLFactory"; +import { testBinaryVersion } from "./firefoxUtils"; +import type { InstallSpec, Installer } from "./installers"; + +export class WindowsInstaller implements Installer { + install(spec: InstallSpec): Promise { + return this.download(spec); + } + + async download({ + version, + platform, + language, + }: InstallSpec): Promise { + const installPath = `C:\\Program Files\\Firefox_${version}`; + if (await this.checkInstall(installPath)) { + core.info(`Already installed @ ${installPath}`); + return installPath; + } + + core.info(`Attempting to download firefox ${version}...`); + + const url = new DownloadURLFactory(version, platform, language) + .create() + .getURL(); + core.info(`Acquiring ${version} from ${url}`); + + const installerPath = await tc.downloadTool(url); + await io.mv(installerPath, `${installerPath}.exe`); + core.info("Extracting Firefox..."); + + await exec.exec(installerPath, [ + "/S", + `/InstallDirectoryName=${path.basename(installPath)}`, + ]); + core.info(`Successfully installed firefox ${version} to ${installPath}`); + + return installPath; + } + + private async checkInstall(dir: string): Promise { + try { + await fs.promises.access(dir, fs.constants.F_OK); + } catch (err) { + return false; + } + return true; + } + + async testVersion(bin: string): Promise { + return testBinaryVersion(bin); + } +} diff --git a/src/firefoxUtils.ts b/src/firefoxUtils.ts new file mode 100644 index 0000000..3a95b1b --- /dev/null +++ b/src/firefoxUtils.ts @@ -0,0 +1,14 @@ +import * as exec from "@actions/exec"; + +export const testBinaryVersion = async (bin: string): Promise => { + const output = await exec.getExecOutput(`"${bin}"`, ["--version"]); + if (output.exitCode !== 0) { + throw new Error( + `firefox exits with status ${output.exitCode}: ${output.stderr}`, + ); + } + if (!output.stdout.startsWith("Mozilla Firefox ")) { + throw new Error(`firefox outputs unexpected results: ${output.stdout}`); + } + return output.stdout.trimEnd().replace("Mozilla Firefox ", ""); +}; diff --git a/src/index.ts b/src/index.ts index 1dac907..12a7ad5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import * as path from "node:path"; import * as core from "@actions/core"; -import InstallerFactory from "./InstallerFactory"; +import { InstallerFactory } from "./installers"; import { getPlatform } from "./platform"; import { LatestVersion } from "./versions"; diff --git a/src/installers.ts b/src/installers.ts new file mode 100644 index 0000000..aef30b4 --- /dev/null +++ b/src/installers.ts @@ -0,0 +1,29 @@ +import { LinuxInstaller } from "./LinuxInstaller"; +import { MacOSInstaller } from "./MacOSInstaller"; +import { WindowsInstaller } from "./WindowsInstaller"; +import { OS, type Platform } from "./platform"; + +export type InstallSpec = { + version: string; + platform: Platform; + language: string; +}; + +export interface Installer { + install(spec: InstallSpec): Promise; + + testVersion(bin: string): Promise; +} + +export class InstallerFactory { + create(platform: Platform): Installer { + switch (platform.os) { + case OS.LINUX: + return new LinuxInstaller(); + case OS.MACOS: + return new MacOSInstaller(); + case OS.WINDOWS: + return new WindowsInstaller(); + } + } +} From 2ce6c302b66476eea113d73d08ab472fbe46184f Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 21 Jul 2025 12:23:01 +0900 Subject: [PATCH 2/5] refactor installation process --- src/LinuxInstaller.ts | 49 ++++++++++++++++++++------------- src/MacOSInstaller.ts | 60 ++++++++++++++++++++++++----------------- src/WindowsInstaller.ts | 46 +++++++++++++++++++------------ 3 files changed, 95 insertions(+), 60 deletions(-) diff --git a/src/LinuxInstaller.ts b/src/LinuxInstaller.ts index e8f2d1f..024c991 100644 --- a/src/LinuxInstaller.ts +++ b/src/LinuxInstaller.ts @@ -4,35 +4,52 @@ import * as tc from "@actions/tool-cache"; import { DownloadURLFactory } from "./DownloadURLFactory"; import { testBinaryVersion } from "./firefoxUtils"; import type { InstallSpec, Installer } from "./installers"; +import { Platform } from "./platform"; export class LinuxInstaller implements Installer { - async install(spec: InstallSpec): Promise { - return this.download(spec); - } - - private async download({ - version, - platform, - language, - }: InstallSpec): Promise { + async install({ version, platform, language }: InstallSpec): Promise { const toolPath = tc.find("firefox", version); if (toolPath) { core.info(`Found in cache @ ${toolPath}`); return toolPath; } core.info(`Attempting to download firefox ${version}...`); + const archivePath = await this.downloadArchive({ + version, + platform, + language, + }); + + core.info("Extracting Firefox..."); + const extPath = await this.extractArchive(archivePath); + core.info(`Successfully extracted firefox ${version} to ${extPath}`); + + core.info("Adding to the cache ..."); + const cachedDir = await tc.cacheDir(extPath, "firefox", version); + core.info(`Successfully cached firefox ${version} to ${cachedDir}`); + + return cachedDir; + } + private async downloadArchive({ + version, + platform, + language, + }: InstallSpec): Promise { const url = new DownloadURLFactory(version, platform, language) .create() .getURL(); core.info(`Acquiring ${version} from ${url}`); const archivePath = await tc.downloadTool(url); - core.info("Extracting Firefox..."); - const handle = await fs.promises.open(archivePath, "r"); + return archivePath; + } + + private async extractArchive(archivePath: string): Promise { + const file = await fs.promises.open(archivePath, "r"); const firstBytes = new Int8Array(3); - if (handle !== null) { - await handle.read(firstBytes, 0, 3, null); + if (file !== null) { + await file.read(firstBytes, 0, 3, null); core.debug( `Extracted ${firstBytes[0]}, ${firstBytes[1]} and ${firstBytes[2]}`, ); @@ -45,12 +62,8 @@ export class LinuxInstaller implements Installer { options, "--strip-components=1", ]); - core.info(`Successfully extracted firefox ${version} to ${extPath}`); - core.info("Adding to the cache ..."); - const cachedDir = await tc.cacheDir(extPath, "firefox", version); - core.info(`Successfully cached firefox ${version} to ${cachedDir}`); - return cachedDir; + return extPath; } async testVersion(bin: string): Promise { diff --git a/src/MacOSInstaller.ts b/src/MacOSInstaller.ts index ff1ba6e..6cc64d2 100644 --- a/src/MacOSInstaller.ts +++ b/src/MacOSInstaller.ts @@ -8,41 +8,49 @@ import type { InstallSpec, Installer } from "./installers"; import { LatestVersion } from "./versions"; export class MacOSInstaller implements Installer { - async install(spec: InstallSpec): Promise { - const installPath = await this.download(spec); - return path.join(installPath, "Contents", "MacOS"); - } - - async download({ - version, - platform, - language, - }: InstallSpec): Promise { + async install({ version, platform, language }: InstallSpec): Promise { const toolPath = tc.find("firefox", version); if (toolPath) { core.info(`Found in cache @ ${toolPath}`); return toolPath; } core.info(`Attempting to download firefox ${version}...`); + const archivePath = await this.downloadArchive({ + version, + platform, + language, + }); + + core.info("Extracting Firefox..."); + const appPath = await this.extractArchive(archivePath, version); + core.info(`Successfully extracted firefox ${version} to ${appPath}`); + + core.info("Adding to the cache ..."); + const cachedDir = await tc.cacheDir(appPath, "firefox", version); + core.info(`Successfully cached firefox ${version} to ${cachedDir}`); + return path.join(cachedDir, "Contents", "MacOS"); + } + + private async downloadArchive({ + version, + platform, + language, + }: InstallSpec): Promise { const url = new DownloadURLFactory(version, platform, language) .create() .getURL(); core.info(`Acquiring ${version} from ${url}`); const archivePath = await tc.downloadTool(url); - core.info("Extracting Firefox..."); + return archivePath; + } + private async extractArchive( + archivePath: string, + version: string, + ): Promise { const mountpoint = path.join("/Volumes", path.basename(archivePath)); - const appPath = (() => { - if (version === LatestVersion.LATEST_NIGHTLY) { - return path.join(mountpoint, "Firefox Nightly.app"); - } else if (version.includes("devedition")) { - return path.join(mountpoint, "Firefox Developer Edition.app"); - } else { - return path.join(mountpoint, "Firefox.app"); - } - })(); await exec.exec("hdiutil", [ "attach", @@ -53,12 +61,14 @@ export class MacOSInstaller implements Installer { mountpoint, archivePath, ]); - core.info(`Successfully extracted firefox ${version} to ${appPath}`); - core.info("Adding to the cache ..."); - const cachedDir = await tc.cacheDir(appPath, "firefox", version); - core.info(`Successfully cached firefox ${version} to ${cachedDir}`); - return cachedDir; + if (version === LatestVersion.LATEST_NIGHTLY) { + return path.join(mountpoint, "Firefox Nightly.app"); + } else if (version.includes("devedition")) { + return path.join(mountpoint, "Firefox Developer Edition.app"); + } else { + return path.join(mountpoint, "Firefox.app"); + } } async testVersion(bin: string): Promise { diff --git a/src/WindowsInstaller.ts b/src/WindowsInstaller.ts index bd85ea8..e726914 100644 --- a/src/WindowsInstaller.ts +++ b/src/WindowsInstaller.ts @@ -9,15 +9,7 @@ import { testBinaryVersion } from "./firefoxUtils"; import type { InstallSpec, Installer } from "./installers"; export class WindowsInstaller implements Installer { - install(spec: InstallSpec): Promise { - return this.download(spec); - } - - async download({ - version, - platform, - language, - }: InstallSpec): Promise { + async install({ version, platform, language }: InstallSpec): Promise { const installPath = `C:\\Program Files\\Firefox_${version}`; if (await this.checkInstall(installPath)) { core.info(`Already installed @ ${installPath}`); @@ -25,7 +17,24 @@ export class WindowsInstaller implements Installer { } core.info(`Attempting to download firefox ${version}...`); + const installerPath = await this.downloadArchive({ + version, + platform, + language, + }); + core.info("Extracting Firefox..."); + await this.extractArchive(installerPath, installPath); + core.info(`Successfully installed firefox ${version} to ${installPath}`); + + return installPath; + } + + private async downloadArchive({ + version, + platform, + language, + }: InstallSpec): Promise { const url = new DownloadURLFactory(version, platform, language) .create() .getURL(); @@ -33,15 +42,8 @@ export class WindowsInstaller implements Installer { const installerPath = await tc.downloadTool(url); await io.mv(installerPath, `${installerPath}.exe`); - core.info("Extracting Firefox..."); - - await exec.exec(installerPath, [ - "/S", - `/InstallDirectoryName=${path.basename(installPath)}`, - ]); - core.info(`Successfully installed firefox ${version} to ${installPath}`); - return installPath; + return installerPath; } private async checkInstall(dir: string): Promise { @@ -53,6 +55,16 @@ export class WindowsInstaller implements Installer { return true; } + private async extractArchive( + installerPath: string, + installPath: string, + ): Promise { + await exec.exec(installerPath, [ + "/S", + `/InstallDirectoryName=${path.basename(installPath)}`, + ]); + } + async testVersion(bin: string): Promise { return testBinaryVersion(bin); } From 4f3e535be4656bcf7fc7108ce38d68679ca6c934 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 21 Jul 2025 12:48:41 +0900 Subject: [PATCH 3/5] return .exe on WindowsInstaller --- src/LinuxInstaller.ts | 20 +++++++++++++++----- src/MacOSInstaller.ts | 18 ++++++++++++++---- src/WindowsInstaller.ts | 18 ++++++++++++++---- src/index.ts | 10 ++++++---- src/installers.ts | 7 ++++++- 5 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/LinuxInstaller.ts b/src/LinuxInstaller.ts index 024c991..86530e2 100644 --- a/src/LinuxInstaller.ts +++ b/src/LinuxInstaller.ts @@ -1,17 +1,24 @@ import fs from "node:fs"; +import path from "node:path"; import * as core from "@actions/core"; import * as tc from "@actions/tool-cache"; import { DownloadURLFactory } from "./DownloadURLFactory"; import { testBinaryVersion } from "./firefoxUtils"; -import type { InstallSpec, Installer } from "./installers"; -import { Platform } from "./platform"; +import type { InstallResult, InstallSpec, Installer } from "./installers"; export class LinuxInstaller implements Installer { - async install({ version, platform, language }: InstallSpec): Promise { + async install({ + version, + platform, + language, + }: InstallSpec): Promise { const toolPath = tc.find("firefox", version); if (toolPath) { core.info(`Found in cache @ ${toolPath}`); - return toolPath; + return { + installedDir: toolPath, + installedBinPath: path.join(toolPath, "firefox"), + }; } core.info(`Attempting to download firefox ${version}...`); const archivePath = await this.downloadArchive({ @@ -28,7 +35,10 @@ export class LinuxInstaller implements Installer { const cachedDir = await tc.cacheDir(extPath, "firefox", version); core.info(`Successfully cached firefox ${version} to ${cachedDir}`); - return cachedDir; + return { + installedDir: extPath, + installedBinPath: path.join(cachedDir, "firefox"), + }; } private async downloadArchive({ diff --git a/src/MacOSInstaller.ts b/src/MacOSInstaller.ts index 6cc64d2..8903ab4 100644 --- a/src/MacOSInstaller.ts +++ b/src/MacOSInstaller.ts @@ -4,15 +4,22 @@ import * as exec from "@actions/exec"; import * as tc from "@actions/tool-cache"; import { DownloadURLFactory } from "./DownloadURLFactory"; import { testBinaryVersion } from "./firefoxUtils"; -import type { InstallSpec, Installer } from "./installers"; +import type { InstallResult, InstallSpec, Installer } from "./installers"; import { LatestVersion } from "./versions"; export class MacOSInstaller implements Installer { - async install({ version, platform, language }: InstallSpec): Promise { + async install({ + version, + platform, + language, + }: InstallSpec): Promise { const toolPath = tc.find("firefox", version); if (toolPath) { core.info(`Found in cache @ ${toolPath}`); - return toolPath; + return { + installedDir: toolPath, + installedBinPath: path.join(toolPath, "Contents", "MacOS", "firefox"), + }; } core.info(`Attempting to download firefox ${version}...`); const archivePath = await this.downloadArchive({ @@ -29,7 +36,10 @@ export class MacOSInstaller implements Installer { const cachedDir = await tc.cacheDir(appPath, "firefox", version); core.info(`Successfully cached firefox ${version} to ${cachedDir}`); - return path.join(cachedDir, "Contents", "MacOS"); + return { + installedDir: cachedDir, + installedBinPath: path.join(cachedDir, "Contents", "MacOS", "firefox"), + }; } private async downloadArchive({ diff --git a/src/WindowsInstaller.ts b/src/WindowsInstaller.ts index e726914..144c19c 100644 --- a/src/WindowsInstaller.ts +++ b/src/WindowsInstaller.ts @@ -6,14 +6,21 @@ import * as io from "@actions/io"; import * as tc from "@actions/tool-cache"; import { DownloadURLFactory } from "./DownloadURLFactory"; import { testBinaryVersion } from "./firefoxUtils"; -import type { InstallSpec, Installer } from "./installers"; +import type { InstallResult, InstallSpec, Installer } from "./installers"; export class WindowsInstaller implements Installer { - async install({ version, platform, language }: InstallSpec): Promise { + async install({ + version, + platform, + language, + }: InstallSpec): Promise { const installPath = `C:\\Program Files\\Firefox_${version}`; if (await this.checkInstall(installPath)) { core.info(`Already installed @ ${installPath}`); - return installPath; + return { + installedDir: installPath, + installedBinPath: path.join(installPath, "firefox.exe"), + }; } core.info(`Attempting to download firefox ${version}...`); @@ -27,7 +34,10 @@ export class WindowsInstaller implements Installer { await this.extractArchive(installerPath, installPath); core.info(`Successfully installed firefox ${version} to ${installPath}`); - return installPath; + return { + installedDir: installPath, + installedBinPath: path.join(installPath, "firefox.exe"), + }; } private async downloadArchive({ diff --git a/src/index.ts b/src/index.ts index 12a7ad5..dda0013 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,3 @@ -import * as path from "node:path"; import * as core from "@actions/core"; import { InstallerFactory } from "./installers"; import { getPlatform } from "./platform"; @@ -17,11 +16,14 @@ const run = async (): Promise => { core.info(`Setup firefox ${version} (${language})`); const installer = new InstallerFactory().create(platform); - const installDir = await installer.install({ version, platform, language }); + const { installedDir, installedBinPath } = await installer.install({ + version, + platform, + language, + }); - core.addPath(installDir); + core.addPath(installedDir); - const installedBinPath = path.join(installDir, "firefox"); const installedVersion = await installer.testVersion(installedBinPath); core.info(`Successfully setup firefox version ${installedVersion}`); core.setOutput("firefox-version", installedVersion); diff --git a/src/installers.ts b/src/installers.ts index aef30b4..aa7eb27 100644 --- a/src/installers.ts +++ b/src/installers.ts @@ -9,8 +9,13 @@ export type InstallSpec = { language: string; }; +export type InstallResult = { + installedDir: string; + installedBinPath: string; +}; + export interface Installer { - install(spec: InstallSpec): Promise; + install(spec: InstallSpec): Promise; testVersion(bin: string): Promise; } From ee7da1a5bc63b458c5a0ce6132f96d482f7e732a Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 21 Jul 2025 12:52:58 +0900 Subject: [PATCH 4/5] check version with output parameter --- .github/workflows/build.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d653140..e35827f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,21 +37,33 @@ jobs: with: name: dist - - uses: ./ + - name: Test default + uses: ./ + id: test-default - run: | firefox --version - - uses: ./ + ${{ steps.test-default.outputs.firefox-path }} --version + - name: Test latest-esr + uses: ./ with: firefox-version: latest-esr + id: test-latest-esr - run: | firefox --version - - uses: ./ + ${{ steps.test-latest-esr.outputs.firefox-path }} --version + - name: Test 132.0 + uses: ./ with: firefox-version: "132.0" + id: test-132-0 - run: | firefox --version - - uses: ./ + ${{ steps.test-132-0.outputs.firefox-path }} --version + - name: Test devedition-132.0b1 + uses: ./ with: firefox-version: "devedition-132.0b1" + id: test-devedition-132-0b1 - run: | firefox --version + ${{ steps.test-devedition-132-0b1.outputs.firefox-path }} --version From 9928e0b362cc0d1f710eafa92255acb44b2ba82d Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 27 Jul 2025 11:27:46 +0900 Subject: [PATCH 5/5] separate tests for Windows and macOS/Linux --- .github/workflows/build.yml | 52 ++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e35827f..6069599 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,7 +30,7 @@ jobs: needs: [build] strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest, windows-11-arm] + os: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/download-artifact@v4 @@ -67,3 +67,53 @@ jobs: - run: | firefox --version ${{ steps.test-devedition-132-0b1.outputs.firefox-path }} --version + + test-windows: + needs: [build] + strategy: + matrix: + os: [windows-latest, windows-11-arm] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/download-artifact@v4 + with: + name: dist + + - name: Test default + uses: ./ + id: test-default + - name: Test default version + shell: pwsh + run: | + firefox --version + & "${{ steps.test-default.outputs.firefox-path }}" --version + - name: Test latest-esr + uses: ./ + with: + firefox-version: latest-esr + id: test-latest-esr + - name: Test latest-esr version + shell: pwsh + run: | + firefox --version + & "${{ steps.test-latest-esr.outputs.firefox-path }}" --version + - name: Test 132.0 + uses: ./ + with: + firefox-version: "132.0" + id: test-132-0 + - name: Test 132.0 version + shell: pwsh + run: | + firefox --version + & "${{ steps.test-132-0.outputs.firefox-path }}" --version + - name: Test devedition-132.0b1 + uses: ./ + with: + firefox-version: "devedition-132.0b1" + id: test-devedition-132-0b1 + - name: Test devedition-132.0b1 version + shell: pwsh + run: | + firefox --version + & "${{ steps.test-devedition-132-0b1.outputs.firefox-path }}" --version