@@ -1080,8 +1080,11 @@ const {
1080
1080
LOCAL_BINARY_FOLDER,
1081
1081
PLATFORMS,
1082
1082
LOCAL_BINARY_NAME,
1083
+ LOCAL_BINARY_ZIP,
1083
1084
LOCAL_LOG_FILE_PREFIX,
1084
1085
LOCAL_BINARY_TRIGGER,
1086
+ RETRY_DELAY_BINARY,
1087
+ BINARY_MAX_TRIES,
1085
1088
ALLOWED_INPUT_VALUES: {
1086
1089
LOCAL_TESTING,
1087
1090
},
@@ -1107,18 +1110,23 @@ class BinaryControl {
1107
1110
* platform and the architecture
1108
1111
*/
1109
1112
_decidePlatformAndBinary() {
1113
+ this.binaryFolder = path.resolve(
1114
+ process.env.GITHUB_WORKSPACE,
1115
+ '..', '..', '..',
1116
+ '_work',
1117
+ 'binary',
1118
+ LOCAL_BINARY_FOLDER,
1119
+ this.platform,
1120
+ );
1110
1121
switch (this.platform) {
1111
1122
case PLATFORMS.DARWIN:
1112
1123
this.binaryLink = BINARY_LINKS.DARWIN;
1113
- this.binaryFolder = path.resolve(process.env.HOME, 'work', 'binary', LOCAL_BINARY_FOLDER, this.platform);
1114
1124
break;
1115
1125
case PLATFORMS.LINUX:
1116
1126
this.binaryLink = os.arch() === 'x32' ? BINARY_LINKS.LINUX_32 : BINARY_LINKS.LINUX_64;
1117
- this.binaryFolder = path.resolve(process.env.HOME, 'work', 'binary', LOCAL_BINARY_FOLDER, this.platform);
1118
1127
break;
1119
1128
case PLATFORMS.WIN32:
1120
1129
this.binaryLink = BINARY_LINKS.WINDOWS;
1121
- this.binaryFolder = path.resolve(process.env.GITHUB_WORKSPACE, '..', '..', 'work', 'binary', LOCAL_BINARY_FOLDER, this.platform);
1122
1130
break;
1123
1131
default:
1124
1132
throw Error(`Unsupported Platform: ${this.platform}. No BrowserStackLocal binary found.`);
@@ -1207,23 +1215,42 @@ class BinaryControl {
1207
1215
};
1208
1216
}
1209
1217
1218
+ async _removeAnyStaleBinary() {
1219
+ const binaryZip = path.resolve(this.binaryFolder, LOCAL_BINARY_ZIP);
1220
+ const previousLocalBinary = path.resolve(
1221
+ this.binaryFolder,
1222
+ `${LOCAL_BINARY_NAME}${this.platform === PLATFORMS.WIN32 ? '.exe' : ''}`,
1223
+ );
1224
+ await Promise.all([io.rmRF(binaryZip), io.rmRF(previousLocalBinary)]);
1225
+ }
1226
+
1210
1227
/**
1211
1228
* Downloads the Local Binary, extracts it and adds it in the PATH variable
1212
1229
*/
1213
1230
async downloadBinary() {
1214
- if (Utils.checkToolInCache(LOCAL_BINARY_NAME)) {
1231
+ const cachedBinaryPath = Utils.checkToolInCache(LOCAL_BINARY_NAME, '1.0.0');
1232
+ if (cachedBinaryPath) {
1215
1233
core.info('BrowserStackLocal binary already exists in cache. Using that instead of downloading again...');
1234
+ // A cached tool is persisted across runs. But the PATH is reset back to its original
1235
+ // state between each run. Thus, adding the cached tool path back to PATH again.
1236
+ core.addPath(cachedBinaryPath);
1216
1237
return;
1217
1238
}
1239
+
1218
1240
try {
1219
1241
await this._makeDirectory();
1242
+ core.debug('BrowserStackLocal binary not found in cache. Deleting any stale/existing binary before downloading...');
1243
+ await this._removeAnyStaleBinary();
1244
+
1220
1245
core.info('Downloading BrowserStackLocal binary...');
1221
- const downloadPath = await tc.downloadTool(this.binaryLink, path.resolve(this.binaryFolder, 'binaryZip'));
1246
+ const downloadPath = await tc.downloadTool(
1247
+ this.binaryLink,
1248
+ path.resolve(this.binaryFolder, LOCAL_BINARY_ZIP),
1249
+ );
1222
1250
const extractedPath = await tc.extractZip(downloadPath, this.binaryFolder);
1223
1251
core.info(`BrowserStackLocal binary downloaded & extracted successfuly at: ${extractedPath}`);
1224
1252
const cachedPath = await tc.cacheDir(extractedPath, LOCAL_BINARY_NAME, '1.0.0');
1225
1253
core.addPath(cachedPath);
1226
- this.binaryPath = extractedPath;
1227
1254
} catch (e) {
1228
1255
throw Error(`BrowserStackLocal binary could not be downloaded due to ${e.message}`);
1229
1256
}
@@ -1233,35 +1260,47 @@ class BinaryControl {
1233
1260
* Starts Local Binary using the args generated for this action
1234
1261
*/
1235
1262
async startBinary() {
1236
- try {
1237
- this._generateArgsForBinary();
1238
- let { localIdentifier } = this.stateForBinary;
1239
- localIdentifier = localIdentifier ? `with local-identifier=${localIdentifier}` : '';
1240
- core.info(`Starting local tunnel ${localIdentifier} in daemon mode...`);
1263
+ this._generateArgsForBinary();
1264
+ let { localIdentifier } = this.stateForBinary;
1265
+ localIdentifier = localIdentifier ? `with local-identifier=${localIdentifier}` : '';
1266
+ core.info(`Starting local tunnel ${localIdentifier} in daemon mode...`);
1241
1267
1242
- const { output, error } = await this._triggerBinary(LOCAL_TESTING.START);
1268
+ let triesAvailable = BINARY_MAX_TRIES;
1269
+
1270
+ while (triesAvailable--) {
1271
+ try {
1272
+ // eslint-disable-next-line no-await-in-loop
1273
+ const { output, error } = await this._triggerBinary(LOCAL_TESTING.START);
1274
+
1275
+ if (!error) {
1276
+ const outputParsed = JSON.parse(output);
1277
+ if (outputParsed.state === LOCAL_BINARY_TRIGGER.START.CONNECTED) {
1278
+ core.info(`Local tunnel status: ${outputParsed.message}`);
1279
+ return;
1280
+ }
1243
1281
1244
- if (!error) {
1245
- const outputParsed = JSON.parse(output);
1246
- if (outputParsed.state === LOCAL_BINARY_TRIGGER.START.CONNECTED) {
1247
- core.info(`Local tunnel status: ${outputParsed.message}`);
1248
- } else {
1249
1282
throw Error(JSON.stringify(outputParsed.message));
1283
+ } else {
1284
+ throw Error(JSON.stringify(error));
1285
+ }
1286
+ } catch (e) {
1287
+ if (triesAvailable) {
1288
+ core.info(`Error in starting local tunnel: ${e.message}. Trying again in 5 seconds...`);
1289
+ // eslint-disable-next-line no-await-in-loop
1290
+ await Utils.sleepFor(RETRY_DELAY_BINARY);
1291
+ } else {
1292
+ throw Error(`Local tunnel could not be started. Error message from binary: ${e.message}`);
1250
1293
}
1251
- } else {
1252
- throw Error(JSON.stringify(error));
1253
1294
}
1254
- } catch (e) {
1255
- throw Error(`Local tunnel could not be started. Error message from binary: ${e.message}`);
1256
1295
}
1257
1296
}
1258
1297
1259
1298
/**
1260
1299
* Stops Local Binary using the args generated for this action
1261
1300
*/
1262
1301
async stopBinary() {
1302
+ this._generateArgsForBinary();
1263
1303
try {
1264
- this._generateArgsForBinary();
1265
1304
let { localIdentifier } = this.stateForBinary;
1266
1305
localIdentifier = localIdentifier ? `with local-identifier=${localIdentifier}` : '';
1267
1306
core.info(`Stopping local tunnel ${localIdentifier} in daemon mode...`);
@@ -7230,9 +7269,15 @@ class Utils {
7230
7269
delete process.env[environmentVariable];
7231
7270
}
7232
7271
7233
- static checkToolInCache(toolName) {
7234
- const toolCache = tc.findAllVersions(toolName);
7235
- return toolCache.length !== 0;
7272
+ static checkToolInCache(toolName, version) {
7273
+ const toolCachePath = tc.find(toolName, version);
7274
+ return toolCachePath;
7275
+ }
7276
+
7277
+ static async sleepFor(ms) {
7278
+ let parsedMilliseconds = parseFloat(ms);
7279
+ parsedMilliseconds = parsedMilliseconds > 0 ? parsedMilliseconds : 0;
7280
+ return new Promise((resolve) => setTimeout(resolve, parsedMilliseconds));
7236
7281
}
7237
7282
}
7238
7283
@@ -13444,10 +13489,14 @@ module.exports = {
13444
13489
},
13445
13490
},
13446
13491
13492
+ BINARY_MAX_TRIES: 3,
13493
+ RETRY_DELAY_BINARY: 5000,
13494
+
13447
13495
RESTRICTED_LOCAL_ARGS: ['k', 'key', 'local-identifier', 'daemon', 'only-automate', 'verbose', 'log-file', 'ci-plugin'],
13448
13496
13449
13497
LOCAL_BINARY_FOLDER: 'LocalBinaryFolder',
13450
13498
LOCAL_BINARY_NAME: 'BrowserStackLocal',
13499
+ LOCAL_BINARY_ZIP: 'binaryZip',
13451
13500
LOCAL_LOG_FILE_PREFIX: 'BrowserStackLocal',
13452
13501
};
13453
13502
0 commit comments