diff --git a/README.md b/README.md index 6cd41f6..a5295b8 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,10 @@ The name of the version to deploy. Default: sha value of the commit triggering A pipe-delimited list of artisan commands to run after the deployment. Example: `clear-compiled|migrate|optimize` +### `writableDirectories` + +A pipe-delimited list of paths relative to the application root that need to be writable by the web server. Example: `storage` for Laravel, `application/cache|application/logs` for Kohana. + ### `artifact` The path to the deployable tarball. Default: `./artifact.tar.gz` @@ -43,6 +47,11 @@ The number of versions to keep on the target VM. The most recent number of conf All others will be removed. The default behavior is to not remove anything. This can also be achieved with an explicit value of `"0"` +### `postDeploymentCommands` + +A pipe-delimited list of commands to run after the deployment. These will be run in the directory to which +the code was deployed. + ## Example usage ``` @@ -54,6 +63,8 @@ with: version:"v1.0.0" key: "~/identityfile" artisanCommands: "config:cache|migrate" + postDeploymentCommands: "sudo supervisorctl restart foo-worker" + writableDirectories: "storage" artifact: "some-other-tarball.tar.gz" numberOfVersionsToKeep: 5 ``` diff --git a/action.yml b/action.yml index bc0d1ed..d7ede7f 100644 --- a/action.yml +++ b/action.yml @@ -30,6 +30,10 @@ inputs: description: "Number of most recent versions to keep. (0 = all)" required: false default: "0" + postDeploymentCommands: + description: "Pipe-delimited list of commands to run as part of the deployment" + required: false + default: "" runs: using: 'node12' diff --git a/dist/index.js b/dist/index.js index 04bb8c1..6332a7d 100644 --- a/dist/index.js +++ b/dist/index.js @@ -956,6 +956,10 @@ function getRequiredInput(input) { return capturedInput; } +function parseArrayFromPipeDelimitedString(pipeDelimitedString) { + return pipeDelimitedString.split("|").filter(x => x !== ""); +} + function getOptions() { return { user: getRequiredInput("user"), @@ -963,9 +967,17 @@ function getOptions() { versionsRoot: getRequiredInput("versionsRoot"), version: core.getInput("version") || process.env.GITHUB_SHA || "", key: getRequiredInput("key"), - artisanCommands: core.getInput("artisanCommands").split("|"), + artisanCommands: parseArrayFromPipeDelimitedString( + core.getInput("artisanCommands") + ), + writableDirectories: parseArrayFromPipeDelimitedString( + core.getInput("writableDirectories") + ), artifact: core.getInput("artifact"), - versionsToKeep: core.getInput("numberOfVersionsToKeep") || 0 + versionsToKeep: core.getInput("numberOfVersionsToKeep") || 0, + postDeploymentCommands: parseArrayFromPipeDelimitedString( + core.getInput("postDeploymentCommands") + ) }; } @@ -1020,7 +1032,14 @@ async function setTargetPermissions(options) { const { versionsRoot, version } = options; const path = `${versionsRoot}/${version}`; await executeSSH(options, `chmod -R 770 ${path}`); - await executeSSH(options, `chmod -R 775 ${path}/storage`); + /* eslint-disable no-restricted-syntax */ + for (const dir of options.writableDirectories) { + // eslint-disable-next-line no-await-in-loop + await executeSSH( + options, + `stat ${path}/${dir} >/dev/null && chmod -R 775 ${path}/${dir}` + ); + } } async function executeArtisan(options) { @@ -1036,6 +1055,16 @@ async function executeArtisan(options) { /* eslint-enable no-restricted-syntax */ } +async function executePostDeploymentCommands(options) { + const { versionsRoot, version } = options; + /* eslint-disable no-restricted-syntax */ + for (const command of options.postDeploymentCommands) { + // eslint-disable-next-line no-await-in-loop + await executeSSH(options, `cd ${versionsRoot}/${version}; ${command}`); + } + /* eslint-enable no-restricted-syntax */ +} + async function updateSymlink(options) { const { version, versionsRoot } = options; await executeSSH(options, `rm -f ${versionsRoot}/current`); @@ -1083,6 +1112,7 @@ async function main() { await updateVersionDirectoryTimeStamp(options); await setTargetPermissions(options); await executeArtisan(options); + await executePostDeploymentCommands(options); await updateSymlink(options); await removeOldVersions(options); } diff --git a/index.js b/index.js index a7a4ba7..077d46e 100644 --- a/index.js +++ b/index.js @@ -10,6 +10,10 @@ function getRequiredInput(input) { return capturedInput; } +function parseArrayFromPipeDelimitedString(pipeDelimitedString) { + return pipeDelimitedString.split("|").filter(x => x !== ""); +} + function getOptions() { return { user: getRequiredInput("user"), @@ -17,9 +21,17 @@ function getOptions() { versionsRoot: getRequiredInput("versionsRoot"), version: core.getInput("version") || process.env.GITHUB_SHA || "", key: getRequiredInput("key"), - artisanCommands: core.getInput("artisanCommands").split("|"), + artisanCommands: parseArrayFromPipeDelimitedString( + core.getInput("artisanCommands") + ), + writableDirectories: parseArrayFromPipeDelimitedString( + core.getInput("writableDirectories") + ), artifact: core.getInput("artifact"), - versionsToKeep: core.getInput("numberOfVersionsToKeep") || 0 + versionsToKeep: core.getInput("numberOfVersionsToKeep") || 0, + postDeploymentCommands: parseArrayFromPipeDelimitedString( + core.getInput("postDeploymentCommands") + ) }; } @@ -74,7 +86,14 @@ async function setTargetPermissions(options) { const { versionsRoot, version } = options; const path = `${versionsRoot}/${version}`; await executeSSH(options, `chmod -R 770 ${path}`); - await executeSSH(options, `chmod -R 775 ${path}/storage`); + /* eslint-disable no-restricted-syntax */ + for (const dir of options.writableDirectories) { + // eslint-disable-next-line no-await-in-loop + await executeSSH( + options, + `stat ${path}/${dir} >/dev/null && chmod -R 775 ${path}/${dir}` + ); + } } async function executeArtisan(options) { @@ -90,6 +109,16 @@ async function executeArtisan(options) { /* eslint-enable no-restricted-syntax */ } +async function executePostDeploymentCommands(options) { + const { versionsRoot, version } = options; + /* eslint-disable no-restricted-syntax */ + for (const command of options.postDeploymentCommands) { + // eslint-disable-next-line no-await-in-loop + await executeSSH(options, `cd ${versionsRoot}/${version}; ${command}`); + } + /* eslint-enable no-restricted-syntax */ +} + async function updateSymlink(options) { const { version, versionsRoot } = options; await executeSSH(options, `rm -f ${versionsRoot}/current`); @@ -137,6 +166,7 @@ async function main() { await updateVersionDirectoryTimeStamp(options); await setTargetPermissions(options); await executeArtisan(options); + await executePostDeploymentCommands(options); await updateSymlink(options); await removeOldVersions(options); } diff --git a/package-lock.json b/package-lock.json index 4e15030..7241925 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "laravel-vm-deployment-action", - "version": "1.0.0", + "version": "1.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c8e4ebe..df1f6df 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "laravel-vm-deployment-action", - "version": "1.0.0", + "version": "1.1.0", "description": "", "main": "dist/index.js", "scripts": {