@suffolklitlab/alkiln 5.15.4 → 5.16.0-fix-artifacts

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.
@@ -0,0 +1,69 @@
1
+ name: Use docassemble image version
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+ workflow_dispatch:
7
+ inputs:
8
+ show_docker_output:
9
+ required: false
10
+ default: false
11
+ type: boolean
12
+ 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.'
13
+ # Experimental
14
+ enable_tmate:
15
+ type: boolean
16
+ description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
17
+ required: false
18
+ default: false
19
+
20
+ jobs:
21
+
22
+ github-server-tests:
23
+ # Avoids running double tests when someone on the team makes a pull request
24
+ # 1: Trigger job on push or dispatch from this repository
25
+ # 2: Trigger job on pull request from a fork
26
+ if: (
27
+ github.event_name != 'pull_request'
28
+ && ! github.event.pull_request.head.repo.fork
29
+ ) || (
30
+ github.event_name == 'pull_request'
31
+ && github.event.pull_request.head.repo.fork
32
+ )
33
+ runs-on: ubuntu-latest
34
+ strategy:
35
+ matrix:
36
+ node-version: [24.x]
37
+
38
+ steps:
39
+ # Place the root directory in this branch to access relative paths to
40
+ # action files
41
+ - uses: actions/checkout@v4
42
+
43
+ - name: "ALKiln - Use a specific docassemble image version to start the isolated temporary docassemble server on GitHub"
44
+ id: github_server
45
+ uses: ./action_for_github_server
46
+ with:
47
+ SHOW_DOCKER_OUTPUT: "${{ github.event.inputs.show_docker_output }}"
48
+ DOCASSEMBLE_IMAGE: "ghcr.io/suffolklitlab/docassemble:sha-7d13853"
49
+ - run: echo "ALKiln finished starting the isolated GitHub docassemble server"
50
+ shell: bash
51
+
52
+ ## Optional debugging to explore things like docker issues
53
+ #- name: Docker debug tmate session
54
+ # #if: ${{ failure() && github.event.inputs.enable_tmate == 'true' }}
55
+ # uses: mxschmitt/action-tmate@v3
56
+
57
+ - name: "ALKiln - Confirm docassemble packages get installed correctly"
58
+ if: ${{ success() }}
59
+ id: alkiln
60
+ uses: ./
61
+ with:
62
+ # Required inputs. See
63
+ # https://assemblyline.suffolklitlab.org/docs/alkiln/writing/#sandbox-inputs
64
+ SERVER_URL: "${{ steps.github_server.outputs.SERVER_URL }}"
65
+ DOCASSEMBLE_DEVELOPER_API_KEY: "${{ steps.github_server.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}"
66
+ INSTALL_METHOD: "server"
67
+ _ALKILN_INTERNAL_TESTS: "true"
68
+ ALKILN_TAG_EXPRESSION: "@e3" # One very simple test
69
+ ALKILN_VERSION: "action_outputs"
@@ -157,10 +157,37 @@ jobs:
157
157
  SERVER_URL: "${{ steps.github_server.outputs.SERVER_URL }}"
158
158
  DOCASSEMBLE_DEVELOPER_API_KEY: "${{ steps.github_server.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}"
159
159
  INSTALL_METHOD: "server"
160
- #### Developer note: You can probably leave the rest out
160
+ #### Developer note: Optional inputs. You can probably leave the rest out
161
161
  #### To learn more, see https://assemblyline.suffolklitlab.org/docs/alkiln/writing/#optional-inputs
162
162
  ALKILN_TAG_EXPRESSION: "${{ env.ALKILN_TAG_EXPRESSION }}"
