@suffolklitlab/alkiln 5.0.2-feat-github-server-14 → 5.1.0-sources-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 +14 -0
- package/action.yml +9 -29
- package/lib/docassemble/docassemble_api_REST.js +2 -10
- package/lib/docassemble/docassemble_api_interface.js +10 -15
- package/lib/docassemble/get_base_interview_url.js +3 -7
- package/lib/docassemble/setup.js +1 -1
- package/lib/run_cucumber.js +54 -31
- package/lib/scope.js +21 -64
- package/lib/utils/log.js +1 -1
- package/lib/utils/session_vars.js +35 -32
- package/npm-shrinkwrap.json +16 -2
- package/package.json +2 -3
- package/setup.py +2 -2
- package/.github/workflows/github_server.yml +0 -83
- package/github_server/action.yml +0 -143
- package/lib/docassemble/server_install.js +0 -9
package/CHANGELOG.md
CHANGED
|
@@ -37,9 +37,19 @@ Format:
|
|
|
37
37
|
|
|
38
38
|
### Security
|
|
39
39
|
-
|
|
40
|
+
|
|
41
|
+
### Internal
|
|
42
|
+
-
|
|
40
43
|
-->
|
|
41
44
|
<!-- ## [Unreleased] -->
|
|
42
45
|
|
|
46
|
+
## [5.1.0] - 2023-08-12
|
|
47
|
+
### Added
|
|
48
|
+
- Comboboxes - can now fill in comboboxes on the latest Docassemble.
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
- Filling out a hidden field right after a date field triggered the date's calendar popup, which I believe ate the input for the next visible field.
|
|
52
|
+
|
|
43
53
|
## [5.0.2] - 2023-07-20
|
|
44
54
|
### Fixed
|
|
45
55
|
- Accept `SERVER_RELOAD_TIMEOUT_SECONDS` as an env var input in GitHub.
|
|
@@ -89,6 +99,10 @@ Format:
|
|
|
89
99
|
server
|
|
90
100
|
- Update dependencies. See [#727](https://github.com/SuffolkLITLab/ALKiln/pull/727).
|
|
91
101
|
|
|
102
|
+
### Internal
|
|
103
|
+
- added a test for multiline json values (only ones set by code not by user input)
|
|
104
|
+
- added an internal section to the change log
|
|
105
|
+
|
|
92
106
|
## [4.11.1] - 2023-03-21
|
|
93
107
|
### Changed
|
|
94
108
|
- Get error data from server errors
|
package/action.yml
CHANGED
|
@@ -23,12 +23,6 @@ inputs:
|
|
|
23
23
|
description: "Max amount of time to give the server to reload if it needs to"
|
|
24
24
|
required: false
|
|
25
25
|
# no default to let the custom Scenario timeouts create the reload timeout
|
|
26
|
-
# INSTALL_LOCATION? Will that get confused with the location passed into the command line?
|
|
27
|
-
# Maybe `INSTALL_LOCATION` could be "playground", "server", or a custom path and we could handle all those.
|
|
28
|
-
INSTALL_METHOD:
|
|
29
|
-
description: "Default is 'playground'. Other option: 'server'. How to install the package onto the server."
|
|
30
|
-
required: false
|
|
31
|
-
default: "playground"
|
|
32
26
|
|
|
33
27
|
runs:
|
|
34
28
|
using: "composite"
|
|
@@ -53,43 +47,29 @@ runs:
|
|
|
53
47
|
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\nSERVER_RELOAD_TIMEOUT_SECONDS is $SERVER_RELOAD_TIMEOUT_SECONDS\n"
|
|
54
48
|
shell: bash
|
|
55
49
|
|
|
56
|
-
# Install
|
|
50
|
+
# Install node
|
|
57
51
|
- name: "ALKiln: Install node packages"
|
|
58
52
|
uses: actions/setup-node@v3
|
|
59
53
|
with:
|
|
60
54
|
node-version: "18"
|
|
61
55
|
- name: Install ALKiln directly from npm
|
|
62
56
|
run: |
|
|
63
|
-
npm install -g @suffolklitlab/alkiln
|
|
57
|
+
npm install -g @suffolklitlab/alkiln
|
|
64
58
|
shell: bash
|
|
65
59
|
|
|
66
|
-
#
|
|
60
|
+
# Run tests
|
|
67
61
|
- name: "ALKiln: Create a Project and pull the package from GitHub"
|
|
68
|
-
if: ${{ inputs.INSTALL_METHOD == 'playground' }}
|
|
69
62
|
run: alkiln-setup
|
|
70
63
|
shell: bash
|
|
71
|
-
- run: echo -e "\n\n====\nALKiln could not create a project on your server's testing account or pull your package into it. Check the messages above this line.\n\n"
|
|
72
|
-
if: ${{ inputs.INSTALL_METHOD == 'playground' && failure() }}
|
|
73
|
-
shell: bash
|
|
74
|
-
|
|
75
|
-
# Install on server
|
|
76
|
-
- name: "ALKiln: Install the GitHub package onto the server"
|
|
77
|
-
if: ${{ inputs.INSTALL_METHOD == 'server' }}
|
|
78
|
-
run: alkiln-server-install
|
|
79
|
-
shell: bash
|
|
80
|
-
- run: echo -e "\n\n====\nALKiln could not install the package on the temporary GitHub docassemble server. Check the steps above this line.\n\n"
|
|
81
|
-
if: ${{ inputs.INSTALL_METHOD == 'server' && failure() }}
|
|
82
|
-
shell: bash
|
|
83
|
-
|
|
84
|
-
# run tests
|
|
85
64
|
- name: "ALKiln: Run tests"
|
|
86
65
|
if: ${{ success() }}
|
|
87
66
|
run: alkiln-run ${{ github.event.inputs.tags && format('{0}', github.event.inputs.tags) }}
|
|
88
67
|
shell: bash
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
68
|
+
- run: echo -e "\n\n====ALKiln could not create a project on your server's testing account or pull your package into it. Check the messages above this line.\n\n"
|
|
69
|
+
if: ${{ failure() }}
|
|
70
|
+
shell: bash
|
|
71
|
+
- name: "ALKiln: Delete project from docassemble test account"
|
|
72
|
+
if: ${{ always() }}
|
|
93
73
|
run: alkiln-takedown
|
|
94
74
|
shell: bash
|
|
95
75
|
|
|
@@ -102,7 +82,7 @@ runs:
|
|
|
102
82
|
path: ./alkiln-*
|
|
103
83
|
|
|
104
84
|
# ##################################
|
|
105
|
-
# # A developer's workflow should look similar to the below
|
|
85
|
+
# # A developer's workflow should look similar to the below
|
|
106
86
|
# # In place of `uses: suffolkLITLab/ALKiln@v5`, they
|
|
107
87
|
# # might use another version.
|
|
108
88
|
#
|
|
@@ -79,21 +79,13 @@ da.pull = async function ( timeout ) {
|
|
|
79
79
|
}; // Ends da.pull()
|
|
80
80
|
|
|
81
81
|
|
|
82
|
-
da.has_playground_task_finished = async function ( task_id, timeout ) {
|
|
83
|
-
return await da.has_task_finished( "/api/restart_status", task_id, timeout);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
da.has_package_task_finished = async function ( task_id, timeout ) {
|
|
87
|
-
return await da.has_task_finished( "/api/package_update_status", task_id, timeout);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
82
|
// node -e 'require("./lib/docassemble/docassemble_api_REST.js").has_task_finished()'
|
|
91
|
-
da.has_task_finished = async function (
|
|
83
|
+
da.has_task_finished = async function ( task_id, timeout ) {
|
|
92
84
|
/* Check task status based on `task_id`. */
|
|
93
85
|
let options = {
|
|
94
86
|
method: 'GET',
|
|
95
87
|
headers: {'X-API-Key': session_vars.get_dev_api_key()},
|
|
96
|
-
url: `${ session_vars.get_da_server_url() }
|
|
88
|
+
url: `${ session_vars.get_da_server_url() }/api/restart_status`,
|
|
97
89
|
params: {
|
|
98
90
|
task_id: task_id,
|
|
99
91
|
},
|
|
@@ -329,8 +329,9 @@ da_i.pull = async function ( pull_options ) {
|
|
|
329
329
|
}
|
|
330
330
|
}; // Ends da_i.pull()
|
|
331
331
|
|
|
332
|
+
|
|
332
333
|
// node -e 'require("./lib/docassemble/docassemble_api_interface.js").has_task_finished()'
|
|
333
|
-
da_i.has_task_finished = async function (
|
|
334
|
+
da_i.has_task_finished = async function ( task_id, options ) {
|
|
334
335
|
/** Check task status if it exists. If not, return true as task did
|
|
335
336
|
* not require a server restart. See da_i.pull().
|
|
336
337
|
* See https://docassemble.org/docs/api.html#restart_status. */
|
|
@@ -341,7 +342,7 @@ da_i.has_task_finished = async function ( api_endpoint, task_id, options ) {
|
|
|
341
342
|
try {
|
|
342
343
|
|
|
343
344
|
// If server did need to restart, check if it's done.
|
|
344
|
-
let response = await _da_REST.has_task_finished(
|
|
345
|
+
let response = await _da_REST.has_task_finished( task_id, timeout );
|
|
345
346
|
log.debug({ pre: `Task status: ${ response.status }. Docassemble status text: ${ response.data.status }. Task id: ${ task_id }` });
|
|
346
347
|
|
|
347
348
|
if ( response.data.status === 'completed' ) {
|
|
@@ -352,15 +353,16 @@ da_i.has_task_finished = async function ( api_endpoint, task_id, options ) {
|
|
|
352
353
|
return false;
|
|
353
354
|
|
|
354
355
|
} else if ( response.data.status === 'unknown' ) {
|
|
355
|
-
// Server is working, but status 'unknown'?
|
|
356
|
-
//
|
|
356
|
+
// Server is working, but status 'unknown'? We shouldn't even
|
|
357
|
+
// get here according to the API docs, but it feels weird to have
|
|
358
|
+
// no default behavior. What to return? Throw?
|
|
357
359
|
log.info({
|
|
358
360
|
pre: `\`task_id\` "${ task_id }" has expired. If it's been `
|
|
359
361
|
+ `less than 1 hour since the task started, the task is `
|
|
360
362
|
+ `complete. See https://docassemble.org/docs/api.html#restart_status.`,
|
|
361
|
-
data: response
|
|
363
|
+
data: response,
|
|
362
364
|
});
|
|
363
|
-
return
|
|
365
|
+
return null;
|
|
364
366
|
} // ends status type
|
|
365
367
|
|
|
366
368
|
} catch ( error ) {
|
|
@@ -376,15 +378,8 @@ da_i.has_task_finished = async function ( api_endpoint, task_id, options ) {
|
|
|
376
378
|
|
|
377
379
|
}; // Ends da_i.has_task_finished()
|
|
378
380
|
|
|
379
|
-
da_i.wait_for_playground_to_restart = async ( task_id, options ) => {
|
|
380
|
-
return await da_i.wait_for_server_to_restart( "/api/restart_status", task_id, options );
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
da_i.wait_for_package_to_restart = async ( task_id, options ) => {
|
|
384
|
-
return await da_i.wait_for_server_to_restart( "/api/package_update_status", task_id, options );
|
|
385
|
-
};
|
|
386
381
|
|
|
387
|
-
da_i.wait_for_server_to_restart = async (
|
|
382
|
+
da_i.wait_for_server_to_restart = async ( task_id, options ) => {
|
|
388
383
|
/** Wait for the server to finish restarting in case a module needs to load.
|
|
389
384
|
* This is a polling function because things may be returned
|
|
390
385
|
* that aren't equivalent to the server being done with a task. */
|
|
@@ -415,7 +410,7 @@ da_i.wait_for_server_to_restart = async ( api_endpoint, task_id, options ) => {
|
|
|
415
410
|
while ( !done_restarting && num_tries <= max_loops ) {
|
|
416
411
|
num_tries++;
|
|
417
412
|
// Wait only a short time for the task to finish, not the full default timeout
|
|
418
|
-
done_restarting = await da_i.has_task_finished(
|
|
413
|
+
done_restarting = await da_i.has_task_finished( task_id, { timeout: wait_for_response } );
|
|
419
414
|
if ( !done_restarting ) {
|
|
420
415
|
if ( num_tries < max_loops ) {
|
|
421
416
|
// Show a slightly different message after a number of tries to reassure
|
|
@@ -11,13 +11,9 @@ let get_base_interview_url = async function () {
|
|
|
11
11
|
* when the user is not logged in.) We can't use `reset=2` because it caused an
|
|
12
12
|
* 'Unable to locate interview session' error. */
|
|
13
13
|
let server_url = session_vars.get_da_server_url();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
let dev_id = await docassemble_api_interface.get_dev_id();
|
|
18
|
-
let project_name = session_vars.get_project_name();
|
|
19
|
-
return `${ server_url }/interview?new_session=1&i=docassemble.playground${ dev_id }${ project_name }%3A`;
|
|
20
|
-
}
|
|
14
|
+
let dev_id = await docassemble_api_interface.get_dev_id();
|
|
15
|
+
let project_name = session_vars.get_project_name();
|
|
16
|
+
return `${ server_url }/interview?new_session=1&i=docassemble.playground${ dev_id }${ project_name }%3A`;
|
|
21
17
|
};
|
|
22
18
|
|
|
23
19
|
module.exports = get_base_interview_url;
|
package/lib/docassemble/setup.js
CHANGED
|
@@ -39,7 +39,7 @@ const setup = async () => {
|
|
|
39
39
|
let task_id = await da_i.pull();
|
|
40
40
|
// Task id will be null if server did not need to restart
|
|
41
41
|
if ( task_id ) {
|
|
42
|
-
await da_i.
|
|
42
|
+
await da_i.wait_for_server_to_restart( task_id );
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// Finish
|
package/lib/run_cucumber.js
CHANGED
|
@@ -6,64 +6,87 @@ const session_vars = require('./utils/session_vars');
|
|
|
6
6
|
|
|
7
7
|
const cucumber_api = require('@cucumber/cucumber/api');
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const environment = { cwd: process.cwd() };
|
|
13
|
-
console.log("alkiln-run: environment: %o", environment);
|
|
9
|
+
function build_config(argv) {
|
|
10
|
+
// The default provided config
|
|
14
11
|
const provided_config = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
publishQuiet: true,
|
|
13
|
+
require: `./lib/index.js`,
|
|
14
|
+
format: [`progress`, `summary:cucumber-report.txt`],
|
|
15
|
+
paths: [`${ argv.sources }/*.feature`],
|
|
16
|
+
retry: 1,
|
|
20
17
|
}
|
|
21
18
|
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// For S3
|
|
27
|
-
provided_config.paths.push(`/tmp/playgroundsources/${session_vars.get_user_id()}/${session_vars.get_user_project_name()}/*.feature`);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
let tags = argv.slice(2);
|
|
31
|
-
if ( session_vars.get_origin() === `playground` ) {
|
|
32
|
-
tags = session_vars.get_tags();
|
|
33
|
-
}
|
|
19
|
+
let tags = argv[`_`];
|
|
20
|
+
// if ( session_vars.get_origin() === `playground` ) {
|
|
21
|
+
// tags = session_vars.get_tags();
|
|
22
|
+
// }
|
|
34
23
|
|
|
35
24
|
if (tags.length > 0) {
|
|
36
25
|
let joined_tags = '';
|
|
37
26
|
// Cucumber expects tags in boolean expressions, like (@a0 or @a1) and @random.
|
|
38
27
|
// If we get a list of only tags, then "or" them all together
|
|
39
|
-
if (tags.every((val) => val.startsWith(
|
|
40
|
-
joined_tags = tags.join(
|
|
28
|
+
if (tags.every((val) => val.startsWith(`@`))) {
|
|
29
|
+
joined_tags = tags.join(` or `);
|
|
41
30
|
}
|
|
42
31
|
// If we get a list of seemingly no tags, assume they meant to use tags
|
|
43
|
-
else if (tags.every((val) => !val.startsWith(
|
|
44
|
-
joined_tags = tags.map((val) =>
|
|
32
|
+
else if (tags.every((val) => !val.startsWith(`@`))) {
|
|
33
|
+
joined_tags = tags.map((val) => `@` + val).join(` or `);
|
|
45
34
|
}
|
|
46
35
|
// If it's a mix of tags and no tags, it's probably a boolean expression!
|
|
47
36
|
else {
|
|
48
|
-
joined_tags = tags.join(
|
|
37
|
+
joined_tags = tags.join(` `);
|
|
49
38
|
}
|
|
50
39
|
|
|
51
40
|
provided_config.tags = joined_tags;
|
|
52
41
|
} // end if there are tags
|
|
53
42
|
|
|
43
|
+
return provided_config;
|
|
44
|
+
}; // Ends build_config()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
(async function main() {
|
|
48
|
+
/** Create the cucumber config, run the tests, create and
|
|
49
|
+
* manipluate the output. */
|
|
50
|
+
const environment = { cwd: process.cwd() };
|
|
51
|
+
console.log("alkiln-run: environment: %o", environment);
|
|
52
|
+
|
|
53
|
+
// process.argv is a list of strings of commands and args.
|
|
54
|
+
let argv = require(`minimist`)( process.argv.slice(2), {
|
|
55
|
+
default: {
|
|
56
|
+
// Testing from GitHub. TODO: Do we want to allow multiple sources paths?
|
|
57
|
+
sources: `./docassemble/*/data/sources`,
|
|
58
|
+
// From playground: `/usr/share/docassemble/files/playgroundsources/<user_id>/<project>/*.feature`
|
|
59
|
+
// From playground with S3: `/tmp/playgroundsources/<user_id>/<project>/*.feature`
|
|
60
|
+
|
|
61
|
+
// // Installed in a user Playground
|
|
62
|
+
// url: `<server>/interview?new_session=1&i=docassemble.playground<user_id><project>%3A`,
|
|
63
|
+
// // server install: `<server>/interview?new_session=1&i=docassemble.<package>%3Adata/questions/`
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
let dir_exists = session_vars.set_sources_path( argv.sources );
|
|
68
|
+
if ( !dir_exists ) {
|
|
69
|
+
// If we don't throw, it'll be more confusing when no tests run
|
|
70
|
+
throw new ReferenceError( `No folder exists at "${ argv.sources }", where ALKiln looks for your \`.feature\` files.`)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const provided_config = build_config( argv );
|
|
74
|
+
|
|
54
75
|
const { runConfiguration } = await cucumber_api.loadConfiguration({
|
|
55
76
|
provided: provided_config
|
|
56
77
|
}, environment);
|
|
78
|
+
|
|
57
79
|
console.log("alkiln-run: runConfiguration: %o", runConfiguration);
|
|
80
|
+
|
|
58
81
|
var path = require('path');
|
|
59
82
|
var codeDir = path.dirname(require.main.filename);
|
|
83
|
+
console.log("alkiln-run: working directory: %o", codeDir);
|
|
60
84
|
const support = await cucumber_api.loadSupport({ support: {
|
|
61
|
-
requireModules: [`${ codeDir }/index.js`],
|
|
62
|
-
requirePaths: [ `${ codeDir }/index.js`],
|
|
85
|
+
requireModules: [ `${ codeDir }/index.js` ],
|
|
86
|
+
requirePaths: [ `${ codeDir }/index.js` ],
|
|
63
87
|
importPaths: [],
|
|
64
88
|
}, sources: {paths: []}}, environment);
|
|
65
89
|
|
|
66
|
-
console.log("alkiln-run: working directory: %o", codeDir);
|
|
67
90
|
console.log(`\n\n`);
|
|
68
91
|
|
|
69
92
|
const { success } = await cucumber_api.runCucumber({...runConfiguration, support});
|
|
@@ -86,6 +109,6 @@ const cucumber_api = require('@cucumber/cucumber/api');
|
|
|
86
109
|
|
|
87
110
|
// Put it in the correct file in the correct folder
|
|
88
111
|
let artifacts_path = session_vars.get_artifacts_path_name();
|
|
89
|
-
fs.appendFileSync( `${ artifacts_path}/${ log.debug_log_file }`, data);
|
|
112
|
+
fs.appendFileSync( `${ artifacts_path }/${ log.debug_log_file }`, data);
|
|
90
113
|
});
|
|
91
114
|
})();
|
package/lib/scope.js
CHANGED
|
@@ -44,9 +44,6 @@ let printable_var_value = function(row) {
|
|
|
44
44
|
/* `row` might be a row, a source row, or an original row. */
|
|
45
45
|
let original = get_original_row(row);
|
|
46
46
|
if ( is_secret_var(original) ) {
|
|
47
|
-
if ( session_vars.get_dangerous_debug() ) {
|
|
48
|
-
return `alkiln_dangerous ${ row.value }`;
|
|
49
|
-
}
|
|
50
47
|
return original.flags.secret_name;
|
|
51
48
|
}
|
|
52
49
|
return row.value;
|
|
@@ -1001,6 +998,11 @@ module.exports = {
|
|
|
1001
998
|
}
|
|
1002
999
|
}
|
|
1003
1000
|
|
|
1001
|
+
if ( !encoded_name ) {
|
|
1002
|
+
// Some fields, like comboboxes, have a weird var name setup
|
|
1003
|
+
encoded_name = $node.attr( `id` );
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1004
1006
|
// ====================
|
|
1005
1007
|
// Table rows
|
|
1006
1008
|
// ====================
|
|
@@ -1475,6 +1477,11 @@ module.exports = {
|
|
|
1475
1477
|
*/
|
|
1476
1478
|
let row_used = null;
|
|
1477
1479
|
|
|
1480
|
+
// Skip hidden fields right away. When a date field was above a combobox,
|
|
1481
|
+
// interacting with the hidden field caused the date field to open its
|
|
1482
|
+
// calendar which blocked input to the combobox
|
|
1483
|
+
if ( field.type === `hidden` ) { return row_used; }
|
|
1484
|
+
|
|
1478
1485
|
let matching_input_rows = await scope.getMatchingRows( scope, { var_data, field });
|
|
1479
1486
|
|
|
1480
1487
|
// Nothing to set if there are no matching table rows
|
|
@@ -1489,6 +1496,8 @@ module.exports = {
|
|
|
1489
1496
|
|
|
1490
1497
|
let handle = await scope.get_handle_from_field( scope, { field: field });
|
|
1491
1498
|
|
|
1499
|
+
// After each previous input, figure out if this input is (now/still) disabled
|
|
1500
|
+
// TODO: Consider testing for disabled this before we get the matching row
|
|
1492
1501
|
let disabled = await handle.evaluate(( elem )=> {
|
|
1493
1502
|
// da's header covers the top of the section containing the fields which means
|
|
1494
1503
|
// sometimes it blocks nodes from clicks. Scroll item to the bottom instead.
|
|
@@ -1778,73 +1787,34 @@ module.exports = {
|
|
|
1778
1787
|
// allow a typo where someone forgot to include a space after a comma.
|
|
1779
1788
|
let uploads_names = answer.split(`,`);
|
|
1780
1789
|
if ( uploads_names.length === 0 ) {
|
|
1781
|
-
await scope.addToReport( scope, {
|
|
1782
|
-
type: `error`,
|
|
1783
|
-
value: `Your list of files to upload is empty.`
|
|
1784
|
-
});
|
|
1785
|
-
return false; // The row wasn't used
|
|
1786
|
-
}
|
|
1787
|
-
|
|
1788
|
-
let dirs = [];
|
|
1789
|
-
if ( session_vars.get_origin() === `playground` ) {
|
|
1790
|
-
let files_playground = fg.sync(
|
|
1791
|
-
[ `/usr/share/docassemble/files/playgroundsources/${session_vars.get_user_id()}/${session_vars.get_user_project_name()}` ],
|
|
1792
|
-
{ onlyFiles: false, suppressErrors: true }
|
|
1793
|
-
);
|
|
1794
|
-
let files_s3 = fg.sync(
|
|
1795
|
-
[ `/tmp/playgroundsources/${session_vars.get_user_id()}/${session_vars.get_user_project_name()}` ],
|
|
1796
|
-
{ onlyFiles: false, suppressErrors: true }
|
|
1797
|
-
);
|
|
1798
|
-
|
|
1799
|
-
dirs = files_playground.concat( files_s3 );
|
|
1800
|
-
} else {
|
|
1801
|
-
dirs = fg.sync(
|
|
1802
|
-
[ `**/docassemble/**/data/sources` ],
|
|
1803
|
-
{ onlyFiles: false, suppressErrors: true }
|
|
1804
|
-
);
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1807
|
-
if ( session_vars.get_debug() ) {
|
|
1808
|
-
console.log( `All discovered dirs to upload from:`, dirs );
|
|
1809
|
-
}
|
|
1810
|
-
|
|
1811
|
-
// Make sure sources directory exists and has files in it
|
|
1812
|
-
if ( dirs.length === 0 ) {
|
|
1813
1790
|
await scope.addToReport( scope, {
|
|
1814
1791
|
type: `warning`,
|
|
1815
|
-
value: `
|
|
1816
|
-
+ `but ALKiln couldn't find the directory or it was empty.`
|
|
1792
|
+
value: `Your list of files to upload is empty.`
|
|
1817
1793
|
});
|
|
1818
1794
|
return false; // The row wasn't used
|
|
1819
1795
|
}
|
|
1820
1796
|
|
|
1821
|
-
|
|
1822
|
-
|
|
1797
|
+
let dir = session_vars.get_sources_path();
|
|
1798
|
+
// Get the full paths of all the existing files
|
|
1823
1799
|
let paths = [];
|
|
1824
1800
|
let missing_files = []; // For any user warnings
|
|
1825
1801
|
for ( let name of uploads_names ) {
|
|
1826
|
-
|
|
1827
1802
|
let trimmed_name = name.trim();
|
|
1828
|
-
let matching_paths =
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
let new_paths = fg.sync([ `${ one_dir }/${ trimmed_name }` ]);
|
|
1833
|
-
matching_paths.push( ...new_paths );
|
|
1834
|
-
} // ends for each dir
|
|
1835
|
-
|
|
1803
|
+
let matching_paths = fg.sync(
|
|
1804
|
+
[ `${ dir }/${ trimmed_name }` ],
|
|
1805
|
+
{ suppressErrors: true }
|
|
1806
|
+
);
|
|
1836
1807
|
if ( matching_paths.length === 0 ) {
|
|
1837
1808
|
missing_files.push( trimmed_name );
|
|
1838
1809
|
} else {
|
|
1839
1810
|
paths.push( ...matching_paths );
|
|
1840
1811
|
}
|
|
1841
|
-
|
|
1842
1812
|
} // ends for each file
|
|
1843
1813
|
|
|
1844
1814
|
if ( missing_files.length > 0 ) {
|
|
1845
1815
|
await scope.addToReport( scope, {
|
|
1846
1816
|
type: `warning`,
|
|
1847
|
-
value: `ALKiln could not find "${ missing_files.join('", "') }" in
|
|
1817
|
+
value: `ALKiln could not find "${ missing_files.join('", "') }" in "${ dir }".`
|
|
1848
1818
|
});
|
|
1849
1819
|
}
|
|
1850
1820
|
|
|
@@ -1891,8 +1861,6 @@ module.exports = {
|
|
|
1891
1861
|
await handle.evaluate( el => { el.value = '' });
|
|
1892
1862
|
await handle.focus();
|
|
1893
1863
|
await handle.type( answer );
|
|
1894
|
-
setTimeout(async () => {
|
|
1895
|
-
}, 500)
|
|
1896
1864
|
},
|
|
1897
1865
|
|
|
1898
1866
|
draw_signature: async function ( scope, name ) {
|
|
@@ -2523,10 +2491,6 @@ module.exports = {
|
|
|
2523
2491
|
/** Sets a non-story table variable to a "secret" value (i.e. an env var) */
|
|
2524
2492
|
// Prevent pictures of a screen with a secret.
|
|
2525
2493
|
scope.disable_error_screenshot = true;
|
|
2526
|
-
if ( session_vars.get_dangerous_debug() ) {
|
|
2527
|
-
scope.disable_error_screenshot = false;
|
|
2528
|
-
}
|
|
2529
|
-
|
|
2530
2494
|
let var_data = await scope.normalizeTable( scope, {
|
|
2531
2495
|
var_data: [{
|
|
2532
2496
|
var: var_name,
|
|
@@ -2670,10 +2634,7 @@ module.exports = {
|
|
|
2670
2634
|
*/
|
|
2671
2635
|
// Don't take a picture of a failed login in case one of the inputs is correct
|
|
2672
2636
|
scope.disable_error_screenshot = true;
|
|
2673
|
-
|
|
2674
|
-
scope.disable_error_screenshot = false;
|
|
2675
|
-
}
|
|
2676
|
-
|
|
2637
|
+
|
|
2677
2638
|
// If there is no browser open, start a new one
|
|
2678
2639
|
if (!scope.browser) {
|
|
2679
2640
|
scope.browser = await scope.driver.launch({ headless: !session_vars.DEBUG });
|
|
@@ -2706,10 +2667,6 @@ module.exports = {
|
|
|
2706
2667
|
let email = process.env[ email_secret_name ];
|
|
2707
2668
|
let password = process.env[ password_secret_name ];
|
|
2708
2669
|
|
|
2709
|
-
if ( session_vars.get_dangerous_debug() ) {
|
|
2710
|
-
log.debug({ type: `unsafe`, data: `login: ${ email }, ${ password }` });
|
|
2711
|
-
}
|
|
2712
|
-
|
|
2713
2670
|
// Give as many useful messages to the user as possible if the env vars
|
|
2714
2671
|
// aren't defined. Eventually, just provide a link to the docs because
|
|
2715
2672
|
// this is complex
|
package/lib/utils/log.js
CHANGED
|
@@ -42,7 +42,7 @@ log.error = function ({ type='', pre='', data='', post='' }) {
|
|
|
42
42
|
|
|
43
43
|
log.debug = function ({ type='', pre='', data='', post='' }) {
|
|
44
44
|
/* If debugging is turned on, log a message that includes `ALKiln` and `debug` */
|
|
45
|
-
if ( session_vars.get_debug()
|
|
45
|
+
if ( session_vars.get_debug() ) {
|
|
46
46
|
let start = create_msg_start([ type, 'debug' ], pre );
|
|
47
47
|
// Log them each on a separate line
|
|
48
48
|
console.log( `ALKiln ${ type } debug: ${ pre }` );
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
+
const fg = require('fast-glob');
|
|
2
3
|
const path = require('path');
|
|
3
4
|
require('dotenv').config();
|
|
4
5
|
|
|
@@ -23,7 +24,6 @@ module.exports = session_vars;
|
|
|
23
24
|
// These default to null
|
|
24
25
|
// TODO: How to isolate debug elsewhere so this file can use the logger?
|
|
25
26
|
session_vars.get_debug = function () { return process.env.DEBUG || null; };
|
|
26
|
-
session_vars.get_dangerous_debug = function () { return process.env._ALKILN_DANGEROUS_DEBUG || null; };
|
|
27
27
|
session_vars.is_dev_env = function () { return process.env.DEV || null; }
|
|
28
28
|
|
|
29
29
|
session_vars.get_dev_api_key = function () { return process.env.DOCASSEMBLE_DEVELOPER_API_KEY || null; };
|
|
@@ -45,6 +45,7 @@ session_vars.get_tags = function () {
|
|
|
45
45
|
return [];
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
|
+
session_vars.get_sources = function () { return process.env._ALKILN_SOURCES || null; };
|
|
48
49
|
|
|
49
50
|
// More complex logic
|
|
50
51
|
session_vars.get_server_reload_timeout = function () {
|
|
@@ -116,7 +117,6 @@ session_vars.get_languages = function () {
|
|
|
116
117
|
|
|
117
118
|
const runtime_config_path = `runtime_config.json`;
|
|
118
119
|
const project_name_key = `da_project_name`;
|
|
119
|
-
const install_type_key = `da_install_type`;
|
|
120
120
|
session_vars.save_project_name = function ( project_name ) {
|
|
121
121
|
/* Saves the name of the project to a json obj so deletion can use it later.
|
|
122
122
|
* Built for local as well as remote testing. Assumes a kosher string.
|
|
@@ -199,36 +199,6 @@ session_vars.save_artifacts_path_name = function ( path_name ) {
|
|
|
199
199
|
return file;
|
|
200
200
|
}; // Ends save_artifacts_path_name()
|
|
201
201
|
|
|
202
|
-
|
|
203
|
-
session_vars.save_install_type = function (install_type) {
|
|
204
|
-
/* Save a key with the name of the current artifacts folder in case it doesn't exist. */
|
|
205
|
-
|
|
206
|
-
// Ensure artifacts path file exists
|
|
207
|
-
if ( !fs.existsSync( runtime_config_path ) ) {
|
|
208
|
-
// If the file doesn't exist, make one because next we need to read it
|
|
209
|
-
fs.writeFileSync( runtime_config_path, JSON.stringify( {}, null, 2 ) );
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Get the json, changing it, and re-write the file from scratch
|
|
213
|
-
let json = JSON.parse( fs.readFileSync( runtime_config_path ) );
|
|
214
|
-
json[ install_type_key ] = install_type;
|
|
215
|
-
let file = fs.writeFileSync( runtime_config_path, JSON.stringify( json, null, 2 ) );
|
|
216
|
-
|
|
217
|
-
return file;
|
|
218
|
-
}; // Ends save_artifacts_path_name()
|
|
219
|
-
|
|
220
|
-
session_vars.get_install_type = function () {
|
|
221
|
-
/* Get the name of the current artifacts path. */
|
|
222
|
-
try {
|
|
223
|
-
let json = JSON.parse( fs.readFileSync( runtime_config_path ));
|
|
224
|
-
let install_type = json[ install_type_key ];
|
|
225
|
-
|
|
226
|
-
return install_type;
|
|
227
|
-
} catch ( error ) {
|
|
228
|
-
return null;
|
|
229
|
-
}
|
|
230
|
-
}; // Ends get_artifacts_path_name()
|
|
231
|
-
|
|
232
202
|
session_vars.get_artifacts_path_name = function () {
|
|
233
203
|
/* Get the name of the current artifacts path. */
|
|
234
204
|
try {
|
|
@@ -242,6 +212,39 @@ session_vars.get_artifacts_path_name = function () {
|
|
|
242
212
|
}
|
|
243
213
|
}; // Ends get_artifacts_path_name()
|
|
244
214
|
|
|
215
|
+
session_vars.set_sources_path = function ( path ) {
|
|
216
|
+
/** Returns whether the given path exists or not. If it does, store
|
|
217
|
+
* the path to the sources folder. Can be used for getting, e.g
|
|
218
|
+
* .feature files, files to upload, etc. May be annoying repetition
|
|
219
|
+
* for some local testing.
|
|
220
|
+
*
|
|
221
|
+
* Our code should ensure this gets run before cucumber gets triggered.
|
|
222
|
+
*
|
|
223
|
+
* @returns bool */
|
|
224
|
+
|
|
225
|
+
let sources = fg.sync(
|
|
226
|
+
[ path ],
|
|
227
|
+
{ onlyFiles: false, suppressErrors: true }
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
if ( sources.length > 0 ) {
|
|
231
|
+
session_vars._sources_path = path;
|
|
232
|
+
return true;
|
|
233
|
+
} else {
|
|
234
|
+
session_vars._sources_path = null;
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
session_vars.get_sources_path = function () {
|
|
240
|
+
/** Get the "sources" folder path. Should never be undefined during
|
|
241
|
+
* a run of the test. run_cucumber.js should make sure it has
|
|
242
|
+
* a default value.
|
|
243
|
+
*
|
|
244
|
+
* @returns str || null */
|
|
245
|
+
return session_vars._sources_path;
|
|
246
|
+
};
|
|
247
|
+
|
|
245
248
|
session_vars.validateEnvironment = function() {
|
|
246
249
|
/** Throw a useful error for the developer if any of the env vars
|
|
247
250
|
* required by absolutely all tests are missing. Gather all
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suffolklitlab/alkiln",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@suffolklitlab/alkiln",
|
|
9
|
-
"version": "5.
|
|
9
|
+
"version": "5.1.0",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@axe-core/puppeteer": "4.7.3",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"dotenv": "8.2.0",
|
|
20
20
|
"fast-glob": "3.2.12",
|
|
21
21
|
"minimatch": "3.0.5",
|
|
22
|
+
"minimist": "1.2.8",
|
|
22
23
|
"mocha": "9.2.2",
|
|
23
24
|
"puppeteer": "20.8.2",
|
|
24
25
|
"qs": "6.10.3",
|
|
@@ -1940,6 +1941,14 @@
|
|
|
1940
1941
|
"node": "*"
|
|
1941
1942
|
}
|
|
1942
1943
|
},
|
|
1944
|
+
"node_modules/minimist": {
|
|
1945
|
+
"version": "1.2.8",
|
|
1946
|
+
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
|
1947
|
+
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
|
1948
|
+
"funding": {
|
|
1949
|
+
"url": "https://github.com/sponsors/ljharb"
|
|
1950
|
+
}
|
|
1951
|
+
},
|
|
1943
1952
|
"node_modules/mitt": {
|
|
1944
1953
|
"version": "3.0.0",
|
|
1945
1954
|
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz",
|
|
@@ -4516,6 +4525,11 @@
|
|
|
4516
4525
|
"brace-expansion": "^1.1.7"
|
|
4517
4526
|
}
|
|
4518
4527
|
},
|
|
4528
|
+
"minimist": {
|
|
4529
|
+
"version": "1.2.8",
|
|
4530
|
+
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
|
4531
|
+
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="
|
|
4532
|
+
},
|
|
4519
4533
|
"mitt": {
|
|
4520
4534
|
"version": "3.0.0",
|
|
4521
4535
|
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suffolklitlab/alkiln",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.1.0-sources-1",
|
|
4
4
|
"description": "Integrated automated end-to-end testing with docassemble, puppeteer, and cucumber.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
"local": "npm run setup && npm run cucumber; npm run takedown",
|
|
10
10
|
"setup": "./lib/docassemble/setup.js",
|
|
11
11
|
"takedown": "./lib/docassemble/takedown.js",
|
|
12
|
-
"server_install": "./lib/docassemble/server_install.js",
|
|
13
12
|
"unit": "mocha tests/unit_tests/*.test.*"
|
|
14
13
|
},
|
|
15
14
|
"repository": {
|
|
@@ -41,6 +40,7 @@
|
|
|
41
40
|
"dotenv": "8.2.0",
|
|
42
41
|
"fast-glob": "3.2.12",
|
|
43
42
|
"minimatch": "3.0.5",
|
|
43
|
+
"minimist": "1.2.8",
|
|
44
44
|
"mocha": "9.2.2",
|
|
45
45
|
"puppeteer": "20.8.2",
|
|
46
46
|
"qs": "6.10.3",
|
|
@@ -48,7 +48,6 @@
|
|
|
48
48
|
"uuid": "8.3.2"
|
|
49
49
|
},
|
|
50
50
|
"bin": {
|
|
51
|
-
"alkiln-server-install": "./lib/docassemble/server_install.js",
|
|
52
51
|
"alkiln-setup": "./lib/docassemble/setup.js",
|
|
53
52
|
"alkiln-takedown": "./lib/docassemble/takedown.js",
|
|
54
53
|
"alkiln-run": "./lib/run_cucumber.js"
|
package/setup.py
CHANGED
|
@@ -50,10 +50,10 @@ setup(name='docassemble.ALKilnTests',
|
|
|
50
50
|
author='plocket',
|
|
51
51
|
author_email='example@example.com',
|
|
52
52
|
license='The MIT License (MIT)',
|
|
53
|
-
url='https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/
|
|
53
|
+
url='https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/automated_integrated_testing',
|
|
54
54
|
packages=find_packages(),
|
|
55
55
|
namespace_packages=['docassemble'],
|
|
56
|
-
install_requires=['docassemble.ALToolbox>=0.
|
|
56
|
+
install_requires=['docassemble.ALToolbox>=0.5.1'],
|
|
57
57
|
zip_safe=False,
|
|
58
58
|
package_data=find_package_data(where='docassemble/ALKilnTests/', package='docassemble.ALKilnTests'),
|
|
59
59
|
)
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
name: GitHub server tests
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
# why is workflow dispatch not showing up in github?
|
|
6
|
-
workflow_dispatch:
|
|
7
|
-
inputs:
|
|
8
|
-
tags:
|
|
9
|
-
required: False
|
|
10
|
-
description: 'Optional. Use a "tag expression" specify which tagged tests to run (https://cucumber.io/docs/cucumber/api/#tag-expressions)'
|
|
11
|
-
# # Only test 2 tests - one uses an env var, the other uses AL.
|
|
12
|
-
# # They test if env vars get set correctly and depencencies get
|
|
13
|
-
# # pulled in correctly.
|
|
14
|
-
# default: '@al1'
|
|
15
|
-
enable_tmate:
|
|
16
|
-
type: boolean
|
|
17
|
-
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
|
|
18
|
-
required: false
|
|
19
|
-
default: false
|
|
20
|
-
# TODO: alkiln_version:
|
|
21
|
-
|
|
22
|
-
jobs:
|
|
23
|
-
|
|
24
|
-
github-server-tests:
|
|
25
|
-
runs-on: ubuntu-latest
|
|
26
|
-
strategy:
|
|
27
|
-
matrix:
|
|
28
|
-
node-version: [18.x]
|
|
29
|
-
|
|
30
|
-
env:
|
|
31
|
-
# How would a dev make another user/password if they wanted to?
|
|
32
|
-
SECRET_VAR1: secret-var1-value
|
|
33
|
-
SECRET_VAR2: secret-var2-value
|
|
34
|
-
SECRET_FOR_MISSING_FIELD: secret for missing field
|
|
35
|
-
#_ALKILN_DANGEROUS_DEBUG: true
|
|
36
|
-
|
|
37
|
-
steps:
|
|
38
|
-
# Place the root directory in this branch
|
|
39
|
-
- uses: actions/checkout@v3
|
|
40
|
-
|
|
41
|
-
# Debugging. Maybe add a long sleep after whatever it is we want to check
|
|
42
|
-
# to give us time to explore.
|
|
43
|
-
- name: Setup tmate session
|
|
44
|
-
if: ${{ inputs.enable_tmate }}
|
|
45
|
-
uses: mxschmitt/action-tmate@v3
|
|
46
|
-
with:
|
|
47
|
-
detached: true
|
|
48
|
-
|
|
49
|
-
- name: Start the temporary GitHub server
|
|
50
|
-
id: github_server
|
|
51
|
-
uses: ./github_server
|
|
52
|
-
with:
|
|
53
|
-
CONFIG_CONTENTS: "${{ secrets.CONFIG_CONTENTS }}"
|
|
54
|
-
- run: echo "Finished starting the GitHub server"
|
|
55
|
-
|
|
56
|
-
# Debugging on failure
|
|
57
|
-
# Trying to catch that intermittent bug mentioned in ./github_server/action.yml
|
|
58
|
-
- name: Docker failure tmate session
|
|
59
|
-
if: ${{ failure() }}
|
|
60
|
-
uses: mxschmitt/action-tmate@v3
|
|
61
|
-
|
|
62
|
-
- name: Env vars from server output
|
|
63
|
-
run: |
|
|
64
|
-
echo "USER1_EMAIL=${{ steps.github_server.outputs.DA_ADMIN_EMAIL }}" >> $GITHUB_ENV
|
|
65
|
-
echo "USER1_PASSWORD=${{ steps.github_server.outputs.DA_ADMIN_PASSWORD }}" >> $GITHUB_ENV
|
|
66
|
-
#- name: Work with docker
|
|
67
|
-
# run: |
|
|
68
|
-
# # Authors can use this to do more with the docker container.
|
|
69
|
-
# # There may be a better way. Would take research. A docker action?
|
|
70
|
-
# container_name=$(docker ps --format '{{.Names}}' | head -n 1)
|
|
71
|
-
# echo "container_name is $container_name"
|
|
72
|
-
|
|
73
|
-
- name: "Run ALKiln tests"
|
|
74
|
-
if: ${{ success() }}
|
|
75
|
-
uses: ./
|
|
76
|
-
with:
|
|
77
|
-
SERVER_URL: "${{ steps.github_server.outputs.SERVER_URL }}"
|
|
78
|
-
DOCASSEMBLE_DEVELOPER_API_KEY: "${{ steps.github_server.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}"
|
|
79
|
-
INSTALL_METHOD: "server"
|
|
80
|
-
# TODO: See what happens if this is an empty string
|
|
81
|
-
ALKILN_VERSION: "5.0.2-feat-github-server-14"
|
|
82
|
-
- run: echo "Finished running ALKiln tests"
|
|
83
|
-
|
package/github_server/action.yml
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
name: "ALKiln/github_server: Isolated docassemble tests"
|
|
2
|
-
description: "Download and start up a temporary docassemble server on GitHub's servers, in an isolated environment. Avoids docassemble reload errors and other external factors."
|
|
3
|
-
|
|
4
|
-
# Bug? Race condition? Exit with 52 when waiting for container to finish starting
|
|
5
|
-
# https://github.com/SuffolkLITLab/ALKiln/actions/runs/5912900256/job/16036751264#step:4:188
|
|
6
|
-
# Had no completion messages, but it exited with an error anyway
|
|
7
|
-
# Took 121 seconds
|
|
8
|
-
# The rerun of the test completed that step just fine, though it took less time
|
|
9
|
-
# Took 120 and was fine: https://github.com/SuffolkLITLab/ALKiln/actions/runs/5913167036/job/16037288791
|
|
10
|
-
# 150 secs with exit code 56:
|
|
11
|
-
# https://github.com/SuffolkLITLab/ALKiln/actions/runs/5914677262/job/16040233419#step:4:196
|
|
12
|
-
# 120 sec with exit code 56:
|
|
13
|
-
# https://github.com/SuffolkLITLab/ALKiln/actions/runs/5914963614/job/16040773624#step:4:206
|
|
14
|
-
|
|
15
|
-
# If we want to control the version of the docassemble image, we'd have
|
|
16
|
-
# to make our own image:
|
|
17
|
-
# You can build your own image by doing git clone jhpyle/docassemble and then
|
|
18
|
-
# using git checkout to select a particular version, and then using docker build
|
|
19
|
-
# to build an image. https://docassemble.org/docs/docker.html#downgrading
|
|
20
|
-
# If we just want to use an older version of da (as long as it works with
|
|
21
|
-
# the latest image):
|
|
22
|
-
# If you have an existing container you can use dainstall from the command
|
|
23
|
-
# line to install docassemble.webapp==1.4.68
|
|
24
|
-
|
|
25
|
-
inputs:
|
|
26
|
-
CONFIG_CONTENTS:
|
|
27
|
-
description: "The contents of the config file of the docassemble server"
|
|
28
|
-
required: false
|
|
29
|
-
MAX_SECONDS_FOR_DOCKER:
|
|
30
|
-
description: "Maximum amount of seconds to give the docassemble docker container to serve the site."
|
|
31
|
-
required: false
|
|
32
|
-
default: 600 # 10 min
|
|
33
|
-
|
|
34
|
-
outputs:
|
|
35
|
-
DOCASSEMBLE_DEVELOPER_API_KEY:
|
|
36
|
-
description: "Use this inside `with:` for the ALKiln step. Temporary admin api key. It will be destroyed after the tests are done."
|
|
37
|
-
value: ${{ steps.api_key_output_step.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}
|
|
38
|
-
SERVER_URL:
|
|
39
|
-
description: "Use this inside `with:` for the ALKiln step. URL of the temporary docassemble server."
|
|
40
|
-
value: "http://localhost"
|
|
41
|
-
DA_ADMIN_EMAIL:
|
|
42
|
-
value: ${{ steps.api_key_output_step.outputs.DA_ADMIN_EMAIL }}
|
|
43
|
-
DA_ADMIN_PASSWORD:
|
|
44
|
-
value: ${{ steps.api_key_output_step.outputs.DA_ADMIN_PASSWORD }}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
runs:
|
|
48
|
-
using: "composite"
|
|
49
|
-
steps:
|
|
50
|
-
- uses: actions/checkout@v3
|
|
51
|
-
|
|
52
|
-
- name: "ALKiln github_server: Set environment variables"
|
|
53
|
-
run: |
|
|
54
|
-
echo "DA_ADMIN_API_KEY=abcd1234abcd1234abcd5678abdc5678" >> $GITHUB_ENV
|
|
55
|
-
echo "MAX_SECONDS_FOR_DOCKER=${{ inputs.MAX_SECONDS_FOR_DOCKER }}" >> $GITHUB_ENV
|
|
56
|
-
echo "DA_ADMIN_EMAIL=admin@example.com" >> $GITHUB_ENV
|
|
57
|
-
# Login will fail if this is "password"
|
|
58
|
-
echo "DA_ADMIN_PASSWORD=@123abcdefg" >> $GITHUB_ENV
|
|
59
|
-
shell: bash
|
|
60
|
-
- id: api_key_output_step
|
|
61
|
-
run: |
|
|
62
|
-
echo "DOCASSEMBLE_DEVELOPER_API_KEY=$DA_ADMIN_API_KEY" >> "$GITHUB_OUTPUT"
|
|
63
|
-
echo "DA_ADMIN_EMAIL=$DA_ADMIN_EMAIL" >> "$GITHUB_OUTPUT"
|
|
64
|
-
echo "DA_ADMIN_PASSWORD=$DA_ADMIN_PASSWORD" >> "$GITHUB_OUTPUT"
|
|
65
|
-
shell: bash
|
|
66
|
-
|
|
67
|
-
- name: "ALKiln github_server: Download and start docker"
|
|
68
|
-
run: |
|
|
69
|
-
mkdir /tmp/config
|
|
70
|
-
echo "${{ inputs.CONFIG_CONTENTS }}" > /tmp/config/myconfig.yml
|
|
71
|
-
docker pull jhpyle/docassemble
|
|
72
|
-
docker run --env DA_ADMIN_EMAIL="${{ env.DA_ADMIN_EMAIL }}" --env DA_ADMIN_PASSWORD="${{ env.DA_ADMIN_PASSWORD }}" --env DA_ADMIN_API_KEY="${{ env.DA_ADMIN_API_KEY }}" --env DA_CONFIG=/tmp/config/myconfig.yml --volume /tmp/config:/tmp/config --cap-add SYS_PTRACE --memory="4gb" -d -p 80:80 jhpyle/docassemble
|
|
73
|
-
shell: bash
|
|
74
|
-
- name: "ALKiln github_server: Wait for server to start"
|
|
75
|
-
run: |
|
|
76
|
-
# ALKiln github_server: Wait for server to start
|
|
77
|
-
|
|
78
|
-
# Reset the SECONDS variable
|
|
79
|
-
SECONDS=0
|
|
80
|
-
# Wait 1 minute before pinging the server constantly
|
|
81
|
-
sleep 60
|
|
82
|
-
|
|
83
|
-
# Use a variable instead of checking $response so we can control to avoid race
|
|
84
|
-
# conditions from preventing the success log message.
|
|
85
|
-
ready="false"
|
|
86
|
-
|
|
87
|
-
while [[ $ready == "false" ]]; do
|
|
88
|
-
echo "Time ellapsed: $SECONDS seconds"
|
|
89
|
-
|
|
90
|
-
# Check if max seconds till loading has passed
|
|
91
|
-
if [[ $SECONDS -ge $MAX_SECONDS_FOR_DOCKER ]]; then
|
|
92
|
-
echo "ALKiln GitHub Server Error: Timed out waiting for docker container to serve the site. If you want to give your docker container more timem to install, set the MAX_SECONDS_FOR_DOCKER input for this action."
|
|
93
|
-
# Exit with failure, or allow this to keep going?
|
|
94
|
-
break
|
|
95
|
-
fi
|
|
96
|
-
|
|
97
|
-
# Set the variable to a new string value in each iteration
|
|
98
|
-
response=$(curl -o /dev/null -s -w "%{http_code}\n" http://localhost:80/health_check?ready=1)
|
|
99
|
-
echo "response is $response"
|
|
100
|
-
|
|
101
|
-
# Check if the string includes the desired text
|
|
102
|
-
if [[ $response == *"200"* ]]; then
|
|
103
|
-
echo "Success! The docker container is ready!"
|
|
104
|
-
ready="true"
|
|
105
|
-
else
|
|
106
|
-
echo "The docker container isn't ready yet. Will check again in 30 seconds."
|
|
107
|
-
sleep 30
|
|
108
|
-
fi
|
|
109
|
-
|
|
110
|
-
done
|
|
111
|
-
shell: bash
|
|
112
|
-
|
|
113
|
-
# Don't rely on the environment's version of python
|
|
114
|
-
- uses: actions/setup-python@v4
|
|
115
|
-
with:
|
|
116
|
-
python-version: '3.10'
|
|
117
|
-
- run: pip install docassemblecli
|
|
118
|
-
shell: bash
|
|
119
|
-
# Install the current directory into docassemble
|
|
120
|
-
- run: dainstall . --apiurl http://localhost --apikey $DA_ADMIN_API_KEY
|
|
121
|
-
shell: bash
|
|
122
|
-
|
|
123
|
-
# Upload artifacts that subscribers can download on the Actions summary page
|
|
124
|
-
- name: "ALKiln github_server: Docker logs"
|
|
125
|
-
if: ${{ always() }}
|
|
126
|
-
run: |
|
|
127
|
-
docker_logs=$(docker logs $(docker ps --filter "ancestor=jhpyle/docassemble" --format {{.ID}}))
|
|
128
|
-
# Should this name have a date/time attached? The logs themselves have timestamps
|
|
129
|
-
echo "$docker_logs" > /tmp/alkiln_docker_logs.txt
|
|
130
|
-
shell: bash
|
|
131
|
-
|
|
132
|
-
# Should this date/time be created at the start of this action?
|
|
133
|
-
- name: "ALKiln github_server: Get folder name with date and time"
|
|
134
|
-
if: ${{ always() }}
|
|
135
|
-
run: |
|
|
136
|
-
echo "GITHUB_SERVER_ARTIFACT_NAME=alkiln-github-server-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC" >> $GITHUB_ENV
|
|
137
|
-
shell: bash
|
|
138
|
-
- name: "ALKiln github_server: Upload artifacts folder"
|
|
139
|
-
if: ${{ always() }}
|
|
140
|
-
uses: actions/upload-artifact@v3
|
|
141
|
-
with:
|
|
142
|
-
name: ${{ env.GITHUB_SERVER_ARTIFACT_NAME }}
|
|
143
|
-
path: /tmp/alkiln_docker_logs.txt
|