@fishawack/lab-env 5.7.0-beta.4 → 5.7.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/commands/create/libs/parallel-runner.js +88 -14
- package/commands/create/libs/vars.js +3 -3
- package/globals.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
## Changelog
|
|
2
2
|
|
|
3
|
+
### 5.7.0-beta.5 (2026-07-03)
|
|
4
|
+
|
|
5
|
+
#### Bug Fixes
|
|
6
|
+
|
|
7
|
+
* allow rekey outside of projects ([94b511b](https://bitbucket.org/fishawackdigital/lab-env/commits/94b511b629fbf80b842a9ab5db9f3671f1f603f0))
|
|
8
|
+
* retry on rate limits and aws errors on key commands ([0244221](https://bitbucket.org/fishawackdigital/lab-env/commits/0244221b8a263256f015380280024c862213b885))
|
|
9
|
+
* safe check for misc bitbucket vars ([cee035c](https://bitbucket.org/fishawackdigital/lab-env/commits/cee035c25f927d1b5f55c00f10fa35f08733e4bf))
|
|
10
|
+
|
|
3
11
|
### 5.7.0-beta.4 (2026-07-03)
|
|
4
12
|
|
|
5
13
|
#### Bug Fixes
|
|
@@ -3,6 +3,33 @@ const chalk = require("chalk");
|
|
|
3
3
|
const { Spinner } = require("./utilities");
|
|
4
4
|
|
|
5
5
|
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
6
|
+
const MAX_RETRIES = 15;
|
|
7
|
+
const INITIAL_DELAY = 2000;
|
|
8
|
+
const MAX_DELAY = 60000;
|
|
9
|
+
|
|
10
|
+
const RETRYABLE_ERRORS = [
|
|
11
|
+
"Throttling",
|
|
12
|
+
"ThrottlingException",
|
|
13
|
+
"TooManyRequestsException",
|
|
14
|
+
"RequestLimitExceeded",
|
|
15
|
+
"ServiceUnavailable",
|
|
16
|
+
"InternalFailure",
|
|
17
|
+
"RequestTimeout",
|
|
18
|
+
"RequestTimeoutException",
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
function isRetryable(err) {
|
|
22
|
+
if (
|
|
23
|
+
RETRYABLE_ERRORS.includes(err.name) ||
|
|
24
|
+
RETRYABLE_ERRORS.includes(err.Code)
|
|
25
|
+
) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const statusCode = err.$metadata?.httpStatusCode;
|
|
30
|
+
|
|
31
|
+
return statusCode === 429 || statusCode === 503 || statusCode === 500;
|
|
32
|
+
}
|
|
6
33
|
|
|
7
34
|
function formatElapsed(ms) {
|
|
8
35
|
const secs = Math.floor(ms / 1000);
|
|
@@ -78,7 +105,20 @@ module.exports = async function parallelRunner(
|
|
|
78
105
|
continue;
|
|
79
106
|
}
|
|
80
107
|
|
|
81
|
-
if (state.status === "
|
|
108
|
+
if (state.status === "retrying") {
|
|
109
|
+
const remaining = Math.max(
|
|
110
|
+
0,
|
|
111
|
+
Math.ceil(
|
|
112
|
+
(state.retryDelay - (Date.now() - state.retryStart)) /
|
|
113
|
+
1000,
|
|
114
|
+
),
|
|
115
|
+
);
|
|
116
|
+
lines.push(
|
|
117
|
+
chalk.yellow(
|
|
118
|
+
` ↻ ${verb}: ${user} - ${state.client} (${state.batchesDone + 1}/${totalBatches}) retry ${state.retryAttempt}/${MAX_RETRIES} ${remaining}s`,
|
|
119
|
+
),
|
|
120
|
+
);
|
|
121
|
+
} else if (state.status === "active") {
|
|
82
122
|
const taskElapsed = Date.now() - state.taskStart;
|
|
83
123
|
let suffix = "";
|
|
84
124
|
if (taskElapsed > 5000) {
|
|
@@ -130,24 +170,58 @@ module.exports = async function parallelRunner(
|
|
|
130
170
|
const groupUsers = group.filter((u) => batch.users.includes(u));
|
|
131
171
|
|
|
132
172
|
await Promise.all(
|
|
133
|
-
groupUsers.map(async (user) => {
|
|
173
|
+
groupUsers.map(async (user, userIndex) => {
|
|
134
174
|
const state = groupStates.get(user);
|
|
135
175
|
state.client = batch.client;
|
|
136
|
-
state.status = "active";
|
|
137
176
|
state.taskStart = Date.now();
|
|
138
177
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
178
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
179
|
+
state.status = "active";
|
|
180
|
+
state.taskStart = Date.now();
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
const res = await batch.fn(user);
|
|
184
|
+
results
|
|
185
|
+
.get(user)
|
|
186
|
+
.push({ client: batch.client, res });
|
|
187
|
+
state.status = "done";
|
|
188
|
+
state.retryAttempt = 0;
|
|
189
|
+
break;
|
|
190
|
+
} catch (err) {
|
|
191
|
+
if (!isRetryable(err) || attempt === MAX_RETRIES) {
|
|
192
|
+
state.status = "error";
|
|
193
|
+
state.hasError = true;
|
|
194
|
+
state.errorMsg = err.message || String(err);
|
|
195
|
+
errors.push({
|
|
196
|
+
user,
|
|
197
|
+
client: batch.client,
|
|
198
|
+
error: err,
|
|
199
|
+
});
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
let delay = Math.min(
|
|
204
|
+
INITIAL_DELAY * Math.pow(2, attempt),
|
|
205
|
+
MAX_DELAY,
|
|
206
|
+
);
|
|
207
|
+
// Stagger retries per user to avoid thundering herd
|
|
208
|
+
delay +=
|
|
209
|
+
Math.floor(Math.random() * delay * 0.3) +
|
|
210
|
+
userIndex * 1000;
|
|
211
|
+
|
|
212
|
+
state.status = "retrying";
|
|
213
|
+
state.retryAttempt = attempt + 1;
|
|
214
|
+
state.retryDelay = delay;
|
|
215
|
+
state.retryStart = Date.now();
|
|
216
|
+
throttleCount++;
|
|
217
|
+
|
|
218
|
+
await new Promise((resolve) =>
|
|
219
|
+
setTimeout(resolve, delay),
|
|
220
|
+
);
|
|
221
|
+
}
|
|
150
222
|
}
|
|
223
|
+
|
|
224
|
+
state.batchesDone++;
|
|
151
225
|
}),
|
|
152
226
|
);
|
|
153
227
|
}
|
|
@@ -68,17 +68,17 @@ const bitbucketApi = (module.exports.bitbucketApi =
|
|
|
68
68
|
"https://api.bitbucket.org/2.0/repositories");
|
|
69
69
|
|
|
70
70
|
module.exports.apis = {
|
|
71
|
-
bbWorkspaceAPI: `${bitbucketApi}/${misc
|
|
71
|
+
bbWorkspaceAPI: `${bitbucketApi}/${misc?.bitbucket?.workspace}`,
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
// URLs
|
|
75
75
|
module.exports.urls = {
|
|
76
|
-
bitbucketSSH: `git@bitbucket.org:${misc
|
|
76
|
+
bitbucketSSH: `git@bitbucket.org:${misc?.bitbucket?.workspace}`,
|
|
77
77
|
};
|
|
78
78
|
|
|
79
79
|
// Request Headers
|
|
80
80
|
module.exports.headers = {
|
|
81
|
-
bbHeaders: encode(misc
|
|
81
|
+
bbHeaders: encode(misc?.bitbucket?.username, misc?.bitbucket?.token),
|
|
82
82
|
};
|
|
83
83
|
|
|
84
84
|
// Required global node modules
|
package/globals.js
CHANGED
|
@@ -279,6 +279,7 @@ if (composer && composer.require && composer.require["laravel/framework"]) {
|
|
|
279
279
|
args[0] !== "new" &&
|
|
280
280
|
args[0] !== "key" &&
|
|
281
281
|
args[0] !== "dekey" &&
|
|
282
|
+
args[0] !== "rekey" &&
|
|
282
283
|
args[0] !== "lint" &&
|
|
283
284
|
args[0] !== "workspace" &&
|
|
284
285
|
args[0] !== "prune"
|