@suffolklitlab/alkiln 5.0.1 → 5.0.2-feat-github-server-2
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/.github/workflows/github_server.yml +61 -0
- package/CHANGELOG.md +4 -0
- package/action.yml +46 -25
- package/github_server/action.yml +83 -0
- package/lib/docassemble/docassemble_api_REST.js +26 -2
- package/lib/docassemble/docassemble_api_interface.js +35 -9
- package/lib/docassemble/get_base_interview_url.js +13 -3
- package/lib/docassemble/setup.js +1 -1
- package/lib/docassemble/startserver.js +69 -0
- package/lib/utils/session_vars.js +31 -0
- package/package.json +3 -1
- package/tmp.bash +7 -0
|
@@ -0,0 +1,61 @@
|
|
|
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: '@e6 or @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: true
|
|
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
|
+
USER1_EMAIL: admin@example.com
|
|
32
|
+
USER1_PASSWORD: password
|
|
33
|
+
SECRET_VAR1: secret-var1-value
|
|
34
|
+
SECRET_VAR2: secret-var2-value
|
|
35
|
+
SECRET_FOR_MISSING_FIELD: secret for missing field
|
|
36
|
+
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v3
|
|
39
|
+
- name: Setup tmate session
|
|
40
|
+
if: ${{ inputs.enable_tmate }}
|
|
41
|
+
uses: mxschmitt/action-tmate@v3
|
|
42
|
+
with:
|
|
43
|
+
detached: true
|
|
44
|
+
|
|
45
|
+
- name: Start the temporary GitHub server
|
|
46
|
+
id: github_server
|
|
47
|
+
uses: ./github_server
|
|
48
|
+
with:
|
|
49
|
+
CONFIG_CONTENTS: "${{ secrets.CONFIG_CONTENTS }}"
|
|
50
|
+
- run: echo "Finished starting the GitHub server"
|
|
51
|
+
|
|
52
|
+
- name: "Run ALKiln tests"
|
|
53
|
+
if: ${{ success() }}
|
|
54
|
+
uses: ./
|
|
55
|
+
with:
|
|
56
|
+
SERVER_URL: "${{ steps.github_server.outputs.SERVER_URL }}"
|
|
57
|
+
DOCASSEMBLE_DEVELOPER_API_KEY: "${{ steps.github_server.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}"
|
|
58
|
+
INSTALL_METHOD: "server"
|
|
59
|
+
ALKILN_VERSION: "5.0.2-feat-github-server-2"
|
|
60
|
+
- run: echo "Finished running ALKiln tests"
|
|
61
|
+
|
package/CHANGELOG.md
CHANGED
|
@@ -40,6 +40,10 @@ Format:
|
|
|
40
40
|
-->
|
|
41
41
|
<!-- ## [Unreleased] -->
|
|
42
42
|
|
|
43
|
+
## [5.0.2] - 2023-07-20
|
|
44
|
+
### Fixed
|
|
45
|
+
- Accept `SERVER_RELOAD_TIMEOUT_SECONDS` as an env var input in GitHub.
|
|
46
|
+
|
|
43
47
|
## [5.0.1] - 2023-07-18
|
|
44
48
|
### Changed
|
|
45
49
|
- Increment version of ALKiln that action.yml is using.
|
package/action.yml
CHANGED
|
@@ -5,15 +5,6 @@ inputs:
|
|
|
5
5
|
SERVER_URL:
|
|
6
6
|
description: 'The url of your docassemble server. This should be in your GitHub SECRETS or the SECRETS of your org.'
|
|
7
7
|
required: true
|
|
8
|
-
PLAYGROUND_EMAIL:
|
|
9
|
-
description: 'The email of your docassemble testing account. This should be in your GitHub SECRETS or the SECRETS of your org.'
|
|
10
|
-
required: true
|
|
11
|
-
PLAYGROUND_PASSWORD:
|
|
12
|
-
description: 'The password of your docassemble testing account. This should be in your GitHub SECRETS or the SECRETS of your org.'
|
|
13
|
-
required: true
|
|
14
|
-
PLAYGROUND_ID:
|
|
15
|
-
description: 'The id of your docassemble testing account. This should be in your GitHub SECRETS or the SECRETS of your org.'
|
|
16
|
-
required: true
|
|
17
8
|
DOCASSEMBLE_DEVELOPER_API_KEY:
|
|
18
9
|
description: 'API key of the testing account with developer permissions on your docassemble server.'
|
|
19
10
|
required: true
|
|
@@ -28,6 +19,16 @@ inputs:
|
|
|
28
19
|
description: "Amount of time to give the Project to upload your package's GitHub code."
|
|
29
20
|
required: false
|
|
30
21
|
default: '120'
|
|
22
|
+
SERVER_RELOAD_TIMEOUT_SECONDS:
|
|
23
|
+
description: "Max amount of time to give the server to reload if it needs to"
|
|
24
|
+
required: false
|
|
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 it 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"
|
|
31
32
|
|
|
32
33
|
runs:
|
|
33
34
|
using: "composite"
|
|
@@ -41,17 +42,15 @@ runs:
|
|
|
41
42
|
echo "REPO_URL=${{ github.server_url }}/${{ github.repository }}" >> $GITHUB_ENV
|
|
42
43
|
echo "BRANCH_PATH=${{ github.ref }}" >> $GITHUB_ENV
|
|
43
44
|
echo "BASE_URL=${{ inputs.SERVER_URL }}" >> $GITHUB_ENV
|
|
44
|
-
echo "PLAYGROUND_EMAIL=${{ inputs.PLAYGROUND_EMAIL }}" >> $GITHUB_ENV
|
|
45
|
-
echo "PLAYGROUND_PASSWORD=${{ inputs.PLAYGROUND_PASSWORD }}" >> $GITHUB_ENV
|
|
46
|
-
echo "PLAYGROUND_ID=${{ inputs.PLAYGROUND_ID }}" >> $GITHUB_ENV
|
|
47
45
|
echo "DOCASSEMBLE_DEVELOPER_API_KEY=${{ inputs.DOCASSEMBLE_DEVELOPER_API_KEY }}" >> $GITHUB_ENV
|
|
48
46
|
echo "ALKILN_VERSION=${{ inputs.ALKILN_VERSION }}" >> $GITHUB_ENV
|
|
49
47
|
echo "MAX_SECONDS_FOR_SETUP=${{ inputs.MAX_SECONDS_FOR_SETUP }}" >> $GITHUB_ENV
|
|
48
|
+
echo "SERVER_RELOAD_TIMEOUT_SECONDS=${{ inputs.SERVER_RELOAD_TIMEOUT_SECONDS }}" >> $GITHUB_ENV
|
|
50
49
|
echo "_ORIGIN=github" >> $GITHUB_ENV
|
|
51
50
|
shell: bash
|
|
52
51
|
- name: "ALKiln: confirm info"
|
|
53
52
|
run: |
|
|
54
|
-
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\n"
|
|
53
|
+
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"
|
|
55
54
|
shell: bash
|
|
56
55
|
|
|
57
56
|
# Install node
|
|
@@ -61,22 +60,44 @@ runs:
|
|
|
61
60
|
node-version: "18"
|
|
62
61
|
- name: Install ALKiln directly from npm
|
|
63
62
|
run: |
|
|
64
|
-
npm install -g @suffolklitlab/alkiln
|
|
63
|
+
npm install -g @suffolklitlab/alkiln@$ALKILN_VERSION
|
|
65
64
|
shell: bash
|
|
66
65
|
|
|
67
|
-
#
|
|
66
|
+
# Install on playground
|
|
68
67
|
- name: "ALKiln: Create a Project and pull the package from GitHub"
|
|
68
|
+
if: ${{ inputs.INSTALL_METHOD == 'playground' }}
|
|
69
69
|
run: alkiln-setup
|
|
70
70
|
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-startserver
|
|
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
|
+
## debugging
|
|
85
|
+
#- name: Setup tmate session
|
|
86
|
+
# uses: mxschmitt/action-tmate@v3
|
|
87
|
+
|
|
88
|
+
###########
|
|
89
|
+
#### !!! WARNING: RESTORE CODE FOR TAGS
|
|
90
|
+
###########
|
|
91
|
+
# run tests
|
|
71
92
|
- name: "ALKiln: Run tests"
|
|
72
93
|
if: ${{ success() }}
|
|
73
|
-
run: alkiln-run
|
|
94
|
+
run: alkiln-run @e6 or @al1
|
|
95
|
+
#run: alkiln-run ${{ github.event.inputs.tags && format('{0}', github.event.inputs.tags) }}
|
|
74
96
|
shell: bash
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if: ${{ always() }}
|
|
97
|
+
|
|
98
|
+
# on playground, delete project
|
|
99
|
+
- name: "ALKiln: Try to delete the project from the playground of the docassemble test account."
|
|
100
|
+
if: ${{ inputs.INSTALL_METHOD == 'playground' }}
|
|
80
101
|
run: alkiln-takedown
|
|
81
102
|
shell: bash
|
|
82
103
|
|
|
@@ -90,10 +111,10 @@ runs:
|
|
|
90
111
|
|
|
91
112
|
# ##################################
|
|
92
113
|
# # A developer's workflow should look similar to the below
|
|
93
|
-
# # In place of `uses: suffolkLITLab/ALKiln@
|
|
114
|
+
# # In place of `uses: suffolkLITLab/ALKiln@v5`, they
|
|
94
115
|
# # might use another version.
|
|
95
116
|
#
|
|
96
|
-
# name:
|
|
117
|
+
# name: ALKiln v5 tests
|
|
97
118
|
# on:
|
|
98
119
|
# push:
|
|
99
120
|
# workflow_dispatch:
|
|
@@ -108,9 +129,9 @@ runs:
|
|
|
108
129
|
# runs-on: ubuntu-latest
|
|
109
130
|
# name: Run interview tests
|
|
110
131
|
# steps:
|
|
111
|
-
# - uses: actions/checkout@
|
|
132
|
+
# - uses: actions/checkout@v3
|
|
112
133
|
# - name: Use ALKiln to run tests
|
|
113
|
-
# uses: suffolkLITLab/ALKiln@
|
|
134
|
+
# uses: suffolkLITLab/ALKiln@v5
|
|
114
135
|
# with:
|
|
115
136
|
# SERVER_URL: "${{ secrets.SERVER_URL }}"
|
|
116
137
|
# DOCASSEMBLE_DEVELOPER_API_KEY: "${{ secrets.DOCASSEMBLE_DEVELOPER_API_KEY }}"
|
|
@@ -0,0 +1,83 @@
|
|
|
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
|
+
|
|
5
|
+
inputs:
|
|
6
|
+
CONFIG_CONTENTS:
|
|
7
|
+
description: "The contents of the config file of the docassemble server"
|
|
8
|
+
required: false
|
|
9
|
+
MAX_SECONDS_FOR_DOCKER:
|
|
10
|
+
description: "Maximum amount of seconds to give the docassemble docker container to serve the site."
|
|
11
|
+
required: false
|
|
12
|
+
default: 600 # 10 min
|
|
13
|
+
|
|
14
|
+
outputs:
|
|
15
|
+
DOCASSEMBLE_DEVELOPER_API_KEY:
|
|
16
|
+
description: "Use this inside `with:` for the ALKiln step. Temporary admin api key. It will be destroyed after the tests are done."
|
|
17
|
+
value: ${{ steps.api_key_output_step.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}
|
|
18
|
+
SERVER_URL:
|
|
19
|
+
description: "Use this inside `with:` for the ALKiln step. URL of the temporary docassemble server."
|
|
20
|
+
value: "http://localhost"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
runs:
|
|
24
|
+
using: "composite"
|
|
25
|
+
steps:
|
|
26
|
+
- name: "github_server: Set environment variables"
|
|
27
|
+
run: |
|
|
28
|
+
echo "DA_ADMIN_API_KEY=abcd1234abcd1234abcd5678abdc5678" >> $GITHUB_ENV
|
|
29
|
+
shell: bash
|
|
30
|
+
- id: api_key_output_step
|
|
31
|
+
run: echo "::set-output name=DOCASSEMBLE_DEVELOPER_API_KEY::$DA_ADMIN_API_KEY"
|
|
32
|
+
shell: bash
|
|
33
|
+
- name: "github_server: Download and start docker"
|
|
34
|
+
run: |
|
|
35
|
+
mkdir /tmp/config
|
|
36
|
+
echo "${{ inputs.CONFIG_CONTENTS }}" > /tmp/config/myconfig.yml
|
|
37
|
+
docker pull jhpyle/docassemble
|
|
38
|
+
docker run --env DA_ADMIN_EMAIL="admin@example.com" --env DA_ADMIN_PASSWORD="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
|
|
39
|
+
shell: bash
|
|
40
|
+
- name: "github_server: Wait for server to start"
|
|
41
|
+
run: |
|
|
42
|
+
# github_server: Wait for server to start
|
|
43
|
+
|
|
44
|
+
# Wait 1 minute before pinging the server constantly
|
|
45
|
+
sleep 60
|
|
46
|
+
|
|
47
|
+
# Use a variable we can control to avoid race conditions from
|
|
48
|
+
# preventing the success log message.
|
|
49
|
+
ready="false"
|
|
50
|
+
# Reset the SECONDS variable
|
|
51
|
+
SECONDS=60
|
|
52
|
+
|
|
53
|
+
while [[ $ready == "false" ]]; do
|
|
54
|
+
echo "Time ellapsed: $SECONDS seconds"
|
|
55
|
+
|
|
56
|
+
# Get input for max number of seconds to wait
|
|
57
|
+
# ${{ inputs.MAX_SECONDS_FOR_DOCKER }} as a number? Bash doesn't have types, just strings
|
|
58
|
+
# Check if max seconds till loading has passed
|
|
59
|
+
if [[ $SECONDS -ge 600 ]]; then
|
|
60
|
+
echo "Error: Timed out waiting for docker container to serve the site."
|
|
61
|
+
break
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# Set the variable to a new string value in each iteration
|
|
65
|
+
result=$(curl -s localhost)
|
|
66
|
+
|
|
67
|
+
# Check if the string includes the desired text
|
|
68
|
+
if [[ ! $result == *"Docassemble is starting"* ]]; then
|
|
69
|
+
echo "Success! The docker container is ready!"
|
|
70
|
+
ready="true"
|
|
71
|
+
else
|
|
72
|
+
echo "The docker container isn't ready yet. Will check again in 30 seconds."
|
|
73
|
+
sleep 30
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
done
|
|
77
|
+
shell: bash
|
|
78
|
+
- name: Docker logs
|
|
79
|
+
if: ${{ always() }}
|
|
80
|
+
# TODO: create an arifact for this instead
|
|
81
|
+
run: |
|
|
82
|
+
docker logs $(docker ps --filter "ancestor=jhpyle/docassemble" --format {{.ID}})
|
|
83
|
+
shell: bash
|
|
@@ -54,6 +54,22 @@ da.create_project = async function ( project_name, timeout ) {
|
|
|
54
54
|
}
|
|
55
55
|
}; // Ends da.create_project()
|
|
56
56
|
|
|
57
|
+
da.install_on_server = async function ( github_repo, branch_name, timeout ) {
|
|
58
|
+
let options = {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
url: `${ session_vars.get_da_server_url() }/api/package`,
|
|
61
|
+
data: qs.stringify( {
|
|
62
|
+
key: session_vars.get_dev_api_key(),
|
|
63
|
+
github_url: github_repo,
|
|
64
|
+
branch: branch_name
|
|
65
|
+
}),
|
|
66
|
+
timeout: timeout,
|
|
67
|
+
};
|
|
68
|
+
console.log("%o", options);
|
|
69
|
+
|
|
70
|
+
return await axios.request(options);
|
|
71
|
+
};
|
|
72
|
+
|
|
57
73
|
|
|
58
74
|
// node -e 'require("./lib/docassemble/docassemble_api_REST.js").pull()'
|
|
59
75
|
da.pull = async function ( timeout ) {
|
|
@@ -79,13 +95,21 @@ da.pull = async function ( timeout ) {
|
|
|
79
95
|
}; // Ends da.pull()
|
|
80
96
|
|
|
81
97
|
|
|
98
|
+
da.has_playground_task_finished = async function ( task_id, timeout ) {
|
|
99
|
+
return await da.has_task_finished( "/api/restart_status", task_id, timeout);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
da.has_package_task_finished = async function ( task_id, timeout ) {
|
|
103
|
+
return await da.has_task_finished( "/api/package_update_status", task_id, timeout);
|
|
104
|
+
}
|
|
105
|
+
|
|
82
106
|
// node -e 'require("./lib/docassemble/docassemble_api_REST.js").has_task_finished()'
|
|
83
|
-
da.has_task_finished = async function ( task_id, timeout ) {
|
|
107
|
+
da.has_task_finished = async function ( api_endpoint, task_id, timeout ) {
|
|
84
108
|
/* Check task status based on `task_id`. */
|
|
85
109
|
let options = {
|
|
86
110
|
method: 'GET',
|
|
87
111
|
headers: {'X-API-Key': session_vars.get_dev_api_key()},
|
|
88
|
-
url: `${ session_vars.get_da_server_url() }
|
|
112
|
+
url: `${ session_vars.get_da_server_url() }${ api_endpoint }`,
|
|
89
113
|
params: {
|
|
90
114
|
task_id: task_id,
|
|
91
115
|
},
|
|
@@ -330,8 +330,28 @@ da_i.pull = async function ( pull_options ) {
|
|
|
330
330
|
}; // Ends da_i.pull()
|
|
331
331
|
|
|
332
332
|
|
|
333
|
+
da_i.install_on_server = async function ( install_options ) {
|
|
334
|
+
let { timeout } = install_options || { timeout: DEFAULT_MAX_REQUEST_MS };
|
|
335
|
+
|
|
336
|
+
try {
|
|
337
|
+
let response = await _da_REST.install_on_server(
|
|
338
|
+
session_vars.get_repo_url(),
|
|
339
|
+
session_vars.get_branch_name(),
|
|
340
|
+
timeout
|
|
341
|
+
);
|
|
342
|
+
if ( response && response.status === 200 ) {
|
|
343
|
+
log.debug({ pre: `install task id: ${ response.data.task_id }` });
|
|
344
|
+
return response.data.task_id;
|
|
345
|
+
}
|
|
346
|
+
return null;
|
|
347
|
+
} catch (error ) {
|
|
348
|
+
log.error({ pre: `Installing on the docassemble serve ran into an unexpected error.`, data: error.toJSON()});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
};
|
|
352
|
+
|
|
333
353
|
// node -e 'require("./lib/docassemble/docassemble_api_interface.js").has_task_finished()'
|
|
334
|
-
da_i.has_task_finished = async function ( task_id, options ) {
|
|
354
|
+
da_i.has_task_finished = async function ( api_endpoint, task_id, options ) {
|
|
335
355
|
/** Check task status if it exists. If not, return true as task did
|
|
336
356
|
* not require a server restart. See da_i.pull().
|
|
337
357
|
* See https://docassemble.org/docs/api.html#restart_status. */
|
|
@@ -342,7 +362,7 @@ da_i.has_task_finished = async function ( task_id, options ) {
|
|
|
342
362
|
try {
|
|
343
363
|
|
|
344
364
|
// If server did need to restart, check if it's done.
|
|
345
|
-
let response = await _da_REST.has_task_finished( task_id, timeout );
|
|
365
|
+
let response = await _da_REST.has_task_finished( api_endpoint, task_id, timeout );
|
|
346
366
|
log.debug({ pre: `Task status: ${ response.status }. Docassemble status text: ${ response.data.status }. Task id: ${ task_id }` });
|
|
347
367
|
|
|
348
368
|
if ( response.data.status === 'completed' ) {
|
|
@@ -353,16 +373,15 @@ da_i.has_task_finished = async function ( task_id, options ) {
|
|
|
353
373
|
return false;
|
|
354
374
|
|
|
355
375
|
} else if ( response.data.status === 'unknown' ) {
|
|
356
|
-
// Server is working, but status 'unknown'?
|
|
357
|
-
// get
|
|
358
|
-
// no default behavior. What to return? Throw?
|
|
376
|
+
// Server is working, but status 'unknown'? Bad design, but this
|
|
377
|
+
// does get returned when install packages, so return true
|
|
359
378
|
log.info({
|
|
360
379
|
pre: `\`task_id\` "${ task_id }" has expired. If it's been `
|
|
361
380
|
+ `less than 1 hour since the task started, the task is `
|
|
362
381
|
+ `complete. See https://docassemble.org/docs/api.html#restart_status.`,
|
|
363
|
-
data: response,
|
|
382
|
+
data: response.data,
|
|
364
383
|
});
|
|
365
|
-
return
|
|
384
|
+
return true;
|
|
366
385
|
} // ends status type
|
|
367
386
|
|
|
368
387
|
} catch ( error ) {
|
|
@@ -378,8 +397,15 @@ da_i.has_task_finished = async function ( task_id, options ) {
|
|
|
378
397
|
|
|
379
398
|
}; // Ends da_i.has_task_finished()
|
|
380
399
|
|
|
400
|
+
da_i.wait_for_playground_to_restart = async ( task_id, options ) => {
|
|
401
|
+
return await da_i.wait_for_server_to_restart( "/api/restart_status", task_id, options );
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
da_i.wait_for_package_to_restart = async ( task_id, options ) => {
|
|
405
|
+
return await da_i.wait_for_server_to_restart( "/api/package_update_status", task_id, options );
|
|
406
|
+
};
|
|
381
407
|
|
|
382
|
-
da_i.wait_for_server_to_restart = async ( task_id, options ) => {
|
|
408
|
+
da_i.wait_for_server_to_restart = async ( api_endpoint, task_id, options ) => {
|
|
383
409
|
/** Wait for the server to finish restarting in case a module needs to load.
|
|
384
410
|
* This is a polling function because things may be returned
|
|
385
411
|
* that aren't equivalent to the server being done with a task. */
|
|
@@ -410,7 +436,7 @@ da_i.wait_for_server_to_restart = async ( task_id, options ) => {
|
|
|
410
436
|
while ( !done_restarting && num_tries <= max_loops ) {
|
|
411
437
|
num_tries++;
|
|
412
438
|
// Wait only a short time for the task to finish, not the full default timeout
|
|
413
|
-
done_restarting = await da_i.has_task_finished( task_id, { timeout: wait_for_response } );
|
|
439
|
+
done_restarting = await da_i.has_task_finished( api_endpoint, task_id, { timeout: wait_for_response } );
|
|
414
440
|
if ( !done_restarting ) {
|
|
415
441
|
if ( num_tries < max_loops ) {
|
|
416
442
|
// Show a slightly different message after a number of tries to reassure
|
|
@@ -11,9 +11,19 @@ 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
|
-
|
|
14
|
+
console.log(session_vars.get_install_type());
|
|
15
|
+
if (session_vars.get_install_type() === "server") {
|
|
16
|
+
let x = `${ server_url }/interview?new_session=1&i=${session_vars.get_package_name().replace("-", ".")}%3Adata/questions/`;
|
|
17
|
+
// e.g. http://localhost/interview?new_session=1&i=ALKiln%3A
|
|
18
|
+
console.log(`base_interview_url: ${x}`)
|
|
19
|
+
return x;
|
|
20
|
+
} else {
|
|
21
|
+
let dev_id = await docassemble_api_interface.get_dev_id();
|
|
22
|
+
let project_name = session_vars.get_project_name();
|
|
23
|
+
let x = `${ server_url }/interview?new_session=1&i=docassemble.playground${ dev_id }${ project_name }%3A`;
|
|
24
|
+
console.log(`base_interview_url: ${x}`)
|
|
25
|
+
return x;
|
|
26
|
+
}
|
|
17
27
|
};
|
|
18
28
|
|
|
19
29
|
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_playground_to_restart( task_id );
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// Finish
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const puppeteer = require('puppeteer');
|
|
3
|
+
const da_i = require('./docassemble_api_interface');
|
|
4
|
+
const session_vars = require('../utils/session_vars');
|
|
5
|
+
|
|
6
|
+
const fs = require('fs')
|
|
7
|
+
|
|
8
|
+
const startserver = async () => {
|
|
9
|
+
// Open the browser, login with env var creds
|
|
10
|
+
/*
|
|
11
|
+
let browser = await puppeteer.launch({headless: !session_vars.get_debug()})
|
|
12
|
+
let page = await browser.newPage();
|
|
13
|
+
// Go to the sign in page
|
|
14
|
+
let login_url = `${ session_vars.get_da_server_url() }/user/sign-in`;
|
|
15
|
+
try {
|
|
16
|
+
// puppeteer will ensure proper timeout.
|
|
17
|
+
await page.goto( login_url, { waitUntil: `domcontentloaded`, timeout: 3000 });
|
|
18
|
+
await page.waitForSelector( `.dabody` );
|
|
19
|
+
} catch ( error ) {
|
|
20
|
+
let err_msg = `Error occurred when ALKiln tried to go to "${ login_url }: ${ error }".`
|
|
21
|
+
console.log(err_msg);
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let email = process.env[ "DA_ADMIN_API_KEY" ];
|
|
26
|
+
let password = process.env[ "USER_PASSWORD" ];
|
|
27
|
+
|
|
28
|
+
// Try to log in
|
|
29
|
+
await page.type( `#email`, email );
|
|
30
|
+
await page.type( `#password`, password );
|
|
31
|
+
let elem = await page.$( `button[name="submit"]` );
|
|
32
|
+
await elem.click();
|
|
33
|
+
await page.waitForNavigation({waitUntil: 'domcontentloaded'});
|
|
34
|
+
|
|
35
|
+
// Wait to see the success message.
|
|
36
|
+
// This is a bit of an assumption and needs success and failure testing
|
|
37
|
+
// TODO: use a Promise.race to fail faster.
|
|
38
|
+
await page.waitForSelector( `.datopcenter .alert-success` );
|
|
39
|
+
// make an API key
|
|
40
|
+
|
|
41
|
+
// TODO(brycew): with or without the API key?
|
|
42
|
+
// Install the package in order to also install all of its dependencies
|
|
43
|
+
let api_key_url = `${ session_vars.get_da_server_url() }/manage_api?action=new`;
|
|
44
|
+
await page.goto( api_key_url, { waitUntil: `domcontentloaded`, timeout: 3000 });
|
|
45
|
+
await page.type( `#name`, "ALKiln tmp key");
|
|
46
|
+
await page.select( `#method`, "none");
|
|
47
|
+
let winner = await Promise.all([page.click(`#submit`), page.waitForNavigation({waitUntil: 'domcontentloaded'})]);
|
|
48
|
+
console.log(`submitted`);
|
|
49
|
+
const api_text = await page.$eval('body p code', elem => elem.innerText);
|
|
50
|
+
process.env.DOCASSEMBLE_DEVELOPER_API_KEY = api_text;
|
|
51
|
+
console.log(`api key: ${api_text}`);
|
|
52
|
+
let file = fs.writeFileSync( ".tmpenv", `export DOCASSEMBLE_DEVELOPER_API_KEY=${api_text}`);
|
|
53
|
+
|
|
54
|
+
await page.goto(`${ session_vars.get_da_server_url() }/user/sign-out`, {waitUntil: `domcontentloaded`});
|
|
55
|
+
console.log(`signed out`);
|
|
56
|
+
await browser.close();
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
let task_id = await da_i.install_on_server();
|
|
60
|
+
if (task_id) {
|
|
61
|
+
console.log("Waiting...")
|
|
62
|
+
await da_i.wait_for_package_to_restart(task_id);
|
|
63
|
+
}
|
|
64
|
+
console.log("Done!")
|
|
65
|
+
session_vars.save_install_type("server");
|
|
66
|
+
|
|
67
|
+
}; // Ends startserver();
|
|
68
|
+
|
|
69
|
+
startserver();
|
|
@@ -115,6 +115,7 @@ session_vars.get_languages = function () {
|
|
|
115
115
|
|
|
116
116
|
const runtime_config_path = `runtime_config.json`;
|
|
117
117
|
const project_name_key = `da_project_name`;
|
|
118
|
+
const install_type_key = `da_install_type`;
|
|
118
119
|
session_vars.save_project_name = function ( project_name ) {
|
|
119
120
|
/* Saves the name of the project to a json obj so deletion can use it later.
|
|
120
121
|
* Built for local as well as remote testing. Assumes a kosher string.
|
|
@@ -197,6 +198,36 @@ session_vars.save_artifacts_path_name = function ( path_name ) {
|
|
|
197
198
|
return file;
|
|
198
199
|
}; // Ends save_artifacts_path_name()
|
|
199
200
|
|
|
201
|
+
|
|
202
|
+
session_vars.save_install_type = function (install_type) {
|
|
203
|
+
/* Save a key with the name of the current artifacts folder in case it doesn't exist. */
|
|
204
|
+
|
|
205
|
+
// Ensure artifacts path file exists
|
|
206
|
+
if ( !fs.existsSync( runtime_config_path ) ) {
|
|
207
|
+
// If the file doesn't exist, make one because next we need to read it
|
|
208
|
+
fs.writeFileSync( runtime_config_path, JSON.stringify( {}, null, 2 ) );
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Get the json, changing it, and re-write the file from scratch
|
|
212
|
+
let json = JSON.parse( fs.readFileSync( runtime_config_path ) );
|
|
213
|
+
json[ install_type_key ] = install_type;
|
|
214
|
+
let file = fs.writeFileSync( runtime_config_path, JSON.stringify( json, null, 2 ) );
|
|
215
|
+
|
|
216
|
+
return file;
|
|
217
|
+
}; // Ends save_artifacts_path_name()
|
|
218
|
+
|
|
219
|
+
session_vars.get_install_type = function () {
|
|
220
|
+
/* Get the name of the current artifacts path. */
|
|
221
|
+
try {
|
|
222
|
+
let json = JSON.parse( fs.readFileSync( runtime_config_path ));
|
|
223
|
+
let install_type = json[ install_type_key ];
|
|
224
|
+
|
|
225
|
+
return install_type;
|
|
226
|
+
} catch ( error ) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
}; // Ends get_artifacts_path_name()
|
|
230
|
+
|
|
200
231
|
session_vars.get_artifacts_path_name = function () {
|
|
201
232
|
/* Get the name of the current artifacts path. */
|
|
202
233
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suffolklitlab/alkiln",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2-feat-github-server-2",
|
|
4
4
|
"description": "Integrated automated end-to-end testing with docassemble, puppeteer, and cucumber.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -9,6 +9,7 @@
|
|
|
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
|
+
"startserver": "./lib/docassemble/startserver.js",
|
|
12
13
|
"unit": "mocha tests/unit_tests/*.test.*"
|
|
13
14
|
},
|
|
14
15
|
"repository": {
|
|
@@ -47,6 +48,7 @@
|
|
|
47
48
|
"uuid": "8.3.2"
|
|
48
49
|
},
|
|
49
50
|
"bin": {
|
|
51
|
+
"alkiln-startserver": "./lib/docassemble/startserver.js",
|
|
50
52
|
"alkiln-setup": "./lib/docassemble/setup.js",
|
|
51
53
|
"alkiln-takedown": "./lib/docassemble/takedown.js",
|
|
52
54
|
"alkiln-run": "./lib/run_cucumber.js"
|