-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
176 lines (155 loc) · 5.28 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
const core = require("@actions/core");
const exec = require("@actions/exec");
function getRequiredInput(input) {
const capturedInput = core.getInput(input);
if (capturedInput === null || capturedInput === "") {
core.setFailed(`Action failed, unable to get required input: ${input}`);
}
return capturedInput;
}
function parseArrayFromPipeDelimitedString(pipeDelimitedString) {
return pipeDelimitedString.split("|").filter(x => x !== "");
}
function getOptions() {
return {
user: getRequiredInput("user"),
host: getRequiredInput("host"),
versionsRoot: getRequiredInput("versionsRoot"),
version: core.getInput("version") || process.env.GITHUB_SHA || "",
artisanCommands: parseArrayFromPipeDelimitedString(
core.getInput("artisanCommands")
),
writableDirectories: parseArrayFromPipeDelimitedString(
core.getInput("writableDirectories")
),
artifact: core.getInput("artifact"),
versionsToKeep: core.getInput("numberOfVersionsToKeep") || 0,
postDeploymentCommands: parseArrayFromPipeDelimitedString(
core.getInput("postDeploymentCommands")
)
};
}
async function executeCall(call, options = {}) {
try {
await exec.exec(call, [], options);
} catch (e) {
core.setFailed(`Action failed ${e}`);
}
}
async function executeSSH({ user, host }, command, execOptions = {}) {
const verbose = core.isDebug() ? "-vvv" : "";
await executeCall(`ssh ${verbose} ${user}@${host} ${command}`, execOptions);
}
async function executeSCP(source, destination) {
const verbose = core.isDebug() ? "-vvv" : "";
await executeCall(`scp ${verbose} ${source} ${destination}`);
}
async function ensureTargetDirectoryExists(options) {
const path = `${options.versionsRoot}/${options.version}`;
await executeSSH(options, `rm -fr ${path}`);
await executeSSH(options, `mkdir -p ${path}`);
}
async function deployArtifact(options) {
const { artifact, user, host, versionsRoot } = options;
const source = artifact;
const destination = `${user}@${host}:${versionsRoot}`;
await executeSCP(source, destination);
}
async function explodeTarball(options) {
const { artifact, version, versionsRoot } = options;
await executeSSH(
options,
`tar -xzf ${versionsRoot}/${artifact} -C ${versionsRoot}/${version}`
);
}
async function removeArtifact(options) {
const { artifact, versionsRoot } = options;
await executeSSH(options, `rm -f ${versionsRoot}/${artifact}`);
}
async function updateVersionDirectoryTimeStamp(options) {
const path = `${options.versionsRoot}/${options.version}`;
await executeSSH(options, `touch --date="now" ${path}`);
}
async function setTargetPermissions(options) {
const { versionsRoot, version } = options;
const path = `${versionsRoot}/${version}`;
await executeSSH(options, `chmod -R 770 ${path}`);
/* 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}`
);
}
/* eslint-enable no-restricted-syntax */
}
async function executeArtisan(options) {
const { versionsRoot, version } = options;
/* eslint-disable no-restricted-syntax */
for (const command of options.artisanCommands) {
// eslint-disable-next-line no-await-in-loop
await executeSSH(
options,
`cd ${versionsRoot}/${version}; php artisan ${command}`
);
}
/* 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`);
await executeSSH(
options,
`ln -s ${versionsRoot}/${version} ${versionsRoot}/current`
);
}
async function removeOldVersions(options) {
const { versionsToKeep, versionsRoot } = options;
if (versionsToKeep === 0) {
return;
}
let output = "";
const execOptions = {};
execOptions.listeners = {
stdout: data => {
output += data.toString();
}
};
await executeSSH(options, `ls -t ${versionsRoot}`, execOptions);
const rawDirs = output.split(/\s+/).filter(dir => dir !== "current");
rawDirs.splice(-1, 1);
if (rawDirs.length <= versionsToKeep) {
return;
}
const dirsToRemove = rawDirs.slice(versionsToKeep);
/* eslint-disable no-restricted-syntax */
for (const dir of dirsToRemove) {
// eslint-disable-next-line no-await-in-loop
await executeSSH(options, `rm -fr ${versionsRoot}/${dir}`);
}
/* eslint-enable no-restricted-syntax */
}
async function main() {
const options = getOptions();
await ensureTargetDirectoryExists(options);
await deployArtifact(options);
await explodeTarball(options);
await removeArtifact(options);
await updateVersionDirectoryTimeStamp(options);
await setTargetPermissions(options);
await executeArtisan(options);
await executePostDeploymentCommands(options);
await updateSymlink(options);
await removeOldVersions(options);
}
main();