@suffolklitlab/alkiln 5.5.0 → 5.7.0
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 +37 -14
- package/.github/workflows/playground.yml +56 -0
- package/.github/workflows/unit_tests.yml +35 -0
- package/CHANGELOG.md +18 -0
- package/action.yml +32 -14
- package/action_for_github_server/action.yml +124 -27
- package/lib/docassemble/docassemble_api_REST.js +3 -81
- package/lib/docassemble/docassemble_api_interface.js +3 -280
- package/lib/docassemble/server_install.js +2 -0
- package/lib/docassemble/setup.js +45 -35
- package/lib/steps.js +4 -0
- package/lib/utils/session_vars.js +1 -3
- package/package.json +1 -1
- package/.github/workflows/test_tests.yml +0 -73
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
name: GitHub server
|
|
1
|
+
name: GitHub server installation
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
|
+
# Default opened, reopened, synchronize. "edited" is something else.
|
|
6
|
+
pull_request_target:
|
|
5
7
|
workflow_dispatch:
|
|
6
8
|
inputs:
|
|
7
9
|
tags:
|
|
8
10
|
required: False
|
|
9
11
|
description: 'Optional. Use a "tag expression" specify which tagged tests to run (https://cucumber.io/docs/cucumber/api/#tag-expressions)'
|
|
12
|
+
show_docker_output:
|
|
13
|
+
required: false
|
|
14
|
+
default: false
|
|
15
|
+
type: boolean
|
|
16
|
+
description: 'Show the docker logs while building the GitHub server container. It will also save the docker log artifact. This might show sensitive config information.'
|
|
17
|
+
#### Developer note: You probably don't need this
|
|
10
18
|
enable_tmate:
|
|
11
19
|
type: boolean
|
|
12
20
|
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
|
|
@@ -27,27 +35,41 @@ jobs:
|
|
|
27
35
|
SECRET_FOR_MISSING_FIELD: secret for missing field
|
|
28
36
|
|
|
29
37
|
steps:
|
|
30
|
-
|
|
38
|
+
#### Developer note: You probably don't need this
|
|
39
|
+
# Place the root directory in this branch to access
|
|
40
|
+
# relative paths to action files
|
|
31
41
|
- uses: actions/checkout@v3
|
|
32
42
|
|
|
33
|
-
- name:
|
|
43
|
+
- name: ALKiln - Start the isolated temporary docassemble server on GitHub
|
|
34
44
|
id: github_server
|
|
45
|
+
#### Developer note: you'll need to replace `.` with the path to
|
|
46
|
+
#### the repo and branch. For example:
|
|
47
|
+
#### suffolkLITLab/ALKiln@v5/action_for_github_server
|
|
35
48
|
uses: ./action_for_github_server
|
|
36
49
|
with:
|
|
37
50
|
CONFIG_CONTENTS: "${{ secrets.CONFIG_CONTENTS }}"
|
|
51
|
+
#### Developer note: Set this to True to show docker logs and
|
|
52
|
+
#### allow ALKiln to create the docker logs output artifact.
|
|
53
|
+
SHOW_DOCKER_OUTPUT: "${{ github.event.inputs.show_docker_output }}"
|
|
38
54
|
- run: echo "ALKiln finished starting the isolated GitHub docassemble server"
|
|
55
|
+
shell: bash
|
|
39
56
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
57
|
+
#### Developer note: You probably don't need this
|
|
58
|
+
# Optional debugging to explore things like config issues
|
|
59
|
+
- name: Docker debug tmate session
|
|
60
|
+
if: ${{ github.event.inputs.enable_tmate }}
|
|
43
61
|
uses: mxschmitt/action-tmate@v3
|
|
44
62
|
|
|
45
|
-
|
|
63
|
+
#### Developer note: You probably don't need this
|
|
64
|
+
- name: Run ALKiln - Env vars for our own tests from server output
|
|
46
65
|
run: |
|
|
47
66
|
echo "USER1_EMAIL=${{ steps.github_server.outputs.DA_ADMIN_EMAIL }}" >> $GITHUB_ENV
|
|
48
67
|
echo "USER1_PASSWORD=${{ steps.github_server.outputs.DA_ADMIN_PASSWORD }}" >> $GITHUB_ENV
|
|
49
|
-
|
|
50
|
-
|
|
68
|
+
|
|
69
|
+
#### Developer note:
|
|
70
|
+
#### Example of working with the docker container after it's been
|
|
71
|
+
#### started. For example, you can make more users with different
|
|
72
|
+
#### permissions and passwords
|
|
51
73
|
#- name: Work with docker
|
|
52
74
|
# run: |
|
|
53
75
|
# container_name=$(docker ps --format '{{.Names}}' | head -n 1)
|
|
@@ -55,14 +77,15 @@ jobs:
|
|
|
55
77
|
|
|
56
78
|
- name: "Run ALKiln tests"
|
|
57
79
|
if: ${{ success() }}
|
|
80
|
+
#### Developer note: you'll need to replace `.` with the path to
|
|
81
|
+
#### the repo and branch and leave off the trailing `/`
|
|
82
|
+
#### For example suffolkLITLab/ALKiln@v5
|
|
58
83
|
uses: ./
|
|
59
84
|
with:
|
|
60
85
|
SERVER_URL: "${{ steps.github_server.outputs.SERVER_URL }}"
|
|
61
86
|
DOCASSEMBLE_DEVELOPER_API_KEY: "${{ steps.github_server.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}"
|
|
62
87
|
INSTALL_METHOD: "server"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
#
|
|
66
|
-
ALKILN_TAG_EXPRESSION: ""
|
|
67
|
-
- run: echo "ALkiln finished running ALKiln tests"
|
|
88
|
+
#### Developer note: Useful for temporarily shortening ALKiln tests
|
|
89
|
+
#### to debug the docker install step
|
|
90
|
+
# ALKILN_TAG_EXPRESSION: @a_tag_expression
|
|
68
91
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: Playground installation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
# Default: opened, reopened, synchronize. "edited" is not what we want.
|
|
6
|
+
pull_request_target:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
tags:
|
|
10
|
+
required: False
|
|
11
|
+
description: 'Optional. Use a "tag expression" specify which tagged tests to run (https://cucumber.io/docs/cucumber/api/#tag-expressions)'
|
|
12
|
+
default: ''
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
|
|
16
|
+
puppeteer-tests:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
|
|
19
|
+
strategy:
|
|
20
|
+
matrix:
|
|
21
|
+
node-version: [18.x]
|
|
22
|
+
|
|
23
|
+
env:
|
|
24
|
+
#### Developer note: Required
|
|
25
|
+
SERVER_URL: ${{ secrets.SERVER_URL }}
|
|
26
|
+
DOCASSEMBLE_DEVELOPER_API_KEY: ${{ secrets.DOCASSEMBLE_DEVELOPER_API_KEY }}
|
|
27
|
+
#### Developer note: you don't need any of these
|
|
28
|
+
# Specific to our repo's tests
|
|
29
|
+
PLAYGROUND_EMAIL: ${{ secrets.PLAYGROUND_EMAIL }}
|
|
30
|
+
PLAYGROUND_PASSWORD: ${{ secrets.PLAYGROUND_PASSWORD }}
|
|
31
|
+
PLAYGROUND_ID: ${{ secrets.PLAYGROUND_ID }}
|
|
32
|
+
USER1_EMAIL: ${{ secrets.USER1_EMAIL }}
|
|
33
|
+
USER1_PASSWORD: ${{ secrets.USER1_PASSWORD }}
|
|
34
|
+
SECRET_VAR1: secret-var1-value
|
|
35
|
+
SECRET_VAR2: secret-var2-value
|
|
36
|
+
SECRET_FOR_MISSING_FIELD: secret for missing field
|
|
37
|
+
# Internal
|
|
38
|
+
_ORIGIN: github
|
|
39
|
+
|
|
40
|
+
name: Run ALKiln tests
|
|
41
|
+
steps:
|
|
42
|
+
#### Developer note: You probably don't need this
|
|
43
|
+
# Place the root directory in this branch to access
|
|
44
|
+
# relative paths to action files
|
|
45
|
+
- uses: actions/checkout@v3
|
|
46
|
+
|
|
47
|
+
#### Developer note: you'll need to replace `.` with the path to
|
|
48
|
+
#### the repo and branch and leave off the trailing `/`
|
|
49
|
+
#### For example suffolkLITLab/ALKiln@v5
|
|
50
|
+
- uses: ./
|
|
51
|
+
with:
|
|
52
|
+
SERVER_URL: "${{ env.SERVER_URL }}"
|
|
53
|
+
DOCASSEMBLE_DEVELOPER_API_KEY: "${{ env.DOCASSEMBLE_DEVELOPER_API_KEY }}"
|
|
54
|
+
#### Developer note: Useful for temporarily shortening ALKiln tests
|
|
55
|
+
#### to debug the docker install step
|
|
56
|
+
# ALKILN_TAG_EXPRESSION: @a_tag_expression
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Unit tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
|
|
9
|
+
unit-tests:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
node-version: [18.x]
|
|
15
|
+
|
|
16
|
+
name: Run unit tests
|
|
17
|
+
steps:
|
|
18
|
+
- name: Set name of artifact folder with date and UTC time
|
|
19
|
+
# https://www.shell-tips.com/linux/how-to-format-date-and-time-in-linux-macos-and-bash/#how-to-format-a-date-in-bash
|
|
20
|
+
run: |
|
|
21
|
+
echo "UNIT_TESTS_ARTIFACT_NAME=_alkiln-misc-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC" >> $GITHUB_ENV
|
|
22
|
+
- uses: actions/checkout@v3
|
|
23
|
+
- uses: actions/setup-node@v3
|
|
24
|
+
with:
|
|
25
|
+
node-version: ${{ matrix.node-version }}
|
|
26
|
+
- run: npm install
|
|
27
|
+
- run: npm run unit
|
|
28
|
+
# Artifacts
|
|
29
|
+
- name: upload unit tests artifacts folder
|
|
30
|
+
uses: actions/upload-artifact@v3
|
|
31
|
+
# This will upload even if a previous step has failed
|
|
32
|
+
if: ${{ always() }}
|
|
33
|
+
with:
|
|
34
|
+
name: ${{ env.UNIT_TESTS_ARTIFACT_NAME }}
|
|
35
|
+
path: ./_alkiln-*
|
package/CHANGELOG.md
CHANGED
|
@@ -45,6 +45,24 @@ Format:
|
|
|
45
45
|
|
|
46
46
|
<!-- ## [Unreleased] -->
|
|
47
47
|
|
|
48
|
+
## [5.7.0] - 2023-11-14
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
- Allow tests to run when a PR is made by switching to docassemblecli's `dainstall` to upload packagese to the Playground. See [#760](https://github.com/SuffolkLITLab/ALKiln/issues/760).
|
|
52
|
+
|
|
53
|
+
### Internal
|
|
54
|
+
- Workflows:
|
|
55
|
+
- Split unit tests into their own file. They have to use `npm install` in our repo and we don't want to use that for Playground tests. It avoids trying to push all the node modules to the Playground which would otherwise cause error 413 "too large".
|
|
56
|
+
- Use our own action in the tests that install on the Playground, to avoid duplicating edits to the action - see [#822](https://github.com/SuffolkLITLab/ALKiln/issues/822).
|
|
57
|
+
- Rename files
|
|
58
|
+
- Also see [#822](https://github.com/SuffolkLITLab/ALKiln/issues/822)
|
|
59
|
+
|
|
60
|
+
## [5.6.0] - 2023-10-27
|
|
61
|
+
|
|
62
|
+
### Changed
|
|
63
|
+
|
|
64
|
+
- For isolated GitHub server, only show GitHub action console logs when `SHOW_DOCKER_LOGS` input is set to `true`. Same for creating the docker logs GitHub artifact. See [#819](https://github.com/SuffolkLITLab/ALKiln/issues/819).
|
|
65
|
+
|
|
48
66
|
## [5.5.0] - 2023-10-27
|
|
49
67
|
|
|
50
68
|
### Added
|
package/action.yml
CHANGED
|
@@ -35,11 +35,15 @@ inputs:
|
|
|
35
35
|
runs:
|
|
36
36
|
using: "composite"
|
|
37
37
|
steps:
|
|
38
|
+
# Place the root directory in this branch
|
|
39
|
+
- uses: actions/checkout@v3
|
|
40
|
+
|
|
38
41
|
# Set environment variables
|
|
39
|
-
- name: "ALKiln: Set environment variables"
|
|
42
|
+
- name: "ALKiln setup info: Set environment variables"
|
|
40
43
|
# Human-readable date/time:
|
|
41
44
|
# https://www.shell-tips.com/linux/how-to-format-date-and-time-in-linux-macos-and-bash/#how-to-format-a-date-in-bash
|
|
42
45
|
run: |
|
|
46
|
+
# ALKiln setup info: Set environment variables
|
|
43
47
|
echo "ARTIFACT_NAME=alkiln-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC" >> $GITHUB_ENV
|
|
44
48
|
echo "REPO_URL=${{ github.server_url }}/${{ github.repository }}" >> $GITHUB_ENV
|
|
45
49
|
echo "BRANCH_PATH=${{ github.ref }}" >> $GITHUB_ENV
|
|
@@ -50,59 +54,75 @@ runs:
|
|
|
50
54
|
echo "SERVER_RELOAD_TIMEOUT_SECONDS=${{ inputs.SERVER_RELOAD_TIMEOUT_SECONDS }}" >> $GITHUB_ENV
|
|
51
55
|
echo "_ORIGIN=github" >> $GITHUB_ENV
|
|
52
56
|
shell: bash
|
|
53
|
-
- name: "ALKiln: confirm
|
|
57
|
+
- name: "ALKiln setup info: confirm environment variables"
|
|
54
58
|
run: |
|
|
59
|
+
# ALKiln setup info: confirm environment variables
|
|
55
60
|
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"
|
|
56
61
|
shell: bash
|
|
57
62
|
|
|
58
63
|
# Install
|
|
59
|
-
- name: "ALKiln: Install node packages"
|
|
64
|
+
- name: "ALKiln setup info: Install node packages"
|
|
60
65
|
uses: actions/setup-node@v3
|
|
61
66
|
with:
|
|
62
67
|
node-version: "18"
|
|
63
68
|
- name: Install ALKiln directly from npm
|
|
64
69
|
run: |
|
|
70
|
+
# ALKiln setup info: Install ALKiln directly from npm
|
|
65
71
|
npm install -g @suffolklitlab/alkiln@$ALKILN_VERSION
|
|
66
72
|
shell: bash
|
|
67
73
|
|
|
68
74
|
# Install on playground
|
|
69
|
-
|
|
75
|
+
|
|
76
|
+
# Don't rely on the environment's version of python
|
|
77
|
+
- uses: actions/setup-python@v4
|
|
78
|
+
if: ${{ inputs.INSTALL_METHOD == 'playground' }}
|
|
79
|
+
with:
|
|
80
|
+
python-version: '3.10'
|
|
81
|
+
- name: "ALKiln: Create a Project and install the package from GitHub"
|
|
70
82
|
if: ${{ inputs.INSTALL_METHOD == 'playground' }}
|
|
71
|
-
run:
|
|
83
|
+
run: |
|
|
84
|
+
# ALKiln setup info: Create a Project and install the package from GitHub
|
|
85
|
+
pip3 install docassemblecli
|
|
86
|
+
alkiln-setup
|
|
72
87
|
shell: bash
|
|
73
|
-
-
|
|
88
|
+
- name: "ALKiln setup ERROR"
|
|
89
|
+
run: echo -e "\n\n====\nALKiln ERROR - 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"
|
|
74
90
|
if: ${{ inputs.INSTALL_METHOD == 'playground' && failure() }}
|
|
75
91
|
shell: bash
|
|
76
92
|
|
|
77
|
-
#
|
|
78
|
-
- name: "ALKiln: Install the GitHub package onto the server"
|
|
93
|
+
# Server installations - find folders and save session vars
|
|
94
|
+
- name: "ALKiln setup info: Install the GitHub package onto the server"
|
|
79
95
|
if: ${{ inputs.INSTALL_METHOD == 'server' }}
|
|
80
96
|
run: alkiln-server-install
|
|
81
97
|
shell: bash
|
|
82
|
-
-
|
|
98
|
+
- name: "ALKiln setup ERROR"
|
|
99
|
+
run: echo -e "\n\n====\nALKiln ERROR - could not install the package on the temporary GitHub docassemble server. Check the steps above this line.\n\n"
|
|
83
100
|
if: ${{ inputs.INSTALL_METHOD == 'server' && failure() }}
|
|
84
101
|
shell: bash
|
|
85
102
|
|
|
86
103
|
# run tests
|
|
87
|
-
- name: "ALKiln: Run tests"
|
|
104
|
+
- name: "ALKiln info: Run tests"
|
|
88
105
|
if: ${{ success() }}
|
|
89
106
|
run: alkiln-run ${{ inputs.ALKILN_TAG_EXPRESSION || github.event.inputs.tags && format('{0}', github.event.inputs.tags) }}
|
|
90
107
|
shell: bash
|
|
91
108
|
|
|
92
109
|
# on playground, delete project
|
|
93
|
-
- name: "ALKiln: Try to delete the project from the playground of the docassemble test account."
|
|
110
|
+
- name: "ALKiln info: Try to delete the project from the playground of the docassemble test account."
|
|
94
111
|
if: ${{ inputs.INSTALL_METHOD == 'playground' }}
|
|
95
112
|
run: alkiln-takedown
|
|
96
113
|
shell: bash
|
|
97
114
|
|
|
98
115
|
# Upload artifacts that subscribers can download on the Actions summary page
|
|
99
|
-
- name: "ALKiln: Upload artifacts folder"
|
|
116
|
+
- name: "ALKiln info: Upload artifacts folder"
|
|
100
117
|
if: ${{ always() }}
|
|
101
118
|
uses: actions/upload-artifact@v3
|
|
102
119
|
with:
|
|
103
120
|
name: ${{ env.ARTIFACT_NAME }}
|
|
104
121
|
path: ./alkiln-*
|
|
105
122
|
|
|
123
|
+
- run: echo "ALkiln finished running tests"
|
|
124
|
+
shell: bash
|
|
125
|
+
|
|
106
126
|
# ##################################
|
|
107
127
|
# # A developer's workflow should look similar to the below.
|
|
108
128
|
# # In place of `uses: suffolkLITLab/ALKiln@v5`, they
|
|
@@ -123,10 +143,8 @@ runs:
|
|
|
123
143
|
# runs-on: ubuntu-latest
|
|
124
144
|
# name: Run interview tests
|
|
125
145
|
# steps:
|
|
126
|
-
# - uses: actions/checkout@v3
|
|
127
146
|
# - name: Use ALKiln to run tests
|
|
128
147
|
# uses: suffolkLITLab/ALKiln@v5
|
|
129
148
|
# with:
|
|
130
149
|
# SERVER_URL: "${{ secrets.SERVER_URL }}"
|
|
131
150
|
# DOCASSEMBLE_DEVELOPER_API_KEY: "${{ secrets.DOCASSEMBLE_DEVELOPER_API_KEY }}"
|
|
132
|
-
# - run: echo "Finished running ALKiln tests"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
name: "ALKiln
|
|
1
|
+
name: "ALKiln isolated GitHub docassemble server tests"
|
|
2
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
3
|
|
|
4
4
|
# If we want to control the version of the docassemble image, we'd have
|
|
@@ -13,19 +13,23 @@ description: "Download and start up a temporary docassemble server on GitHub's s
|
|
|
13
13
|
|
|
14
14
|
inputs:
|
|
15
15
|
CONFIG_CONTENTS:
|
|
16
|
-
description: "The contents of the config file of the docassemble server"
|
|
16
|
+
description: "The contents of the config file of the docassemble server."
|
|
17
|
+
required: false
|
|
18
|
+
SHOW_DOCKER_OUTPUT:
|
|
19
|
+
description: 'Default is "false" to prevent docker from showing output in GitHub, like logs and artifacts. When set to "true", this will give you the docker output. It will be visible to those who can see the output, like people with admin or write permissions.'
|
|
20
|
+
default: false
|
|
17
21
|
required: false
|
|
18
22
|
MAX_SECONDS_FOR_DOCKER:
|
|
19
|
-
description: "Maximum amount of seconds to give the docassemble docker container to serve the site."
|
|
23
|
+
description: "Default is 600 seconds. Maximum amount of seconds to give the docassemble docker container to serve the site."
|
|
20
24
|
required: false
|
|
21
25
|
default: 600 # 10 min
|
|
22
26
|
|
|
23
27
|
outputs:
|
|
24
28
|
DOCASSEMBLE_DEVELOPER_API_KEY:
|
|
25
|
-
description:
|
|
29
|
+
description: 'Use this inside "with:" for the ALKiln step. Temporary admin api key. It will be destroyed after the tests are done.'
|
|
26
30
|
value: ${{ steps.api_key_output_step.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}
|
|
27
31
|
SERVER_URL:
|
|
28
|
-
description:
|
|
32
|
+
description: 'Use this inside "with:" for the ALKiln step. URL of the temporary docassemble server.'
|
|
29
33
|
value: "http://localhost"
|
|
30
34
|
DA_ADMIN_EMAIL:
|
|
31
35
|
value: ${{ steps.api_key_output_step.outputs.DA_ADMIN_EMAIL }}
|
|
@@ -36,9 +40,10 @@ outputs:
|
|
|
36
40
|
runs:
|
|
37
41
|
using: "composite"
|
|
38
42
|
steps:
|
|
43
|
+
# Place the root directory in this branch
|
|
39
44
|
- uses: actions/checkout@v3
|
|
40
45
|
|
|
41
|
-
- name: "ALKiln
|
|
46
|
+
- name: "ALKiln GitHub server - Set environment variables"
|
|
42
47
|
run: |
|
|
43
48
|
echo "DA_ADMIN_API_KEY=abcd1234abcd1234abcd5678abdc5678" >> $GITHUB_ENV
|
|
44
49
|
echo "MAX_SECONDS_FOR_DOCKER=${{ inputs.MAX_SECONDS_FOR_DOCKER }}" >> $GITHUB_ENV
|
|
@@ -53,20 +58,72 @@ runs:
|
|
|
53
58
|
echo "DA_ADMIN_PASSWORD=$DA_ADMIN_PASSWORD" >> "$GITHUB_OUTPUT"
|
|
54
59
|
shell: bash
|
|
55
60
|
|
|
56
|
-
- name: "ALKiln
|
|
61
|
+
- name: "ALKiln GitHub server - Get config"
|
|
57
62
|
run: |
|
|
63
|
+
# ALKiln GitHub server info: config values
|
|
58
64
|
mkdir /tmp/config
|
|
65
|
+
# Worth making this silent by defining a variable with > /dev/null...?
|
|
59
66
|
if [ -n "${{ inputs.CONFIG_CONTENTS }}" ]
|
|
60
67
|
then
|
|
61
|
-
echo "ALKiln
|
|
68
|
+
echo "ALKiln GitHub server - The developer did provide a custom docassemble config file as an input into this action."
|
|
62
69
|
echo "${{ inputs.CONFIG_CONTENTS }}" > /tmp/config/myconfig.yml
|
|
63
70
|
echo "CONFIG_ARGS=--env DA_CONFIG=/tmp/config/myconfig.yml --volume /tmp/config:/tmp/config " >> $GITHUB_ENV
|
|
64
71
|
else
|
|
65
|
-
echo "ALKiln
|
|
72
|
+
echo "ALKiln GitHub server - The developer did NOT provide a custom docassemble config file as an input into this action. Docassemble will use its default config."
|
|
66
73
|
echo "CONFIG_ARGS=" >> $GITHUB_ENV
|
|
67
74
|
fi
|
|
68
75
|
shell: bash
|
|
69
|
-
|
|
76
|
+
|
|
77
|
+
# GitHub masks secret values like the config, so we don't really
|
|
78
|
+
# need to stop that yet, but users may start using variables, so
|
|
79
|
+
# a question: If in future we allow variables instead of just secrets,
|
|
80
|
+
# should we let those be visible or prevent them along with the docker logs?
|
|
81
|
+
|
|
82
|
+
# Also, does this leave GitHub job environment output While just
|
|
83
|
+
# hiding the output from the job console?
|
|
84
|
+
|
|
85
|
+
# Define the var to prevent/show docker output
|
|
86
|
+
- name: Env var for showing docker output
|
|
87
|
+
run: |
|
|
88
|
+
# ALKiln GitHub server info: Docker logs visibility decision
|
|
89
|
+
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
|
90
|
+
echo "OUTPUT_DOCKER=${{ inputs.SHOW_DOCKER_OUTPUT }}" >> $GITHUB_ENV
|
|
91
|
+
else
|
|
92
|
+
echo "OUTPUT_DOCKER=false" >> $GITHUB_ENV
|
|
93
|
+
fi
|
|
94
|
+
shell: bash
|
|
95
|
+
|
|
96
|
+
# Messages about output
|
|
97
|
+
- if: ${{ env.OUTPUT_DOCKER == 'false' }}
|
|
98
|
+
run: |
|
|
99
|
+
# ALKiln GitHub server info: no output
|
|
100
|
+
printf '===\nALKiln GitHub server - GitHub will now stop showing output to avoid possibly showing details about your config. If you want to get output to see more of what is going on, use "with:" and set the input "SHOW_DOCKER_OUTPUT" to "true". This output will only be visible to those who can already see the action output, like people with admin or write permissions.\n==='
|
|
101
|
+
shell: bash
|
|
102
|
+
- if: ${{ env.OUTPUT_DOCKER == 'true' }}
|
|
103
|
+
run: |
|
|
104
|
+
# ALKiln GitHub server info: show output
|
|
105
|
+
printf '===\nALKiln GitHub server - GitHub will now show the output of docker creation. ALKiln cannot control this output. If you want to prevent output, use "with:" and set the input "SHOW_DOCKER_OUTPUT" to "false". This output will only be visible to those who can already see the action output, like people with admin or write permissions.\n==='
|
|
106
|
+
shell: bash
|
|
107
|
+
|
|
108
|
+
# No output
|
|
109
|
+
- name: "ALKiln GitHub server - Download and start docker silently"
|
|
110
|
+
if: ${{ env.OUTPUT_DOCKER == 'false' }}
|
|
111
|
+
run: |
|
|
112
|
+
# ALKiln GitHub server info: Silent docker pull/run
|
|
113
|
+
docker pull jhpyle/docassemble > /dev/null 2>&1
|
|
114
|
+
docker run --name docassemble_container \
|
|
115
|
+
--env DA_ADMIN_EMAIL="${{ env.DA_ADMIN_EMAIL }}" \
|
|
116
|
+
--env DA_ADMIN_PASSWORD="${{ env.DA_ADMIN_PASSWORD }}" \
|
|
117
|
+
--env DA_ADMIN_API_KEY="${{ env.DA_ADMIN_API_KEY }}" \
|
|
118
|
+
${{ env.CONFIG_ARGS }} \
|
|
119
|
+
--cap-add SYS_PTRACE \
|
|
120
|
+
--memory="4gb" -d -p 80:80 jhpyle/docassemble > /dev/null 2>&1
|
|
121
|
+
shell: bash
|
|
122
|
+
# With output
|
|
123
|
+
- name: "ALKiln GitHub server - Download and start docker"
|
|
124
|
+
if: ${{ env.OUTPUT_DOCKER == 'true' }}
|
|
125
|
+
run: |
|
|
126
|
+
# ALKiln GitHub server info: Docker pull/run
|
|
70
127
|
docker pull jhpyle/docassemble
|
|
71
128
|
docker run --name docassemble_container \
|
|
72
129
|
--env DA_ADMIN_EMAIL="${{ env.DA_ADMIN_EMAIL }}" \
|
|
@@ -76,9 +133,17 @@ runs:
|
|
|
76
133
|
--cap-add SYS_PTRACE \
|
|
77
134
|
--memory="4gb" -d -p 80:80 jhpyle/docassemble
|
|
78
135
|
shell: bash
|
|
79
|
-
|
|
136
|
+
|
|
137
|
+
# Show the time it takes to start the server.
|
|
138
|
+
- if: ${{ env.OUTPUT_DOCKER == 'false' }}
|
|
139
|
+
run: |
|
|
140
|
+
# ALKiln GitHub server info: temporary visible logs
|
|
141
|
+
echo "ALKiln GitHub server - ALKiln will show safe ALKiln-only output temporarily as ALKiln waits for the server to start"
|
|
142
|
+
shell: bash
|
|
143
|
+
|
|
144
|
+
- name: "ALKiln GitHub server - Wait for server to start"
|
|
80
145
|
run: |
|
|
81
|
-
# ALKiln
|
|
146
|
+
# ALKiln GitHub server - Wait for server to start
|
|
82
147
|
|
|
83
148
|
# Reset the SECONDS variable
|
|
84
149
|
SECONDS=0
|
|
@@ -86,56 +151,88 @@ runs:
|
|
|
86
151
|
sleep 60
|
|
87
152
|
|
|
88
153
|
response="start"
|
|
89
|
-
|
|
90
154
|
while [[ $response != *"200"* ]]; do
|
|
91
|
-
echo "ALKiln
|
|
155
|
+
echo "ALKiln GitHub server - Time elapsed: $SECONDS seconds"
|
|
92
156
|
|
|
93
157
|
# Check if max seconds till loading has passed
|
|
94
158
|
if [[ $SECONDS -ge $MAX_SECONDS_FOR_DOCKER ]]; then
|
|
95
|
-
echo "ALKiln
|
|
159
|
+
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."
|
|
96
160
|
exit 1
|
|
97
161
|
fi
|
|
98
162
|
|
|
99
163
|
# Set the variable to a new string value in each iteration
|
|
100
164
|
response=$(curl -o /dev/null -s -w "%{http_code}\n" http://localhost:80/health_check?ready=1)
|
|
101
|
-
echo "ALKiln
|
|
165
|
+
echo "ALKiln GitHub server - response is $response"
|
|
102
166
|
|
|
103
167
|
# Check if the string includes the desired text
|
|
104
168
|
if [[ $response == *"200"* ]]; then
|
|
105
|
-
echo "ALKiln
|
|
169
|
+
echo "ALKiln GitHub server - Success! The docker container is ready!"
|
|
106
170
|
else
|
|
107
|
-
echo "ALKiln
|
|
171
|
+
echo "ALKiln GitHub server - The docker container is not ready yet. Will check again in 30 seconds."
|
|
108
172
|
sleep 30
|
|
109
173
|
fi
|
|
110
174
|
|
|
111
175
|
done
|
|
112
176
|
shell: bash
|
|
113
177
|
|
|
178
|
+
# Output visibility message
|
|
179
|
+
- name: Message about docassemble install output
|
|
180
|
+
if: ${{ env.OUTPUT_DOCKER == 'false' }}
|
|
181
|
+
run: |
|
|
182
|
+
# ALKiln GitHub server info: Silent install message
|
|
183
|
+
echo "ALKiln GitHub server - ALKiln will now prevent output again"
|
|
184
|
+
shell: bash
|
|
185
|
+
|
|
114
186
|
# Don't rely on the environment's version of python
|
|
115
187
|
- uses: actions/setup-python@v4
|
|
116
188
|
with:
|
|
117
189
|
python-version: '3.10'
|
|
190
|
+
# No output
|
|
191
|
+
- run: pip install docassemblecli > /dev/null 2>&1
|
|
192
|
+
if: ${{ env.OUTPUT_DOCKER == 'false' }}
|
|
193
|
+
shell: bash
|
|
194
|
+
# Install the package, the current directory (.), onto the docassemble server
|
|
195
|
+
- run: dainstall . --apiurl http://localhost --apikey $DA_ADMIN_API_KEY > /dev/null 2>&1
|
|
196
|
+
if: ${{ env.OUTPUT_DOCKER == 'false' }}
|
|
197
|
+
shell: bash
|
|
198
|
+
|
|
199
|
+
# With output
|
|
118
200
|
- run: pip install docassemblecli
|
|
201
|
+
if: ${{ env.OUTPUT_DOCKER == 'true' }}
|
|
119
202
|
shell: bash
|
|
120
|
-
# Install the current directory onto the docassemble server
|
|
203
|
+
# Install the package, the current directory (.), onto the docassemble server
|
|
121
204
|
- run: dainstall . --apiurl http://localhost --apikey $DA_ADMIN_API_KEY
|
|
205
|
+
if: ${{ env.OUTPUT_DOCKER == 'true' }}
|
|
122
206
|
shell: bash
|
|
123
207
|
|
|
124
|
-
# Upload artifacts that
|
|
125
|
-
|
|
126
|
-
|
|
208
|
+
# Upload artifacts that devs can download on the Actions summary page
|
|
209
|
+
# Only if the developer wants to get that info, though
|
|
210
|
+
- name: "ALKiln GitHub server - Get path names with date and time"
|
|
211
|
+
if: ${{ always() && env.OUTPUT_DOCKER == 'true' }}
|
|
127
212
|
run: |
|
|
128
213
|
echo "GITHUB_SERVER_LOG_FILE_NAME=/tmp/alkiln_docker_logs-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC.txt" >> $GITHUB_ENV
|
|
129
214
|
echo "GITHUB_SERVER_ARTIFACT_NAME=alkiln_github_server-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC" >> $GITHUB_ENV
|
|
130
215
|
shell: bash
|
|
131
|
-
- name: "ALKiln
|
|
132
|
-
if: ${{ always() }}
|
|
216
|
+
- name: "ALKiln GitHub server - Docker output"
|
|
217
|
+
if: ${{ always() && env.OUTPUT_DOCKER == 'true' }}
|
|
133
218
|
run: |
|
|
134
|
-
echo "$(docker
|
|
219
|
+
echo "$(docker output docassemble_container)" > "${{ env.GITHUB_SERVER_LOG_FILE_NAME }}"
|
|
135
220
|
shell: bash
|
|
136
|
-
- name: "ALKiln
|
|
137
|
-
if: ${{ always() }}
|
|
221
|
+
- name: "ALKiln GitHub server - Upload artifacts folder"
|
|
222
|
+
if: ${{ always() && env.OUTPUT_DOCKER == 'true' }}
|
|
138
223
|
uses: actions/upload-artifact@v3
|
|
139
224
|
with:
|
|
140
225
|
name: ${{ env.GITHUB_SERVER_ARTIFACT_NAME }}
|
|
141
226
|
path: ${{ env.GITHUB_SERVER_LOG_FILE_NAME }}
|
|
227
|
+
|
|
228
|
+
- run: |
|
|
229
|
+
# ALKiln GitHub server info: End silent output
|
|
230
|
+
echo "ALKiln GitHub server - ALKiln will show output again"
|
|
231
|
+
if: ${{ always() && env.OUTPUT_DOCKER == 'false' }}
|
|
232
|
+
shell: bash
|
|
233
|
+
|
|
234
|
+
- run: |
|
|
235
|
+
# ALKiln GitHub server info: Done
|
|
236
|
+
echo "ALKiln GitHub server - ALKiln will show output again"
|
|
237
|
+
if: ${{ always() && env.OUTPUT_DOCKER == 'false' }}
|
|
238
|
+
shell: bash
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
const axios = require('axios');
|
|
2
|
-
const qs = require('qs');
|
|
3
2
|
|
|
3
|
+
// Ours
|
|
4
4
|
const session_vars = require('../utils/session_vars' );
|
|
5
5
|
|
|
6
6
|
/* Requests to make to the developer's docassemble server.
|
|
7
7
|
* As close to plain requests as we can get so we don't have
|
|
8
8
|
* to think about this file again.
|
|
9
|
-
|
|
10
|
-
* - We are not using `.create()` because we want to get
|
|
11
|
-
* the environment variables fresh every time. */
|
|
9
|
+
*/
|
|
12
10
|
|
|
13
11
|
let da = {};
|
|
14
12
|
module.exports = da;
|
|
@@ -33,82 +31,6 @@ da.get_dev_id = async function ( timeout ) {
|
|
|
33
31
|
}; // Ends da.get_dev_id()
|
|
34
32
|
|
|
35
33
|
|
|
36
|
-
// node -e 'require("./lib/docassemble/docassemble_api_REST.js").create_project( "create1" )'
|
|
37
|
-
da.create_project = async function ( project_name, timeout ) {
|
|
38
|
-
/* Create a new project on the user's da server. */
|
|
39
|
-
let options = {
|
|
40
|
-
method: 'POST',
|
|
41
|
-
headers: {'X-API-Key': session_vars.get_dev_api_key()},
|
|
42
|
-
url: `${ session_vars.get_da_server_url() }/api/playground/project`,
|
|
43
|
-
data: qs.stringify({
|
|
44
|
-
project: project_name,
|
|
45
|
-
}),
|
|
46
|
-
timeout: timeout,
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
return await axios.request( options );
|
|
51
|
-
} catch (error) {
|
|
52
|
-
let response = error.response || {data: null}
|
|
53
|
-
throw {...error.toJSON(), data: response.data};
|
|
54
|
-
}
|
|
55
|
-
}; // Ends da.create_project()
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// node -e 'require("./lib/docassemble/docassemble_api_REST.js").pull()'
|
|
59
|
-
da.pull = async function ( timeout ) {
|
|
60
|
-
/* Pull github code into an existing Project. */
|
|
61
|
-
let options = {
|
|
62
|
-
method: 'POST',
|
|
63
|
-
headers: {'X-API-Key': session_vars.get_dev_api_key()},
|
|
64
|
-
url: `${ session_vars.get_da_server_url() }/api/playground_pull`,
|
|
65
|
-
data: qs.stringify({
|
|
66
|
-
project: session_vars.get_project_name(),
|
|
67
|
-
github_url: session_vars.get_repo_url(),
|
|
68
|
-
branch: session_vars.get_branch_name(),
|
|
69
|
-
}),
|
|
70
|
-
timeout: timeout,
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
try {
|
|
74
|
-
return await axios.request( options );
|
|
75
|
-
} catch (error) {
|
|
76
|
-
let response = error.response || {data: null}
|
|
77
|
-
throw {...error.toJSON(), data: response.data};
|
|
78
|
-
}
|
|
79
|
-
}; // Ends da.pull()
|
|
80
|
-
|
|
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
|
-
// node -e 'require("./lib/docassemble/docassemble_api_REST.js").has_task_finished()'
|
|
91
|
-
da.has_task_finished = async function ( api_endpoint, task_id, timeout ) {
|
|
92
|
-
/* Check task status based on `task_id`. */
|
|
93
|
-
let options = {
|
|
94
|
-
method: 'GET',
|
|
95
|
-
headers: {'X-API-Key': session_vars.get_dev_api_key()},
|
|
96
|
-
url: `${ session_vars.get_da_server_url() }${ api_endpoint }`,
|
|
97
|
-
params: {
|
|
98
|
-
task_id: task_id,
|
|
99
|
-
},
|
|
100
|
-
timeout: timeout,
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
return await axios.request( options );
|
|
105
|
-
} catch (error) {
|
|
106
|
-
let response = error.response || {data: null}
|
|
107
|
-
throw {...error.toJSON(), data: response.data};
|
|
108
|
-
}
|
|
109
|
-
}; // Ends da.has_task_finished()
|
|
110
|
-
|
|
111
|
-
|
|
112
34
|
// node -e 'require("./lib/docassemble/docassemble_api_REST.js").delete_project( "create1" )'
|
|
113
35
|
da.delete_project = async function ( timeout ) {
|
|
114
36
|
/* Delete a project on the user's da server. */
|
|
@@ -160,4 +82,4 @@ da.__delete_projects_starting_with = async function ( base_name, starting_num=1,
|
|
|
160
82
|
}
|
|
161
83
|
name_incrementor++;
|
|
162
84
|
}
|
|
163
|
-
}; // Ends
|
|
85
|
+
}; // Ends da.__delete_projects_starting_with()
|
|
@@ -12,7 +12,7 @@ const time = require('../utils/time');
|
|
|
12
12
|
// do it before trying to load a page.
|
|
13
13
|
|
|
14
14
|
// TODO: How can we test busy server stuff properly? Especially down
|
|
15
|
-
// to specific functions,
|
|
15
|
+
// to specific functions, which can run in a very small
|
|
16
16
|
// window.
|
|
17
17
|
|
|
18
18
|
/** Notes:
|
|
@@ -171,287 +171,10 @@ da_i.get_dev_id = async function ( dev_id_options ) {
|
|
|
171
171
|
return dev_id;
|
|
172
172
|
}; // Ends da_i.get_dev_id();
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
// node -e 'require("./lib/docassemble/docassemble_api_interface.js").validate_api_key()'
|
|
176
|
-
da_i.validate_api_key = async function ( api_key_options ) {
|
|
177
|
-
/** Make sure the api key is the right one for this server.
|
|
178
|
-
* See https://docassemble.org/docs/api.html#user. */
|
|
179
|
-
|
|
180
|
-
log.info({ pre: `Checking the testing account's API key.` });
|
|
181
|
-
|
|
182
|
-
// Default timeouts
|
|
183
|
-
api_key_options = api_key_options || { timeout: DEFAULT_MAX_REQUEST_MS };
|
|
184
|
-
|
|
185
|
-
try {
|
|
186
|
-
|
|
187
|
-
// There's only one possible success result
|
|
188
|
-
// As long as this succeeds, we're good
|
|
189
|
-
await _da_REST.get_dev_id( api_key_options.timeout );
|
|
190
|
-
log.info({ pre: `Your testing account's API key is perfectly valid on this server.` });
|
|
191
|
-
return true;
|
|
192
|
-
|
|
193
|
-
} catch ( error ) {
|
|
194
|
-
// There's only one possible sever response error
|
|
195
|
-
if ( error.response && error.response.status === 403 ) {
|
|
196
|
-
// Throw in here, or at the caller?
|
|
197
|
-
log.error({
|
|
198
|
-
pre: `The API key in the GitHub secret DOCASSEMBLE_DEVELOPER_API_KEY `
|
|
199
|
-
+ `failed on this server with "Access Denied". Are you sure your `
|
|
200
|
-
+ `DOCASSEMBLE_DEVELOPER_API_KEY secret is set to the API key for `
|
|
201
|
-
+ `the docassemble account that runs the tests on this server? `
|
|
202
|
-
+ `Are you sure your SERVER_URL GitHub secret is set to the server `
|
|
203
|
-
+ `address on which this testing account exists?`
|
|
204
|
-
+ `To update your GitHub secrets, either set this repository's `
|
|
205
|
-
+ `secrets at ${ session_vars.get_repo_url() }/settings/secrets `
|
|
206
|
-
+ `or ask your GitHub organization admin to set the `
|
|
207
|
-
+ `organization's secrets.`
|
|
208
|
-
});
|
|
209
|
-
} // ends 403 message
|
|
210
|
-
throw error;
|
|
211
|
-
} // ends try to get dev_id
|
|
212
|
-
}; // Ends da_i.validate_api_key()
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
// node -e 'require("./lib/docassemble/docassemble_api_interface.js").loop_to_create_project()'
|
|
216
|
-
da_i.loop_to_create_project = async function( creation_options ) {
|
|
217
|
-
/** Create a docassemble Project on the docassemble server's account.
|
|
218
|
-
* Loop through potential project names until we find one that
|
|
219
|
-
* isn't already taken and then use that name to create the Project. */
|
|
220
|
-
|
|
221
|
-
// Defaults
|
|
222
|
-
creation_options = creation_options || {};
|
|
223
|
-
let timeout = creation_options.timeout || DEFAULT_MAX_REQUEST_MS;
|
|
224
|
-
let max_tries = creation_options.max_tries || 15;
|
|
225
|
-
let wait_seconds = creation_options.wait_seconds || 5;
|
|
226
|
-
|
|
227
|
-
let project_name = null;
|
|
228
|
-
// Unlikely, but 2 devs could run locally and create the same Project name
|
|
229
|
-
let num_tries = 0;
|
|
230
|
-
|
|
231
|
-
// Try to create a project. If the project name is already taken, increment and loop again.
|
|
232
|
-
while ( num_tries <= max_tries ) {
|
|
233
|
-
num_tries++;
|
|
234
|
-
try {
|
|
235
|
-
|
|
236
|
-
// Try next name that could be unique. Must remove all non-valid characters
|
|
237
|
-
// TODO: This sanitization is already done in session_vars, so remove it from here
|
|
238
|
-
project_name = session_vars.get_project_base_name().replace(/[^A-Za-z0-9]/g, '') + `${Date.now()}`;
|
|
239
|
-
log.info({ pre: `Trying to create a docassemble Project with the name ${ project_name }` });
|
|
240
|
-
let response = await _da_REST.create_project( project_name, timeout );
|
|
241
|
-
log.info({ pre: `The docassemble server is ready. Created a Project named ${ project_name }` });
|
|
242
|
-
// If succeeded in creating project, return the name that worked
|
|
243
|
-
return project_name;
|
|
244
|
-
|
|
245
|
-
} catch ( error ) {
|
|
246
|
-
// TODO: Make a `normalize_ajax_responses_and_errors()`?
|
|
247
|
-
let response = error;
|
|
248
|
-
|
|
249
|
-
if ( response && response.data ) {
|
|
250
|
-
if ( response.data.includes( `Invalid project` ) ) {
|
|
251
|
-
if ( num_tries < max_tries ) {
|
|
252
|
-
// A non-unique project name. Try the next project name.
|
|
253
|
-
continue;
|
|
254
|
-
|
|
255
|
-
} else {
|
|
256
|
-
// On the last loop, failed because there were too many project
|
|
257
|
-
// names already taken
|
|
258
|
-
log.error({
|
|
259
|
-
pre: `There were already ${ max_tries } projects with the base `
|
|
260
|
-
+ `name ${ session_vars.get_project_base_name() }. If you need to allow `
|
|
261
|
-
+ `more, file an issue at https://github.com/SuffolkLITLab/ALKiln/issues.`
|
|
262
|
-
});
|
|
263
|
-
throw( error );
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// ends "Invalid project" error
|
|
267
|
-
} else {
|
|
268
|
-
// Other response errors should be thrown with link to docs
|
|
269
|
-
log.error({
|
|
270
|
-
type: `docassemble ${ response.status } "${ response.data }"`,
|
|
271
|
-
pre: `See https://docassemble.org/docs/api.html#playground_post_project.`
|
|
272
|
-
});
|
|
273
|
-
throw ( error );
|
|
274
|
-
}
|
|
275
|
-
} else { // for if error.response
|
|
276
|
-
|
|
277
|
-
// If it's a timeout error, server is busy. Try again after waiting.
|
|
278
|
-
// Why are we using `max_tries` for timeout error as well?
|
|
279
|
-
if ( is_timeout_error( error ) && num_tries < max_tries ) {
|
|
280
|
-
log.info({ pre: `The docassemble server was busy when we tried to `
|
|
281
|
-
+ `create the Project. Attempt ${ num_tries } of `
|
|
282
|
-
+ `${ max_tries }. Will try again in ${ wait_seconds } seconds.` });
|
|
283
|
-
num_tries--; // Don't count this try
|
|
284
|
-
await time.waitForTimeout( wait_seconds * 1000 );
|
|
285
|
-
continue;
|
|
286
|
-
|
|
287
|
-
// A non-timeout, non-server error should just be thrown
|
|
288
|
-
} else {
|
|
289
|
-
log.error({ pre: `Ran into unexpected error when trying to create the Project.` });
|
|
290
|
-
throw error;
|
|
291
|
-
|
|
292
|
-
} // ends type of non-response error
|
|
293
|
-
} // ends type of response error
|
|
294
|
-
} // ends try
|
|
295
|
-
} // ends while
|
|
296
|
-
}; // Ends da_i.loop_to_create_project()
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
// node -e 'require("./lib/docassemble/docassemble_api_interface.js").pull()'
|
|
300
|
-
da_i.pull = async function ( pull_options ) {
|
|
301
|
-
/** Pull github code into an existing Project. */
|
|
302
|
-
|
|
303
|
-
log.info({ pre: `Trying to pull code from the "${ session_vars.get_branch_name() }" branch.` });
|
|
304
|
-
|
|
305
|
-
// Default timeouts
|
|
306
|
-
let { timeout } = pull_options || { timeout: DEFAULT_MAX_REQUEST_MS };
|
|
307
|
-
|
|
308
|
-
try {
|
|
309
|
-
|
|
310
|
-
let response = await _da_REST.pull( timeout );
|
|
311
|
-
|
|
312
|
-
// If server didn't need to restart
|
|
313
|
-
if ( response && response.status === 204 ) {
|
|
314
|
-
log.info({ pre: `Your Docassemble server finished pulling the package's code.` });
|
|
315
|
-
return null;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// If server needed to restart because of the pulled code
|
|
319
|
-
if ( response && response.status === 200 ) {
|
|
320
|
-
log.debug({ pre: `Pull task id: ${ response.data.task_id }` });
|
|
321
|
-
return response.data.task_id;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
} catch ( error ) {
|
|
325
|
-
// Pulling should not error
|
|
326
|
-
log.error({ pre: `Pulling into the docassemble Project ran into an unexpected error.` });
|
|
327
|
-
log.debug({ pre: `See https://docassemble.org/docs/api.html#playground_pull.` });
|
|
328
|
-
throw error;
|
|
329
|
-
}
|
|
330
|
-
}; // Ends da_i.pull()
|
|
331
|
-
|
|
332
|
-
// node -e 'require("./lib/docassemble/docassemble_api_interface.js").has_task_finished()'
|
|
333
|
-
da_i.has_task_finished = async function ( api_endpoint, task_id, options ) {
|
|
334
|
-
/** Check task status if it exists. If not, return true as task did
|
|
335
|
-
* not require a server restart. See da_i.pull().
|
|
336
|
-
* See https://docassemble.org/docs/api.html#restart_status. */
|
|
337
|
-
|
|
338
|
-
// Defaults
|
|
339
|
-
let { timeout } = options || { timeout: DEFAULT_MAX_REQUEST_MS };
|
|
340
|
-
|
|
341
|
-
try {
|
|
342
|
-
|
|
343
|
-
// If server did need to restart, check if it's done.
|
|
344
|
-
let response = await _da_REST.has_task_finished( api_endpoint, task_id, timeout );
|
|
345
|
-
log.debug({ pre: `Task status: ${ response.status }. Docassemble status text: ${ response.data.status }. Task id: ${ task_id }` });
|
|
346
|
-
|
|
347
|
-
if ( response.data.status === 'completed' ) {
|
|
348
|
-
return true;
|
|
349
|
-
|
|
350
|
-
} else if ( response.data.status === 'working' ) {
|
|
351
|
-
log.info({ pre: `The docassemble server is uploading the package.` });
|
|
352
|
-
return false;
|
|
353
|
-
|
|
354
|
-
} else if ( response.data.status === 'unknown' ) {
|
|
355
|
-
// Server is working, but status 'unknown'? Bad design, but this
|
|
356
|
-
// does get returned when install packages, so return true
|
|
357
|
-
log.info({
|
|
358
|
-
pre: `\`task_id\` "${ task_id }" has expired. If it's been `
|
|
359
|
-
+ `less than 1 hour since the task started, the task is `
|
|
360
|
-
+ `complete. See https://docassemble.org/docs/api.html#restart_status.`,
|
|
361
|
-
data: response.data,
|
|
362
|
-
});
|
|
363
|
-
return true;
|
|
364
|
-
} // ends status type
|
|
365
|
-
|
|
366
|
-
} catch ( error ) {
|
|
367
|
-
// Timeout means the server is busy.
|
|
368
|
-
if ( is_timeout_error( error ) ) {
|
|
369
|
-
log.info({ pre: `The docassemble server is still uploading the package.` });
|
|
370
|
-
return false;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
log.error({ pre: `Tried to check that the package was uploaded, but ran into an unexpected error.` });
|
|
374
|
-
throw error;
|
|
375
|
-
} // ends try to check for server done restarting
|
|
376
|
-
|
|
377
|
-
}; // Ends da_i.has_task_finished()
|
|
378
|
-
|
|
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
|
-
|
|
387
|
-
da_i.wait_for_server_to_restart = async ( api_endpoint, task_id, options ) => {
|
|
388
|
-
/** Wait for the server to finish restarting in case a module needs to load.
|
|
389
|
-
* This is a polling function because things may be returned
|
|
390
|
-
* that aren't equivalent to the server being done with a task. */
|
|
391
|
-
log.info({ pre: `Docassemble is pulling this package. The task_id is `
|
|
392
|
-
+ `"${ task_id }". A task_id is usually created for a package `
|
|
393
|
-
+ `with a module. It can take a few minutes to finish uploading.` });
|
|
394
|
-
|
|
395
|
-
// Base default
|
|
396
|
-
options = options || {};
|
|
397
|
-
// Default timeout
|
|
398
|
-
let timeout = options.timeout || DEFAULT_MAX_REQUEST_MS;
|
|
399
|
-
// Other defaults
|
|
400
|
-
let default_wait_between_loops = 4 * 1000;
|
|
401
|
-
let default_wait_for_response = 1 * 1000;
|
|
402
|
-
let default_max_loops = timeout/( default_wait_between_loops + default_wait_for_response );
|
|
403
|
-
// Actual values
|
|
404
|
-
let wait_between_loops = options.wait_between_loops || default_wait_between_loops;
|
|
405
|
-
let wait_for_response = options.wait_for_response || default_wait_for_response;
|
|
406
|
-
let max_loops = options.max_loops || default_max_loops;
|
|
407
|
-
|
|
408
|
-
// Flags for stopping the `while` loop
|
|
409
|
-
let num_tries = 0;
|
|
410
|
-
let done_restarting = false;
|
|
411
|
-
|
|
412
|
-
// Why loop instead of one long timeout? Because it might not just hang.
|
|
413
|
-
// We might get a return value that's just `waiting`, meaning the
|
|
414
|
-
// task is not done.
|
|
415
|
-
while ( !done_restarting && num_tries <= max_loops ) {
|
|
416
|
-
num_tries++;
|
|
417
|
-
// Wait only a short time for the task to finish, not the full default timeout
|
|
418
|
-
done_restarting = await da_i.has_task_finished( api_endpoint, task_id, { timeout: wait_for_response } );
|
|
419
|
-
if ( !done_restarting ) {
|
|
420
|
-
if ( num_tries < max_loops ) {
|
|
421
|
-
// Show a slightly different message after a number of tries to reassure
|
|
422
|
-
// users we're still paying attention
|
|
423
|
-
let msg_start = `Not yet complete`;
|
|
424
|
-
if ( num_tries > 3 ) { msg_start = `Still not complete`; }
|
|
425
|
-
|
|
426
|
-
// When the server is busy, the task timeout causes this loop to actually
|
|
427
|
-
// take 5 seconds to complete, but this only waits for 4. I'm not sure how
|
|
428
|
-
// to make that clear
|
|
429
|
-
log.info({ pre: `${ msg_start }. Check ${ num_tries } of ${ max_loops }. `
|
|
430
|
-
+ `Will check again in ${( wait_between_loops + wait_for_response )/1000 } seconds.`
|
|
431
|
-
});
|
|
432
|
-
await time.waitForTimeout( wait_between_loops );
|
|
433
|
-
|
|
434
|
-
} else {
|
|
435
|
-
// This is our last round, let's wrap it up
|
|
436
|
-
let server_msg = `ALKiln setup: It seems like the docassemble server `
|
|
437
|
-
+ `didn't finish uploading the code after ${ timeout/1000 } `
|
|
438
|
-
+ `seconds. Some things you can try: check your server is up, try `
|
|
439
|
-
+ `re-running the test, and try pulling the package manually `
|
|
440
|
-
+ `into the playground.`;
|
|
441
|
-
// Add link to docs once the docs are more comprehensive
|
|
442
|
-
throw( server_msg );
|
|
443
|
-
} // ends if ran out of tries
|
|
444
|
-
} // ends if done_restarting
|
|
445
|
-
} // ends while not done restarting
|
|
446
|
-
|
|
447
|
-
log.info({ pre: `The docassemble server has uploaded your package.` });
|
|
448
|
-
}; // Ends da_i.wait_for_server_to_restart()
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
// Delete the Project
|
|
452
174
|
// node -e 'require("./lib/docassemble/docassemble_api_interface.js").delete_project( "create1" )'
|
|
453
175
|
da_i.delete_project = async function ( delete_options ) {
|
|
454
|
-
/** Delete a project on the user's da server.
|
|
176
|
+
/** Delete a project on the user's da server. Do we need to watch
|
|
177
|
+
* for a timeout? */
|
|
455
178
|
|
|
456
179
|
// Defaults
|
|
457
180
|
let { timeout } = delete_options || { timeout: DEFAULT_MAX_REQUEST_MS };
|
|
@@ -7,6 +7,7 @@ const fg = require('fast-glob');
|
|
|
7
7
|
const server_install = async () => {
|
|
8
8
|
session_vars.save_install_method(`server`);
|
|
9
9
|
|
|
10
|
+
// Get path to folders inside repo main "docassemble" folder
|
|
10
11
|
let current_dir = process.cwd();
|
|
11
12
|
let path = `${ current_dir }/docassemble/*`;
|
|
12
13
|
let dirs = fg.sync(
|
|
@@ -19,6 +20,7 @@ const server_install = async () => {
|
|
|
19
20
|
|
|
20
21
|
let folders = dirs.map(function (dir) { return dir.split('/').pop(); })
|
|
21
22
|
|
|
23
|
+
// Get names of all folders in repo "docassemble" folder
|
|
22
24
|
let chosen_folder = folders[0];
|
|
23
25
|
if ( folders.length === 0 ) {
|
|
24
26
|
let msg = `There are 0 folders at ${path}. Tests won't run.`;
|
package/lib/docassemble/setup.js
CHANGED
|
@@ -1,50 +1,60 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
const log = require('../utils/log');
|
|
5
|
-
const session_vars = require('../utils/session_vars' );
|
|
6
|
-
const files = require('../utils/files' );
|
|
3
|
+
// TODO: Rename to playground_install?
|
|
7
4
|
|
|
5
|
+
const child_process = require(`child_process`);
|
|
6
|
+
|
|
7
|
+
const log = require(`../utils/log`);
|
|
8
|
+
const session_vars = require(`../utils/session_vars` );
|
|
8
9
|
|
|
9
10
|
const setup = async () => {
|
|
10
|
-
|
|
11
|
+
/** In the docassemble testing account identified by the
|
|
11
12
|
* DOCASSEMBLE_DEVELOPER_API_KEY secret, create a new Project,
|
|
12
13
|
* pull code into that project, and, if needed, wait for the
|
|
13
|
-
* server to
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// Should the error be thrown here?
|
|
19
|
-
await da_i.validate_api_key();
|
|
20
|
-
|
|
21
|
-
// Create a project on the da server's account with a unique name then
|
|
22
|
-
// store it locally for later deleting the project.
|
|
23
|
-
let project_name = null;
|
|
24
|
-
// Explicit try-catch prevents "Unhandled promise rejection error"
|
|
25
|
-
// avoids showing confusing node errors to users that they shouldn't have to fix
|
|
26
|
-
try {
|
|
27
|
-
project_name = await da_i.loop_to_create_project();
|
|
28
|
-
log.info({type: `setup`, pre: `Created a Project named ${ project_name }`});
|
|
29
|
-
} catch (error) {
|
|
30
|
-
log.error({type: `setup`, pre: `an unexpected error occurred while trying to create a docassemble project in the user's account`, data: JSON.stringify(error, null, 4)})
|
|
31
|
-
// we don't re-throw the exception, so make sure to exit with 1 to let Github Actions know the script failed
|
|
32
|
-
process.exitCode = 1;
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
// Once the name is created, save that name to a local file.
|
|
14
|
+
* server to reload.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// Make and save project name
|
|
18
|
+
let project_name = session_vars.get_project_base_name().replace(/[^A-Za-z0-9]/g, '') + `${Date.now()}`;
|
|
36
19
|
session_vars.save_project_name( project_name );
|
|
37
20
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
21
|
+
log.info({ type: `setup`, pre: `Starting to upload this package to `
|
|
22
|
+
+ `a new Project called ${project_name} in the Playground `
|
|
23
|
+
+ `of your server's testing account. It may take a couple of minutes.` });
|
|
24
|
+
|
|
25
|
+
// dainstall . --apiurl https://site.org --apikey $API_KEY --playground --project=name
|
|
26
|
+
// I think this won't run on windows? Why do I think this? Where on the
|
|
27
|
+
// internet did I find this. Some command here or in dainstall doesn't
|
|
28
|
+
// work on windows.
|
|
29
|
+
let result = child_process.spawnSync(
|
|
30
|
+
`dainstall`,
|
|
31
|
+
[
|
|
32
|
+
`.`, `--apiurl`, session_vars.get_da_server_url(),
|
|
33
|
+
`--apikey`, session_vars.get_dev_api_key(), // validates api key
|
|
34
|
+
`--playground`, `--project=${ project_name }`
|
|
35
|
+
],
|
|
36
|
+
// Prints messages from the process to the console while it's running
|
|
37
|
+
{ stdio: 'inherit', }
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// 403 is invalid API key, but I'm not sure how to output
|
|
41
|
+
// the response to find out the error code
|
|
42
|
+
|
|
43
|
+
if ( result.status !== 0 ) {
|
|
44
|
+
log.error({
|
|
45
|
+
type: `setup`,
|
|
46
|
+
pre: `Status code ${ result.status }. Could not dainstall this package on your server. See above for more details.`
|
|
47
|
+
});
|
|
48
|
+
throw(result.stderr);
|
|
43
49
|
}
|
|
44
50
|
|
|
45
|
-
|
|
46
|
-
|
|
51
|
+
log.info({
|
|
52
|
+
type: `setup`,
|
|
53
|
+
pre: `Success! ALKiln created a Project in your Playground named "${ project_name }"`
|
|
54
|
+
});
|
|
47
55
|
}; // Ends setup();
|
|
48
56
|
|
|
49
57
|
|
|
58
|
+
// Before everything, make sure all the required env vars exist
|
|
59
|
+
session_vars.validateEnvironment();
|
|
50
60
|
setup();
|
package/lib/steps.js
CHANGED
|
@@ -67,6 +67,10 @@ to detect that.
|
|
|
67
67
|
regex thoughts: https://stackoverflow.com/questions/171480/regex-grabbing-values-between-quotation-marks
|
|
68
68
|
*/
|
|
69
69
|
|
|
70
|
+
// Make sure all the required env vars exist. Required to be
|
|
71
|
+
// here as well as `setup`` specifically for local development.
|
|
72
|
+
session_vars.validateEnvironment();
|
|
73
|
+
|
|
70
74
|
// Hoping that most load and download times will be under 30 seconds.
|
|
71
75
|
// TODO: Check what average load and download times are in our current interviews.
|
|
72
76
|
let default_timeout = 30 * 1000
|
|
@@ -371,8 +371,6 @@ session_vars.validateEnvironment = function() {
|
|
|
371
371
|
errorMessage = errorMessage.trim();
|
|
372
372
|
|
|
373
373
|
if (errorMessage !== '') {
|
|
374
|
-
throw new ReferenceError(`ALKiln error
|
|
374
|
+
throw new ReferenceError(`ALKiln error:\n${errorMessage}`);
|
|
375
375
|
}
|
|
376
376
|
};
|
|
377
|
-
|
|
378
|
-
session_vars.validateEnvironment();
|
package/package.json
CHANGED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
name: Test the tests
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
workflow_dispatch:
|
|
6
|
-
inputs:
|
|
7
|
-
tags:
|
|
8
|
-
required: False
|
|
9
|
-
description: 'Optional. Use a "tag expression" specify which tagged tests to run (https://cucumber.io/docs/cucumber/api/#tag-expressions)'
|
|
10
|
-
default: ''
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
|
|
14
|
-
puppeteer-tests:
|
|
15
|
-
runs-on: ubuntu-latest
|
|
16
|
-
|
|
17
|
-
strategy:
|
|
18
|
-
matrix:
|
|
19
|
-
node-version: [18.x]
|
|
20
|
-
|
|
21
|
-
env:
|
|
22
|
-
BASE_URL: ${{ secrets.SERVER_URL }}
|
|
23
|
-
PLAYGROUND_EMAIL: ${{ secrets.PLAYGROUND_EMAIL }}
|
|
24
|
-
PLAYGROUND_PASSWORD: ${{ secrets.PLAYGROUND_PASSWORD }}
|
|
25
|
-
PLAYGROUND_ID: ${{ secrets.PLAYGROUND_ID }}
|
|
26
|
-
DOCASSEMBLE_DEVELOPER_API_KEY: ${{ secrets.DOCASSEMBLE_DEVELOPER_API_KEY }}
|
|
27
|
-
USER1_EMAIL: ${{ secrets.USER1_EMAIL }}
|
|
28
|
-
USER1_PASSWORD: ${{ secrets.USER1_PASSWORD }}
|
|
29
|
-
SECRET_VAR1: secret-var1-value
|
|
30
|
-
SECRET_VAR2: secret-var2-value
|
|
31
|
-
SECRET_FOR_MISSING_FIELD: secret for missing field
|
|
32
|
-
_ORIGIN: github
|
|
33
|
-
|
|
34
|
-
name: Run Puppeteer tests
|
|
35
|
-
steps:
|
|
36
|
-
- name: Set Github-related environment variables
|
|
37
|
-
run: |
|
|
38
|
-
echo "REPO_URL=${{ github.server_url }}/${{ github.repository }}" >> $GITHUB_ENV
|
|
39
|
-
echo "BRANCH_PATH=${{ github.ref }}" >> $GITHUB_ENV
|
|
40
|
-
- name: Set name of artifact folder with date and UTC time
|
|
41
|
-
# https://www.shell-tips.com/linux/how-to-format-date-and-time-in-linux-macos-and-bash/#how-to-format-a-date-in-bash
|
|
42
|
-
run: |
|
|
43
|
-
echo "ARTIFACT_NAME=alkiln-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC" >> $GITHUB_ENV
|
|
44
|
-
echo "UNIT_TESTS_ARTIFACT_NAME=_alkiln-misc-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC" >> $GITHUB_ENV
|
|
45
|
-
# For the testing repo, the `REPO_URL` is that of a different repo and is created in `env:`
|
|
46
|
-
- run: echo "Repo address is $REPO_URL"
|
|
47
|
-
- name: Checkout
|
|
48
|
-
uses: actions/checkout@v3
|
|
49
|
-
- name: Setup environment
|
|
50
|
-
uses: actions/setup-node@v3
|
|
51
|
-
with:
|
|
52
|
-
node-version: ${{ matrix.node-version }}
|
|
53
|
-
- run: npm install
|
|
54
|
-
- run: npm run setup
|
|
55
|
-
- run: npm run test ${{ github.event.inputs.tags && format('{0}', github.event.inputs.tags) }}
|
|
56
|
-
# Artifacts
|
|
57
|
-
- name: upload unit tests artifacts folder
|
|
58
|
-
uses: actions/upload-artifact@v3
|
|
59
|
-
# This will upload even if a previous step has failed
|
|
60
|
-
if: ${{ always() }}
|
|
61
|
-
with:
|
|
62
|
-
name: ${{ env.UNIT_TESTS_ARTIFACT_NAME }}
|
|
63
|
-
path: ./_alkiln-*
|
|
64
|
-
- name: upload integration tests artifacts folder
|
|
65
|
-
uses: actions/upload-artifact@v3
|
|
66
|
-
if: ${{ always() }}
|
|
67
|
-
with:
|
|
68
|
-
name: ${{ env.ARTIFACT_NAME }}
|
|
69
|
-
path: ./alkiln-*
|
|
70
|
-
# Delete Playground Project and project name file
|
|
71
|
-
- name: Cleanup
|
|
72
|
-
if: ${{ always() }}
|
|
73
|
-
run: npm run takedown
|