From fa7a79e39d573cb68e74ef24ae900948431d3d20 Mon Sep 17 00:00:00 2001 From: Eli Uriegas Date: Wed, 14 Apr 2021 11:14:09 -0700 Subject: [PATCH] add option to skip dependency installation apt-get is not available on certain distributions so it's better to have the option to leave it out so we can still have the ability to run this action without having to be on ubuntu. Signed-off-by: Eli Uriegas Signed-off-by: Johannes Schindelin --- README.md | 18 ++++++++++++- action.yml | 4 +++ lib/index.js | 64 +++++++++++++++++++++++---------------------- src/index.js | 66 ++++++++++++++++++++++++----------------------- src/index.test.js | 44 ++++++++++++++++++++++++++++--- 5 files changed, 128 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index ae2b0c21..bcb01ff5 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ You can then [manually run a workflow](https://docs.github.com/en/actions/managi ## Without sudo -By default we run the commands using sudo. If you get `sudo: not found` you can use the parameter below to execute the commands directly. +By default we run installation commands using sudo on Linux. If you get `sudo: not found` you can use the parameter below to execute the commands directly. ```yaml name: CI @@ -165,6 +165,22 @@ jobs: tmate-server-ed25519-fingerprint: SHA256:jfttvoypkHiQYUqUCwKeqd9d1fJj/ZiQlFOHVl6E9sI ``` +## Skip installing tmate + +By default, tmate and its dependencies are installed in a platform-dependent manner. When using self-hosted agents, this can become unnecessary or can even break. You can skip installing tmate and its dependencies using `install-dependencies`: + +```yaml +name: CI +on: [push] +jobs: + build: + runs-on: [self-hosted, linux] + steps: + - uses: mxschmitt/action-tmate@v3 + with: + install-dependencies: false +``` + ## Continue a workflow If you want to continue a workflow and you are inside a tmate session, just create a empty file with the name `continue` either in the root directory or in the project directory by running `touch continue` or `sudo touch /continue`. diff --git a/action.yml b/action.yml index 3e84a28b..e641e7e0 100644 --- a/action.yml +++ b/action.yml @@ -11,6 +11,10 @@ inputs: description: 'If apt should be executed with sudo or without' required: false default: 'true' + install-dependencies: + description: 'Whether or not to install dependencies for tmate on linux (openssh-client, xz-utils)' + required: false + default: 'true' limit-access-to-actor: description: 'If only the public SSH keys of the user triggering the workflow should be authorized' required: false diff --git a/lib/index.js b/lib/index.js index 5fada82b..e670611d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -10334,44 +10334,46 @@ const TMATE_ARCH_MAP = { const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); async function run() { - const optionalSudoPrefix = core.getInput('sudo') === "true" ? "sudo " : ""; try { - core.debug("Installing dependencies") let tmateExecutable = "tmate" - if (process.platform === "darwin") { - await execShellCommand('brew install tmate'); - } else if (process.platform === "win32") { - await execShellCommand('pacman -Sy --noconfirm tmate'); - tmateExecutable = 'CHERE_INVOKING=1 tmate' - } else { - const distro = await getLinuxDistro(); - core.debug("linux distro: [" + distro + "]"); - if (distro === "alpine") { - // for set -e workaround, we need to install bash because alpine doesn't have it - await execShellCommand(optionalSudoPrefix + 'apk add openssh-client xz bash'); + if (core.getInput("install-dependencies") !== "false") { + core.debug("Installing dependencies") + if (process.platform === "darwin") { + await execShellCommand('brew install tmate'); + } else if (process.platform === "win32") { + await execShellCommand('pacman -Sy --noconfirm tmate'); } else { - await execShellCommand(optionalSudoPrefix + 'apt-get update'); - await execShellCommand(optionalSudoPrefix + 'apt-get install -y openssh-client xz-utils'); - } + const optionalSudoPrefix = core.getInput("sudo") === "true" ? "sudo " : ""; + const distro = await getLinuxDistro(); + core.debug("linux distro: [" + distro + "]"); + if (distro === "alpine") { + // for set -e workaround, we need to install bash because alpine doesn't have it + await execShellCommand(optionalSudoPrefix + 'apk add openssh-client xz bash'); + } else { + await execShellCommand(optionalSudoPrefix + 'apt-get update'); + await execShellCommand(optionalSudoPrefix + 'apt-get install -y openssh-client xz-utils'); + } - const tmateArch = TMATE_ARCH_MAP[external_os_default().arch()]; - if (!tmateArch) { - throw new Error(`Unsupported architecture: ${external_os_default().arch()}`) - } - const tmateReleaseTar = await tool_cache.downloadTool(`https://github.com/tmate-io/tmate/releases/download/${TMATE_LINUX_VERSION}/tmate-${TMATE_LINUX_VERSION}-static-linux-${tmateArch}.tar.xz`); - const tmateDir = external_path_default().join(external_os_default().tmpdir(), "tmate") - tmateExecutable = external_path_default().join(tmateDir, "tmate") + const tmateArch = TMATE_ARCH_MAP[external_os_default().arch()]; + if (!tmateArch) { + throw new Error(`Unsupported architecture: ${external_os_default().arch()}`) + } + const tmateReleaseTar = await tool_cache.downloadTool(`https://github.com/tmate-io/tmate/releases/download/${TMATE_LINUX_VERSION}/tmate-${TMATE_LINUX_VERSION}-static-linux-${tmateArch}.tar.xz`); + const tmateDir = external_path_default().join(external_os_default().tmpdir(), "tmate") + tmateExecutable = external_path_default().join(tmateDir, "tmate") - if (external_fs_default().existsSync(tmateExecutable)) - external_fs_default().unlinkSync(tmateExecutable) - external_fs_default().mkdirSync(tmateDir, { recursive: true }) - await execShellCommand(`tar x -C ${tmateDir} -f ${tmateReleaseTar} --strip-components=1`) - external_fs_default().unlinkSync(tmateReleaseTar) + if (external_fs_default().existsSync(tmateExecutable)) + external_fs_default().unlinkSync(tmateExecutable) + external_fs_default().mkdirSync(tmateDir, { recursive: true }) + await execShellCommand(`tar x -C ${tmateDir} -f ${tmateReleaseTar} --strip-components=1`) + external_fs_default().unlinkSync(tmateReleaseTar) + } + core.debug("Installed dependencies successfully"); } - core.debug("Installed dependencies successfully"); - - if (process.platform !== "win32") { + if (process.platform === "win32") { + tmateExecutable = 'CHERE_INVOKING=1 tmate' + } else { core.debug("Generating SSH keys") external_fs_default().mkdirSync(external_path_default().join(external_os_default().homedir(), ".ssh"), { recursive: true }) try { diff --git a/src/index.js b/src/index.js index a74c45ca..4855b32c 100644 --- a/src/index.js +++ b/src/index.js @@ -25,44 +25,46 @@ const TMATE_ARCH_MAP = { const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); export async function run() { - const optionalSudoPrefix = core.getInput('sudo') === "true" ? "sudo " : ""; try { - core.debug("Installing dependencies") let tmateExecutable = "tmate" - if (process.platform === "darwin") { - await execShellCommand('brew install tmate'); - } else if (process.platform === "win32") { - await execShellCommand('pacman -Sy --noconfirm tmate'); - tmateExecutable = 'CHERE_INVOKING=1 tmate' - } else { - const distro = await getLinuxDistro(); - core.debug("linux distro: [" + distro + "]"); - if (distro === "alpine") { - // for set -e workaround, we need to install bash because alpine doesn't have it - await execShellCommand(optionalSudoPrefix + 'apk add openssh-client xz bash'); + if (core.getInput("install-dependencies") !== "false") { + core.debug("Installing dependencies") + if (process.platform === "darwin") { + await execShellCommand('brew install tmate'); + } else if (process.platform === "win32") { + await execShellCommand('pacman -Sy --noconfirm tmate'); } else { - await execShellCommand(optionalSudoPrefix + 'apt-get update'); - await execShellCommand(optionalSudoPrefix + 'apt-get install -y openssh-client xz-utils'); - } - - const tmateArch = TMATE_ARCH_MAP[os.arch()]; - if (!tmateArch) { - throw new Error(`Unsupported architecture: ${os.arch()}`) + const optionalSudoPrefix = core.getInput("sudo") === "true" ? "sudo " : ""; + const distro = await getLinuxDistro(); + core.debug("linux distro: [" + distro + "]"); + if (distro === "alpine") { + // for set -e workaround, we need to install bash because alpine doesn't have it + await execShellCommand(optionalSudoPrefix + 'apk add openssh-client xz bash'); + } else { + await execShellCommand(optionalSudoPrefix + 'apt-get update'); + await execShellCommand(optionalSudoPrefix + 'apt-get install -y openssh-client xz-utils'); + } + + const tmateArch = TMATE_ARCH_MAP[os.arch()]; + if (!tmateArch) { + throw new Error(`Unsupported architecture: ${os.arch()}`) + } + const tmateReleaseTar = await tc.downloadTool(`https://github.com/tmate-io/tmate/releases/download/${TMATE_LINUX_VERSION}/tmate-${TMATE_LINUX_VERSION}-static-linux-${tmateArch}.tar.xz`); + const tmateDir = path.join(os.tmpdir(), "tmate") + tmateExecutable = path.join(tmateDir, "tmate") + + if (fs.existsSync(tmateExecutable)) + fs.unlinkSync(tmateExecutable) + fs.mkdirSync(tmateDir, { recursive: true }) + await execShellCommand(`tar x -C ${tmateDir} -f ${tmateReleaseTar} --strip-components=1`) + fs.unlinkSync(tmateReleaseTar) } - const tmateReleaseTar = await tc.downloadTool(`https://github.com/tmate-io/tmate/releases/download/${TMATE_LINUX_VERSION}/tmate-${TMATE_LINUX_VERSION}-static-linux-${tmateArch}.tar.xz`); - const tmateDir = path.join(os.tmpdir(), "tmate") - tmateExecutable = path.join(tmateDir, "tmate") - - if (fs.existsSync(tmateExecutable)) - fs.unlinkSync(tmateExecutable) - fs.mkdirSync(tmateDir, { recursive: true }) - await execShellCommand(`tar x -C ${tmateDir} -f ${tmateReleaseTar} --strip-components=1`) - fs.unlinkSync(tmateReleaseTar) + core.debug("Installed dependencies successfully"); } - core.debug("Installed dependencies successfully"); - - if (process.platform !== "win32") { + if (process.platform === "win32") { + tmateExecutable = 'CHERE_INVOKING=1 tmate' + } else { core.debug("Generating SSH keys") fs.mkdirSync(path.join(os.homedir(), ".ssh"), { recursive: true }) try { diff --git a/src/index.test.js b/src/index.test.js index 53659bc9..658c0fcc 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -28,11 +28,24 @@ describe('Tmate GitHub integration', () => { Object.defineProperty(process, "platform", { value: "win32" }) - core.getInput.mockReturnValueOnce("true").mockReturnValue("false") + core.getInput.mockReturnValueOnce("true").mockReturnValueOnce("false") const customConnectionString = "foobar" execShellCommand.mockReturnValue(Promise.resolve(customConnectionString)) await run() - expect(execShellCommand).toHaveBeenNthCalledWith(1, "pacman -Sy --noconfirm tmate") + expect(execShellCommand).toHaveBeenNthCalledWith(1, "pacman -Sy --noconfirm tmate"); + expect(core.info).toHaveBeenNthCalledWith(1, `Web shell: ${customConnectionString}`); + expect(core.info).toHaveBeenNthCalledWith(2, `SSH: ${customConnectionString}`); + expect(core.info).toHaveBeenNthCalledWith(3, "Exiting debugging session because the continue file was created"); + }); + it('should handle the main loop for Windows without dependency installation', async () => { + Object.defineProperty(process, "platform", { + value: "win32" + }) + core.getInput.mockReturnValueOnce("false") + const customConnectionString = "foobar" + execShellCommand.mockReturnValue(Promise.resolve(customConnectionString)) + await run() + expect(execShellCommand).not.toHaveBeenNthCalledWith(1, "pacman -Sy --noconfirm tmate"); expect(core.info).toHaveBeenNthCalledWith(1, `Web shell: ${customConnectionString}`); expect(core.info).toHaveBeenNthCalledWith(2, `SSH: ${customConnectionString}`); expect(core.info).toHaveBeenNthCalledWith(3, "Exiting debugging session because the continue file was created"); @@ -41,7 +54,7 @@ describe('Tmate GitHub integration', () => { Object.defineProperty(process, "platform", { value: "linux" }) - core.getInput.mockReturnValueOnce("true").mockReturnValue("false") + core.getInput.mockReturnValueOnce("true").mockReturnValueOnce("true").mockReturnValueOnce("false") const customConnectionString = "foobar" execShellCommand.mockReturnValue(Promise.resolve(customConnectionString)) await run() @@ -54,7 +67,7 @@ describe('Tmate GitHub integration', () => { Object.defineProperty(process, "platform", { value: "linux" }) - core.getInput.mockReturnValue("false") + core.getInput.mockReturnValueOnce("true").mockReturnValueOnce("false").mockReturnValueOnce("false") const customConnectionString = "foobar" execShellCommand.mockReturnValue(Promise.resolve(customConnectionString)) await run() @@ -63,11 +76,34 @@ describe('Tmate GitHub integration', () => { expect(core.info).toHaveBeenNthCalledWith(2, `SSH: ${customConnectionString}`); expect(core.info).toHaveBeenNthCalledWith(3, "Exiting debugging session because the continue file was created"); }); + it('should be handle the main loop for linux without installing dependencies', async () => { + Object.defineProperty(process, "platform", { + value: "linux" + }) + core.getInput.mockReturnValueOnce("false").mockReturnValueOnce("false") + const customConnectionString = "foobar" + execShellCommand.mockReturnValue(Promise.resolve(customConnectionString)) + await run() + expect(execShellCommand).not.toHaveBeenNthCalledWith(1, "apt-get update") + expect(core.info).toHaveBeenNthCalledWith(1, `Web shell: ${customConnectionString}`); + expect(core.info).toHaveBeenNthCalledWith(2, `SSH: ${customConnectionString}`); + expect(core.info).toHaveBeenNthCalledWith(3, "Exiting debugging session because the continue file was created"); + }); it('should install tmate via brew for darwin', async () => { Object.defineProperty(process, "platform", { value: "darwin" }) + core.getInput.mockReturnValueOnce("true") await run() + expect(core.getInput).toHaveBeenNthCalledWith(1, "install-dependencies") expect(execShellCommand).toHaveBeenNthCalledWith(1, "brew install tmate") }); + it('should not install dependencies for darwin', async () => { + Object.defineProperty(process, "platform", { + value: "darwin" + }) + core.getInput.mockReturnValueOnce("false") + await run() + expect(execShellCommand).not.toHaveBeenNthCalledWith(1, "brew install tmate") + }); });