@suffolklitlab/alkiln 5.13.2 → 5.13.3-feat-random-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 +10 -8
- package/.github/workflows/playground.yml +5 -2
- package/.github/workflows/unit_tests.yml +1 -1
- package/CHANGELOG.md +32 -1
- package/_alkiln_meta/shift_logs.js +75 -0
- package/action.yml +89 -31
- package/action_for_github_server/action.yml +65 -29
- package/docs/4_environments.md +243 -0
- package/docs/artifacts_folder_name.md +135 -0
- package/docs/constrained_random_tests.md +254 -0
- package/docs/decisions/006_which_log_level_to_pick_2024_09_5.md +70 -0
- package/docs/decisions/007_getting_and_storing_logs.md +179 -0
- package/docs/decisions/move_runtime_config_to_sources_folder.md +5 -0
- package/docs/decisions/reports_and_logs_2024_08_11.md +161 -0
- package/docs/kinds_of_errors.md +26 -0
- package/docs/prioritize_constrained_random_tests.md +60 -0
- package/lib/docassemble/docassemble_api_interface.js +77 -51
- package/lib/docassemble/server_install.js +32 -9
- package/lib/docassemble/setup.js +40 -25
- package/lib/docassemble/takedown.js +33 -10
- package/lib/globals.js +10 -0
- package/lib/run_cucumber.js +141 -69
- package/lib/scope.js +101 -77
- package/lib/setup/TestGenerator.js +1755 -0
- package/lib/setup/artifacts.js +20 -0
- package/lib/setup/generate.js +42 -0
- package/lib/setup/get_Gherkin_AST.js +26 -0
- package/lib/setup/validate.js +89 -0
- package/lib/steps.js +132 -54
- package/lib/utils/Log.js +1145 -0
- package/lib/utils/_alkiln-constrained_random_tests_old.js +1776 -0
- package/lib/utils/files.js +18 -11
- package/lib/utils/get_error_stacks.js +16 -0
- package/lib/utils/reports.js +100 -34
- package/lib/utils/session_vars.js +107 -73
- package/lib/utils/set_sources_paths.js +98 -0
- package/lib/utils/time.js +44 -0
- package/package.json +18 -7
- package/tests/log_codes/check_codes.sh +18 -13
- package/tests/log_codes/log_code_expected_instances.txt +91 -9
- package/tests/unit_tests/constrained_random_answers/invalid.fixtures.js +177 -0
- package/tests/unit_tests/constrained_random_answers/invalid.test.js +251 -0
- package/tests/unit_tests/constrained_random_answers/valid.fixtures.js +936 -0
- package/tests/unit_tests/constrained_random_answers/valid.test.js +541 -0
- package/tests/unit_tests/example_of_chai_test_lifecycle.js +78 -0
- package/tests/unit_tests/getAllFields.test.js +5 -0
- package/tests/unit_tests/getMatchingRows.test.js +5 -0
- package/tests/unit_tests/log.test.js +557 -0
- package/tests/unit_tests/normalizeTable.test.js +5 -0
- package/lib/utils/log.js +0 -96
- /package/docs/{expected_inernal_results.md → expected_internal_results.md} +0 -0
|
@@ -47,12 +47,33 @@ runs:
|
|
|
47
47
|
# Place the root directory in this branch
|
|
48
48
|
- uses: actions/checkout@v4
|
|
49
49
|
|
|
50
|
+
- shell: bash
|
|
51
|
+
run: |
|
|
52
|
+
log="💡 ALK0018 INFO: Get path names with date and time"
|
|
53
|
+
timestamp="$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)"
|
|
54
|
+
# Where to get the contents for the artifact
|
|
55
|
+
debug_dir="/tmp"
|
|
56
|
+
debug_logs_path="$debug_dir/alkiln_docker_logs-${timestamp}UTC.txt"
|
|
57
|
+
# Where to put the artifact
|
|
58
|
+
artifact_folder="alkiln_github_server-${timestamp}UTC"
|
|
59
|
+
echo "debug_logs_path: $debug_logs_path"
|
|
60
|
+
echo "artifact_folder: $artifact_folder"
|
|
61
|
+
|
|
62
|
+
mkdir -p "$debug_dir"
|
|
63
|
+
mkdir -p "$artifact_folder"
|
|
64
|
+
echo -e "$log" >> "$debug_logs_path"
|
|
65
|
+
|
|
66
|
+
echo "DEBUG_LOGS_PATH=$debug_logs_path" >> $GITHUB_ENV
|
|
67
|
+
echo "GITHUB_SERVER_ARTIFACT_NAME=$artifact_folder" >> $GITHUB_ENV
|
|
68
|
+
|
|
50
69
|
- shell: bash
|
|
51
70
|
env:
|
|
52
71
|
MAX_SECONDS_FOR_DOCKER: ${{ inputs.MAX_SECONDS_FOR_DOCKER }}
|
|
53
72
|
DOCASSEMBLECLI_VERSION: ${{ inputs.DOCASSEMBLECLI_VERSION }}
|
|
54
73
|
run: |
|
|
55
|
-
|
|
74
|
+
log="💡 ALK0001 INFO: Set environment variables"
|
|
75
|
+
echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}"
|
|
76
|
+
|
|
56
77
|
echo "MAX_SECONDS_FOR_DOCKER=$MAX_SECONDS_FOR_DOCKER" >> $GITHUB_ENV
|
|
57
78
|
echo "DOCASSEMBLECLI_VERSION=$DOCASSEMBLECLI_VERSION" >> $GITHUB_ENV
|
|
58
79
|
echo "DA_ADMIN_API_KEY=abcd1234abcd1234abcd5678abdc5678" >> $GITHUB_ENV
|
|
@@ -63,7 +84,8 @@ runs:
|
|
|
63
84
|
id: api_key_output_step
|
|
64
85
|
shell: bash
|
|
65
86
|
run: |
|
|
66
|
-
|
|
87
|
+
log="💡 ALK0002 INFO: Create GitHub step output variables"
|
|
88
|
+
echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}"
|
|
67
89
|
echo "DOCASSEMBLE_DEVELOPER_API_KEY=$DA_ADMIN_API_KEY" >> "$GITHUB_OUTPUT"
|
|
68
90
|
echo "DA_ADMIN_EMAIL=$DA_ADMIN_EMAIL" >> "$GITHUB_OUTPUT"
|
|
69
91
|
echo "DA_ADMIN_PASSWORD=$DA_ADMIN_PASSWORD" >> "$GITHUB_OUTPUT"
|
|
@@ -73,16 +95,20 @@ runs:
|
|
|
73
95
|
CONFIG: ${{ inputs.CONFIG_CONTENTS }}
|
|
74
96
|
shell: bash
|
|
75
97
|
run: |
|
|
76
|
-
|
|
98
|
+
log="💡 ALK0003 INFO: Get config"
|
|
99
|
+
echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}"
|
|
100
|
+
|
|
77
101
|
mkdir /tmp/config
|
|
78
102
|
# Worth making this silent by defining a variable with > /dev/null...?
|
|
79
103
|
if [ -n "$CONFIG" ]
|
|
80
104
|
then
|
|
81
|
-
|
|
105
|
+
log2="💡 ALK0004 INFO: The developer did provide a custom docassemble config file as an input into this action."
|
|
106
|
+
echo -e "\n$log2" >> "${{ env.DEBUG_LOGS_PATH }}" echo "$log2"
|
|
82
107
|
echo "$CONFIG" > /tmp/config/myconfig.yml
|
|
83
108
|
echo "CONFIG_ARGS=--env DA_CONFIG=/tmp/config/myconfig.yml --volume /tmp/config:/tmp/config " >> $GITHUB_ENV
|
|
84
109
|
else
|
|
85
|
-
|
|
110
|
+
log3="💡 ALK0005 INFO: The developer did NOT provide a custom docassemble config file as an input into this action. Docassemble will use its default config."
|
|
111
|
+
echo -e "\n$log3" >> "${{ env.DEBUG_LOGS_PATH }}" echo "$log3"
|
|
86
112
|
echo "CONFIG_ARGS=" >> $GITHUB_ENV
|
|
87
113
|
fi
|
|
88
114
|
|
|
@@ -97,11 +123,14 @@ runs:
|
|
|
97
123
|
SHOW_DOCKER_OUTPUT: ${{ inputs.SHOW_DOCKER_OUTPUT }}
|
|
98
124
|
shell: bash
|
|
99
125
|
run: |
|
|
100
|
-
|
|
126
|
+
log="💡 ALK0006 INFO: Determine docker logs visibility"
|
|
127
|
+
echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}"
|
|
101
128
|
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
|
102
129
|
echo "OUTPUT_DOCKER=$SHOW_DOCKER_OUTPUT" >> $GITHUB_ENV
|
|
130
|
+
echo -e "\n$SHOW_DOCKER_OUTPUT" >> "${{ env.DEBUG_LOGS_PATH }}"
|
|
103
131
|
else
|
|
104
132
|
echo "OUTPUT_DOCKER=false" >> $GITHUB_ENV
|
|
133
|
+
echo -e "\nfalse" >> "${{ env.DEBUG_LOGS_PATH }}"
|
|
105
134
|
fi
|
|
106
135
|
|
|
107
136
|
# Messages about output
|
|
@@ -110,13 +139,15 @@ runs:
|
|
|
110
139
|
shell: bash
|
|
111
140
|
run: |
|
|
112
141
|
# 💡 ALK0007 INFO: ALKiln will now hide docker output
|
|
113
|
-
|
|
142
|
+
log="===\n💡 ALK0007 INFO: ALKiln will now hide docker 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==="
|
|
143
|
+
echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}" && echo -e "$log"
|
|
114
144
|
- name: "💡 ALK0008 INFO: ALKiln will show docker output"
|
|
115
145
|
if: ${{ env.OUTPUT_DOCKER == 'true' }}
|
|
116
146
|
shell: bash
|
|
117
147
|
run: |
|
|
118
148
|
# 💡 ALK0008 INFO: ALKiln will show docker output
|
|
119
|
-
|
|
149
|
+
log="===\n💡 ALK0008 INFO: ALKiln will show docker output. 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==="
|
|
150
|
+
echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}" && echo -e "$log"
|
|
120
151
|
|
|
121
152
|
# TODO: Reduce these to 1 block by putting ` > /dev/null 2>&1` into an env var
|
|
122
153
|
# No docker output
|
|
@@ -126,7 +157,8 @@ runs:
|
|
|
126
157
|
CONFIG_ARGS: ${{ env.CONFIG_ARGS }}
|
|
127
158
|
shell: bash
|
|
128
159
|
run: |
|
|
129
|
-
|
|
160
|
+
log="💡 ALK0009 INFO: Download and start docker silently"
|
|
161
|
+
echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}"
|
|
130
162
|
docker pull jhpyle/docassemble > /dev/null 2>&1
|
|
131
163
|
docker run --name docassemble_container \
|
|
132
164
|
--env DA_ADMIN_EMAIL="$DA_ADMIN_EMAIL" \
|
|
@@ -142,7 +174,8 @@ runs:
|
|
|
142
174
|
CONFIG_ARGS: ${{ env.CONFIG_ARGS }}
|
|
143
175
|
shell: bash
|
|
144
176
|
run: |
|
|
145
|
-
|
|
177
|
+
log="💡 ALK0010 INFO: Download and start docker"
|
|
178
|
+
echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}"
|
|
146
179
|
docker pull jhpyle/docassemble
|
|
147
180
|
docker run --name docassemble_container \
|
|
148
181
|
--env DA_ADMIN_EMAIL="$DA_ADMIN_EMAIL" \
|
|
@@ -159,12 +192,14 @@ runs:
|
|
|
159
192
|
shell: bash
|
|
160
193
|
run: |
|
|
161
194
|
# 💡 ALK0011 INFO: The following messages are not docker output
|
|
162
|
-
|
|
195
|
+
log="💡 ALK0011 INFO: The following messages are NOT docker output, just ALKiln waiting for the server to start"
|
|
196
|
+
echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}" && echo -e "$log"
|
|
163
197
|
|
|
164
198
|
- name: "💡 ALK0012 INFO: Waiting for server to start"
|
|
165
199
|
shell: bash
|
|
166
200
|
run: |
|
|
167
|
-
|
|
201
|
+
log="💡 ALK0012 INFO: Waiting for server to start"
|
|
202
|
+
echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}"
|
|
168
203
|
|
|
169
204
|
# Reset the SECONDS variable
|
|
170
205
|
SECONDS=0
|
|
@@ -173,23 +208,28 @@ runs:
|
|
|
173
208
|
|
|
174
209
|
response="start"
|
|
175
210
|
while [[ $response != *"200"* ]]; do
|
|
176
|
-
|
|
211
|
+
log2="💡 ALK0013 INFO: Time elapsed: $SECONDS seconds"
|
|
212
|
+
echo -e "\n$log2" >> "${{ env.DEBUG_LOGS_PATH }}" && echo -e "$log2"
|
|
177
213
|
|
|
178
214
|
# Check if max seconds till loading has passed
|
|
179
215
|
if [[ $SECONDS -ge $MAX_SECONDS_FOR_DOCKER ]]; then
|
|
180
|
-
|
|
216
|
+
log3="🤕 ALK0014 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."
|
|
217
|
+
echo -e "\n$log3" >> "${{ env.DEBUG_LOGS_PATH }}" && echo -e "$log3"
|
|
181
218
|
exit 1
|
|
182
219
|
fi
|
|
183
220
|
|
|
184
221
|
# Set the variable to a new string value in each iteration
|
|
185
222
|
response=$(curl -o /dev/null -s -w "%{http_code}\n" http://localhost:80/health_check?ready=1)
|
|
186
|
-
|
|
223
|
+
log4="💡 ALK0015 INFO: Response is $response"
|
|
224
|
+
echo -e "\n$log4" >> "${{ env.DEBUG_LOGS_PATH }}" && echo -e "$log4"
|
|
187
225
|
|
|
188
226
|
# Check if the string includes the desired text
|
|
189
227
|
if [[ $response == *"200"* ]]; then
|
|
190
|
-
|
|
228
|
+
log5="💡 ALK0016 SUCCESS: Success! The docker container is ready!"
|
|
229
|
+
echo -e "\n$log5" >> "${{ env.DEBUG_LOGS_PATH }}" && echo -e "$log5"
|
|
191
230
|
else
|
|
192
|
-
|
|
231
|
+
log6="💡 ALK0017 INFO: The docker container is not ready yet. Will check again in 30 seconds."
|
|
232
|
+
echo -e "\n$log6" >> "${{ env.DEBUG_LOGS_PATH }}" && echo -e "$log6"
|
|
193
233
|
sleep 30
|
|
194
234
|
fi
|
|
195
235
|
|
|
@@ -219,32 +259,28 @@ runs:
|
|
|
219
259
|
|
|
220
260
|
# Upload artifacts that devs can download on the Actions summary page
|
|
221
261
|
# Only if the developer wants to get that info, though
|
|
222
|
-
- name: "💡 ALK0018 INFO: Get path names with date and time"
|
|
223
|
-
if: ${{ always() && env.OUTPUT_DOCKER == 'true' }}
|
|
224
|
-
shell: bash
|
|
225
|
-
run: |
|
|
226
|
-
# 💡 ALK0018 INFO: Get path names with date and time
|
|
227
|
-
echo "GITHUB_SERVER_LOG_FILE_NAME=/tmp/alkiln_docker_logs-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC.txt" >> $GITHUB_ENV
|
|
228
|
-
echo "GITHUB_SERVER_ARTIFACT_NAME=alkiln_github_server-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC" >> $GITHUB_ENV
|
|
229
262
|
- name: "💡 ALK0019 INFO: Create docker artifact data"
|
|
230
263
|
if: ${{ always() && env.OUTPUT_DOCKER == 'true' }}
|
|
231
264
|
shell: bash
|
|
232
265
|
run: |
|
|
233
|
-
|
|
234
|
-
echo "$
|
|
266
|
+
log="💡 ALK0019 INFO: Create docker artifact data"
|
|
267
|
+
echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}"
|
|
268
|
+
echo "$(docker output docassemble_container)" >> "${{ env.DEBUG_LOGS_PATH }}"
|
|
235
269
|
- name: "💡 ALK0020 INFO: Upload artifacts folder"
|
|
236
270
|
if: ${{ always() && env.OUTPUT_DOCKER == 'true' }}
|
|
237
271
|
uses: actions/upload-artifact@v4
|
|
238
272
|
with:
|
|
239
273
|
name: ${{ env.GITHUB_SERVER_ARTIFACT_NAME }}
|
|
240
|
-
path: ${{ env.
|
|
274
|
+
path: ${{ env.DEBUG_LOGS_PATH }}
|
|
241
275
|
|
|
242
276
|
- shell: bash
|
|
243
277
|
if: ${{ success() }}
|
|
244
278
|
run: |
|
|
245
|
-
|
|
279
|
+
log="💡 ALK0021 SUCCESS: ALKiln created the docker container and started the server!"
|
|
280
|
+
echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}" && echo -e "$log"
|
|
246
281
|
|
|
247
282
|
- shell: bash
|
|
248
283
|
if: ${{ failure() }}
|
|
249
284
|
run: |
|
|
250
|
-
|
|
285
|
+
log="🤕 ALK0022 ERROR: Something went wrong. See above for more details."
|
|
286
|
+
echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}" && echo -e "$log"
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# Designing for the complexity of the 4 environments in which ALKiln can run
|
|
2
|
+
|
|
3
|
+
## Context and scope
|
|
4
|
+
|
|
5
|
+
Authors have different testing needs. For example, sometimes authors need to run individual tests more quickly as they are developing code and sometimes authors need to run a whole test suite on a weekly schedule to make sure their online forms keep working over time. To run individual tests more quickly, an author can run the tests directly on their development server. To run scheduled tests, an author can run tests on GitHub. Those are very different environments.
|
|
6
|
+
|
|
7
|
+
Internal ALKiln developers need to run tests in more environments as well.
|
|
8
|
+
|
|
9
|
+
To help with all these, ALKiln can work in 4 different environments. We have to design ALKiln's architecture with that in mind.
|
|
10
|
+
|
|
11
|
+
## Goals
|
|
12
|
+
|
|
13
|
+
- Help authors to test in the environments that best help them develop.
|
|
14
|
+
- Help internal ALKiln developers develop the framework comfortably enough.
|
|
15
|
+
- Keep openings where authors can interact directly with the systems we're using so they can customize behavior that we can't account for.
|
|
16
|
+
|
|
17
|
+
## Non/anti-goals
|
|
18
|
+
|
|
19
|
+
- Be an intermediary between the author and all the possible customization they need for their tests.
|
|
20
|
+
|
|
21
|
+
## The actual design
|
|
22
|
+
|
|
23
|
+
This design involves:
|
|
24
|
+
|
|
25
|
+
- The 4 environments, the ALKiln flow for each, and the advantages each environment has.
|
|
26
|
+
- The 4 separate command line commands.
|
|
27
|
+
- Passing information between different runtime processes.
|
|
28
|
+
- The 2 composite action scripts.
|
|
29
|
+
|
|
30
|
+
<!-- Maybe the flows below should each be shown in the relevant individual sections for each environment. -->
|
|
31
|
+
|
|
32
|
+
The flow for each environment is different.
|
|
33
|
+
|
|
34
|
+
The temporary GitHub docasseble server action:
|
|
35
|
+
|
|
36
|
+
1. Author workflow file > `./action_for_github/action.yml` > author workflow file > `./action.yml` > `alkiln-server-install` > `alkiln-run` > author workflow file
|
|
37
|
+
|
|
38
|
+
<!-- Not sure how to represent this relationship. Trying to show what processes have access to what parts of the process. I'm not sure showing how `./action.yml` threads in and out is actually useful. I'm trying to show that the author's workflow has access in between `./action_for_github/action.yml` and `./action.yml` where they can do things so when someone reads about it later, they can understand.
|
|
39
|
+
|
|
40
|
+
Author workflow
|
|
41
|
+
`./action_for_github/action.yml`
|
|
42
|
+
Author workflow
|
|
43
|
+
`./action.yml`
|
|
44
|
+
`alkiln-server-install`
|
|
45
|
+
`./action.yml`
|
|
46
|
+
`alkiln-run`
|
|
47
|
+
`./action.yml`
|
|
48
|
+
Author workflow
|
|
49
|
+
|
|
50
|
+
Author workflow
|
|
51
|
+
`./action_for_github/action.yml`
|
|
52
|
+
Author workflow
|
|
53
|
+
`./action.yml`
|
|
54
|
+
`alkiln-server-install`
|
|
55
|
+
`alkiln-run`
|
|
56
|
+
Author workflow
|
|
57
|
+
-->
|
|
58
|
+
|
|
59
|
+
A GitHub action that installs tests in an author's account on their own docasseble server:
|
|
60
|
+
|
|
61
|
+
1. Author workflow file > `./action.yml` > `alkiln-setup` > `alkiln-run` > `alkiln-takedown` > author workflow file
|
|
62
|
+
|
|
63
|
+
<!-- Not sure how to represent this relationship
|
|
64
|
+
Author workflow
|
|
65
|
+
`./action.yml`
|
|
66
|
+
`alkiln-setup`
|
|
67
|
+
`alkiln-run`
|
|
68
|
+
`alkiln-takedown`
|
|
69
|
+
Author workflow
|
|
70
|
+
-->
|
|
71
|
+
|
|
72
|
+
ALKilnInThePlayground:
|
|
73
|
+
|
|
74
|
+
1. `alkiln-run`
|
|
75
|
+
|
|
76
|
+
A local developer might customize these steps in various ways in their console. If they are using the default workflow, this is what it looks like functionally when they develop a feature:
|
|
77
|
+
|
|
78
|
+
1. Command line > `alkiln-setup` once
|
|
79
|
+
2. Command line > `alkiln-run` many times
|
|
80
|
+
3. Command line > `alkiln-takedown` once
|
|
81
|
+
|
|
82
|
+
### 4 environments we need to account for
|
|
83
|
+
|
|
84
|
+
#### 2 GitHub options
|
|
85
|
+
|
|
86
|
+
Authors or admins use GitHub workflows to run our GitHub composite actions if they:
|
|
87
|
+
|
|
88
|
+
- Want to run tests every time an author commits code.
|
|
89
|
+
- Want to run tests based on other triggers, like a schedule or manually triggering the workflow.
|
|
90
|
+
- They want to require that all tests pass before they merge a branch.
|
|
91
|
+
- Use other CI pipelines.
|
|
92
|
+
|
|
93
|
+
**Run on a temporary GitHub server**
|
|
94
|
+
|
|
95
|
+
1. Author: commits code to GitHub.
|
|
96
|
+
2. ALKiln: Creates a docassemble server, installs the docassemble package globally on the server, run the test suite once, and destroys the server.
|
|
97
|
+
|
|
98
|
+
Authors use this if they:
|
|
99
|
+
|
|
100
|
+
- Want less flake.
|
|
101
|
+
- Want to test with latest version of da.
|
|
102
|
+
- Don't mind extra setup time each test suite takes.
|
|
103
|
+
- Know how to use bash to work with a Docker container (if needed).
|
|
104
|
+
|
|
105
|
+
**Run from GitHub, but on their own server**
|
|
106
|
+
|
|
107
|
+
1. Author: commits code to GitHub.
|
|
108
|
+
2. ALKiln: Installs the docassemble package in the author's account on their own docassemble server, runs the test suite once, and deletes the docassemble package.
|
|
109
|
+
|
|
110
|
+
Authors use this if they:
|
|
111
|
+
|
|
112
|
+
- Want to Use data from SS3 and other remote databases.
|
|
113
|
+
- Want to test with their own version of docassemble.
|
|
114
|
+
- Don't want to have to be so careful with all their dependencies (like having to put all dependencies on pypi) because they have installed them on their server themselves.
|
|
115
|
+
|
|
116
|
+
#### Running directly on docassemble server
|
|
117
|
+
|
|
118
|
+
A docassemble server doesn't just serve forms to end users. It also lets authors develop the code of their forms[^1]. That is why it is useful to install and use ALKiln on an author's docassemble server. They do this by using the AlKilnInThePlayground package.
|
|
119
|
+
|
|
120
|
+
An author installs AlKilnInThePlayground package on their server. They run the online form that package has. That lets them install ALKiln on their server. The package can tell who the user is and offers the user a choice of which of their Playground development Projects to test, and they run the tests right their on their server.
|
|
121
|
+
|
|
122
|
+
1. Author: Installs the package they want to test into their account on the docassemble 1. server, edits their package, triggers the test run.
|
|
123
|
+
2. ALKiln: Runs tests.
|
|
124
|
+
3. Author: Edits, tests, and repeats. Finally, the author deletes the package in their account on the docassemble server.
|
|
125
|
+
|
|
126
|
+
Authors use this if they:
|
|
127
|
+
|
|
128
|
+
- Want to run tests faster than the GitHub test flow allows (a faster iteration cycle).
|
|
129
|
+
- Want to avoid server reloads (in the case of a package with python modules).
|
|
130
|
+
- Feel uncomfortable with failures on GitHub - they can get tests passing before pushing to GitHub.
|
|
131
|
+
- Have the right version of nodejs on their docassemble server, which is based on what Docker image they have installed.
|
|
132
|
+
|
|
133
|
+
#### Command line
|
|
134
|
+
|
|
135
|
+
<!-- Do we mention that internal devs don't always use the bins? They use the package.json scripts? Seems like an unnecessary complication. -->
|
|
136
|
+
|
|
137
|
+
1. Internal developer with ALKiln's help or with their own command line arguments: Installs the package on a specified docassemble server (local or remote).
|
|
138
|
+
2. Internal developer with ALKiln's help: runs the tests as many times as they need while they develop the framework code.
|
|
139
|
+
3. Internal developer with ALKiln's help or with their own command line arguments: deletes the package from the docassemble server.
|
|
140
|
+
|
|
141
|
+
Internal developers do this if they:
|
|
142
|
+
|
|
143
|
+
- Have to edit ALKiln's own code.
|
|
144
|
+
- Want to run tests faster than the GitHub test flow allows (a faster iteration cycle).
|
|
145
|
+
- Want to run tests on a local server.
|
|
146
|
+
- See ALKiln's behavior live and with more detail.
|
|
147
|
+
|
|
148
|
+
### 4 node command line commands
|
|
149
|
+
|
|
150
|
+
`package.json` has 4 command-line commands. They are broken up by the different needs of the 4 different environments - installing packages on a server, saving temporary server information, running the core framework code[^2], deleting packages on a server. As this document describes. Some environments need only one of the commands.
|
|
151
|
+
|
|
152
|
+
Read the API section for more details.
|
|
153
|
+
|
|
154
|
+
Looking only at the command line commands does miss a crucial 1st part of the temporary GitHub docassemble server workflow - creating the docassemble server. That is done completely through `./action_for_github/action.yml`. See the section on GitHub composite actions for details.
|
|
155
|
+
|
|
156
|
+
### Passing information between different processes.
|
|
157
|
+
|
|
158
|
+
ALKiln needs to pass information between its different processes to do things like go to the right interview urls and store artifacts (like reports, debug logs, and screenshots) in the right folder.
|
|
159
|
+
|
|
160
|
+
**`runtime_config.json`**
|
|
161
|
+
|
|
162
|
+
Since different runtime processes can't pass information between them any other way, we create and modify `runtime_config.json` as each process runs to store information that other processes need. Different environments need to save different information or to save information differently.
|
|
163
|
+
|
|
164
|
+
For example, `alkiln-setup` needs to create a Project on an author's Playground[^1] to store the code of the online forms and show the forms online. Later, `alkiln-run` needs to know how to find the URL for that specific Project on the server so it can interact with the forms.
|
|
165
|
+
|
|
166
|
+
The name of the artifacts folder is an example of using `runtime_config.json` and how the complexity of these 4 environments invades ALKiln's core code. See the doc about the artifacts folder name.
|
|
167
|
+
|
|
168
|
+
<!-- Do we need to list the specific possible values here? These aren't recorded anywhere else, so it's worth considering, but it doesn't feel like the right place. This is incomplete. Holding off until we decide where it goes.
|
|
169
|
+
Everything uses these:
|
|
170
|
+
|
|
171
|
+
- `artifacts_path`
|
|
172
|
+
|
|
173
|
+
Temp GitHub docassemble server install uses these:
|
|
174
|
+
|
|
175
|
+
`da_install_method` - `server` or `playground`
|
|
176
|
+
`da_repo_folder_name` - For example, EvictionDefense in the docassemble-EvictionDefense repo. (see session_vars.js)
|
|
177
|
+
|
|
178
|
+
Installation in an author's account on their own docassemble server and command line uses these:
|
|
179
|
+
|
|
180
|
+
Does ALKilnInThePlayground also use the below?
|
|
181
|
+
|
|
182
|
+
- `da_project_name` - The name of the docassemble project. Helps get the url of the interview. In local internal development, this lets developers keep using the same Project over and over so they don't need to make a new Project, and upload the package code, every time they run a test.
|
|
183
|
+
-->
|
|
184
|
+
|
|
185
|
+
**Env vars**
|
|
186
|
+
|
|
187
|
+
ALKiln and test authors use environment variables to pass information to different processes. GitHub workflows and actions store them in their `.yml` files. ALKilnInThePlayground uses the server's configuration file. Local developers use their `.env` file. This is also the way authors and internal developers pass sensitive information to ALKiln. On GitHub, authors store sensitive information in GitHub secrets and then use them as environment variables.
|
|
188
|
+
|
|
189
|
+
### 2 GitHub composite actions
|
|
190
|
+
|
|
191
|
+
Authors use our GitHub composite actions in their GitHub workflow files.
|
|
192
|
+
|
|
193
|
+
- `./action_for_github/action.yml` - Creates the temporary GitHub docassemble server. This action is a crucial part of the flow for temporary GitHub docassemble servers. The fact that it is a separate action gives authors the information and environment they need to change and customize the temporary server themselves in more ways than we can account for. For example, authors might need to make user accounts so they can test what a logged-in user sees. Right now, it cannot help them access remote databases like S3.
|
|
194
|
+
- `./action.yml` - Installs packages on servers in the ways we've described, runs the tests, deletes packages on servers, and gives authors information from the test run, like reports and screenshots.
|
|
195
|
+
|
|
196
|
+
The rest of the details and API are in the files themselves and in the author-facing documentation about GitHub workflow files at https://assemblyline.suffolklitlab.org/docs/alkiln/writing/#workflows.
|
|
197
|
+
|
|
198
|
+
## APIs
|
|
199
|
+
|
|
200
|
+
### Command-line API
|
|
201
|
+
|
|
202
|
+
ALKiln's `package.json` offers 4 command-line commands:
|
|
203
|
+
|
|
204
|
+
1. `alkiln-server-install` - Stores `runtime_config.json` variables of a temporary GitHub docassemble server for the core framework code[^2].
|
|
205
|
+
2. `alkiln-setup` - Installs the docassemble package on the author's account and stores `runtime_config.json` variables for core framework code.
|
|
206
|
+
3. `alkiln-run` - Wraps and then runs the framework's core code to run the tests.
|
|
207
|
+
4. `alkiln-takedown` - Deletes the package there.
|
|
208
|
+
|
|
209
|
+
### GitHub composite actions API
|
|
210
|
+
|
|
211
|
+
The general description of the composite actions is in the composite action section. The details of composite action API is in the author-facing documentation about GitHub workflow files at https://assemblyline.suffolklitlab.org/docs/alkiln/writing/#workflows.
|
|
212
|
+
|
|
213
|
+
## Degree of constraint
|
|
214
|
+
|
|
215
|
+
This design is working within systems that limit how we can do what we need to do.
|
|
216
|
+
|
|
217
|
+
- GitHub's action and workflow API and environment. For example, interacting with the temporary GitHub docassemble server vs. interacting with an author's server. Also, the ways in which we need to store and use environment variables.
|
|
218
|
+
- docassemble's API and environment. It wasn't designed to be automated and used this way. For example, it stores package files very differently than the way GitHub arranges them and very differently depending on where we install the package, it has different memory constraints for installing the packages globally vs. in an individual developer's account, etc.
|
|
219
|
+
- cucumberjs's inability to pass non-primitives to core framework code[^2].
|
|
220
|
+
- 3rd party database storage systems, like S3, are hard to integrate into GitHub temporary server tests. We have excluded this feature at the moment. Authors would need to write their own workflow or composite action to access remote databases.
|
|
221
|
+
|
|
222
|
+
## Alternatives considered
|
|
223
|
+
|
|
224
|
+
Alternative: Get rid of our support for some of these environments. The temporary GitHub docassemble server environment hasn't been used by a lot of authors. Other than that, the other environments have gotten a lot of use. Even though authors have not yet used the temporary GitHub environment much, they say they want that functionality. The trouble there seems to be complexity with initial set up.
|
|
225
|
+
|
|
226
|
+
Alternative: Instead of dealing with separate runtimes, have one command and script that wraps all these currently separate processes in one runtime and handles which ones to trigger under what circumstances. If we included `./action_for_github/action.yml` in that command, we would prevent authors from customizing the temporary GitHub docassemble server. That would not be acceptable. To avoid closing off access to server customization, we can only partially integrate these different processes. Also, GitHub actions in general will still have to deal with some core business sometimes. For example, they have to create the artifacts folder name so they can use it later to upload the artifacts. This combined runtime also feels more coupled/entangled and therefore harder to maintain. The need for more command line arguments could make local development more complicated. It is still worth considering.
|
|
227
|
+
|
|
228
|
+
<!-- Discuss: How to articulate the entanglement with more specifics and examples. -->
|
|
229
|
+
|
|
230
|
+
Alternative script names: `install_package`, `save_server`, `delete_package`.
|
|
231
|
+
|
|
232
|
+
## Cross-cutting concerns
|
|
233
|
+
|
|
234
|
+
_Security, privacy, observability, etc._
|
|
235
|
+
|
|
236
|
+
- Some tests need to use sensitive information. For example, some tests need a logged-in user and thus ALKiln needs the login info for a user. Different environments store this information differently and there is documentation about how to use sensitive information securely and privately.
|
|
237
|
+
- Core ALKiln code[^2] ends up needing to handle some of the complexity of the 4 environments. Example - the `Log` class `path` takes an optional initial argument to set the artifacts path at the beginning of that runtime process. Other parts of the process have to assume that this path already exists. We have tried to abstract environment complexity out to `run_cucumber.js`, the script that wraps the core code, but there is still logic that the core code handles.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
[^1]: A docassemble server can have multiple purposes. One is to contain the packages for online forms which end users then use. Those packages are stored in a special place on the server and admins configure the server to give end users a list of those forms. Another purpose of the docassemble server is to be a development environment in which to create the forms. An author/developer of the forms has a developer account on the server. That account can store multiple packages and versions of packages. It also has an IDE that authors can use to work on those packages. They can push those files to GitHub from that IDE. They can also pull those packages from GitHub using that IDE.
|
|
242
|
+
|
|
243
|
+
[^2]: **Core framework code/core code:** the code that implements the Steps in the `.feature` test files.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Creating and using the name of the artifacts folder
|
|
2
|
+
|
|
3
|
+
## Context and scope
|
|
4
|
+
|
|
5
|
+
The artifacts folder is where an author can see the results of their tests, like the reports, screenshots, and downloaded documents.
|
|
6
|
+
|
|
7
|
+
The name of this folder has a specific format to make it as short as possible while it still stays recognizable to users and that it is unique. To help keep it unique it includes a timestamp. (The human readable date/time is not as precise and also longer than the timestamp).
|
|
8
|
+
|
|
9
|
+
Because of the 4 environments ALKiln can run in (see the docs about the 4 environments), we have different ways to make sure we use one unique artifacts folder name for each test run.
|
|
10
|
+
|
|
11
|
+
## Goals
|
|
12
|
+
|
|
13
|
+
- Minimize code duplication
|
|
14
|
+
- In each of the 4 ALKiln environments, be able to track one unique folder name for each test suite run
|
|
15
|
+
|
|
16
|
+
## The actual design
|
|
17
|
+
|
|
18
|
+
Our 4 environments can be condensed into 3 environments for the purpose of managing the artifacts folder name:
|
|
19
|
+
|
|
20
|
+
- GitHub action (`./action.yml`)
|
|
21
|
+
- ALKilnInThePlayground
|
|
22
|
+
- The command line for internal development
|
|
23
|
+
|
|
24
|
+
The GitHub action creates an artifact folder name and sends it to various scripts that use an instance of the `Log` class to create the folder and save the name. In other environments, an instance of the `Log` class both creates the name, creates the folder, and saves the name. The instance of the `Log` saves the name in `runtime_config.json`. That instance of `Log` and other ALKiln code uses that name to create and store files in that artifacts folder.
|
|
25
|
+
|
|
26
|
+
The artifact folder name generation code is in 2 places - the GitHub action and ALKiln's core code[^1]. In future, we may reduce that to just one location - the core code.
|
|
27
|
+
|
|
28
|
+
<!-- More complex description that I don't think we need now, but want to double check:
|
|
29
|
+
The scripts that GitHub action uses need to store its output in the same artifacts folder. The GitHub action therefore builds the name of the artifact folder and passes that around to the different scripts. The scripts pass the folder name to the `Log` class every time, which saves the folder name in `runtime_config.json`. After that, the core code uses that `json` value to put other artifacts in the same folder. We also have folder-naming code in the core code which we use for other purposes. The GitHub action duplicates that folder-naming code, which is unfortunate.
|
|
30
|
+
|
|
31
|
+
At the same time, tests that run in ALKilnInThePlayground don't have GitHub to manage the artifact folder name. It only uses the `run_cucumber` script, not any of the others...
|
|
32
|
+
|
|
33
|
+
Adding to that confusion, when people (like internal ALKiln developers) run tests from their command line, they do use the `setup` script once at first, but then run test suites repeatedly...
|
|
34
|
+
|
|
35
|
+
Neither of the last 2 can depend on the `runtime_config.json` folder name that `setup` creates. If they did, all their multiple test runs would save to that first folder. Since both those environments use `run_cucumber.js` alone repeatedly, and since we don't want to duplicate folder-naming behavior between even more scripts, we decided that those non-GitHub environments should be able to let `Log` create a folder name from scratch every time. The `Log` constructor has to be able to accept a `path` argument with a folder name and also to accept an undefined `path` argument.
|
|
36
|
+
-->
|
|
37
|
+
|
|
38
|
+
A future goal is to remove the need to store the name in the runtime configuration file to reduce that complexity a bit. These flows are up for discussion.
|
|
39
|
+
|
|
40
|
+
Below are more detailed descriptions of the different paths the folder name takes in the different environments. Where the folder name is created, gets passed, gets saved, and gets used. Note that there's a little glossing over the details. For example, everything saves to `runtime_config.json`, but only the core code[^1] ever uses the value there.
|
|
41
|
+
|
|
42
|
+
The diagrams highlight `Log` to help visualize a common point in all the flows.
|
|
43
|
+
|
|
44
|
+
### GitHub action
|
|
45
|
+
|
|
46
|
+
1. GitHub action creates a new folder name, passes that name to `setup`, which passes that name to `Log`, which creates the artifacts folder and saves the name in `runtime_config.json`. The setup `Log` uses the name to store logs in the folder. The setup uses its `Log`.
|
|
47
|
+
2. GitHub action uses the same folder name, passes that same name to `run_cucumber`, which passes that same name to `Log`. The `runtime_cucumber` process uses that `Log`. The `run_cucumber` process also triggers the core code, which uses the folder name in `runtime_config.json` to create its own `Log`. The core code also uses that name to store other artifact files in the folder.
|
|
48
|
+
3. GitHub action creates the folder name, passes that same name to `takedown`, which passes that same name when instantiating its `Log`. The takedown `Log` uses the name to store logs in the folder.
|
|
49
|
+
|
|
50
|
+
```mermaid
|
|
51
|
+
%% "pass name too" has 2 o's at the end because mermaid makes one of them disappear
|
|
52
|
+
|
|
53
|
+
flowchart LR
|
|
54
|
+
action[action part 1] --create/pass name too--> setup
|
|
55
|
+
setup["setup"] --pass name too--> log1["#96;Log#96;"]:::log
|
|
56
|
+
log1 --store name in/ignore--> runtime1["runtime config file"]
|
|
57
|
+
log1 --create with name--> folder1[folder]
|
|
58
|
+
|
|
59
|
+
action2[action part 2] --pass name too--> run["run"]
|
|
60
|
+
run --pass name too--> log2["#96;Log#96;"]:::log
|
|
61
|
+
log2 --store name in/ignore--> runtime2["runtime config file"]
|
|
62
|
+
log2 --use with name--> folder2[folder]
|
|
63
|
+
run --> core["core code"]
|
|
64
|
+
core --pass name too--> log3["#96;Log#96;"]:::log
|
|
65
|
+
core --use with name--> folder2
|
|
66
|
+
core --get name from--> runtime2
|
|
67
|
+
log3 --use with name--> folder2
|
|
68
|
+
log3 --store name in/ignore--> runtime2
|
|
69
|
+
|
|
70
|
+
action3[action part 3] --pass name too--> takedown["takedown"]
|
|
71
|
+
takedown --pass name too--> log4["#96;Log#96;"]:::log
|
|
72
|
+
log4 --store name in/ignore--> runtime3["runtime config file"]
|
|
73
|
+
log4 --create with name--> folder5[folder]
|
|
74
|
+
|
|
75
|
+
classDef log fill:#d6fd88,stroke:#000,stroke-width:2px,color:#000
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### ALKilnInThePlayground
|
|
79
|
+
|
|
80
|
+
1. ALKilnInThePlayground triggers `run_cucumber` without a folder name which triggers `Log` without a folder name. `Log` creates a new folder name and saves it in `runtime_config.json`. It also creates the artifacts folder. The `run_cucumber` process also triggers the core code, which uses the folder name in `runtime_config.json` to create its own `Log`. The core code also uses that name to store other artifact files in the folder.
|
|
81
|
+
|
|
82
|
+
```mermaid
|
|
83
|
+
flowchart LR
|
|
84
|
+
ALKilnInThePlayground --> run["run"]
|
|
85
|
+
run --> log2["#96;Log#96;"]:::log
|
|
86
|
+
log2 --store name in/ignore--> runtime2["runtime config file"]
|
|
87
|
+
log2 --create with name--> folder2[folder]
|
|
88
|
+
run --> core["core code"]
|
|
89
|
+
core --> log3["#96;Log#96;"]:::log
|
|
90
|
+
core --use with name--> folder2
|
|
91
|
+
core --get name from--> runtime2
|
|
92
|
+
log3 --use with name--> folder2
|
|
93
|
+
log3 --store name in/ignore--> runtime2
|
|
94
|
+
|
|
95
|
+
classDef log fill:#d6fd88,stroke:#000,stroke-width:2px,color:#000
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Command line
|
|
99
|
+
|
|
100
|
+
1. The developer uses the command line to trigger setup without a folder name which triggers `Log` without a folder name. `Log` creates a name and creates the artifacts folder, then stores files in that folder.
|
|
101
|
+
2. The developer uses the command line to trigger `run_cucumber` without a folder name which triggers `Log` without a folder name. `Log` creates and saves a new folder name in `runtime_config.json`, and creates the artifacts folder. The `run_cucumber` process also triggers the core code, which uses the folder name in `runtime_config.json` to create its own `Log`. The core code also uses that name to store other artifact files in the folder.
|
|
102
|
+
3. The developer uses the command line to trigger `takedown` without a folder name which triggers `Log` without a folder name. `Log` creates a name and the artifacts folder, then stores files in that folder.
|
|
103
|
+
|
|
104
|
+
```mermaid
|
|
105
|
+
flowchart LR
|
|
106
|
+
cmd1[command line] --> setup
|
|
107
|
+
setup["setup"] --> log1["#96;Log#96;"]:::log
|
|
108
|
+
log1 --store name in/ignore--> runtime1["runtime config file"]
|
|
109
|
+
log1 --create with/use with name--> folder1[folder]
|
|
110
|
+
|
|
111
|
+
cmd2[command line] --> run["run"]
|
|
112
|
+
run --> log2["#96;Log#96;"]:::log
|
|
113
|
+
log2 --store name in/ignore--> runtime2["runtime config file"]
|
|
114
|
+
log2 --create with name--> folder2[folder]
|
|
115
|
+
run --> core["core code"]
|
|
116
|
+
core --> log3["#96;Log#96;"]:::log
|
|
117
|
+
core --use with name--> folder2
|
|
118
|
+
core --get name from--> runtime2
|
|
119
|
+
log3 --use with name--> folder2
|
|
120
|
+
log3 --store name in/ignore--> runtime2
|
|
121
|
+
|
|
122
|
+
cmd3[command line] --> takedown["takedown"]
|
|
123
|
+
takedown --> log4["#96;Log#96;"]:::log
|
|
124
|
+
log4 --store name in/ignore--> runtime3["runtime config file"]
|
|
125
|
+
log4 --create with name--> folder5[folder]
|
|
126
|
+
|
|
127
|
+
classDef log fill:#d6fd88,stroke:#000,stroke-width:2px,color:#000
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Alternatives considered
|
|
131
|
+
|
|
132
|
+
- One script for creating the artifacts folder name: Make a script that saves the folder name to the ALKiln `runtime_config.json`. Then all the other code, including instances of `Log`, would always use `runtime_config.json`. We would want `package.json` scripts for the command line environment that would include getting the name of the folder. That potentially complicates the code and process for internal development. We will see how our current design behaves first.
|
|
133
|
+
- Use `Log`'s path name instead of the one in `runtime_config.json`. We thought we would want to save in previous artifacts folders, but it now seems potentially unnecessary. This seems the most viable option for the future, but it is unclear how we can integrate `Log` with all the other files. I wouldn't consider PDFs and screenshots to be logs.
|
|
134
|
+
|
|
135
|
+
[^1]: **Core framework code/core code:** the code that implements the Steps in the `.feature` test files.
|