From deffa1b5dbf5df31f4fde92a18f47cf585add053 Mon Sep 17 00:00:00 2001 From: Ben Gauger <92540908+bgauger@users.noreply.github.com> Date: Thu, 4 Jun 2026 14:22:27 +0000 Subject: [PATCH] fix: check composer global deployer binary --- README.md | 3 +- dist/index.js | 35 +++++++++++++++++------ package.json | 1 + src/deployerBinary.ts | 37 ++++++++++++++++++++++++ src/index.ts | 23 ++++++++------- test/deployer-binary.test.mjs | 53 +++++++++++++++++++++++++++++++++++ 6 files changed, 132 insertions(+), 20 deletions(-) create mode 100644 src/deployerBinary.ts create mode 100644 test/deployer-binary.test.mjs diff --git a/README.md b/README.md index 613f024..739a7ee 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,8 @@ # - `vendor/bin/deployer.phar` # - `vendor/bin/dep` # - `deployer.phar` - # If the binary not found, phar version will be downloaded from + # - `vendor/bin/dep` in Composer's global home + # If the binary is not found, phar version will be downloaded from # deployer.org. # Optional. deployer-version: '7.0.0' diff --git a/dist/index.js b/dist/index.js index fe6c47f..c47e73e 100644 --- a/dist/index.js +++ b/dist/index.js @@ -36630,6 +36630,21 @@ var import_build = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((expo })))(), 1); var { VERSION, YAML, argv, dotenv, echo, expBackoff, fetch, fs, glob, globby, minimist, nothrow, parseArgv, question, quiet, retry, sleep, spinner, stdin, tempdir, tempfile, tmpdir, tmpfile, updateArgv, version, versions, $, Fail, ProcessOutput, ProcessPromise, bus, cd, chalk, defaults, kill, log, os: os$1, path, ps, quote, quotePowerShell, resolveDefaults, syncProcessCwd, useBash, usePowerShell, usePwsh, which, within } = globalThis.Deno ? globalThis.require("./index.cjs") : import_build; //#endregion +//#region src/deployerBinary.ts +var PROJECT_LOCAL_DEPLOYER_BINARIES = [ + "vendor/bin/deployer.phar", + "vendor/bin/dep", + "deployer.phar" +]; +async function findLocalDeployerBinary({ fs, getComposerGlobalHome }) { + for (const candidate of PROJECT_LOCAL_DEPLOYER_BINARIES) if (fs.existsSync(candidate)) return candidate; + const composerGlobalHome = (await getComposerGlobalHome?.())?.trim(); + if (composerGlobalHome === void 0 || composerGlobalHome === "") return ""; + const composerGlobalDep = `${composerGlobalHome.replace(/\/+$/, "")}/vendor/bin/dep`; + if (fs.existsSync(composerGlobalDep)) return composerGlobalDep; + return ""; +} +//#endregion //#region src/index.ts $.verbose = true; (async function main() { @@ -36674,15 +36689,17 @@ async function dep() { const subDirectory = getInput("sub-directory").trim(); if (subDirectory !== "") cd(subDirectory); if (bin === "") { - for (const c of [ - "vendor/bin/deployer.phar", - "vendor/bin/dep", - "deployer.phar" - ]) if (fs.existsSync(c)) { - bin = c; - console.log(`Using "${c}".`); - break; - } + bin = await findLocalDeployerBinary({ + fs, + getComposerGlobalHome: async () => { + try { + return (await $`composer -n config --global home`).stdout.trim(); + } catch { + return; + } + } + }); + if (bin !== "") console.log(`Using "${bin}".`); } if (bin === "") { let version = getInput("deployer-version"); diff --git a/package.json b/package.json index c773d4d..5781fc9 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ }, "scripts": { "build": "vite build", + "test": "node --test test/*.test.mjs", "typecheck": "tsc --noEmit", "format": "prettier --write .", "format:check": "prettier --check ." diff --git a/src/deployerBinary.ts b/src/deployerBinary.ts new file mode 100644 index 0000000..a23df5a --- /dev/null +++ b/src/deployerBinary.ts @@ -0,0 +1,37 @@ +interface FileSystemLike { + existsSync(path: string): boolean +} + +export interface FindLocalDeployerBinaryOptions { + fs: FileSystemLike + getComposerGlobalHome?: () => Promise +} + +const PROJECT_LOCAL_DEPLOYER_BINARIES = [ + 'vendor/bin/deployer.phar', + 'vendor/bin/dep', + 'deployer.phar', +] + +export async function findLocalDeployerBinary({ + fs, + getComposerGlobalHome, +}: FindLocalDeployerBinaryOptions): Promise { + for (const candidate of PROJECT_LOCAL_DEPLOYER_BINARIES) { + if (fs.existsSync(candidate)) { + return candidate + } + } + + const composerGlobalHome = (await getComposerGlobalHome?.())?.trim() + if (composerGlobalHome === undefined || composerGlobalHome === '') { + return '' + } + + const composerGlobalDep = `${composerGlobalHome.replace(/\/+$/, '')}/vendor/bin/dep` + if (fs.existsSync(composerGlobalDep)) { + return composerGlobalDep + } + + return '' +} diff --git a/src/index.ts b/src/index.ts index 3864887..dd61f8b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ import * as core from '@actions/core' import { $, fs, cd } from 'zx' +import { findLocalDeployerBinary } from './deployerBinary' $.verbose = true @@ -71,16 +72,18 @@ async function dep(): Promise { } if (bin === '') { - for (const c of [ - 'vendor/bin/deployer.phar', - 'vendor/bin/dep', - 'deployer.phar', - ]) { - if (fs.existsSync(c)) { - bin = c - console.log(`Using "${c}".`) - break - } + bin = await findLocalDeployerBinary({ + fs, + getComposerGlobalHome: async () => { + try { + return (await $`composer -n config --global home`).stdout.trim() + } catch { + return undefined + } + }, + }) + if (bin !== '') { + console.log(`Using "${bin}".`) } } diff --git a/test/deployer-binary.test.mjs b/test/deployer-binary.test.mjs new file mode 100644 index 0000000..2261c19 --- /dev/null +++ b/test/deployer-binary.test.mjs @@ -0,0 +1,53 @@ +import assert from 'node:assert/strict' +import { test } from 'node:test' +import { findLocalDeployerBinary } from '../src/deployerBinary.ts' + +function fakeFs(existingPaths) { + const existing = new Set(existingPaths) + return { + existsSync(path) { + return existing.has(path) + }, + } +} + +test('finds composer global dep when no project-local deployer binary exists', async () => { + const bin = await findLocalDeployerBinary({ + fs: fakeFs(['/tmp/composer-home/vendor/bin/dep']), + getComposerGlobalHome: async () => '/tmp/composer-home', + }) + + assert.equal(bin, '/tmp/composer-home/vendor/bin/dep') +}) + +test('prefers project-local deployer binary over composer global dep', async () => { + const bin = await findLocalDeployerBinary({ + fs: fakeFs(['vendor/bin/dep', '/tmp/composer-home/vendor/bin/dep']), + getComposerGlobalHome: async () => '/tmp/composer-home', + }) + + assert.equal(bin, 'vendor/bin/dep') +}) + +test('trims trailing slashes from composer global home before checking dep path', async () => { + const bin = await findLocalDeployerBinary({ + fs: fakeFs(['/tmp/composer-home/vendor/bin/dep']), + getComposerGlobalHome: async () => '/tmp/composer-home///', + }) + + assert.equal(bin, '/tmp/composer-home/vendor/bin/dep') +}) + +test('ignores missing or empty composer global home', async () => { + const missingHome = await findLocalDeployerBinary({ + fs: fakeFs([]), + getComposerGlobalHome: async () => '', + }) + const failedCommand = await findLocalDeployerBinary({ + fs: fakeFs([]), + getComposerGlobalHome: async () => undefined, + }) + + assert.equal(missingHome, '') + assert.equal(failedCommand, '') +})