@suffolklitlab/alkiln 5.4.0 → 5.4.1-feat-github-server-15

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,85 @@
1
+ name: GitHub server tests
2
+
3
+ on:
4
+ push:
5
+ # `workflow dispatch` isn't showing up in github because it's not the default branch
6
+ # See https://stackoverflow.com/a/75250828
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
+ # # Only test 2 tests - one uses an env var, the other uses AL.
13
+ # # They test if env vars get set correctly and depencencies get
14
+ # # pulled in correctly.
15
+ # default: '@al1'
16
+ enable_tmate:
17
+ type: boolean
18
+ description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
19
+ required: false
20
+ default: false
21
+ # TODO: alkiln_version:
22
+
23
+ jobs:
24
+
25
+ github-server-tests:
26
+ runs-on: ubuntu-latest
27
+ strategy:
28
+ matrix:
29
+ node-version: [18.x]
30
+
31
+ env:
32
+ # How would a dev make another user/password if they wanted to?
33
+ SECRET_VAR1: secret-var1-value
34
+ SECRET_VAR2: secret-var2-value
35
+ SECRET_FOR_MISSING_FIELD: secret for missing field
36
+ #_ALKILN_DANGEROUS_DEBUG: true
37
+
38
+ steps:
39
+ # Place the root directory in this branch
40
+ - uses: actions/checkout@v3
41
+
42
+ # Debugging. Maybe add a long sleep after whatever it is we want to check
43
+ # to give us time to explore.
44
+ - name: Setup tmate session
45
+ if: ${{ inputs.enable_tmate }}
46
+ uses: mxschmitt/action-tmate@v3
47
+ with:
48
+ detached: true
49
+
50
+ - name: Start the temporary GitHub server
51
+ id: github_server
52
+ uses: ./github_server
53
+ with:
54
+ CONFIG_CONTENTS: "${{ secrets.CONFIG_CONTENTS }}"
55
+ - run: echo "Finished starting the GitHub server"
56
+
57
+ # Debugging on failure
58
+ # Trying to catch that intermittent bug mentioned in ./github_server/action.yml
59
+ - name: Docker failure tmate session
60
+ if: ${{ failure() }}
61
+ uses: mxschmitt/action-tmate@v3
62
+
63
+ - name: Env vars from server output
64
+ run: |
65
+ echo "USER1_EMAIL=${{ steps.github_server.outputs.DA_ADMIN_EMAIL }}" >> $GITHUB_ENV
66
+ echo "USER1_PASSWORD=${{ steps.github_server.outputs.DA_ADMIN_PASSWORD }}" >> $GITHUB_ENV
67
+ #- name: Work with docker
68
+ # run: |
69
+ # # Authors can use this to do more with the docker container.
70
+ # # There may be a better way. Would take research. A docker action?
71
+ # container_name=$(docker ps --format '{{.Names}}' | head -n 1)
72
+ # echo "container_name is $container_name"
73
+
74
+ - name: "Run ALKiln tests"
75
+ if: ${{ success() }}
76
+ uses: ./
77
+ with:
78
+ SERVER_URL: "${{ steps.github_server.outputs.SERVER_URL }}"
79
+ DOCASSEMBLE_DEVELOPER_API_KEY: "${{ steps.github_server.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}"
80
+ INSTALL_METHOD: "server"
81
+ # TODO: See what happens if this is an empty string
82
+ ALKILN_VERSION: "5.4.1-feat-github-server-15"
83
+ ALKILN_TAG_EXPRESSION: "@al1"
84
+ - run: echo "Finished running ALKiln tests"
85
+
package/CHANGELOG.md CHANGED
@@ -44,6 +44,11 @@ Format:
44
44
  -->
45
45
  <!-- ## [Unreleased] -->
46
46
 
