From 20f826bfe76164099ab2403d9ea8509e16843223 Mon Sep 17 00:00:00 2001 From: Nikolai Laevskii <130154213+nikolai-laevskii@users.noreply.github.com> Date: Tue, 14 Nov 2023 20:15:26 +0100 Subject: [PATCH] Add platform info utilities to @actions/core (#1551) * Introduce platform utilities into @actions/core * Add tests for the platform helper * Update README.md * Update README.md with more details --- packages/core/README.md | 25 +++++++ packages/core/__tests__/platform.test.ts | 29 ++++++++ packages/core/package-lock.json | 27 ++++++++ packages/core/package.json | 1 + packages/core/src/core.ts | 5 ++ packages/core/src/platform.ts | 87 ++++++++++++++++++++++++ 6 files changed, 174 insertions(+) create mode 100644 packages/core/__tests__/platform.test.ts create mode 100644 packages/core/src/platform.ts diff --git a/packages/core/README.md b/packages/core/README.md index 8a471430..35bd72db 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -333,3 +333,28 @@ toPlatformPath('/foo/bar') // => \foo\bar // On a Linux runner. toPlatformPath('\\foo\\bar') // => /foo/bar ``` + +#### Platform helper + +Provides shorthands for getting information about platform action is running on. + +```js +import { platform } from '@actions/core' + +/* equals to a call of os.platform() */ +platform.platform // 'win32' | 'darwin' | 'linux' | 'freebsd' | 'openbsd' | 'android' | 'cygwin' | 'sunos' + +/* equals to a call of os.arch() */ +platform.arch // 'x64' | 'arm' | 'arm64' | 'ia32' | 'mips' | 'mipsel' | 'ppc' | 'ppc64' | 'riscv64' | 's390' | 's390x' + +/* common shorthands for platform-specific logic */ +platform.isWindows // true +platform.isMacOS // false +platform.isLinux // false + +/* run platform-specific script to get more details about the exact platform, works on Windows, MacOS and Linux */ +const { + name, // Microsoft Windows 11 Enterprise + version, // 10.0.22621 +} = await platform.getDetails() +``` diff --git a/packages/core/__tests__/platform.test.ts b/packages/core/__tests__/platform.test.ts new file mode 100644 index 00000000..c80be330 --- /dev/null +++ b/packages/core/__tests__/platform.test.ts @@ -0,0 +1,29 @@ +import os from 'os' +import {platform} from '../src/core' + +describe('getInfo', () => { + it('returns the platform info', async () => { + const info = await platform.getDetails() + expect(info).toEqual({ + name: expect.any(String), + platform: expect.any(String), + arch: expect.any(String), + version: expect.any(String), + isWindows: expect.any(Boolean), + isMacOS: expect.any(Boolean), + isLinux: expect.any(Boolean) + }) + }) + + it('returns the platform info with the correct name', async () => { + const isWindows = os.platform() === 'win32' + const isMacOS = os.platform() === 'darwin' + const isLinux = os.platform() === 'linux' + + const info = await platform.getDetails() + expect(info.platform).toEqual(os.platform()) + expect(info.isWindows).toEqual(isWindows) + expect(info.isMacOS).toEqual(isMacOS) + expect(info.isLinux).toEqual(isLinux) + }) +}) diff --git a/packages/core/package-lock.json b/packages/core/package-lock.json index d86f7ef0..7b1cf7bb 100644 --- a/packages/core/package-lock.json +++ b/packages/core/package-lock.json @@ -9,6 +9,7 @@ "version": "1.10.1", "license": "MIT", "dependencies": { + "@actions/exec": "^1.1.1", "@actions/http-client": "^2.0.1", "uuid": "^8.3.2" }, @@ -17,6 +18,14 @@ "@types/uuid": "^8.3.4" } }, + "node_modules/@actions/exec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", + "dependencies": { + "@actions/io": "^1.0.1" + } + }, "node_modules/@actions/http-client": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.0.tgz", @@ -25,6 +34,11 @@ "tunnel": "^0.0.6" } }, + "node_modules/@actions/io": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", + "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==" + }, "node_modules/@types/node": { "version": "12.0.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz", @@ -55,6 +69,14 @@ } }, "dependencies": { + "@actions/exec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", + "requires": { + "@actions/io": "^1.0.1" + } + }, "@actions/http-client": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.0.tgz", @@ -63,6 +85,11 @@ "tunnel": "^0.0.6" } }, + "@actions/io": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", + "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==" + }, "@types/node": { "version": "12.0.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz", diff --git a/packages/core/package.json b/packages/core/package.json index 1558268c..2eda27b5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -36,6 +36,7 @@ "url": "https://github.com/actions/toolkit/issues" }, "dependencies": { + "@actions/exec": "^1.1.1", "@actions/http-client": "^2.0.1", "uuid": "^8.3.2" }, diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 1e8d940a..0a141693 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -386,3 +386,8 @@ export {markdownSummary} from './summary' * Path exports */ export {toPosixPath, toWin32Path, toPlatformPath} from './path-utils' + +/** + * Platform utilities exports + */ +export * as platform from './platform' diff --git a/packages/core/src/platform.ts b/packages/core/src/platform.ts new file mode 100644 index 00000000..55fdee64 --- /dev/null +++ b/packages/core/src/platform.ts @@ -0,0 +1,87 @@ +import os from 'os' +import * as exec from '@actions/exec' + +const getWindowsInfo = async (): Promise<{name: string; version: string}> => { + const {stdout: version} = await exec.getExecOutput( + 'powershell -command "(Get-CimInstance -ClassName Win32_OperatingSystem).Version"', + undefined, + { + silent: true + } + ) + + const {stdout: name} = await exec.getExecOutput( + 'powershell -command "(Get-CimInstance -ClassName Win32_OperatingSystem).Caption"', + undefined, + { + silent: true + } + ) + + return { + name: name.trim(), + version: version.trim() + } +} + +const getMacOsInfo = async (): Promise<{ + name: string + version: string +}> => { + const {stdout} = await exec.getExecOutput('sw_vers', undefined, { + silent: true + }) + + const version = stdout.match(/ProductVersion:\s*(.+)/)?.[1] ?? '' + const name = stdout.match(/ProductName:\s*(.+)/)?.[1] ?? '' + + return { + name, + version + } +} + +const getLinuxInfo = async (): Promise<{ + name: string + version: string +}> => { + const {stdout} = await exec.getExecOutput('lsb_release', ['-i', '-r', '-s'], { + silent: true + }) + + const [name, version] = stdout.trim().split('\n') + + return { + name, + version + } +} + +export const platform = os.platform() +export const arch = os.arch() +export const isWindows = platform === 'win32' +export const isMacOS = platform === 'darwin' +export const isLinux = platform === 'linux' + +export async function getDetails(): Promise<{ + name: string + platform: string + arch: string + version: string + isWindows: boolean + isMacOS: boolean + isLinux: boolean +}> { + return { + ...(await (isWindows + ? getWindowsInfo() + : isMacOS + ? getMacOsInfo() + : getLinuxInfo())), + platform, + arch, + isWindows, + isMacOS, + isLinux + } +}