@suffolklitlab/alkiln 4.1.1 → 4.2.1-custom-setup-timeout.1

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 CHANGED
@@ -38,7 +38,10 @@ Format:
38
38
  ### Security
39
39
  -
40
40
  -->
41
- <!-- ## [Unreleased] -->
41
+ ## [Unreleased]
42
+ ### Added
43
+ - GitHub environment variable MAX_SECONDS_FOR_SETUP to set a custom maximum time for setup and takedown for packages that take a long time to load.
44
+
42
45
  ## [4.1.1] - 2022-04-01
43
46
  ### Added
44
47
  - Step to set vars to secret variables. That is, using environment variables while hiding the names of those variables in the report, errors, and console logs.
package/action.yml CHANGED
@@ -28,6 +28,10 @@ inputs:
28
28
  description: 'Version of ALKiln to get from npm.'
29
29
  required: false
30
30
  default: '^4.0.0'
31
+ MAX_SECONDS_FOR_SETUP:
32
+ description: 'Amount of time to give the Project to upload your package's GitHub code.'
33
+ required: false
34
+ default: '120'
31
35
 
32
36
  runs:
33
37
  using: "composite"
@@ -54,9 +58,11 @@ runs:
54
58
  echo "PLAYGROUND_ID=${{ inputs.PLAYGROUND_ID }}" >> $GITHUB_ENV
55
59
  echo "DOCASSEMBLE_DEVELOPER_API_KEY=${{ inputs.DOCASSEMBLE_DEVELOPER_API_KEY }}" >> $GITHUB_ENV
56
60
  echo "ALKILN_VERSION=${{ inputs.ALKILN_VERSION }}" >> $GITHUB_ENV
61
+ echo "MAX_SECONDS_FOR_SETUP=${{ inputs.MAX_SECONDS_FOR_SETUP }}" >> $GITHUB_ENV
57
62
  shell: bash
58
63
  - name: "ALKiln: confirm info"
59
64
  run: echo -e "\nRepo is $REPO_URL\nBranch ref is $BRANCH_PATH\nManually added languages are $EXTRA_LANGUAGES\nAll other data is secret\n"
65
+ run: echo -e "\nALKiln version is $ALKILN_VERSION\nRepo is $REPO_URL\nBranch ref is $BRANCH_PATH\nMAX_SECONDS_FOR_SETUP is $MAX_SECONDS_FOR_SETUP\nManually added languages are $EXTRA_LANGUAGES\n"
60
66
  shell: bash
61
67
 
62
68
  # This doesn't use an already established package-lock.json and that
@@ -59,6 +59,10 @@ let da_i = {};
59
59
  module.exports = da_i;
60
60
 
61
61
 
