Use op-cli-installed as local package
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import os from "os";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
import * as tc from "@actions/tool-cache";
|
||||
|
||||
export type SupportedPlatform = Extract<
|
||||
NodeJS.Platform,
|
||||
"linux" | "darwin" | "win32"
|
||||
>;
|
||||
|
||||
// maps OS architecture names to 1Password CLI installer architecture names
|
||||
export const archMap: Record<string, string> = {
|
||||
ia32: "386",
|
||||
x64: "amd64",
|
||||
arm: "arm",
|
||||
arm64: "arm64",
|
||||
};
|
||||
|
||||
// Builds the download URL for the 1Password CLI based on the platform and version.
|
||||
export const cliUrlBuilder: Record<
|
||||
SupportedPlatform,
|
||||
(version: string, arch?: string) => string
|
||||
> = {
|
||||
linux: (version, arch) =>
|
||||
`https://cache.agilebits.com/dist/1P/op2/pkg/${version}/op_linux_${arch}_${version}.zip`,
|
||||
darwin: (version) =>
|
||||
`https://cache.agilebits.com/dist/1P/op2/pkg/${version}/op_apple_universal_${version}.pkg`,
|
||||
win32: (version, arch) =>
|
||||
`https://cache.agilebits.com/dist/1P/op2/pkg/${version}/op_windows_${arch}_${version}.zip`,
|
||||
};
|
||||
|
||||
export class CliInstaller {
|
||||
public readonly version: string;
|
||||
public readonly arch: string;
|
||||
|
||||
public constructor(version: string) {
|
||||
this.version = version;
|
||||
this.arch = this.getArch();
|
||||
}
|
||||
|
||||
public async install(url: string): Promise<void> {
|
||||
console.info(`Downloading 1Password CLI from: ${url}`);
|
||||
const downloadPath = await tc.downloadTool(url);
|
||||
console.info("Installing 1Password CLI");
|
||||
const extractedPath = await tc.extractZip(downloadPath);
|
||||
core.addPath(extractedPath);
|
||||
core.info("1Password CLI installed");
|
||||
}
|
||||
|
||||
private getArch(): string {
|
||||
const arch = archMap[os.arch()];
|
||||
if (!arch) {
|
||||
throw new Error("Unsupported architecture");
|
||||
}
|
||||
|
||||
return arch;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { type Installer, newCliInstaller } from "./installer";
|
||||
@@ -0,0 +1,43 @@
|
||||
import os from "os";
|
||||
|
||||
import { newCliInstaller } from "./installer";
|
||||
import { LinuxInstaller } from "./linux";
|
||||
import { MacOsInstaller } from "./macos";
|
||||
import { WindowsInstaller } from "./windows";
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("newCliInstaller", () => {
|
||||
const version = "1.0.0";
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it("should return LinuxInstaller for linux platform", () => {
|
||||
jest.spyOn(os, "platform").mockReturnValue("linux");
|
||||
const installer = newCliInstaller(version);
|
||||
expect(installer).toBeInstanceOf(LinuxInstaller);
|
||||
});
|
||||
|
||||
it("should return MacOsInstaller for darwin platform", () => {
|
||||
jest.spyOn(os, "platform").mockReturnValue("darwin");
|
||||
const installer = newCliInstaller(version);
|
||||
expect(installer).toBeInstanceOf(MacOsInstaller);
|
||||
});
|
||||
|
||||
it("should return WindowsInstaller for win32 platform", () => {
|
||||
jest.spyOn(os, "platform").mockReturnValue("win32");
|
||||
const installer = newCliInstaller(version);
|
||||
expect(installer).toBeInstanceOf(WindowsInstaller);
|
||||
});
|
||||
|
||||
it("should throw error for unsupported platform", () => {
|
||||
jest.spyOn(os, "platform").mockReturnValue("sunos");
|
||||
expect(() => newCliInstaller(version)).toThrow(
|
||||
"Unsupported platform: sunos",
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import os from "os";
|
||||
|
||||
import { LinuxInstaller } from "./linux";
|
||||
import { MacOsInstaller } from "./macos";
|
||||
import { WindowsInstaller } from "./windows";
|
||||
|
||||
export interface Installer {
|
||||
installCli(): Promise<void>;
|
||||
}
|
||||
|
||||
export const newCliInstaller = (version: string): Installer => {
|
||||
const platform = os.platform();
|
||||
switch (platform) {
|
||||
case "linux":
|
||||
return new LinuxInstaller(version);
|
||||
case "darwin":
|
||||
return new MacOsInstaller(version);
|
||||
case "win32":
|
||||
return new WindowsInstaller(version);
|
||||
default:
|
||||
throw new Error(`Unsupported platform: ${platform}`);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
import os from "os";
|
||||
|
||||
import {
|
||||
archMap,
|
||||
CliInstaller,
|
||||
cliUrlBuilder,
|
||||
type SupportedPlatform,
|
||||
} from "./cli-installer";
|
||||
import { LinuxInstaller } from "./linux";
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("LinuxInstaller", () => {
|
||||
const version = "1.2.3";
|
||||
const arch: NodeJS.Architecture = "arm64";
|
||||
|
||||
it("should construct with given version and architecture", () => {
|
||||
jest.spyOn(os, "arch").mockReturnValue(arch);
|
||||
const installer = new LinuxInstaller(version);
|
||||
expect(installer.version).toEqual(version);
|
||||
expect(installer.arch).toEqual(archMap[arch]);
|
||||
});
|
||||
|
||||
it("should call install with correct URL", async () => {
|
||||
const installer = new LinuxInstaller(version);
|
||||
const installMock = jest
|
||||
.spyOn(CliInstaller.prototype, "install")
|
||||
.mockResolvedValue();
|
||||
|
||||
await installer.installCli();
|
||||
|
||||
const builder = cliUrlBuilder["linux" as SupportedPlatform];
|
||||
const url = builder(version, installer.arch);
|
||||
expect(installMock).toHaveBeenCalledWith(url);
|
||||
});
|
||||
});
|
||||
19
src/op-cli-installer/github-action/cli-installer/linux.ts
Normal file
19
src/op-cli-installer/github-action/cli-installer/linux.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import {
|
||||
CliInstaller,
|
||||
cliUrlBuilder,
|
||||
type SupportedPlatform,
|
||||
} from "./cli-installer";
|
||||
import type { Installer } from "./installer";
|
||||
|
||||
export class LinuxInstaller extends CliInstaller implements Installer {
|
||||
private readonly platform: SupportedPlatform = "linux"; // Node.js platform identifier for Linux
|
||||
|
||||
public constructor(version: string) {
|
||||
super(version);
|
||||
}
|
||||
|
||||
public async installCli(): Promise<void> {
|
||||
const urlBuilder = cliUrlBuilder[this.platform];
|
||||
await super.install(urlBuilder(this.version, this.arch));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import os from "os";
|
||||
|
||||
import {
|
||||
archMap,
|
||||
cliUrlBuilder,
|
||||
type SupportedPlatform,
|
||||
} from "./cli-installer";
|
||||
import { MacOsInstaller } from "./macos";
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("MacOsInstaller", () => {
|
||||
const version = "1.2.3";
|
||||
const arch: NodeJS.Architecture = "x64";
|
||||
|
||||
it("should construct with given version and architecture", () => {
|
||||
jest.spyOn(os, "arch").mockReturnValue(arch);
|
||||
const installer = new MacOsInstaller(version);
|
||||
expect(installer.version).toEqual(version);
|
||||
expect(installer.arch).toEqual(archMap[arch]);
|
||||
});
|
||||
|
||||
it("should call install with correct URL", async () => {
|
||||
const installer = new MacOsInstaller(version);
|
||||
const installMock = jest.spyOn(installer, "install").mockResolvedValue();
|
||||
|
||||
await installer.installCli();
|
||||
|
||||
const builder = cliUrlBuilder["darwin" as SupportedPlatform];
|
||||
const url = builder(version, installer.arch);
|
||||
expect(installMock).toHaveBeenCalledWith(url);
|
||||
});
|
||||
});
|
||||
49
src/op-cli-installer/github-action/cli-installer/macos.ts
Normal file
49
src/op-cli-installer/github-action/cli-installer/macos.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { exec } from "child_process";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { promisify } from "util";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
import * as tc from "@actions/tool-cache";
|
||||
|
||||
import {
|
||||
CliInstaller,
|
||||
cliUrlBuilder,
|
||||
type SupportedPlatform,
|
||||
} from "./cli-installer";
|
||||
import { type Installer } from "./installer";
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
export class MacOsInstaller extends CliInstaller implements Installer {
|
||||
private readonly platform: SupportedPlatform = "darwin"; // Node.js platform identifier for macOS
|
||||
|
||||
public constructor(version: string) {
|
||||
super(version);
|
||||
}
|
||||
|
||||
public async installCli(): Promise<void> {
|
||||
const urlBuilder = cliUrlBuilder[this.platform];
|
||||
await this.install(urlBuilder(this.version));
|
||||
}
|
||||
|
||||
// @actions/tool-cache package does not support .pkg files, so we need to handle the installation manually
|
||||
public override async install(downloadUrl: string): Promise<void> {
|
||||
console.info(`Downloading 1Password CLI from: ${downloadUrl}`);
|
||||
const pkgPath = await tc.downloadTool(downloadUrl);
|
||||
const pkgWithExtension = `${pkgPath}.pkg`;
|
||||
fs.renameSync(pkgPath, pkgWithExtension);
|
||||
|
||||
const expandDir = "temp-pkg";
|
||||
await execAsync(`pkgutil --expand "${pkgWithExtension}" "${expandDir}"`);
|
||||
const payloadPath = path.join(expandDir, "op.pkg", "Payload");
|
||||
console.info("Installing 1Password CLI");
|
||||
const cliPath = await tc.extractTar(payloadPath);
|
||||
core.addPath(cliPath);
|
||||
|
||||
fs.rmSync(expandDir, { recursive: true, force: true });
|
||||
fs.rmSync(pkgPath, { force: true });
|
||||
|
||||
core.info("1Password CLI installed");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import os from "os";
|
||||
|
||||
import {
|
||||
archMap,
|
||||
CliInstaller,
|
||||
cliUrlBuilder,
|
||||
type SupportedPlatform,
|
||||
} from "./cli-installer";
|
||||
import { WindowsInstaller } from "./windows";
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("WindowsInstaller", () => {
|
||||
const version = "1.2.3";
|
||||
const arch: NodeJS.Architecture = "x64";
|
||||
|
||||
it("should construct with given version and architecture", () => {
|
||||
jest.spyOn(os, "arch").mockReturnValue(arch);
|
||||
const installer = new WindowsInstaller(version);
|
||||
expect(installer.version).toEqual(version);
|
||||
expect(installer.arch).toEqual(archMap[arch]);
|
||||
});
|
||||
|
||||
it("should call install with correct URL", async () => {
|
||||
const installer = new WindowsInstaller(version);
|
||||
const installMock = jest
|
||||
.spyOn(CliInstaller.prototype, "install")
|
||||
.mockResolvedValue();
|
||||
|
||||
await installer.installCli();
|
||||
|
||||
const builder = cliUrlBuilder["win32" as SupportedPlatform];
|
||||
const url = builder(version, installer.arch);
|
||||
expect(installMock).toHaveBeenCalledWith(url);
|
||||
});
|
||||
});
|
||||
19
src/op-cli-installer/github-action/cli-installer/windows.ts
Normal file
19
src/op-cli-installer/github-action/cli-installer/windows.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import {
|
||||
CliInstaller,
|
||||
cliUrlBuilder,
|
||||
type SupportedPlatform,
|
||||
} from "./cli-installer";
|
||||
import type { Installer } from "./installer";
|
||||
|
||||
export class WindowsInstaller extends CliInstaller implements Installer {
|
||||
private readonly platform: SupportedPlatform = "win32"; // Node.js platform identifier for Windows
|
||||
|
||||
public constructor(version: string) {
|
||||
super(version);
|
||||
}
|
||||
|
||||
public async installCli(): Promise<void> {
|
||||
const urlBuilder = cliUrlBuilder[this.platform];
|
||||
await super.install(urlBuilder(this.version, this.arch));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user