From d1c539d005a6799d260d491109184e0fad007f23 Mon Sep 17 00:00:00 2001 From: Alfi Maulana Date: Wed, 7 Aug 2024 21:20:14 +0700 Subject: [PATCH] refactor: refactor inputs to context (#400) * refactor: rename `inputs` to `context` * refactor: merge compiler and flags inputs to options input * refactor: separate configure and build context --- dist/index.mjs | 100 +++++++++--------- src/cmake.test.ts | 99 ++++++++---------- src/cmake.ts | 42 +++----- src/{inputs.test.ts => context.test.ts} | 129 +++++++++++++++++------- src/context.ts | 74 ++++++++++++++ src/index.ts | 12 +-- src/inputs.ts | 48 --------- 7 files changed, 283 insertions(+), 221 deletions(-) rename src/{inputs.test.ts => context.test.ts} (52%) create mode 100644 src/context.ts delete mode 100644 src/inputs.ts diff --git a/dist/index.mjs b/dist/index.mjs index 9c15387..9d69773 100644 --- a/dist/index.mjs +++ b/dist/index.mjs @@ -8,40 +8,28 @@ function r(r){return function(r){if("object"==typeof(e=r)&&null!==e&&"message"in /** * Configures the build system of a CMake project. * - * @param inputs - The action inputs. + * @param context - The action context. */ -function configureProject(inputs) { +function configureProject(context) { const configureArgs = []; - if (inputs.sourceDir) { - configureArgs.push(inputs.sourceDir); + if (context.sourceDir) { + configureArgs.push(context.sourceDir); } - configureArgs.push("-B", inputs.buildDir); - if (inputs.generator) { - configureArgs.push(...["-G", inputs.generator]); + configureArgs.push("-B", context.buildDir); + if (context.configure.generator) { + configureArgs.push(...["-G", context.configure.generator]); } - if (inputs.cCompiler) { - configureArgs.push("-DCMAKE_C_COMPILER=" + inputs.cCompiler); - } - if (inputs.cxxCompiler) { - configureArgs.push("-DCMAKE_CXX_COMPILER=" + inputs.cxxCompiler); - } - if (inputs.cFlags) { - configureArgs.push("-DCMAKE_C_FLAGS=" + inputs.cFlags); - } - if (inputs.cxxFlags) { - configureArgs.push("-DCMAKE_CXX_FLAGS=" + inputs.cxxFlags); - } - configureArgs.push(...inputs.options.map((opt) => "-D" + opt)); - configureArgs.push(...inputs.args); + configureArgs.push(...context.configure.options.map((opt) => "-D" + opt)); + configureArgs.push(...context.configure.args); execFileSync("cmake", configureArgs, { stdio: "inherit" }); } /** * Build a CMake project. * - * @param inputs - The action inputs. + * @param context - The action context. */ -function buildProject(inputs) { - execFileSync("cmake", ["--build", inputs.buildDir, ...inputs.buildArgs], { +function buildProject(context) { + execFileSync("cmake", ["--build", context.buildDir, ...context.build.args], { stdio: "inherit", }); } @@ -55,35 +43,57 @@ function getInput(key) { const value = process.env[`INPUT_${key.toUpperCase()}`] || ""; return value.trim(); } -function getInputs() { +function getContext() { const sourceDir = getInput("source-dir"); + const options = []; + let input = getInput("c-compiler"); + if (input) + options.push(`CMAKE_C_COMPILER=${input}`); + input = getInput("cxx-compiler"); + if (input) + options.push(`CMAKE_CXX_COMPILER=${input}`); + input = getInput("c-flags"); + if (input) { + const flags = input.replaceAll(/\s+/g, " "); + options.push(`CMAKE_C_FLAGS=${flags}`); + } + input = getInput("cxx-flags"); + if (input) { + const flags = input.replaceAll(/\s+/g, " "); + options.push(`CMAKE_CXX_FLAGS=${flags}`); + } + input = getInput("options"); + if (input) { + const opts = input.split(/\s+/).filter((arg) => arg != ""); + for (const opt of opts) { + options.push(opt); + } + } return { sourceDir, buildDir: getInput("build-dir") || path.join(sourceDir, "build"), - generator: getInput("generator"), - cCompiler: getInput("c-compiler"), - cxxCompiler: getInput("cxx-compiler"), - cFlags: getInput("c-flags").replaceAll(/\s+/g, " "), - cxxFlags: getInput("cxx-flags").replaceAll(/\s+/g, " "), - options: getInput("options") - .split(/\s+/) - .filter((arg) => arg != ""), - args: getInput("args") - .split(/\s+/) - .filter((arg) => arg != ""), - runBuild: getInput("run-build") == "true", - buildArgs: getInput("build-args") - .split(/\s+/) - .filter((arg) => arg != ""), + configure: { + generator: getInput("generator"), + options, + args: getInput("args") + .split(/\s+/) + .filter((arg) => arg != ""), + }, + build: { + enabled: getInput("run-build") == "true", + args: getInput("build-args") + .split(/\s+/) + .filter((arg) => arg != ""), + }, }; } try { - const inputs = getInputs(); - configureProject(inputs); - fs.appendFileSync(process.env["GITHUB_OUTPUT"], `build-dir=${inputs.buildDir}${os.EOL}`); - if (inputs.runBuild) { - buildProject(inputs); + const context = getContext(); + configureProject(context); + fs.appendFileSync(process.env["GITHUB_OUTPUT"], `build-dir=${context.buildDir}${os.EOL}`); + if (context.build.enabled) { + buildProject(context); } } catch (err) { diff --git a/src/cmake.test.ts b/src/cmake.test.ts index 7f43287..0b676e8 100644 --- a/src/cmake.test.ts +++ b/src/cmake.test.ts @@ -1,24 +1,24 @@ import { jest } from "@jest/globals"; -import type { Inputs } from "./inputs.js"; +import type { Context } from "./context.js"; interface TestCase { name: string; - inputs?: Partial; + context?: Partial; expectedArgs: string[]; } -const defaultInputs: Inputs = { +const defaultContext: Context = { sourceDir: "", buildDir: "build", - generator: "", - cCompiler: "", - cxxCompiler: "", - cFlags: "", - cxxFlags: "", - options: [], - args: [], - runBuild: true, - buildArgs: [], + configure: { + generator: "", + options: [], + args: [], + }, + build: { + enabled: true, + args: [], + }, }; jest.unstable_mockModule("node:child_process", () => ({ @@ -33,42 +33,28 @@ describe("configure a CMake project", () => { }, { name: "with source directory specified", - inputs: { sourceDir: "project" }, + context: { sourceDir: "project" }, expectedArgs: ["project", "-B", "build"], }, { name: "with build directory specified", - inputs: { buildDir: "output" }, + context: { buildDir: "output" }, expectedArgs: ["-B", "output"], }, { name: "with generator specified", - inputs: { generator: "Ninja" }, + context: { configure: { generator: "Ninja", options: [], args: [] } }, expectedArgs: ["-B", "build", "-G", "Ninja"], }, - { - name: "with C compiler specified", - inputs: { cCompiler: "clang" }, - expectedArgs: ["-B", "build", "-DCMAKE_C_COMPILER=clang"], - }, - { - name: "with C++ compiler specified", - inputs: { cxxCompiler: "clang++" }, - expectedArgs: ["-B", "build", "-DCMAKE_CXX_COMPILER=clang++"], - }, - { - name: "with C flags specified", - inputs: { cFlags: "-Werror -Wall" }, - expectedArgs: ["-B", "build", "-DCMAKE_C_FLAGS=-Werror -Wall"], - }, - { - name: "with C++ flags specified", - inputs: { cxxFlags: "-Werror -Wall -Wextra" }, - expectedArgs: ["-B", "build", "-DCMAKE_CXX_FLAGS=-Werror -Wall -Wextra"], - }, { name: "with additional options specified", - inputs: { options: ["BUILD_TESTING=ON", "BUILD_EXAMPLES=ON"] }, + context: { + configure: { + generator: "", + options: ["BUILD_TESTING=ON", "BUILD_EXAMPLES=ON"], + args: [], + }, + }, expectedArgs: [ "-B", "build", @@ -78,21 +64,25 @@ describe("configure a CMake project", () => { }, { name: "with additional arguments specified", - inputs: { args: ["-Wdev", "-Wdeprecated"] }, + context: { + configure: { + generator: "", + options: [], + args: ["-Wdev", "-Wdeprecated"], + }, + }, expectedArgs: ["-B", "build", "-Wdev", "-Wdeprecated"], }, { name: "with all specified", - inputs: { + context: { sourceDir: "project", buildDir: "output", - generator: "Ninja", - cCompiler: "clang", - cxxCompiler: "clang++", - cFlags: "-Werror -Wall", - cxxFlags: "-Werror -Wall -Wextra", - options: ["BUILD_TESTING=ON", "BUILD_EXAMPLES=ON"], - args: ["-Wdev", "-Wdeprecated"], + configure: { + generator: "Ninja", + options: ["BUILD_TESTING=ON", "BUILD_EXAMPLES=ON"], + args: ["-Wdev", "-Wdeprecated"], + }, }, expectedArgs: [ "project", @@ -100,10 +90,6 @@ describe("configure a CMake project", () => { "output", "-G", "Ninja", - "-DCMAKE_C_COMPILER=clang", - "-DCMAKE_CXX_COMPILER=clang++", - "-DCMAKE_C_FLAGS=-Werror -Wall", - "-DCMAKE_CXX_FLAGS=-Werror -Wall -Wextra", "-DBUILD_TESTING=ON", "-DBUILD_EXAMPLES=ON", "-Wdev", @@ -119,7 +105,7 @@ describe("configure a CMake project", () => { jest.mocked(execFileSync).mockReset(); - configureProject({ ...defaultInputs, ...testCase.inputs }); + configureProject({ ...defaultContext, ...testCase.context }); expect(execFileSync).toHaveBeenCalledTimes(1); expect(execFileSync).toHaveBeenLastCalledWith( @@ -139,19 +125,22 @@ describe("build a CMake project", () => { }, { name: "with build directory specified", - inputs: { buildDir: "output" }, + context: { buildDir: "output" }, expectedArgs: ["--build", "output"], }, { name: "with additional arguments specified", - inputs: { buildArgs: ["--target", "foo"] }, + context: { build: { enabled: true, args: ["--target", "foo"] } }, expectedArgs: ["--build", "build", "--target", "foo"], }, { name: "with all specified", - inputs: { + context: { buildDir: "output", - buildArgs: ["--target", "foo"], + build: { + enabled: true, + args: ["--target", "foo"], + }, }, expectedArgs: ["--build", "output", "--target", "foo"], }, @@ -164,7 +153,7 @@ describe("build a CMake project", () => { jest.mocked(execFileSync).mockReset(); - buildProject({ ...defaultInputs, ...testCase.inputs }); + buildProject({ ...defaultContext, ...testCase.context }); expect(execFileSync).toHaveBeenCalledTimes(1); expect(execFileSync).toHaveBeenLastCalledWith( diff --git a/src/cmake.ts b/src/cmake.ts index ba56a44..512aa6b 100644 --- a/src/cmake.ts +++ b/src/cmake.ts @@ -1,42 +1,26 @@ import { execFileSync } from "node:child_process"; -import type { Inputs } from "./inputs.js"; +import type { Context } from "./context.js"; /** * Configures the build system of a CMake project. * - * @param inputs - The action inputs. + * @param context - The action context. */ -export function configureProject(inputs: Inputs): void { +export function configureProject(context: Context): void { const configureArgs = []; - if (inputs.sourceDir) { - configureArgs.push(inputs.sourceDir); + if (context.sourceDir) { + configureArgs.push(context.sourceDir); } - configureArgs.push("-B", inputs.buildDir); + configureArgs.push("-B", context.buildDir); - if (inputs.generator) { - configureArgs.push(...["-G", inputs.generator]); + if (context.configure.generator) { + configureArgs.push(...["-G", context.configure.generator]); } - if (inputs.cCompiler) { - configureArgs.push("-DCMAKE_C_COMPILER=" + inputs.cCompiler); - } - - if (inputs.cxxCompiler) { - configureArgs.push("-DCMAKE_CXX_COMPILER=" + inputs.cxxCompiler); - } - - if (inputs.cFlags) { - configureArgs.push("-DCMAKE_C_FLAGS=" + inputs.cFlags); - } - - if (inputs.cxxFlags) { - configureArgs.push("-DCMAKE_CXX_FLAGS=" + inputs.cxxFlags); - } - - configureArgs.push(...inputs.options.map((opt) => "-D" + opt)); - configureArgs.push(...inputs.args); + configureArgs.push(...context.configure.options.map((opt) => "-D" + opt)); + configureArgs.push(...context.configure.args); execFileSync("cmake", configureArgs, { stdio: "inherit" }); } @@ -44,10 +28,10 @@ export function configureProject(inputs: Inputs): void { /** * Build a CMake project. * - * @param inputs - The action inputs. + * @param context - The action context. */ -export function buildProject(inputs: Inputs): void { - execFileSync("cmake", ["--build", inputs.buildDir, ...inputs.buildArgs], { +export function buildProject(context: Context): void { + execFileSync("cmake", ["--build", context.buildDir, ...context.build.args], { stdio: "inherit", }); } diff --git a/src/inputs.test.ts b/src/context.test.ts similarity index 52% rename from src/inputs.test.ts rename to src/context.test.ts index d171513..ee0ba3e 100644 --- a/src/inputs.test.ts +++ b/src/context.test.ts @@ -1,11 +1,11 @@ import path from "node:path"; -import { Inputs, getInputs } from "./inputs.js"; +import { Context, getContext } from "./context.js"; -describe("get action inputs", () => { +describe("get action context", () => { interface TestCase { name: string; env?: Record; - expectedInputs?: Partial; + expectedContext?: Partial; } const testCases: TestCase[] = [ @@ -15,7 +15,7 @@ describe("get action inputs", () => { { name: "with source directory specified", env: { "INPUT_SOURCE-DIR": "project" }, - expectedInputs: { + expectedContext: { sourceDir: "project", buildDir: path.join("project", "build"), }, @@ -23,7 +23,7 @@ describe("get action inputs", () => { { name: "with build directory specified", env: { "INPUT_BUILD-DIR": "output" }, - expectedInputs: { buildDir: "output" }, + expectedContext: { buildDir: "output" }, }, { name: "with source and build directories specified", @@ -31,7 +31,7 @@ describe("get action inputs", () => { "INPUT_SOURCE-DIR": "project", "INPUT_BUILD-DIR": "output", }, - expectedInputs: { + expectedContext: { sourceDir: "project", buildDir: "output", }, @@ -39,51 +39,96 @@ describe("get action inputs", () => { { name: "with generator specified", env: { INPUT_GENERATOR: "Ninja" }, - expectedInputs: { generator: "Ninja" }, + expectedContext: { + configure: { + generator: "Ninja", + options: [], + args: [], + }, + }, }, { name: "with C compiler specified", env: { "INPUT_C-COMPILER": "clang" }, - expectedInputs: { cCompiler: "clang" }, + expectedContext: { + configure: { + generator: "", + options: ["CMAKE_C_COMPILER=clang"], + args: [], + }, + }, }, { name: "with C++ compiler specified", env: { "INPUT_CXX-COMPILER": "clang++" }, - expectedInputs: { cxxCompiler: "clang++" }, + expectedContext: { + configure: { + generator: "", + options: ["CMAKE_CXX_COMPILER=clang++"], + args: [], + }, + }, }, { name: "with C flags specified", env: { "INPUT_C-FLAGS": "-Werror -Wall\n-Wextra" }, - expectedInputs: { cFlags: "-Werror -Wall -Wextra" }, + expectedContext: { + configure: { + generator: "", + options: ["CMAKE_C_FLAGS=-Werror -Wall -Wextra"], + args: [], + }, + }, }, { name: "with C++ flags specified", env: { "INPUT_CXX-FLAGS": "-Werror -Wall\n-Wextra -Wpedantic" }, - expectedInputs: { cxxFlags: "-Werror -Wall -Wextra -Wpedantic" }, + expectedContext: { + configure: { + generator: "", + options: ["CMAKE_CXX_FLAGS=-Werror -Wall -Wextra -Wpedantic"], + args: [], + }, + }, }, { name: "with additional options specified", env: { INPUT_OPTIONS: "BUILD_TESTING=ON BUILD_EXAMPLES=ON\nBUILD_DOCS=ON", }, - expectedInputs: { - options: ["BUILD_TESTING=ON", "BUILD_EXAMPLES=ON", "BUILD_DOCS=ON"], + expectedContext: { + configure: { + generator: "", + options: ["BUILD_TESTING=ON", "BUILD_EXAMPLES=ON", "BUILD_DOCS=ON"], + args: [], + }, }, }, { name: "with additional arguments specified", env: { INPUT_ARGS: "-Wdev -Wdeprecated\n--fresh" }, - expectedInputs: { args: ["-Wdev", "-Wdeprecated", "--fresh"] }, + expectedContext: { + configure: { + generator: "", + options: [], + args: ["-Wdev", "-Wdeprecated", "--fresh"], + }, + }, }, { name: "with run build specified", env: { "INPUT_RUN-BUILD": "true" }, - expectedInputs: { runBuild: true }, + expectedContext: { build: { enabled: true, args: [] } }, }, { name: "with additional build arguments specified", env: { "INPUT_BUILD-ARGS": "--target foo\n--parallel 8" }, - expectedInputs: { buildArgs: ["--target", "foo", "--parallel", "8"] }, + expectedContext: { + build: { + enabled: false, + args: ["--target", "foo", "--parallel", "8"], + }, + }, }, { name: "with all specified", @@ -100,43 +145,51 @@ describe("get action inputs", () => { "INPUT_RUN-BUILD": "true", "INPUT_BUILD-ARGS": "--target foo\n--parallel 8", }, - expectedInputs: { + expectedContext: { sourceDir: "project", buildDir: "output", - generator: "Ninja", - cCompiler: "clang", - cxxCompiler: "clang++", - cFlags: "-Werror -Wall -Wextra", - cxxFlags: "-Werror -Wall -Wextra -Wpedantic", - options: ["BUILD_TESTING=ON", "BUILD_EXAMPLES=ON", "BUILD_DOCS=ON"], - args: ["-Wdev", "-Wdeprecated", "--fresh"], - runBuild: true, - buildArgs: ["--target", "foo", "--parallel", "8"], + configure: { + generator: "Ninja", + options: [ + "CMAKE_C_COMPILER=clang", + "CMAKE_CXX_COMPILER=clang++", + "CMAKE_C_FLAGS=-Werror -Wall -Wextra", + "CMAKE_CXX_FLAGS=-Werror -Wall -Wextra -Wpedantic", + "BUILD_TESTING=ON", + "BUILD_EXAMPLES=ON", + "BUILD_DOCS=ON", + ], + args: ["-Wdev", "-Wdeprecated", "--fresh"], + }, + build: { + enabled: true, + args: ["--target", "foo", "--parallel", "8"], + }, }, }, ]; for (const testCase of testCases) { - it(`should get the action inputs ${testCase.name}`, async () => { + it(`should get the action context ${testCase.name}`, async () => { const prevEnv = process.env; process.env = { ...process.env, ...testCase.env, }; - expect(getInputs()).toStrictEqual({ + expect(getContext()).toStrictEqual({ sourceDir: "", buildDir: "build", - generator: "", - cCompiler: "", - cxxCompiler: "", - cFlags: "", - cxxFlags: "", - options: [], - args: [], - runBuild: false, - buildArgs: [], - ...testCase.expectedInputs, + configure: { + generator: "", + options: [], + args: [], + }, + build: { + enabled: false, + args: [], + }, + ...testCase.expectedContext, }); process.env = prevEnv; diff --git a/src/context.ts b/src/context.ts new file mode 100644 index 0000000..8f6ac2a --- /dev/null +++ b/src/context.ts @@ -0,0 +1,74 @@ +import path from "node:path"; + +export interface Context { + sourceDir: string; + buildDir: string; + configure: { + generator: string; + options: string[]; + args: string[]; + }; + build: { + enabled: boolean; + args: string[]; + }; +} + +/** + * Retrieves an action input. + * @param key - The key of the action input. + * @returns The action input value as a string. + */ +function getInput(key: string): string { + const value = process.env[`INPUT_${key.toUpperCase()}`] || ""; + return value.trim(); +} + +export function getContext(): Context { + const sourceDir = getInput("source-dir"); + const options: string[] = []; + + let input = getInput("c-compiler"); + if (input) options.push(`CMAKE_C_COMPILER=${input}`); + + input = getInput("cxx-compiler"); + if (input) options.push(`CMAKE_CXX_COMPILER=${input}`); + + input = getInput("c-flags"); + if (input) { + const flags = input.replaceAll(/\s+/g, " "); + options.push(`CMAKE_C_FLAGS=${flags}`); + } + + input = getInput("cxx-flags"); + if (input) { + const flags = input.replaceAll(/\s+/g, " "); + options.push(`CMAKE_CXX_FLAGS=${flags}`); + } + + input = getInput("options"); + if (input) { + const opts = input.split(/\s+/).filter((arg) => arg != ""); + for (const opt of opts) { + options.push(opt); + } + } + + return { + sourceDir, + buildDir: getInput("build-dir") || path.join(sourceDir, "build"), + configure: { + generator: getInput("generator"), + options, + args: getInput("args") + .split(/\s+/) + .filter((arg) => arg != ""), + }, + build: { + enabled: getInput("run-build") == "true", + args: getInput("build-args") + .split(/\s+/) + .filter((arg) => arg != ""), + }, + }; +} diff --git a/src/index.ts b/src/index.ts index 356c264..5238f92 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,20 +2,20 @@ import { getErrorMessage } from "catched-error-message"; import fs from "node:fs"; import os from "node:os"; import { buildProject, configureProject } from "./cmake.js"; -import { getInputs } from "./inputs.js"; +import { getContext } from "./context.js"; try { - const inputs = getInputs(); + const context = getContext(); - configureProject(inputs); + configureProject(context); fs.appendFileSync( process.env["GITHUB_OUTPUT"] as string, - `build-dir=${inputs.buildDir}${os.EOL}`, + `build-dir=${context.buildDir}${os.EOL}`, ); - if (inputs.runBuild) { - buildProject(inputs); + if (context.build.enabled) { + buildProject(context); } } catch (err) { process.exitCode = 1; diff --git a/src/inputs.ts b/src/inputs.ts deleted file mode 100644 index f4a01eb..0000000 --- a/src/inputs.ts +++ /dev/null @@ -1,48 +0,0 @@ -import path from "node:path"; - -export interface Inputs { - sourceDir: string; - buildDir: string; - generator: string; - cCompiler: string; - cxxCompiler: string; - cFlags: string; - cxxFlags: string; - options: string[]; - args: string[]; - runBuild: boolean; - buildArgs: string[]; -} - -/** - * Retrieves an action input. - * @param key - The key of the action input. - * @returns The action input value as a string. - */ -function getInput(key: string): string { - const value = process.env[`INPUT_${key.toUpperCase()}`] || ""; - return value.trim(); -} - -export function getInputs(): Inputs { - const sourceDir = getInput("source-dir"); - return { - sourceDir, - buildDir: getInput("build-dir") || path.join(sourceDir, "build"), - generator: getInput("generator"), - cCompiler: getInput("c-compiler"), - cxxCompiler: getInput("cxx-compiler"), - cFlags: getInput("c-flags").replaceAll(/\s+/g, " "), - cxxFlags: getInput("cxx-flags").replaceAll(/\s+/g, " "), - options: getInput("options") - .split(/\s+/) - .filter((arg) => arg != ""), - args: getInput("args") - .split(/\s+/) - .filter((arg) => arg != ""), - runBuild: getInput("run-build") == "true", - buildArgs: getInput("build-args") - .split(/\s+/) - .filter((arg) => arg != ""), - }; -}