163
- # ALKILN_VERSION:
163
+ _ALKILN_INTERNAL_TESTS: "true"
164
+ ALKILN_VERSION: "action_outputs"
165
+
166
+ #### Developer note: You can leave out this section
167
+ # Test our own action output
168
+ - shell: bash
169
+ if: ${{ always() }}
170
+ env:
171
+ GH_TOKEN: ${{ github.token }}
172
+ PATH_TO_ARTIFACTS: "${{ steps.alkiln.outputs.PATH_TO_ARTIFACTS }}"
173
+ PATH_TO_REPORT_FILE: "${{ steps.alkiln.outputs.PATH_TO_REPORT_FILE }}"
174
+ PATH_TO_REPORT_LOG_FILE: "${{ steps.alkiln.outputs.PATH_TO_REPORT_LOG_FILE }}"
175
+ PATH_TO_UNEXPECTED_RESULTS_FILE: "${{ steps.alkiln.outputs.PATH_TO_UNEXPECTED_RESULTS_FILE }}"
176
+ PATH_TO_DEBUG_LOG_FILE: "${{ steps.alkiln.outputs.PATH_TO_DEBUG_LOG_FILE }}"
177
+ run: |
178
+ echo "PATH_TO_ARTIFACTS: $PATH_TO_ARTIFACTS"
179
+ echo "PATH_TO_REPORT_FILE: $PATH_TO_REPORT_FILE"
180
+ echo "PATH_TO_REPORT_LOG_FILE: $PATH_TO_REPORT_LOG_FILE"
181
+ echo "PATH_TO_UNEXPECTED_RESULTS_FILE: $PATH_TO_UNEXPECTED_RESULTS_FILE"
182
+ echo "PATH_TO_DEBUG_LOG_FILE: $PATH_TO_DEBUG_LOG_FILE"
183
+
184
+ # Test accessing the report file
185
+ if [ -f "${{ env.PATH_TO_REPORT_FILE }}" ]; then
186
+ REPORT_TEXT=$(cat "${{ env.PATH_TO_REPORT_FILE }}")
187
+ echo "The report file exists and we can get its text"
188
+ else
189
+ echo "The report file does not exist. Something other than the interview tests may have failed."
190
+ fi
164
191
 
165
192
  #### Developer note: Example of making an issue when tests fail
166
193
  #### that includes the text of the failure output file
@@ -176,13 +203,13 @@ jobs:
176
203
  # Make an issue with file contents or 'no file' message as part of the body
177
204
 
178
205
  if [ -f "${{ env.PATH_TO_UNEXPECTED_RESULTS_FILE }}" ]; then
179
- UNEXPECTED_2=$(cat "${{ env.PATH_TO_UNEXPECTED_RESULTS_FILE }}")
206
+ UNEXPECTED_RESULTS_TEXT=$(cat "${{ env.PATH_TO_UNEXPECTED_RESULTS_FILE }}")
180
207
  else
181
- UNEXPECTED_2="unexpected_results.txt does not exist. Something other than the interview tests may have failed."
208
+ UNEXPECTED_RESULTS_TEXT="unexpected_results.txt does not exist. Something other than the interview tests may have failed."
182
209
  fi
183
210
 
184
211
  gh issue create --body "An ALKiln test run failed. See the action at ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}.
185
212
 
186
213
  ### Results:
187
214
 
188
- $UNEXPECTED_2" --repo "$GITHUB_REPOSITORY" --label "testing" --title "ALKiln tests failed"
215
+ $UNEXPECTED_RESULTS_TEXT" --repo "$GITHUB_REPOSITORY" --label "testing" --title "ALKiln tests failed"
@@ -1,7 +1,6 @@
1
1
  name: Playground installation
2
2
 
3
3
  on:
4
- push:
5
4
  pull_request:
6
5
  workflow_dispatch:
7
6
  inputs:
@@ -9,6 +8,8 @@ on:
9
8
  required: False
10
9
  description: 'Optional. Use a "tag expression" specify which tagged tests to run (https://cucumber.io/docs/cucumber/api/#tag-expressions)'
11
10
  default: ''
11
+ schedule:
12
+ - cron: "0 1 * * SUN"
12
13
 
13
14
  jobs:
14
15
 
@@ -32,7 +33,7 @@ jobs:
32
33
 
33
34
  env:
34
35
  #### Developer note: We recommend turning these into environment
35
- #### variables before using them as inputs later
36
+ #### variables, like we do here, before using them as inputs later
36
37
  SERVER_URL: ${{ secrets.SERVER_URL }}
37
38
  DOCASSEMBLE_DEVELOPER_API_KEY: ${{ secrets.DOCASSEMBLE_DEVELOPER_API_KEY }}
38
39
 
@@ -78,8 +79,9 @@ jobs:
78
79
  #### You can probably leave this out
79
80
  ALKILN_MAX_RANDOM_TESTS_PER_SCENARIO: 10
80
81
  # Internal: docassemble changes sometimes break @a11y tests. That is
81
- # a da problem, not ours. We will trigger these tests manually when we
82
+ # a da problem, not ours. We must trigger @a11y tests manually when we
82
83
  # want to check up on this.
