mirror of
				https://github.com/threeal/cmake-action.git
				synced 2025-11-03 21:33:42 +00:00 
			
		
		
		
	feat: use asynchronous version of the exec file function (#522)
* feat: add `exec` function Signed-off-by: Alfi Maulana <alfi.maulana.f@gmail.com> * feat: use `exec` function in `configureProject` and `buildProject` functions Signed-off-by: Alfi Maulana <alfi.maulana.f@gmail.com> --------- Signed-off-by: Alfi Maulana <alfi.maulana.f@gmail.com>
This commit is contained in:
		
							parent
							
								
									5dcae6263b
								
							
						
					
					
						commit
						478382dd46
					
				
							
								
								
									
										60
									
								
								dist/action.mjs
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								dist/action.mjs
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -2,7 +2,7 @@ import 'node:fs';
 | 
				
			|||||||
import fsPromises from 'node:fs/promises';
 | 
					import fsPromises from 'node:fs/promises';
 | 
				
			||||||
import os from 'node:os';
 | 
					import os from 'node:os';
 | 
				
			||||||
import path from 'node:path';
 | 
					import path from 'node:path';
 | 
				
			||||||
import { execFileSync } from 'node:child_process';
 | 
					import { spawn } from 'node:child_process';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @internal
 | 
					 * @internal
 | 
				
			||||||
@ -52,32 +52,64 @@ function logError(err) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Configures the build system of a CMake project.
 | 
					 * Executes a command with the given arguments.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param context - The action context.
 | 
					 * The command is executed with `stdin` ignored and both `stdout` and `stderr` inherited by the parent process.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param command The command to execute.
 | 
				
			||||||
 | 
					 * @param args The arguments to pass to the command.
 | 
				
			||||||
 | 
					 * @returns A promise that resolves when the command exits successfully or rejects if it exits with a non-zero status code or encounters an error.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function configureProject(context) {
 | 
					async function exec(command, args) {
 | 
				
			||||||
 | 
					    return new Promise((resolve, reject) => {
 | 
				
			||||||
 | 
					        const proc = spawn(command, args, {
 | 
				
			||||||
 | 
					            stdio: ["ignore", "inherit", "inherit"],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        proc.on("error", reject);
 | 
				
			||||||
 | 
					        proc.on("close", (code) => {
 | 
				
			||||||
 | 
					            if (code === 0) {
 | 
				
			||||||
 | 
					                resolve();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                reject(new Error(`Command exited with status code ${code}`));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Configures the build system for a CMake project.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Constructs and runs the `cmake` command to configure the project with the specified
 | 
				
			||||||
 | 
					 * source directory, build directory, generator, options, and additional arguments.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param context - The action context containing configuration details.
 | 
				
			||||||
 | 
					 * @returns A promise that resolves when the build system is successfully configured.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					async function configureProject(context) {
 | 
				
			||||||
    const configureArgs = [];
 | 
					    const configureArgs = [];
 | 
				
			||||||
    if (context.sourceDir) {
 | 
					    if (context.sourceDir) {
 | 
				
			||||||
        configureArgs.push(context.sourceDir);
 | 
					        configureArgs.push(context.sourceDir);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    configureArgs.push("-B", context.buildDir);
 | 
					    configureArgs.push("-B", context.buildDir);
 | 
				
			||||||
    if (context.configure.generator) {
 | 
					    if (context.configure.generator) {
 | 
				
			||||||
        configureArgs.push(...["-G", context.configure.generator]);
 | 
					        configureArgs.push("-G", context.configure.generator);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    configureArgs.push(...context.configure.options.map((opt) => "-D" + opt));
 | 
					    configureArgs.push(...context.configure.options.map((opt) => "-D" + opt));
 | 
				
			||||||
    configureArgs.push(...context.configure.args);
 | 
					    configureArgs.push(...context.configure.args);
 | 
				
			||||||
    execFileSync("cmake", configureArgs, { stdio: "inherit" });
 | 
					    await exec("cmake", configureArgs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Build a CMake project.
 | 
					 * Builds a CMake project.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param context - The action context.
 | 
					 * Runs the `cmake --build` command to build the project using the specified
 | 
				
			||||||
 | 
					 * build directory and additional arguments.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param context - The action context containing build details.
 | 
				
			||||||
 | 
					 * @returns A promise that resolves when the project is successfully built.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function buildProject(context) {
 | 
					async function buildProject(context) {
 | 
				
			||||||
    execFileSync("cmake", ["--build", context.buildDir, ...context.build.args], {
 | 
					    await exec("cmake", ["--build", context.buildDir, ...context.build.args]);
 | 
				
			||||||
        stdio: "inherit",
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var shellQuote = {};
 | 
					var shellQuote = {};
 | 
				
			||||||
@ -393,10 +425,10 @@ function getContext() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
try {
 | 
					try {
 | 
				
			||||||
    const context = getContext();
 | 
					    const context = getContext();
 | 
				
			||||||
    configureProject(context);
 | 
					    await configureProject(context);
 | 
				
			||||||
    await setOutput("build-dir", context.buildDir);
 | 
					    await setOutput("build-dir", context.buildDir);
 | 
				
			||||||
    if (context.build.enabled) {
 | 
					    if (context.build.enabled) {
 | 
				
			||||||
        buildProject(context);
 | 
					        await buildProject(context);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
catch (err) {
 | 
					catch (err) {
 | 
				
			||||||
 | 
				
			|||||||
@ -5,12 +5,12 @@ import { getContext } from "./context.js";
 | 
				
			|||||||
try {
 | 
					try {
 | 
				
			||||||
  const context = getContext();
 | 
					  const context = getContext();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  configureProject(context);
 | 
					  await configureProject(context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await setOutput("build-dir", context.buildDir);
 | 
					  await setOutput("build-dir", context.buildDir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (context.build.enabled) {
 | 
					  if (context.build.enabled) {
 | 
				
			||||||
    buildProject(context);
 | 
					    await buildProject(context);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
} catch (err) {
 | 
					} catch (err) {
 | 
				
			||||||
  logError(err);
 | 
					  logError(err);
 | 
				
			||||||
 | 
				
			|||||||
@ -21,8 +21,8 @@ const defaultContext: Context = {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jest.unstable_mockModule("node:child_process", () => ({
 | 
					jest.unstable_mockModule("./exec.js", () => ({
 | 
				
			||||||
  execFileSync: jest.fn(),
 | 
					  exec: jest.fn(),
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("configure a CMake project", () => {
 | 
					describe("configure a CMake project", () => {
 | 
				
			||||||
@ -101,18 +101,14 @@ describe("configure a CMake project", () => {
 | 
				
			|||||||
  for (const testCase of testCases) {
 | 
					  for (const testCase of testCases) {
 | 
				
			||||||
    it(`should execute the correct command ${testCase.name}`, async () => {
 | 
					    it(`should execute the correct command ${testCase.name}`, async () => {
 | 
				
			||||||
      const { configureProject } = await import("./cmake.js");
 | 
					      const { configureProject } = await import("./cmake.js");
 | 
				
			||||||
      const { execFileSync } = await import("node:child_process");
 | 
					      const { exec } = await import("./exec.js");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      jest.mocked(execFileSync).mockReset();
 | 
					      jest.mocked(exec).mockReset();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      configureProject({ ...defaultContext, ...testCase.context });
 | 
					      await configureProject({ ...defaultContext, ...testCase.context });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(execFileSync).toHaveBeenCalledTimes(1);
 | 
					      expect(exec).toHaveBeenCalledTimes(1);
 | 
				
			||||||
      expect(execFileSync).toHaveBeenLastCalledWith(
 | 
					      expect(exec).toHaveBeenLastCalledWith("cmake", testCase.expectedArgs);
 | 
				
			||||||
        "cmake",
 | 
					 | 
				
			||||||
        testCase.expectedArgs,
 | 
					 | 
				
			||||||
        { stdio: "inherit" },
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
@ -149,18 +145,14 @@ describe("build a CMake project", () => {
 | 
				
			|||||||
  for (const testCase of testCases) {
 | 
					  for (const testCase of testCases) {
 | 
				
			||||||
    it(`should execute the correct command ${testCase.name}`, async () => {
 | 
					    it(`should execute the correct command ${testCase.name}`, async () => {
 | 
				
			||||||
      const { buildProject } = await import("./cmake.js");
 | 
					      const { buildProject } = await import("./cmake.js");
 | 
				
			||||||
      const { execFileSync } = await import("node:child_process");
 | 
					      const { exec } = await import("./exec.js");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      jest.mocked(execFileSync).mockReset();
 | 
					      jest.mocked(exec).mockReset();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      buildProject({ ...defaultContext, ...testCase.context });
 | 
					      await buildProject({ ...defaultContext, ...testCase.context });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(execFileSync).toHaveBeenCalledTimes(1);
 | 
					      expect(exec).toHaveBeenCalledTimes(1);
 | 
				
			||||||
      expect(execFileSync).toHaveBeenLastCalledWith(
 | 
					      expect(exec).toHaveBeenLastCalledWith("cmake", testCase.expectedArgs);
 | 
				
			||||||
        "cmake",
 | 
					 | 
				
			||||||
        testCase.expectedArgs,
 | 
					 | 
				
			||||||
        { stdio: "inherit" },
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										30
									
								
								src/cmake.ts
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								src/cmake.ts
									
									
									
									
									
								
							@ -1,12 +1,16 @@
 | 
				
			|||||||
import { execFileSync } from "node:child_process";
 | 
					import { exec } from "./exec.js";
 | 
				
			||||||
import type { Context } from "./context.js";
 | 
					import type { Context } from "./context.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Configures the build system of a CMake project.
 | 
					 * Configures the build system for a CMake project.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param context - The action context.
 | 
					 * Constructs and runs the `cmake` command to configure the project with the specified
 | 
				
			||||||
 | 
					 * source directory, build directory, generator, options, and additional arguments.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param context - The action context containing configuration details.
 | 
				
			||||||
 | 
					 * @returns A promise that resolves when the build system is successfully configured.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export function configureProject(context: Context): void {
 | 
					export async function configureProject(context: Context): Promise<void> {
 | 
				
			||||||
  const configureArgs = [];
 | 
					  const configureArgs = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (context.sourceDir) {
 | 
					  if (context.sourceDir) {
 | 
				
			||||||
@ -16,22 +20,24 @@ export function configureProject(context: Context): void {
 | 
				
			|||||||
  configureArgs.push("-B", context.buildDir);
 | 
					  configureArgs.push("-B", context.buildDir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (context.configure.generator) {
 | 
					  if (context.configure.generator) {
 | 
				
			||||||
    configureArgs.push(...["-G", context.configure.generator]);
 | 
					    configureArgs.push("-G", context.configure.generator);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  configureArgs.push(...context.configure.options.map((opt) => "-D" + opt));
 | 
					  configureArgs.push(...context.configure.options.map((opt) => "-D" + opt));
 | 
				
			||||||
  configureArgs.push(...context.configure.args);
 | 
					  configureArgs.push(...context.configure.args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  execFileSync("cmake", configureArgs, { stdio: "inherit" });
 | 
					  await exec("cmake", configureArgs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Build a CMake project.
 | 
					 * Builds a CMake project.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param context - The action context.
 | 
					 * Runs the `cmake --build` command to build the project using the specified
 | 
				
			||||||
 | 
					 * build directory and additional arguments.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param context - The action context containing build details.
 | 
				
			||||||
 | 
					 * @returns A promise that resolves when the project is successfully built.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export function buildProject(context: Context): void {
 | 
					export async function buildProject(context: Context): Promise<void> {
 | 
				
			||||||
  execFileSync("cmake", ["--build", context.buildDir, ...context.build.args], {
 | 
					  await exec("cmake", ["--build", context.buildDir, ...context.build.args]);
 | 
				
			||||||
    stdio: "inherit",
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										13
									
								
								src/exec.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/exec.test.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					import { exec } from "./exec.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe("execute commands", () => {
 | 
				
			||||||
 | 
					  it("should successfully execute a command", async () => {
 | 
				
			||||||
 | 
					    await exec("node", ["--version"]);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it("should fail to execute a command", async () => {
 | 
				
			||||||
 | 
					    await expect(exec("node", ["--invalid"])).rejects.toThrow(
 | 
				
			||||||
 | 
					      "Command exited with status code 9",
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										26
									
								
								src/exec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/exec.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import { spawn } from "node:child_process";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Executes a command with the given arguments.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The command is executed with `stdin` ignored and both `stdout` and `stderr` inherited by the parent process.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param command The command to execute.
 | 
				
			||||||
 | 
					 * @param args The arguments to pass to the command.
 | 
				
			||||||
 | 
					 * @returns A promise that resolves when the command exits successfully or rejects if it exits with a non-zero status code or encounters an error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export async function exec(command: string, args: string[]): Promise<void> {
 | 
				
			||||||
 | 
					  return new Promise<void>((resolve, reject) => {
 | 
				
			||||||
 | 
					    const proc = spawn(command, args, {
 | 
				
			||||||
 | 
					      stdio: ["ignore", "inherit", "inherit"],
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    proc.on("error", reject);
 | 
				
			||||||
 | 
					    proc.on("close", (code) => {
 | 
				
			||||||
 | 
					      if (code === 0) {
 | 
				
			||||||
 | 
					        resolve();
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        reject(new Error(`Command exited with status code ${code}`));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user