47
+ ## [5.4.1] - 2023-10-18
48
+
49
+ ### Internal
50
+ - BREAKS ALKilnInThePlayground v1.2.0 and below (as we discussed) as that project is still exploratory. Can now take the location of the "sources" folder or folders as an argument in the command line. The formats are `npm run cucumber @tags -- --sources=./foo` and `alkiln-run @tags --sources=./foo`.
51
+
47
52
  ## [5.4.0] - 2023-10-14
48
53
 
49
54
  ### Added
package/action.yml CHANGED
@@ -22,6 +22,15 @@ inputs:
22
22
  description: "Max amount of time to give the server to reload if it needs to"
23
23
  required: false
24
24
  # no default to let the custom Scenario timeouts create the reload timeout
25
+ # INSTALL_LOCATION? Will that get confused with the location passed into the command line?
26
+ # Maybe `INSTALL_LOCATION` could be "playground", "server", or a custom path and we could handle all those.
27
+ INSTALL_METHOD:
28
+ description: "Default is 'playground'. Other option: 'server'. How to install the package onto the server."
29
+ required: false
30
+ default: "playground"
31
+ ALKILN_TAG_EXPRESSION:
32
+ description: "The tag expression to use to limit which tests to run. Default is no tag expression."
33
+ required: false
25
34
 
26
35
  runs:
27
36
  using: "composite"
@@ -46,29 +55,43 @@ runs:
46
55
  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"
47
56
  shell: bash
48
57
 
49
- # Install node
58
+ # Install
50
59
  - name: "ALKiln: Install node packages"
51
60
  uses: actions/setup-node@v3
52
61
  with:
53
62
  node-version: "18"
54
63
  - name: Install ALKiln directly from npm
55
64
  run: |
56
- npm install -g @suffolklitlab/alkiln
65
+ npm install -g @suffolklitlab/alkiln@$ALKILN_VERSION
57
66
  shell: bash
58
67
 
59
- # Run tests
68
+ # Install on playground
60
69
  - name: "ALKiln: Create a Project and pull the package from GitHub"
70
+ if: ${{ inputs.INSTALL_METHOD == 'playground' }}
61
71
  run: alkiln-setup
62
72
  shell: bash
73
+ - run: echo -e "\n\n====\nALKiln could not create a project on your server's testing account or pull your package into it. Check the messages above this line.\n\n"
74
+ if: ${{ inputs.INSTALL_METHOD == 'playground' && failure() }}
75
+ shell: bash
76
+
77
+ # Install on server
78
+ - name: "ALKiln: Install the GitHub package onto the server"
79
+ if: ${{ inputs.INSTALL_METHOD == 'server' }}
80
+ run: alkiln-server-install
81
+ shell: bash
82
+ - run: echo -e "\n\n====\nALKiln could not install the package on the temporary GitHub docassemble server. Check the steps above this line.\n\n"
83
+ if: ${{ inputs.INSTALL_METHOD == 'server' && failure() }}
84
+ shell: bash
85
+
86
+ # run tests
63
87
  - name: "ALKiln: Run tests"
64
88
  if: ${{ success() }}
65
- run: alkiln-run ${{ github.event.inputs.tags && format('{0}', github.event.inputs.tags) }}
66
- shell: bash
67
- - run: echo -e "\n\n====ALKiln could not create a project on your server's testing account or pull your package into it. Check the messages above this line.\n\n"
68
- if: ${{ failure() }}
89
+ run: alkiln-run ${{ inputs.ALKILN_TAG_EXPRESSION || github.event.inputs.tags && format('{0}', github.event.inputs.tags) }}
69
90
  shell: bash
70
- - name: "ALKiln: Delete project from docassemble test account"
71
- if: ${{ always() }}
91
+
92
+ # on playground, delete project
93
+ - name: "ALKiln: Try to delete the project from the playground of the docassemble test account."
94
+ if: ${{ inputs.INSTALL_METHOD == 'playground' }}
72
95
  run: alkiln-takedown
73
96
  shell: bash
74
97
 
@@ -81,7 +104,7 @@ runs:
81
104
  path: ./alkiln-*