84
+ #### Developer note: Optional inputs. You can probably leave the rest out
83
85
  ALKILN_TAG_EXPRESSION: "${{ env.ALKILN_TAG_EXPRESSION }}"
84
- #### Developer note: You can probably leave this out
85
- # ALKILN_VERSION:
86
+ _ALKILN_INTERNAL_TESTS: "true"
87
+ ALKILN_VERSION: "action_outputs"
package/CHANGELOG.md CHANGED
@@ -43,7 +43,40 @@ Format:
43
43
  -
44
44
  -->
45
45
 
46
- <!-- ## [Unreleased] -->
46
+ ## [Unreleased]
47
+
48
+ ### Added
49
+
50
+ - Added `_ALKILN_INTERNAL_TESTS` action.yml input to allow us to skip some security flags to install and test our development releases of ALKiln.
51
+
52
+ ### Changed
53
+
54
+ - In action.yml, temporarily (we hope) replaced `npm rebuild` with an explicit search for existing puppeteer chrome executables. There is no fallback if all of those are missing. Addresses [#1088](https://github.com/suffolkLITLab/aLKiln/issues/1088). We hope to find a proper fix in the future.
55
+
56
+ ### Fixed
57
+ - Artifacts were being created in the wrong dir when using the main action.yml in GitHub actions. See [#1055](https://github.com/suffolkLITLab/aLKiln/issues/1055). We will have to release a temporary fix in the action to let people run passing tests until the week is up and the fix passes our new security measures.
58
+
59
+
60
+ ## [5.16.0] - 2026-05-14
61
+
62
+ ### Added
63
+
64
+ - Adds a new optional parameter to `action_for_github_server/action.yml`, the full name of the docassemble image. It defaults to `jhpyle/docassemble:latest`, what we previously used, but can also be changed to an earlier version (`jhpyle/docassemble:1.9.8`) or a different fork of docassemble (`ghcr.io/suffolklitlab/docassemble:latest`). Note that old docassemble versions may sometimes get removed.
65
+
66
+ ### Changed
67
+
68
+ - Changed the default version of docassemblecli to 0.0.25
69
+ - Use `cwd` as the base of file paths. Motivated by ALKiP's upcoming need to change the way it handles its own file paths.
70
+ - Handle curl failures while waiting for docassemble server startup. Wrapped the curl call with set +e / set -e so GitHub Actions does not exit on curl failures. All non-zero curl exit codes are treated as "not ready yet" and retried - this covers transient errors like exit code 56 (connection dropped) and exit code 7 (connection refused) that may come up during startup. Added a comment explaining the permissive approach. Changed response value from "000" to "missing" for clarity in logs. See [#1044](https://github.com/SuffolkLITLab/ALKiln/issues/1044).
71
+
72
+ ### Fixed
73
+
74
+ - Print error correctly when missing sources paths
75
+ - Changed the default version of docassemblecli to 0.0.25
76
+
77
+ ### Security
78
+
79
+ - Security: Gave our main action's `npm install` call the arguments ` --ignore-scripts --min-release-age=7` to improve security against malicious `pre-install` and `post-install` scripts. See [#1053](https://github.com/SuffolkLITLab/ALKiln/issues/1053).
47
80
 
48
81
  ## [5.15.4] - 2025-11-29
49
82
 
@@ -1235,4 +1268,4 @@ Note: published on incorrect commit
1235
1268
  - `example.feature` - an example test to get a project started
1236
1269
  - `github/workflows/run_form_tests.yml` - Automated github workflow to run tests when code is pushed and a manual trigger for testing without needing to push
1237
1270
  - `.gitignore` - ignores files that are generated by the tests and shouldn't be added to the repo
1238
- - `package.json` - keep up-to-date version of this test repository and hold scripts that the automated tests run
1271
+ - `package.json` - keep up-to-date version of this test repository and hold scripts that the automated tests run
package/action.yml CHANGED
@@ -37,6 +37,11 @@ inputs:
37
37
  description: "The maximum number of tests ALKiln will generate for every Scenario that can generate tests."
38
38
  required: false
39
39
  # Default will be internal to avoid duplication of data
40
+ _ALKILN_INTERNAL_TESTS:
41
+ description: "If true, will use different security settings."
42
+ type: boolean
43
+ required: false
44
+ default: false
40
45
 
41
46
  outputs:
42
47
  PATH_TO_ARTIFACTS:
@@ -115,12 +120,60 @@ runs:
115
120
  with:
116
121
  node-version: "24.x"
117
122
  package-manager-cache: false
118
- - name: "💡 ALK0026 INFO: Install ALKiln directly from npm"
123
+
124
+ # For regular authors
125
+ - name: "💡 ALK0026 INFO: Install ALKiln directly from npm (at least 7 days old)"
126
+ if: ${{ inputs._ALKILN_INTERNAL_TESTS != true }}
119
127
  shell: bash
120
128
  run: |
121
129
  log="💡 ALK0026 INFO: Install ALKiln directly from npm"
130
+ repo_name="${{ github.event.repository.name }}"
131
+ if [[ $repo_name == *"ALKiln"* ]]; then
132
+ echo "⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️ YOU MAY BE MISSING THE _ALKILN_INTERNAL_TESTS FLAG ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️"
133
+ fi
122
134
  echo -e "\n$log" >> "${{ env.DEBUG_PATH }}"
123
- npm install -g "@suffolklitlab/alkiln@$ALKILN_VERSION"
135
+ if [[ $repo_name == *"ALKiln"* ]]; then
136
+ echo "⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️"
137
+ fi
138
+ npm install --ignore-scripts --min-release-age=7 -g "@suffolklitlab/alkiln@$ALKILN_VERSION"
139
+
140
+ # For internal development, allow testing with more recent versions of ALKiln
141
+ - name: "🔎 ALK0279 WARNING: Install recent version of ALKiln directly from npm"
142
+ if: ${{ inputs._ALKILN_INTERNAL_TESTS == true }}
143
+ shell: bash
144
+ run: |
145
+ log="🔎 ALK0279 WARNING: Install **recent** version of ALKiln directly from npm"
146
+ repo_name="${{ github.event.repository.name }}"
147
+ if [[ $repo_name != *"ALKiln"* ]]; then
148
+ echo "⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️ YOU MAY BE USING AN UNSAFE VERSION OF ALKILN ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️"
149
+ fi
150
+ echo -e "\n$log" >> "${{ env.DEBUG_PATH }}"
151
+ if [[ $repo_name != *"ALKiln"* ]]; then
152
+ echo "⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️"
153
+ fi
154
+ npm install --ignore-scripts -g "@suffolklitlab/alkiln@$ALKILN_VERSION"
155
+
156
+ # Install puppeteer browser that we skipped with security feature --ignore-scripts
157
+ - name: "💡 ALK0280 INFO: Install puppeteer browser that we skipped with security feature --ignore-scripts"
158
+ if: ${{ inputs._ALKILN_INTERNAL_TESTS == true }}
159
+ shell: bash
160
+ run: |
161
+ BROWSER="$(
162
+ command -v google-chrome-stable ||
163
+ command -v google-chrome ||
164
+ command -v chrome ||
165
+ command -v chromium-browser ||
166
+ command -v chromium ||
167
+ true
168
+ )"
169
+ if [[ -n "$BROWSER" ]]; then
170
+ echo "💡 ALK0280 INFO: Found puppeteer browser executable at '$BROWSER'"
171
+ echo "PUPPETEER_EXECUTABLE_PATH=$BROWSER" >> "$GITHUB_ENV"
172
+ else
173
+ echo "🤕 ALK0281 INFO: Unable to find puppeteer browser executable"
174
+ # Our project uses bash error codes in the 50's. This may change.
175
+ exit 51
176
+ fi
124
177
 
125
178
  # Files prep
126
179
  - shell: bash
@@ -23,10 +23,14 @@ inputs:
23
23
  description: "Default is 600 seconds. Maximum amount of seconds to give the docassemble docker container to serve the site."
24
24
  required: false
25
25
  default: 600 # 10 min
26
+ DOCASSEMBLE_IMAGE:
27
+ description: "The specific docassemble image to use."
28
+ required: false
29
+ default: jhpyle/docassemble
26
30
  DOCASSEMBLECLI_VERSION:
27
31
  description: "The version of docassemblecli to install."
28
32
  required: false
29
- default: "0.0.17"
33
+ default: "0.0.25"
30
34
 
31
35
  outputs:
32
36
  DOCASSEMBLE_DEVELOPER_API_KEY:
@@ -155,35 +159,37 @@ runs:
155
159
  if: ${{ env.OUTPUT_DOCKER == 'false' }}
156
160
  env:
157
161
  CONFIG_ARGS: ${{ env.CONFIG_ARGS }}
162
+ DOCASSEMBLE_IMAGE: "${{ inputs.DOCASSEMBLE_IMAGE }}"
158
163
  shell: bash
159
164
  run: |
160
165
  log="💡 ALK0009 INFO: Download and start docker silently"
161
166
  echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}"
162
- docker pull jhpyle/docassemble > /dev/null 2>&1
167
+ docker pull "$DOCASSEMBLE_IMAGE" > /dev/null 2>&1
163
168
  docker run --name docassemble_container \
164
169
  --env DA_ADMIN_EMAIL="$DA_ADMIN_EMAIL" \
165
170
  --env DA_ADMIN_PASSWORD="$DA_ADMIN_PASSWORD" \
166
171
  --env DA_ADMIN_API_KEY="$DA_ADMIN_API_KEY" \
167
172
  $CONFIG_ARGS \
168
173
  --cap-add SYS_PTRACE \
169
- --memory="4gb" -d -p 80:80 jhpyle/docassemble > /dev/null 2>&1
174
+ --memory="4gb" -d -p 80:80 "$DOCASSEMBLE_IMAGE" > /dev/null 2>&1
170
175
  # With output
171
176
  - name: "💡 ALK0010 INFO: Download and start docker"
172
177
  if: ${{ env.OUTPUT_DOCKER == 'true' }}
173
178
  env:
174
179
  CONFIG_ARGS: ${{ env.CONFIG_ARGS }}
180
+ DOCASSEMBLE_IMAGE: "${{ inputs.DOCASSEMBLE_IMAGE }}"
175
181
  shell: bash
176
182
  run: |
177
183
  log="💡 ALK0010 INFO: Download and start docker"
178
184
  echo -e "\n$log" >> "${{ env.DEBUG_LOGS_PATH }}"
179
- docker pull jhpyle/docassemble
185
+ docker pull "$DOCASSEMBLE_IMAGE"
180
186
  docker run --name docassemble_container \
181
187
  --env DA_ADMIN_EMAIL="$DA_ADMIN_EMAIL" \
182
188
  --env DA_ADMIN_PASSWORD="$DA_ADMIN_PASSWORD" \
183
189
  --env DA_ADMIN_API_KEY="$DA_ADMIN_API_KEY" \
184
190
  $CONFIG_ARGS \
185
191
  --cap-add SYS_PTRACE \
186
- --memory="4gb" -d -p 80:80 jhpyle/docassemble
192
+ --memory="4gb" -d -p 80:80 "$DOCASSEMBLE_IMAGE"
187
193
 
188
194
  # Section for showing the time it takes to start the server.
189
195
 
@@ -213,14 +219,25 @@ runs:
213
219
 
214
220
  # Check if max seconds till loading has passed
215
221
  if [[ $SECONDS -ge $MAX_SECONDS_FOR_DOCKER ]]; then
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."
222
+ log3="🤕 ALK0014 ERROR: Timed out waiting for docker container to serve the site. If you want to give your docker container more time to install, set the MAX_SECONDS_FOR_DOCKER input for this action."
217
223
  echo -e "\n$log3" >> "${{ env.DEBUG_LOGS_PATH }}" && echo -e "$log3"
218
224
  exit 1
219
225
  fi
220
226
 
221
227
  # Set the variable to a new string value in each iteration
222
- response=$(curl -o /dev/null -s -w "%{http_code}\n" http://localhost:80/health_check?ready=1)
223
- log4="💡 ALK0015 INFO: Response is $response"
228
+ # We intentionally skip all non-zero curl exit codes here instead of handling specific ones.
229
+ # During server startup there are several transient errors that can come up and since we already log the exit code and have a timeout,
230
+ # retrying on all of them is safer than trying to maintain a list of specific codes to handle.
231
+ set +e
232
+ response=$(curl -o /dev/null -s -w "%{http_code}" http://localhost:80/health_check?ready=1)
233
+ status=$?
234
+ set -e
235
+
236
+ if [[ $status -ne 0 ]]; then
237
+ response="missing"
238
+ fi
239
+
240
+ log4="💡 ALK0015 INFO: Response is $response (curl exit code: $status)"
224
241
  echo -e "\n$log4" >> "${{ env.DEBUG_LOGS_PATH }}" && echo -e "$log4"
225
242
 
226
243
  # Check if the string includes the desired text
@@ -228,7 +245,7 @@ runs:
228
245
  log5="💡 ALK0016 SUCCESS: Success! The docker container is ready!"
229
246
  echo -e "\n$log5" >> "${{ env.DEBUG_LOGS_PATH }}" && echo -e "$log5"
230
247
  else
231
- log6="💡 ALK0017 INFO: The docker container is not ready yet. Will check again in 30 seconds."
248
+ log6="💡 ALK0017 INFO: The docker container is not ready yet (HTTP=$response, curl exit code=$status). Will check again in 30 seconds."
232
249
  echo -e "\n$log6" >> "${{ env.DEBUG_LOGS_PATH }}" && echo -e "$log6"
233
250
  sleep 30
234
251
  fi
@@ -0,0 +1,17 @@
1
+ # Root path
2
+
3
+ This code assumes the current working directory (cwd) will contain the necessary files and folders to get files like `.feature` files and the test run runtime config file.
4
+
5
+ When you run ALKiln on the command line, run the tests in the root directory of the docassemble package with the tests. There are other ways to tell processes where the root directory is. For example, ALKiP, a docassemble package that uses ALKiln inside an author's server, runs `subprocess.run()` or `subprocess.Popen()` with `cwd=`. In ALKiP the `cwd` is most likely `/tmp`.
6
+
7
+ Files that make this root path assumption:
8
+
9
+ - lib/utils/set_sources_paths.js
10
+ - lib/utils/files.js
11
+ - lib/utils/session_vars.js
12
+
13
+ ALKiln makes assumptions about specific folder names inside the root directory. See `lib/utils/set_sources_paths.js` and `validate.js` for where it looks for `.feature` files.
14
+
15
+ ## Anti-goals
16
+
17
+ It is possible for us to make the root path configurable in a few ways (env vars, command line args, etc.), but we are avoiding adding that maintenance cost until we see a need.
package/lib/scope.js CHANGED
@@ -2768,7 +2768,7 @@ module.exports = {
2768
2768
  pic_name = `pic_on-${ short_id }-${ timestamp }`;
2769
2769
  }
2770
2770
 
2771
- await scope.take_a_screenshot( scope, { path: `./${ scope.paths.scenario }/${ pic_name }.jpg` });
2771
+ await scope.take_a_screenshot( scope, { path: `${ scope.paths.scenario }/${ pic_name }.jpg` });
2772
2772
 
2773
2773
  await scope.afterStep( scope );
2774
2774
  }, // Ends scope.steps.screenshot()
@@ -2,19 +2,24 @@
2
2
 
3
3
  const session_vars = require(`../utils/session_vars`);
4
4
  const files = require(`../utils/files`);
5
- const Log = require(`../setup/artifacts.js`);
5
+ const Log = require(`../utils/Log.js`);
6
6
 
7
- /** Reset and refresh artifacts path name */
7
+ /**
8
+ * Reset and refresh artifacts path name. Use this at the start of every test
9
+ * run for that run's unique results.
10
+ * */
8
11
 
9
12
  session_vars.delete_artifacts_path_name();
10
13
 
11
14
  // process.argv is a list of strings of commands and args.
12
- // If using `npm run cucumber` (as opposed to the bin commands),
13
- // use `--` before `--sources=./foo`
14
- const argv = require(`minimist`)( process.argv.slice(2) );
15
- const artifacts_path = files.make_artifacts_folder( argv.path );
16
-
15
+ // If using `npm run artifacts` (as opposed to the bin commands),
16
+ // use `--` before, for example, `--sources=./foo`
17
+ // Envs like action.yml reuse their own .path when return vals are hard to get
18
+ const forced_path = require(`minimist`)( process.argv.slice(2) )?.path;
19
+ const artifacts_path = files.make_artifacts_folder( forced_path );
17
20
  session_vars.save_artifacts_path_name( artifacts_path );
18
21
 
19
- // Leave the config Project name value as it is. Local developers find it
20
- // useful to re-use that value.
22
+ const log = new Log({ path: artifacts_path, context: `artifacts` });
23
+ log.info({ code: `ALK0278`, context: `artifacts`,},
24
+ `Created the artifacts folder at "${ artifacts_path }"`
25
+ );
package/lib/utils/Log.js CHANGED
@@ -228,6 +228,7 @@ class Log {
228
228
  }
229
229
 
230
230
  if ( !fs.existsSync( dir )) {
231
+ process.stdout.write(`Making artifacts folder in Log at ${ dir }`)
231
232
  files.make_artifacts_folder( dir );
232
233
  }
233
234
 
@@ -1,5 +1,6 @@
1
1
  const fs = require('fs');
2
2
  const safe_filename = require('sanitize-filename');
3
+ const path = require(`path`);
3
4
 
4
5
  let files = {};
5
6
 
@@ -21,27 +22,30 @@ files.readable_date = function() {
21
22
  return fancy_str;
22
23
  }; // Ends files.readable_date()
23
24
 
24
- files.make_artifacts_folder = function (path) {
25
+ files.make_artifacts_folder = function ( file_path ) {
25
26
  /** Makes a folder in the root of the project if it doesn't
26
27
  * already exist, either with the given name or with a default name.
27
28
  *
28
29
  * Works for local development as well, without action.yml or workflow files.
29
30
  * */
30
- if (path) {
31
- let name_parts = path.split(`/`);
31
+ if (file_path) {
32
+ let name_parts = file_path.split(`/`);
32
33
  let safe_parts = [];
33
34
  for ( let part of name_parts ) {
34
35
  safe_parts.push(safe_filename( part ));
35
36
  }
36
- path = safe_parts.join(`/`);
37
+ file_path = path.join( ...safe_parts );
37
38
  } else {
38
- path = `alkiln-${ files.readable_date() }`
39
+ file_path = `alkiln-${ files.readable_date() }`
39
40
  }
40
41
 
42
+ const root = process.cwd();
43
+ root_path = path.join( root, file_path );
44
+
41
45
  // `recursive` avoids errors if folder already exists
42
46
  // https://nodejs.org/docs/latest-v18.x/api/fs.html#fspromisesmkdirpath-options
43
- fs.mkdirSync( path, { recursive: true });
44
- return path;
47
+ fs.mkdirSync( root_path, { recursive: true });
48
+ return root_path;
45
49
  }; // Ends files.make_artifacts_folder()
46
50
 
47
51
  module.exports = files;
@@ -52,6 +52,10 @@ session_vars.get_origin = function () {
52
52
  };
53
53
  session_vars.get_user_project_name = function () { return process.env._PROJECT_NAME || null; };
54
54
  session_vars.get_user_id = function () { return process.env._USER_ID || null; };
55
+ session_vars.get_runtime_config_path = function () {
56
+ const root = process.cwd(); // absolute path just to be sure
57
+ return path.join( root, `runtime_config.json` );
58
+ }
55
59
 
56
60
  // More complex logic
57
61
  session_vars.get_server_reload_timeout = function () {
@@ -133,7 +137,6 @@ session_vars.get_languages = function () {
133
137
  }; // Ends session_vars.get_languages()
134
138
 
135
139
 
136
- const runtime_config_path = `runtime_config.json`;
137
140
  const project_name_key = `da_project_name`;
138
141
  session_vars.save_project_name = function ( project_name ) {
139
142
  /* Saves the name of the project to a json obj so deletion can use it later.
@@ -142,6 +145,7 @@ session_vars.save_project_name = function ( project_name ) {
142
145
  * Should we try to prevent someone overwriting a previous project name?
143
146
  *
144
147
  * @param project_name { string } - purely alphanumeric string */
148
+ const runtime_config_path = session_vars.get_runtime_config_path();
145
149
 
146
150
  // Warn local developers if file already exists
147
151
  if ( fs.existsSync( runtime_config_path ) ) {
@@ -172,6 +176,8 @@ session_vars.get_project_name = function () {
172
176
  if ( session_vars.get_origin() === 'playground' ) {
173
177
  return session_vars.get_user_project_name();
174
178
  }
179
+
180
+ const runtime_config_path = session_vars.get_runtime_config_path();
175
181
  let json = JSON.parse( fs.readFileSync( runtime_config_path ));
176
182
  let project_name = json[ project_name_key ] || null;
177
183
  if ( session_vars.get_debug() ) { console.debug( `🐛 ALK0037 DEBUG: Project name from file is "${ project_name }".` ); }
@@ -180,6 +186,7 @@ session_vars.get_project_name = function () {
180
186
 
181
187
  session_vars.delete_project_name = function () {
182
188
  /* Empty the key storing the name of the docassemble Project */
189
+ const runtime_config_path = session_vars.get_runtime_config_path();
183
190
  try {
184
191
  // Get the json, changing it, and re-write the file from scratch
185
192
  let json = JSON.parse( fs.readFileSync( runtime_config_path ));
@@ -252,6 +259,7 @@ session_vars.save_runtime_config_var = function ({ key, value }) {
252
259
  *
253
260
  * @returns {binary?} file Runtime config file
254
261
  */
262
+ const runtime_config_path = session_vars.get_runtime_config_path();
255
263
 
256
264
  // Ensure runtime config file exists
257
265
  if ( !fs.existsSync( runtime_config_path ) ) {
@@ -277,6 +285,7 @@ session_vars.get_runtime_config_var = function ( key ) {
277
285
  *
278
286
  * @returns {any} - Value of given key in runtime config file or null
279
287
  */
288
+ const runtime_config_path = session_vars.get_runtime_config_path();
280
289
  try {
281
290
  let json = JSON.parse( fs.readFileSync( runtime_config_path ));
282
291
  let value = json[ key ];
@@ -300,6 +309,7 @@ session_vars.delete_runtime_config_var = function ({ key }) {
300
309
  *
301
310
  * @returns {null}
302
311
  * */
312
+ const runtime_config_path = session_vars.get_runtime_config_path();
303
313
  try {
304
314
  if ( !fs.existsSync( runtime_config_path )) { return null; }
305
315
 
@@ -1,4 +1,5 @@
1
1
  const fast_glob = require(`fast-glob`);
2
+ const path = require(`path`);
2
3
 
3
4
  const session_vars = require(`./session_vars`);
4
5
 
@@ -18,7 +19,7 @@ module.exports = function set_sources_paths({ log }) {
18
19
  let maybe_paths = get_potential_paths();
19
20
 
20
21
  let sources_paths = get_sources_paths({ maybe_paths });
21
- if ( sources_paths === 0 ) {
22
+ if ( sources_paths.length === 0 ) {
22
23
  // If we don't throw, it'll be more confusing when no tests run
23
24
  log.throw({ code: `ALK0050`, context: `sources`,
24
25
  error: new ReferenceError(
@@ -45,6 +46,7 @@ function get_potential_paths() {
45
46
  // `project` is the name in the server docassemble "Project" page
46
47
  let project = session_vars.get_user_project_name();
47
48
  let id = session_vars.get_user_id();
49
+ let root = process.cwd(); // Assumes correct root. See docs about root path.
48
50
 
49
51
  // process.argv is a list of strings of commands and args.
50
52
  // Internal note: If using `npm run cucumber`, use `--` before
@@ -53,8 +55,8 @@ function get_potential_paths() {
53
55
  default: {
54
56
  sources: [
55
57
  `./docassemble/*/data/sources`, // In GitHub folder
56
- `/usr/share/docassemble/files/playgroundsources/${id}/${project}/*.feature`, // From playground without S3
57
- `/tmp/playgroundsources/${id}/${project}/*.feature` // From playground with S3
58
+ `/usr/share/docassemble/files/playgroundsources/${id}/${project}`, // From playground without S3
59
+ path.join( root, `/playgroundsources/${id}/${project}`), // From playground with S3
58
60
  ],
59
61
  }
60
62
  });
@@ -81,16 +83,16 @@ function get_sources_paths({ maybe_paths }) {
81
83
  // Check every path, tracking which exist and which are missing
82
84
  let existing_paths = [];
83
85
  let missing_paths = [];
84
- for ( let path of maybe_paths ) {
86
+ for ( let maybe_path of maybe_paths ) {
85
87
  let dirs = fast_glob.sync(
86
- [ path ],
88
+ [ maybe_path ],
87
89
  { onlyFiles: false, suppressErrors: true }
88
90
  );
89
91
 
90
92
  if ( dirs.length > 0 ) {
91
93
  existing_paths.push( ...dirs );
92
94
  } else {
93
- missing_paths.push( path );
95
+ missing_paths.push( maybe_path );
94
96
  }
95
97
  }
96
98
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suffolklitlab/alkiln",
3
- "version": "5.15.4",
3
+ "version": "5.16.0-fix-artifacts",
4
4
  "description": "Integrated automated end-to-end testing with docassemble, puppeteer, and cucumber.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -288,4 +288,8 @@ ALK0273:1
288
288
  ALK0274:1
289
289
  ALK0275:1
290
290
  ALK0276:1
291
- ALK0277:1
291
+ ALK0277:1
292
+ ALK0278:1
293
+ ALK0279:2
294
+ ALK0280:1
295
+ ALK0281:1