diff --git a/src/git.js b/src/git.js index bfd84822..e52ef1f7 100644 --- a/src/git.js +++ b/src/git.js @@ -1,6 +1,6 @@ const core = require("@actions/core"); -const { run } = require("./utils/action"); +const { execute } = require("./utils/action"); /** * Fetches and checks out the remote Git branch (if it exists, the fork repository will be used) @@ -10,27 +10,23 @@ function checkOutRemoteBranch(context) { if (context.repository.hasFork) { // Fork: Add fork repo as remote core.info(`Adding "${context.repository.forkName}" fork as remote with Git`); - run( - `git remote add fork https://${context.actor}:${context.token}@github.com/${context.repository.forkName}.git`, - ); + execute("git", ["remote", "add", "fork", `https://${context.actor}:${context.token}@github.com/${context.repository.forkName}.git`]); } else { // No fork: Update remote URL to include auth information (so auto-fixes can be pushed) core.info(`Adding auth information to Git remote URL`); - run( - `git remote set-url origin https://${context.actor}:${context.token}@github.com/${context.repository.repoName}.git`, - ); + execute("git", ["remote", "set-url", "origin", `https://${context.actor}:${context.token}@github.com/${context.repository.repoName}.git`]); } const remote = context.repository.hasFork ? "fork" : "origin"; // Fetch remote branch core.info(`Fetching remote branch "${context.branch}"`); - run(`git fetch --no-tags --depth=1 ${remote} ${context.branch}`); + execute("git", ["fetch", "--no-tags", "--depth=1", remote, context.branch]); // Switch to remote branch core.info(`Switching to the "${context.branch}" branch`); - run(`git branch --force ${context.branch} --track ${remote}/${context.branch}`); - run(`git checkout ${context.branch}`); + execute("git", ["branch", "--force", context.branch, "--track", `${remote}/${context.branch}`]); + execute("git", ["checkout", context.branch]); } /** @@ -39,7 +35,7 @@ function checkOutRemoteBranch(context) { */ function commitChanges(message) { core.info(`Committing changes`); - run(`git commit -am "${message}"`); + execute("git", ["commit", "-am", `"${message}"`]); } /** @@ -47,7 +43,7 @@ function commitChanges(message) { * @returns {string} - Head SHA */ function getHeadSha() { - const sha = run("git rev-parse HEAD").stdout; + const sha = execute("git", ["rev-parse", "HEAD"]).stdout; core.info(`SHA of last commit is "${sha}"`); return sha; } @@ -57,7 +53,7 @@ function getHeadSha() { * @returns {boolean} - Boolean indicating whether changes exist */ function hasChanges() { - const output = run("git diff-index --name-status --exit-code HEAD --", { ignoreErrors: true }); + const output = execute("git", ["diff-index", "--name-status", "--exit-code", "HEAD", "--"], { ignoreErrors: true }); const hasChangedFiles = output.status === 1; core.info(`${hasChangedFiles ? "Changes" : "No changes"} found with Git`); return hasChangedFiles; @@ -68,7 +64,7 @@ function hasChanges() { */ function pushChanges() { core.info("Pushing changes with Git"); - run("git push"); + execute("git", ["push"]); } /** @@ -78,8 +74,8 @@ function pushChanges() { */ function setUserInfo(name, email) { core.info(`Setting Git user information`); - run(`git config --global user.name "${name}"`); - run(`git config --global user.email "${email}"`); + execute("git", ["config", "--global", "user.name", `"${name}"`]); + execute("git", ["config", "--global", "user.email", `"${email}"`]); } module.exports = { diff --git a/src/utils/action.js b/src/utils/action.js index 4807170d..cc036dec 100644 --- a/src/utils/action.js +++ b/src/utils/action.js @@ -1,8 +1,9 @@ -const { execSync } = require("child_process"); +const { execSync, spawnSync } = require("child_process"); const core = require("@actions/core"); const RUN_OPTIONS_DEFAULTS = { dir: null, ignoreErrors: false, prefix: "" }; +const EXECUTE_OPTIONS_DEFAULTS = { dir: null, ignoreErrors: false }; /** * Returns the value for an environment variable. If the variable is required but doesn't have a @@ -72,7 +73,44 @@ function run(cmd, options) { } } +/** + * Executes the provided binary with the given arguments. + * @param {string} command - binary to execute + * @param {{dir: string, ignoreErrors: boolean}} [options] - {@see EXECUTE_OPTIONS_DEFAULTS} + * @returns {{status: number, stdout: string, stderr: string}} - Output of the command + */ +function execute(command, args, options) { + const optionsWithDefaults = { + ...EXECUTE_OPTIONS_DEFAULTS, + ...options, + }; + + core.debug(`${command} ${args.filter(e => e).join(" ")}`); + + const process = spawnSync(command, args.filter(e => e), { + cwd: optionsWithDefaults.dir, + encoding: "utf-8", + maxBuffer: 20 * 1024 * 1024, + }); + + const output = { + status: process.status, + stdout: process.stdout.trim(), + stderr: process.stderr.trim(), + }; + + core.debug(`Exit code: ${output.status}`); + core.debug(`Stdout: ${output.stdout}`); + core.debug(`Stderr: ${output.stderr}`); + + if (!optionsWithDefaults.ignoreErrors && child.status != 0) { + throw child.error; + } + return output; +} + module.exports = { + execute, getEnv, run, };