82
105
 
83
106
  # ##################################
84
- # # A developer's workflow should look similar to the below
107
+ # # A developer's workflow should look similar to the below.
85
108
  # # In place of `uses: suffolkLITLab/ALKiln@v5`, they
86
109
  # # might use another version.
87
110
  #
@@ -0,0 +1,165 @@
1
+ name: "ALKiln/github_server: Isolated docassemble tests"
2
+ description: "Download and start up a temporary docassemble server on GitHub's servers, in an isolated environment. Avoids docassemble reload errors and other external factors."
3
+
4
+ # Bug? Race condition? Exit with 52 when waiting for container to finish starting
5
+ # https://github.com/SuffolkLITLab/ALKiln/actions/runs/5912900256/job/16036751264#step:4:188
6
+ # Had no completion messages, but it exited with an error anyway
7
+ # Took 121 seconds
8
+ # The rerun of the test completed that step just fine, though it took less time
9
+ # Took 120 and was fine: https://github.com/SuffolkLITLab/ALKiln/actions/runs/5913167036/job/16037288791
10
+ # 150 secs with exit code 56:
11
+ # https://github.com/SuffolkLITLab/ALKiln/actions/runs/5914677262/job/16040233419#step:4:196
12
+ # 120 sec with exit code 56:
13
+ # https://github.com/SuffolkLITLab/ALKiln/actions/runs/5914963614/job/16040773624#step:4:206
14
+
15
+ # If we want to control the version of the docassemble image, we'd have
16
+ # to make our own image:
17
+ # You can build your own image by doing git clone jhpyle/docassemble and then
18
+ # using git checkout to select a particular version, and then using docker build
19
+ # to build an image. https://docassemble.org/docs/docker.html#downgrading
20
+ # If we just want to use an older version of da (as long as it works with
21
+ # the latest image):
22
+ # If you have an existing container you can use dainstall from the command
23
+ # line to install docassemble.webapp==1.4.68
24
+
25
+ inputs:
26
+ CONFIG_CONTENTS:
27
+ description: "The contents of the config file of the docassemble server"
28
+ required: false
29
+ MAX_SECONDS_FOR_DOCKER:
30
+ description: "Maximum amount of seconds to give the docassemble docker container to serve the site."
31
+ required: false
32
+ default: 600 # 10 min
33
+
34
+ outputs:
35
+ DOCASSEMBLE_DEVELOPER_API_KEY:
36
+ description: "Use this inside `with:` for the ALKiln step. Temporary admin api key. It will be destroyed after the tests are done."
37
+ value: ${{ steps.api_key_output_step.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}
38
+ SERVER_URL:
39
+ description: "Use this inside `with:` for the ALKiln step. URL of the temporary docassemble server."
40
+ value: "http://localhost"
41
+ DA_ADMIN_EMAIL:
42
+ value: ${{ steps.api_key_output_step.outputs.DA_ADMIN_EMAIL }}
43
+ DA_ADMIN_PASSWORD:
44
+ value: ${{ steps.api_key_output_step.outputs.DA_ADMIN_PASSWORD }}
45
+
46
+
47
+ runs:
48
+ using: "composite"
49
+ steps:
50
+ - uses: actions/checkout@v3
51
+
52
+ - name: "ALKiln github_server: Set environment variables"
53
+ run: |
54
+ echo "DA_ADMIN_API_KEY=abcd1234abcd1234abcd5678abdc5678" >> $GITHUB_ENV
55
+ echo "MAX_SECONDS_FOR_DOCKER=${{ inputs.MAX_SECONDS_FOR_DOCKER }}" >> $GITHUB_ENV
56
+ echo "DA_ADMIN_EMAIL=admin@example.com" >> $GITHUB_ENV
57
+ # Login will fail if this is "password"
58
+ echo "DA_ADMIN_PASSWORD=@123abcdefg" >> $GITHUB_ENV
59
+ shell: bash
60
+ - id: api_key_output_step
61
+ run: |
62
+ echo "DOCASSEMBLE_DEVELOPER_API_KEY=$DA_ADMIN_API_KEY" >> "$GITHUB_OUTPUT"
63
+ echo "DA_ADMIN_EMAIL=$DA_ADMIN_EMAIL" >> "$GITHUB_OUTPUT"
64
+ echo "DA_ADMIN_PASSWORD=$DA_ADMIN_PASSWORD" >> "$GITHUB_OUTPUT"
65
+ shell: bash
66
+
67
+ - name: "ALKiln github_server: Download and start docker"
68
+ run: |
69
+ mkdir /tmp/config
70
+ echo "${{ inputs.CONFIG_CONTENTS }}" > /tmp/config/myconfig.yml
71
+ docker pull jhpyle/docassemble
72
+ docker run --env DA_ADMIN_EMAIL="${{ env.DA_ADMIN_EMAIL }}" --env DA_ADMIN_PASSWORD="${{ env.DA_ADMIN_PASSWORD }}" --env DA_ADMIN_API_KEY="${{ env.DA_ADMIN_API_KEY }}" --env DA_CONFIG=/tmp/config/myconfig.yml --volume /tmp/config:/tmp/config --cap-add SYS_PTRACE --memory="4gb" -d -p 80:80 jhpyle/docassemble
73
+ shell: bash
74
+ - name: "ALKiln github_server: Wait for server to start"
75
+ run: |
76
+ # ALKiln github_server: Wait for server to start
77
+
78
+ # Reset the SECONDS variable
79
+ SECONDS=0
80
+ # Wait 1 minute before pinging the server constantly
81
+ sleep 60
82
+
83
+ # Use a variable instead of checking $response so we can control to avoid race
84
+ # conditions from preventing the success log message.
85
+ ready="false"
86
+
87
+ while [[ $ready == "false" ]]; do
88
+ echo "Time ellapsed: $SECONDS seconds"
89
+
90
+ # Check if max seconds till loading has passed
91
+ if [[ $SECONDS -ge $MAX_SECONDS_FOR_DOCKER ]]; then
92
+ echo "ALKiln GitHub Server Error: Timed out waiting for docker container to serve the site. If you want to give your docker container more timem to install, set the MAX_SECONDS_FOR_DOCKER input for this action."
93
+ # Exit with failure, or allow this to keep going?
94
+ break
95
+ fi
96
+
97
+ # Set the variable to a new string value in each iteration
98
+ response=$(curl -o /dev/null -s -w "%{http_code}\n" http://localhost:80/health_check?ready=1)
99
+ echo "response is $response"
100
+
101
+ # Check if the string includes the desired text
102
+ if [[ $response == *"200"* ]]; then
103
+ echo "Success! The docker container is ready!"
104
+ ready="true"
105
+ else
106
+ echo "The docker container isn't ready yet. Will check again in 30 seconds."
107
+ sleep 30
108
+ fi
109
+
110
+ done
111
+ shell: bash
112
+
113
+ # Don't rely on the environment's version of python
114
+ - uses: actions/setup-python@v4
115
+ with:
116
+ python-version: '3.10'
117
+ - run: pip install docassemblecli
118
+ shell: bash
119
+ # Install the current directory onto the docassemble server
120
+
121
+ #- name: Setup tmate session
122
+ # uses: mxschmitt/action-tmate@v3
123
+
124
+ ## da doesn't need to know the name of the folder
125
+ ## alkiln does so it can locate the Project or package installed on the server
126
+ - run: |
127
+ # if `docassemble` cd `docassemble`
128
+ #cd docassemble
129
+ ## Get the name of the package folder
130
+ #dirs2=(*/)
131
+ #len=${#dirs2[@]}
132
+ #if (( $len > 1 ));
133
+ #then echo There are multiple files in your repo's `docassemble` folder. ALkiln will use the first one;
134
+ #fi
135
+ #folder=5
136
+ #
137
+ #
138
+ ## Get back out of the docassemble folder
139
+ #cd ..
140
+ ## Install on server
141
+
142
+ dainstall . --apiurl http://localhost --apikey $DA_ADMIN_API_KEY
143
+ shell: bash
144
+
145
+ # Upload artifacts that subscribers can download on the Actions summary page
146
+ - name: "ALKiln github_server: Docker logs"
147
+ if: ${{ always() }}
148
+ run: |
149
+ docker_logs=$(docker logs $(docker ps --filter "ancestor=jhpyle/docassemble" --format {{.ID}}))
150
+ # Should this name have a date/time attached? The logs themselves have timestamps
151
+ echo "$docker_logs" > /tmp/alkiln_docker_logs.txt
152
+ shell: bash
153
+
154
+ # Should this date/time be created at the start of this action?
155
+ - name: "ALKiln github_server: Get folder name with date and time"
156
+ if: ${{ always() }}
157
+ run: |
158
+ echo "GITHUB_SERVER_ARTIFACT_NAME=alkiln-github-server-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC" >> $GITHUB_ENV
159
+ shell: bash
160
+ - name: "ALKiln github_server: Upload artifacts folder"
161
+ if: ${{ always() }}
162
+ uses: actions/upload-artifact@v3
163
+ with:
164
+ name: ${{ env.GITHUB_SERVER_ARTIFACT_NAME }}
165
+ path: /tmp/alkiln_docker_logs.txt
@@ -79,13 +79,21 @@ da.pull = async function ( timeout ) {
79
79
  }; // Ends da.pull()
80
80
 
81
81
 
82
+ da.has_playground_task_finished = async function ( task_id, timeout ) {
83
+ return await da.has_task_finished( "/api/restart_status", task_id, timeout);
84
+ }
85
+
86
+ da.has_package_task_finished = async function ( task_id, timeout ) {
87
+ return await da.has_task_finished( "/api/package_update_status", task_id, timeout);
88
+ }
89
+
82
90
  // node -e 'require("./lib/docassemble/docassemble_api_REST.js").has_task_finished()'
83
- da.has_task_finished = async function ( task_id, timeout ) {
91
+ da.has_task_finished = async function ( api_endpoint, task_id, timeout ) {
84
92
  /* Check task status based on `task_id`. */
85
93
  let options = {
86
94
  method: 'GET',
87
95
  headers: {'X-API-Key': session_vars.get_dev_api_key()},
88
- url: `${ session_vars.get_da_server_url() }/api/restart_status`,
96
+ url: `${ session_vars.get_da_server_url() }${ api_endpoint }`,
89
97
  params: {
90
98
  task_id: task_id,
91
99
  },
@@ -329,9 +329,8 @@ da_i.pull = async function ( pull_options ) {
329
329
  }
330
330
  }; // Ends da_i.pull()
331
331
 
332
-
333
332
  // node -e 'require("./lib/docassemble/docassemble_api_interface.js").has_task_finished()'
334
- da_i.has_task_finished = async function ( task_id, options ) {
333
+ da_i.has_task_finished = async function ( api_endpoint, task_id, options ) {
335
334
  /** Check task status if it exists. If not, return true as task did
336
335
  * not require a server restart. See da_i.pull().
337
336
  * See https://docassemble.org/docs/api.html#restart_status. */
@@ -342,7 +341,7 @@ da_i.has_task_finished = async function ( task_id, options ) {
342
341
  try {
343
342
 
344
343
  // If server did need to restart, check if it's done.
345
- let response = await _da_REST.has_task_finished( task_id, timeout );
344
+ let response = await _da_REST.has_task_finished( api_endpoint, task_id, timeout );
346
345
  log.debug({ pre: `Task status: ${ response.status }. Docassemble status text: ${ response.data.status }. Task id: ${ task_id }` });
347
346
 
348
347
  if ( response.data.status === 'completed' ) {
@@ -353,16 +352,15 @@ da_i.has_task_finished = async function ( task_id, options ) {
353
352
  return false;
354
353
 
355
354
  } else if ( response.data.status === 'unknown' ) {
356
- // Server is working, but status 'unknown'? We shouldn't even
357
- // get here according to the API docs, but it feels weird to have
358
- // no default behavior. What to return? Throw?
355
+ // Server is working, but status 'unknown'? Bad design, but this
356
+ // does get returned when install packages, so return true
359
357
  log.info({
360
358
  pre: `\`task_id\` "${ task_id }" has expired. If it's been `
361
359
  + `less than 1 hour since the task started, the task is `
362
360
  + `complete. See https://docassemble.org/docs/api.html#restart_status.`,
363
- data: response,
361
+ data: response.data,
364
362
  });
365
- return null;
363
+ return true;
366
364
  } // ends status type
367
365
 
368
366
  } catch ( error ) {
@@ -378,8 +376,15 @@ da_i.has_task_finished = async function ( task_id, options ) {
378
376
 
379
377
  }; // Ends da_i.has_task_finished()
380
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
+ };
381
386
 
382
- da_i.wait_for_server_to_restart = async ( task_id, options ) => {
387
+ da_i.wait_for_server_to_restart = async ( api_endpoint, task_id, options ) => {
383
388
  /** Wait for the server to finish restarting in case a module needs to load.
384
389
  * This is a polling function because things may be returned
385
390
  * that aren't equivalent to the server being done with a task. */
@@ -410,7 +415,7 @@ da_i.wait_for_server_to_restart = async ( task_id, options ) => {
410
415
  while ( !done_restarting && num_tries <= max_loops ) {
411
416
  num_tries++;
412
417
  // Wait only a short time for the task to finish, not the full default timeout
413
- done_restarting = await da_i.has_task_finished( task_id, { timeout: wait_for_response } );
418
+ done_restarting = await da_i.has_task_finished( api_endpoint, task_id, { timeout: wait_for_response } );
414
419
  if ( !done_restarting ) {
415
420
  if ( num_tries < max_loops ) {
416
421
  // Show a slightly different message after a number of tries to reassure
@@ -10,10 +10,20 @@ let get_base_interview_url = async function () {
10
10
  * When finishing a test, we go to the sign out page (which is supposed to help even
11
11
  * when the user is not logged in.) We can't use `reset=2` because it caused an
12
12
  * 'Unable to locate interview session' error. */
13
+
13
14
  let server_url = session_vars.get_da_server_url();
14
- let dev_id = await docassemble_api_interface.get_dev_id();
15
- let project_name = session_vars.get_project_name();
16
- return `${ server_url }/interview?new_session=1&i=docassemble.playground${ dev_id }${ project_name }%3A`;
15
+
16
+ if (session_vars.get_install_type() === `server`) {
17
+
18
+ return `${ server_url }/interview?new_session=1&i=docassemble.${session_vars.get_repo_folder_name()}%3Adata/questions/`;
19
+
20
+ } else {
21
+
22
+ let dev_id = await docassemble_api_interface.get_dev_id();
23
+ let project_name = session_vars.get_project_name();
24
+ return `${ server_url }/interview?new_session=1&i=docassemble.playground${ dev_id }${ project_name }%3A`;
25
+
26
+ }
17
27
  };
18
28
 
19
29
  module.exports = get_base_interview_url;
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env node
2
+
3
+ const session_vars = require('../utils/session_vars');
4
+ const log = require('../utils/log');
5
+ // const path = require('path');
6
+ // const fs = require('fs');
7
+ const fg = require('fast-glob');
8
+
9
+ const server_install = async () => {
10
+ session_vars.save_install_type(`server`);
11
+
12
+ let current_dir = process.cwd();
13
+ let path = `${ current_dir }/docassemble/*`;
14
+ let dirs = fg.sync(
15
+ [ path ],
16
+ {
17
+ suppressErrors: true,
18
+ onlyDirectories: true
19
+ }
20
+ );
21
+ console.log(`\n===========\n${dirs}\n===========\n`);
22
+
23
+ let chosen_dir = dirs[0];
24
+ if ( dirs.length === 0 ) {
25
+ let msg = `There are 0 folders at ${path}. Tests won't run.`;
26
+ log.error({ type: `setup`, data: msg })
27
+ throw new ReferenceError( msg );
28
+ }
29
+
30
+ if ( dirs.length > 1 ) {
31
+ log.warn({
32
+ type: `setup`,
33
+ data: `There are ${dirs.length} folders at ${path}: "${dirs.join('", ')}". ALKiln chose to use the folder "${chosen_dir}".`
34
+ })
35
+ }
36
+
37
+ session_vars.set_repo_folder_name( chosen_dir );
38
+ }; // Ends server_install();
39
+
40
+ server_install();
@@ -39,7 +39,7 @@ const setup = async () => {
39
39
  let task_id = await da_i.pull();
40
40
  // Task id will be null if server did not need to restart
41
41
  if ( task_id ) {
42
- await da_i.wait_for_server_to_restart( task_id );
42
+ await da_i.wait_for_playground_to_restart( task_id );
43
43
  }
44
44
 
45
45
  // Finish
@@ -6,64 +6,97 @@ const session_vars = require('./utils/session_vars');
6
6
 
7
7
  const cucumber_api = require('@cucumber/cucumber/api');
8
8
 
9
- (async function main() {
10
- let argv = process.argv;
11
-
12
- const environment = { cwd: process.cwd() };
13
- console.log("alkiln-run: environment: %o", environment);
14
- const provided_config = {
15
- "publishQuiet": true,
16
- "require": "./lib/index.js",
17
- "format": ["progress", "summary:cucumber-report.txt"],
18
- "paths": ["docassemble/*/data/sources/*.feature"],
19
- "retry": 1,
20
- }
21
-
22
-
23
- // If they're running it from an interview on their server instead of from GitHub
24
- if ( session_vars.get_origin() === `playground` ) {
25
- provided_config.paths.push(`/usr/share/docassemble/files/playgroundsources/${session_vars.get_user_id()}/${session_vars.get_user_project_name()}/*.feature`);
26
- // For S3
27
- provided_config.paths.push(`/tmp/playgroundsources/${session_vars.get_user_id()}/${session_vars.get_user_project_name()}/*.feature`);
9
+ function build_config( command_args ) {
10
+ // Turn all the paths to the sources folders into paths to the feature files
11
+ let sources_paths = session_vars.get_sources_paths();
12
+ let feature_paths = [];
13
+ for ( let source of sources_paths ) {
14
+ feature_paths.push( `${ source }/*.feature` );
28
15
  }
29
16
 
30
- let tags = argv.slice(2);
31
- if ( session_vars.get_origin() === `playground` ) {
32
- tags = session_vars.get_tags();
17
+ const config = {
18
+ publishQuiet: true,
19
+ require: `./lib/index.js`,
20
+ format: [`progress`, `summary:cucumber-report.txt`],
21
+ paths: feature_paths,
22
+ retry: 1,
33
23
  }
34
24
 
25
+ // Normalize tag expressions, if there are any
26
+ let tags = command_args[`_`];
35
27
  if (tags.length > 0) {
36
28
  let joined_tags = '';
37
29
  // Cucumber expects tags in boolean expressions, like (@a0 or @a1) and @random.
38
30
  // If we get a list of only tags, then "or" them all together
39
- if (tags.every((val) => val.startsWith("@"))) {
40
- joined_tags = tags.join(' or ');
31
+ if (tags.every((val) => val.startsWith(`@`))) {
32
+ joined_tags = tags.join(` or `);
41
33
  }
42
34
  // If we get a list of seemingly no tags, assume they meant to use tags
43
- else if (tags.every((val) => !val.startsWith("@"))) {
44
- joined_tags = tags.map((val) => "@" + val).join(' or ');
35
+ else if (tags.every((val) => !val.startsWith(`@`))) {
36
+ joined_tags = tags.map((val) => `@` + val).join(` or `);
45
37
  }
46
38
  // If it's a mix of tags and no tags, it's probably a boolean expression!
47
39
  else {
48
- joined_tags = tags.join(' ');
40
+ joined_tags = tags.join(` `);
49
41
  }
50
42
 
51
- provided_config.tags = joined_tags;
52
- } // end if there are tags
43
+ config.tags = joined_tags;
44
+ }
45
+
46
+ return config;
47
+ }; // Ends build_config()
48
+
49
+
50
+ (async function main() {
51
+ /** Create the cucumber config, run the tests, create and
52
+ * manipluate the output. */
53
+ const environment = { cwd: process.cwd() };
54
+ console.log("alkiln-run: environment: %o", environment);
55
+
56
+ // We'll use the user info to construct the possible paths to /sources
57
+ let id = session_vars.get_user_id();
58
+ // `project` is the name in the server docassemble "Project" page
59
+ let project = session_vars.get_user_project_name();
60
+
61
+ // process.argv is a list of strings of commands and args.
62
+ // If using `npm run cucumber`, use `--` before `--sources=./foo`
63
+ let argv = require(`minimist`)( process.argv.slice(2), {
64
+ default: {
65
+ sources: [
66
+ `./docassemble/*/data/sources`, // In GitHub folder
67
+ `/usr/share/docassemble/files/playgroundsources/${id}/${project}/*.feature`, // From playground without S3
68
+ `/tmp/playgroundsources/${id}/${project}/*.feature` // From playground with S3
69
+ ],
70
+ }
71
+ });
72
+
73
+ // Make sure `sources` is always a list
74
+ let sources_list = argv.sources;
75
+ if ( typeof argv.sources === `string` ) {
76
+ sources_list = [ argv.sources ];
77
+ }
53
78
 
79
+ let one_dir_exists = session_vars.set_sources_paths( sources_list );
80
+ if ( !one_dir_exists ) {
81
+ // If we don't throw, it'll be more confusing when no tests run
82
+ throw new ReferenceError( `ALKiln ERROR: ALKiln can't find your "sources" folder(s). See above for details.`);
83
+ }
84
+
54
85
  const { runConfiguration } = await cucumber_api.loadConfiguration({
55
- provided: provided_config
86
+ provided: build_config( argv ),
56
87
  }, environment);
88
+
57
89
  console.log("alkiln-run: runConfiguration: %o", runConfiguration);
90
+
58
91
  var path = require('path');
59
92
  var codeDir = path.dirname(require.main.filename);
93
+ console.log("alkiln-run: working directory: %o", codeDir);
60
94
  const support = await cucumber_api.loadSupport({ support: {
61
- requireModules: [`${ codeDir }/index.js`],
62
- requirePaths: [ `${ codeDir }/index.js`],
95
+ requireModules: [ `${ codeDir }/index.js` ],
96
+ requirePaths: [ `${ codeDir }/index.js` ],
63
97
  importPaths: [],
64
98
  }, sources: {paths: []}}, environment);
65
99
 
66
- console.log("alkiln-run: working directory: %o", codeDir);
67
100
  console.log(`\n\n`);
68
101
 
69
102
  const { success } = await cucumber_api.runCucumber({...runConfiguration, support});
@@ -86,6 +119,6 @@ const cucumber_api = require('@cucumber/cucumber/api');
86
119
 
87
120
  // Put it in the correct file in the correct folder
88
121
  let artifacts_path = session_vars.get_artifacts_path_name();
89
- fs.appendFileSync( `${ artifacts_path}/${ log.debug_log_file }`, data);
122
+ fs.appendFileSync( `${ artifacts_path }/${ log.debug_log_file }`, data);
90
123
  });
91
124
  })();