62
+ // Constants
63
+ const DEFAULT_MAX_REQUEST_MS = session_vars.get_setup_timeout_ms();
64
+
65
+
62
66
  let is_timeout_error = function( error ) {
63
67
  /** Return whether the error is an axios timeout error.
64
68
  * See:
@@ -84,7 +88,7 @@ da_i.throw_an_error_if_server_is_not_responding = async function ( options ) {
84
88
  */
85
89
 
86
90
  // Defaults
87
- let { timeout } = options || { timeout: 5 * 1000 };
91
+ let { timeout } = options || { timeout: DEFAULT_MAX_REQUEST_MS };
88
92
  log.info({ pre: `Waiting for the docassemble server to respond. Will wait for ${ timeout/1000 } seconds at most.` });
89
93
 
90
94
  try {
@@ -123,7 +127,7 @@ da_i.get_dev_id = async function ( dev_id_options ) {
123
127
  * See https://docassemble.org/docs/api.html#user. */
124
128
 
125
129
  // Default timeouts
126
- let { timeout } = dev_id_options || { timeout: 75 * 1000 };
130
+ let { timeout } = dev_id_options || { timeout: DEFAULT_MAX_REQUEST_MS };
127
131
  let response = await _da_REST.get_dev_id( timeout );
128
132
  return response.data.id;
129
133
  }; // Ends da_i.get_dev_id();
@@ -137,7 +141,7 @@ da_i.validate_api_key = async function ( api_key_options ) {
137
141
  log.info({ pre: `Checking the testing account's API key.` });
138
142
 
139
143
  // Default timeouts
140
- api_key_options = api_key_options || { timeout: 75 * 1000 };
144
+ api_key_options = api_key_options || { timeout: DEFAULT_MAX_REQUEST_MS };
141
145
 
142
146
  try {
143
147
 
@@ -174,8 +178,13 @@ da_i.loop_to_create_project = async function( creation_options ) {
174
178
  /** Create a docassemble Project on the docassemble server's account.
175
179
  * Loop through potential project names until we find one that
176
180
  * isn't already taken and then use that name to create the Project. */
177
- let default_opts = { timeout: 3 * 1000, max_tries: 15, wait_seconds: 5 };
178
- let { timeout, max_tries, wait_seconds } = creation_options || default_opts;
181
+
182
+ // Defaults
183
+ creation_options = creation_options || {};
184
+ let default_opts = { timeout: DEFAULT_MAX_REQUEST_MS, max_tries: 15, wait_seconds: 5 };
185
+ let timeout = creation_options.timeout || default_opts.timeout;
186
+ let max_tries = creation_options.max_tries || default_opts.max_tries;
187
+ let wait_seconds = creation_options.wait_seconds || default_opts.wait_seconds;
179
188
 
180
189
  let project_name = null;
181
190
  let name_incrementor = 0;
@@ -229,6 +238,7 @@ da_i.loop_to_create_project = async function( creation_options ) {
229
238
  } else {
230
239
 
231
240
  // If it's a timeout error, server is busy. Try again after waiting.
241
+ // Why are we using `max_tries` for timeout error as well?
232
242
  if ( is_timeout_error( error ) && name_incrementor < max_tries ) {
233
243
  log.info({ pre: `The docassemble server was busy when we tried to `
234
244
  + `create the Project. Attempt ${ name_incrementor } of `
@@ -256,7 +266,7 @@ da_i.pull = async function ( pull_options ) {
256
266
  log.info({ pre: `Trying to pull code from the "${ session_vars.get_branch_name() }" branch.` });
257
267
 
258
268
  // Default timeouts
259
- let { timeout } = pull_options || { timeout: 75 * 1000 };
269
+ let { timeout } = pull_options || { timeout: DEFAULT_MAX_REQUEST_MS };
260
270
 
261
271
  try {
262
272
 
@@ -290,7 +300,7 @@ da_i.has_task_finished = async function ( task_id, options ) {
290
300
  * See https://docassemble.org/docs/api.html#restart_status. */
291
301
 
292
302
  // Defaults
293
- let { timeout } = options || { timeout: 3 * 1000 };
303
+ let { timeout } = options || { timeout: DEFAULT_MAX_REQUEST_MS };
294
304
 
295
305
  try {
296
306
 
@@ -340,8 +350,17 @@ da_i.wait_for_server_to_restart = async ( task_id, options ) => {
340
350
  + `"${ task_id }". A task_id is usually created for a package `
341
351
  + `with a module. It can take a few minutes to finish uploading.` });
342
352
 
343
- // Defaults
344
- let { wait_seconds_per_loop, max_loops } = options || { wait_seconds_per_loop: 5, max_loops: 15 };
353
+ // Base default
354
+ options = options || {};
355
+ // Default timeout
356
+ let default_timeout = DEFAULT_MAX_REQUEST_MS;
357
+ let timeout = options.timeout || default_timeout;
358
+ // Other defaults
359
+ let default_wait_per_loop = 5 * 1000;
360
+ let default_max_loops = timeout/default_wait_per_loop;
361
+ // Actual values
362
+ let wait_ms_per_loop = options.wait_ms_per_loop || default_wait_per_loop;
363
+ let max_loops = options.max_loops || default_max_loops;
345
364
 
346
365
  // Flags for stopping the `while` loop
347
366
  let num_tries = 0;
@@ -350,22 +369,28 @@ da_i.wait_for_server_to_restart = async ( task_id, options ) => {
350
369
  // Why loop instead of one long timeout? Because it might not just hang.
351
370
  // We might get a return value that's just `waiting`, meaning the
352
371
  // task is not done.
353
- // - [ ] How many tries/time do we give this? Do we allow customization of those values?
354
372
  while ( !done_restarting && num_tries <= max_loops ) {
355
373
  num_tries++;
356
-
357
- done_restarting = await da_i.has_task_finished( task_id );
374
+ // Wait only a short time for the task to finish, not the full default timeout
375
+ done_restarting = await da_i.has_task_finished( task_id, { timeout: 1 * 1000 } );
358
376
  if ( !done_restarting ) {
359
377
  if ( num_tries < max_loops ) {
360
- log.info({ pre: `Not yet complete. Check ${ num_tries } of ${ max_loops }. `
361
- + `Will check again in ${ wait_seconds_per_loop } seconds.`
378
+ // Show a slightly different message after a number of tries to reassure
379
+ // users we're still paying attention
380
+ let msg_start = `Not yet complete`;
381
+ if ( num_tries > 3 ) { msg_start = `Still not complete`; }
382
+
383
+ // When the server is busy, the task timeout causes this loop to actually
384
+ // take 6 seconds to complete, not 5, but I'm not sure how to make that clear
385
+ log.info({ pre: `${ msg_start }. Check ${ num_tries } of ${ max_loops }. `
386
+ + `Will check again in ${ wait_ms_per_loop/1000 } seconds.`
362
387
  });
363
- await time.waitForTimeout( wait_seconds_per_loop * 1000 );
388
+ await time.waitForTimeout( wait_ms_per_loop );
364
389
 
365
390
  } else {
366
391
  // This is our last round, let's wrap it up
367
392
  let server_msg = `ALKiln setup: It seems like the docassemble server `
368
- + `didn't finish uploading the code after ${ max_loops * wait_seconds_per_loop } `
393
+ + `didn't finish uploading the code after ${ max_loops * (wait_ms_per_loop/1000) } `
369
394
  + `seconds. Some things you can try: check your server is up, try `
370
395
  + `re-running the test, and try pulling the package manually `
371
396
  + `into the playground.`;
@@ -385,7 +410,7 @@ da_i.delete_project = async function ( delete_options ) {
385
410
  /** Delete a project on the user's da server. */
386
411
 
387
412
  // Defaults
388
- let { timeout } = delete_options || { timeout: 75 * 1000 };
413
+ let { timeout } = delete_options || { timeout: DEFAULT_MAX_REQUEST_MS };
389
414
 
390
415
  let project_name = session_vars.get_project_name()
391
416
  log.info({ pre: `Trying to delete Project ${ project_name }` });
@@ -396,7 +421,9 @@ da_i.delete_project = async function ( delete_options ) {
396
421
  log.info({ pre: `Deleted Project "${ project_name }"` });
397
422
 
398
423
  } catch ( error ) {
399
- // Should we throw in here?
424
+ // TODO: Add more useful error messages, like project doesn't exist. The devs
425
+ // shouldn't be deleting projects by hand, but it's still very possible they would
426
+ // Status 400
400
427
  log.error({ pre: `Ran into an error when deleting Project "${ project_name }"` });
401
428
  log.debug({ pre: `See https://docassemble.org/docs/api.html#playground_delete_project.` });
402
429
  throw error;
@@ -20,10 +20,20 @@ const session_vars = {};
20
20
 
21
21
  module.exports = session_vars;
22
22
 
23
+ // Default to null
23
24
  session_vars.get_debug = function () { return process.env.DEBUG || null; };
24
25
  session_vars.get_dev_api_key = function () { return process.env.DOCASSEMBLE_DEVELOPER_API_KEY || null; };
25
26
  session_vars.get_repo_url = function () { return process.env.REPO_URL || null; };
26
27
 
28
+ // More complex logic
29
+ session_vars.get_setup_timeout_ms = function () {
30
+ let timeout = 120 * 1000;
31
+ if ( process.env.MAX_SECONDS_FOR_SETUP ) {
32
+ timeout = parseFloat( process.env.MAX_SECONDS_FOR_SETUP ) * 1000;
33
+ }
34
+ return timeout;
35
+ };
36
+
27
37
  session_vars.get_da_server_url = function () {
28
38
  try {
29
39
  let url = process.env.SERVER_URL || process.env.BASE_URL;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suffolklitlab/alkiln",
3
- "version": "4.1.1",
3
+ "version": "4.2.1-custom-setup-timeout.1",
4
4
  "description": "Integrated automated end-to-end testing with docassemble, puppeteer, and cucumber.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {