@suffolklitlab/alkiln 3.0.9 → 4.0.0-pre-api.4
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/test_tests.yml +11 -2
- package/CHANGELOG.md +22 -20
- package/action.yml +42 -32
- package/lib/cucumber_8_shim.js +25 -0
- package/lib/docassemble/docassemble_api_REST.js +130 -0
- package/lib/docassemble/docassemble_api_interface.js +404 -0
- package/lib/docassemble/setup.js +38 -0
- package/lib/docassemble/takedown.js +18 -0
- package/lib/scope.js +337 -60
- package/lib/steps.js +209 -138
- package/lib/utils/env_vars.js +73 -69
- package/lib/utils/log.js +51 -0
- package/lib/utils/session_vars.js +188 -0
- package/lib/utils/time.js +26 -0
- package/lib/world.js +2 -2
- package/package.json +13 -12
- package/tests/features/establishing_steps.feature +15 -0
- package/tests/features/observation_steps.feature +31 -0
- package/tests/features/reports.feature +70 -12
- package/lib/github_integration/install-branch.js +0 -84
- package/lib/github_integration/puppeteer-utils.js +0 -224
- package/lib/github_integration/setup.js +0 -4
- package/lib/github_integration/takedown.js +0 -4
|
@@ -18,16 +18,19 @@ jobs:
|
|
|
18
18
|
|
|
19
19
|
strategy:
|
|
20
20
|
matrix:
|
|
21
|
-
node-version: [
|
|
21
|
+
node-version: [17.x]
|
|
22
22
|
|
|
23
23
|
env:
|
|
24
|
-
BASE_URL:
|
|
24
|
+
BASE_URL: ${{ secrets.SERVER_URL }}
|
|
25
25
|
PLAYGROUND_EMAIL: ${{ secrets.PLAYGROUND_EMAIL }}
|
|
26
26
|
PLAYGROUND_PASSWORD: ${{ secrets.PLAYGROUND_PASSWORD }}
|
|
27
27
|
PLAYGROUND_ID: ${{ secrets.PLAYGROUND_ID }}
|
|
28
|
+
DOCASSEMBLE_DEVELOPER_API_KEY: ${{ secrets.DOCASSEMBLE_DEVELOPER_API_KEY }}
|
|
28
29
|
BRANCH_PATH: main
|
|
29
30
|
EXTRA_LANGUAGES: ${{ secrets.EXTRA_LANGUAGES }}
|
|
30
31
|
REPO_URL: https://github.com/plocket/docassemble-ALAutomatedTestingTests
|
|
32
|
+
USER1_EMAIL: ${{ secrets.USER1_EMAIL }}
|
|
33
|
+
USER1_PASSWORD: ${{ secrets.USER1_PASSWORD }}
|
|
31
34
|
|
|
32
35
|
name: Run Puppeteer tests
|
|
33
36
|
steps:
|
|
@@ -72,6 +75,12 @@ jobs:
|
|
|
72
75
|
with:
|
|
73
76
|
name: report
|
|
74
77
|
path: ./**/*_report_*
|
|
78
|
+
- name: log artifact
|
|
79
|
+
uses: actions/upload-artifact@v2
|
|
80
|
+
if: ${{ always() }}
|
|
81
|
+
with:
|
|
82
|
+
name: log file
|
|
83
|
+
path: ./log.txt
|
|
75
84
|
- name: Cleanup
|
|
76
85
|
if: ${{ always() }}
|
|
77
86
|
run: npm run takedown
|
package/CHANGELOG.md
CHANGED
|
@@ -38,30 +38,29 @@ Format:
|
|
|
38
38
|
### Security
|
|
39
39
|
-
|
|
40
40
|
-->
|
|
41
|
-
<!--
|
|
42
|
-
## [3.0.9] - 2022-01-10
|
|
43
|
-
### Security
|
|
44
|
-
- Install the security fix in the action's package.json as well. Because dependents have to require cucumber itself, if they're not using our action (if they have their own package.json), they're going to have to implement this fix in their repo too. That's why our fix isn't working. We'll start the process of helping developers update. We also need to deprecate all previous versions of ALKiln. See #489.
|
|
45
|
-
|
|
46
|
-
## [3.0.8] - 2022-01-10
|
|
47
|
-
### Security
|
|
48
|
-
- Fully publish the security fix in v3.0.7
|
|
49
|
-
|
|
50
|
-
## [3.0.7] - 2022-01-10
|
|
51
|
-
### Security
|
|
52
|
-
- Pinned colors library to 1.4.0. See https://www.bleepingcomputer.com/news/security/dev-corrupts-npm-libs-colors-and-faker-breaking-thousands-of-apps/. We don't use faker, so we don't need to handle that.
|
|
41
|
+
<!--2022-02-11 -->
|
|
53
42
|
|
|
54
|
-
## [
|
|
55
|
-
### Changed
|
|
56
|
-
- See #371
|
|
57
|
-
- Scenario heading tags are now on a second line
|
|
58
|
-
- Artifact filenames use dashes more and are created separately from Scenario headings
|
|
59
|
-
- Scenario ids are separated from filenames and Scenario headings
|
|
60
|
-
|
|
61
|
-
## [3.0.5] - 2022-01-06
|
|
43
|
+
## [Unreleased]
|
|
62
44
|
### Added
|
|
63
45
|
- Add action.yml that runs most of what users' workflows run now, along with notes for a new user workflow that will take less maintainance. See #420. We need to add documentation on how to write a workflow file as it currently is if they want to take back control. Setup interview has not yet been updated with this workflow.
|
|
64
46
|
- Add package.json creation/overwriting to action.yml. Simplify package.json.
|
|
47
|
+
- Step: `the text in the JSON variable "variable_with_text_value" should be`. Compare JSON variable with a text value to given text. See #470. Does not accept nested values, e.g. "child.name.first". Downloads all the JSON vars to a .json file in the "downloads" artifacts.
|
|
48
|
+
- Step to log the page's JSON variables and values in the report. Future goal: save to file. See #454.
|
|
49
|
+
- Step to log into the developer's docassemble server account using GitHub SECRETs. See #499.
|
|
50
|
+
- Create log.txt for report items and uploaded as github artifact so there's always some kind of output.
|
|
51
|
+
- Add control of alkiln npm version to the action.yml
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
- Update to v13 of puppeteer
|
|
55
|
+
- Update to v7 of cucumber
|
|
56
|
+
- Update action.yml node to v17
|
|
57
|
+
- Use alkiln v4 package.json we create during the test run in `action.yml` (as discussed in #489)
|
|
58
|
+
- Remove and ignore package-lock.json so that our tests will behave more like our users' tests
|
|
59
|
+
- Use API key to access da server, create projects, pull code, delete projects, and check for server restart.
|
|
60
|
+
- Add warning in steps.js for name input with too many parts. Add test in reports.
|
|
61
|
+
- fix typo in the report
|
|
62
|
+
- Throw an error for uploading nonexistent file, changed to error instead of warning in reports.
|
|
63
|
+
- Allow a developer to wait as a first Step. See #387.
|
|
65
64
|
|
|
66
65
|
<!-- ## [3.0.1-peer-deps.1] - 2021-12-07 -->
|
|
67
66
|
### Removed
|
|
@@ -69,6 +68,9 @@ Format:
|
|
|
69
68
|
|
|
70
69
|
### Fixed
|
|
71
70
|
- Fixed interview name not allowing url parameters. #449
|
|
71
|
+
- Freeze colors npm package to before bug in both package.json and action.yml
|
|
72
|
+
- Fix invalid project name allowed.
|
|
73
|
+
- fix typo in the report.
|
|
72
74
|
|
|
73
75
|
## [3.0.4] - 2021-12-11
|
|
74
76
|
### Fixed
|
package/action.yml
CHANGED
|
@@ -14,45 +14,32 @@ inputs:
|
|
|
14
14
|
PLAYGROUND_ID:
|
|
15
15
|
description: 'The id of your docassemble testing account. This should be in your GitHub SECRETS or the SECRETS of your org.'
|
|
16
16
|
required: true
|
|
17
|
+
DOCASSEMBLE_DEVELOPER_API_KEY:
|
|
18
|
+
description: 'API key of the testing account with developer permissions on your docassemble server.'
|
|
19
|
+
required: true
|
|
17
20
|
EXTRA_LANGUAGES:
|
|
18
21
|
description: 'Other languages you want to test. This should be in your GitHub SECRETS or the SECRETS of your org.'
|
|
19
22
|
required: false
|
|
20
23
|
default: ''
|
|
24
|
+
# This is necessary to test pre-releases at the very least. It does seem
|
|
25
|
+
# strange considering we're controlling everything through the action, but
|
|
26
|
+
# that actually doesn't touch the npm version that's pulled in.
|
|
27
|
+
ALKILN_VERSION:
|
|
28
|
+
description: 'Version of ALKiln to get from npm.'
|
|
29
|
+
required: false
|
|
30
|
+
default: '^4.0.0'
|
|
21
31
|
|
|
22
32
|
runs:
|
|
23
33
|
using: "composite"
|
|
24
34
|
steps:
|
|
25
|
-
# This doesn't use an already established package-lock.json and that
|
|
26
|
-
# comes with some types of test breaking risks. Same problem as before.
|
|
27
|
-
- name: Overwrite or create package.json
|
|
28
|
-
run: |
|
|
29
|
-
cat << EOF > "package.json"
|
|
30
|
-
{
|
|
31
|
-
"scripts": {
|
|
32
|
-
"test": "npm run langs_setup && npm run cucumber -- $@",
|
|
33
|
-
"cucumber_base": "./node_modules/.bin/cucumber-js --require ./node_modules/docassemble-cucumber/lib/index.js",
|
|
34
|
-
"cucumber": "run_cucumber(){ npm run cucumber_base -- \"$@\" docassemble/*/data/sources/*.feature; }; run_cucumber",
|
|
35
|
-
"langs": "npm run langs_setup && ./node_modules/.bin/cucumber-js --require ./node_modules/docassemble-cucumber/lib/index.js docassemble/*/data/sources/*_lang*.feature",
|
|
36
|
-
"langs_setup": "node_modules/.bin/da-langs 'docassemble/*/data/sources/*.feature'",
|
|
37
|
-
"setup": "node_modules/.bin/da-setup",
|
|
38
|
-
"takedown": "node_modules/.bin/da-takedown"
|
|
39
|
-
},
|
|
40
|
-
"dependencies": {
|
|
41
|
-
"cucumber": "^6.0.5",
|
|
42
|
-
"docassemble-cucumber": "^3.0.0",
|
|
43
|
-
"colors": "1.4.0"
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
shell: bash
|
|
47
|
-
|
|
48
35
|
# Install node
|
|
49
36
|
- name: "ALKiln: Install node packages"
|
|
50
37
|
uses: actions/setup-node@v1
|
|
51
38
|
with:
|
|
52
|
-
node-version: "
|
|
39
|
+
node-version: "17"
|
|
53
40
|
- run: npm install
|
|
54
41
|
shell: bash
|
|
55
|
-
|
|
42
|
+
|
|
56
43
|
# Set environment variables
|
|
57
44
|
- name: "ALKiln: Set environment variables"
|
|
58
45
|
# If extra languages were set manually, override the repository
|
|
@@ -72,6 +59,30 @@ runs:
|
|
|
72
59
|
echo "PLAYGROUND_EMAIL=${{ inputs.PLAYGROUND_EMAIL }}" >> $GITHUB_ENV
|
|
73
60
|
echo "PLAYGROUND_PASSWORD=${{ inputs.PLAYGROUND_PASSWORD }}" >> $GITHUB_ENV
|
|
74
61
|
echo "PLAYGROUND_ID=${{ inputs.PLAYGROUND_ID }}" >> $GITHUB_ENV
|
|
62
|
+
echo "DOCASSEMBLE_DEVELOPER_API_KEY=${{ inputs.DOCASSEMBLE_DEVELOPER_API_KEY }}" >> $GITHUB_ENV
|
|
63
|
+
echo "ALKILN_VERSION=${{ inputs.ALKILN_VERSION }}" >> $GITHUB_ENV
|
|
64
|
+
shell: bash
|
|
65
|
+
# This doesn't use an already established package-lock.json and that
|
|
66
|
+
# comes with some types of test breaking risks. Same problem as before.
|
|
67
|
+
- name: Overwrite or create package.json
|
|
68
|
+
run: |
|
|
69
|
+
cat << EOF > "package.json"
|
|
70
|
+
{
|
|
71
|
+
"scripts": {
|
|
72
|
+
"test": "npm run langs_setup && npm run cucumber -- $@",
|
|
73
|
+
"cucumber_base": "./node_modules/.bin/cucumber-js --require ./node_modules/.bin/alkiln-cucumber",
|
|
74
|
+
"cucumber": "run_cucumber(){ npm run cucumber_base -- \"$@\" docassemble/*/data/sources/*.feature; }; run_cucumber",
|
|
75
|
+
"langs": "npm run langs_setup && ./node_modules/.bin/cucumber-js --require ./node_modules/.bin/alkiln-cucumber docassemble/*/data/sources/*_lang*.feature",
|
|
76
|
+
"langs_setup": "node_modules/.bin/alkiln-langs 'docassemble/*/data/sources/*.feature'",
|
|
77
|
+
"setup": "node_modules/.bin/alkiln-setup",
|
|
78
|
+
"takedown": "node_modules/.bin/alkiln-takedown"
|
|
79
|
+
},
|
|
80
|
+
"dependencies": {
|
|
81
|
+
"colors": "1.4.0",
|
|
82
|
+
"@cucumber/cucumber": "^7.3.2",
|
|
83
|
+
"@suffolklitlab/alkiln": "$ALKILN_VERSION"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
75
86
|
shell: bash
|
|
76
87
|
- name: "ALKiln: confirm info"
|
|
77
88
|
run: echo -e "\nRepo is $REPO_URL\nBranch ref is $BRANCH_PATH\nManually added languages are $EXTRA_LANGUAGES\nAll other data is secret\n"
|
|
@@ -125,10 +136,8 @@ runs:
|
|
|
125
136
|
# # A developer's workflow should look similar to the below
|
|
126
137
|
# # In place of `uses: suffolkLITLab/ALKiln@releases/v4`, they
|
|
127
138
|
# # might use another version.
|
|
128
|
-
|
|
129
|
-
# name: Use the ALKiln testing framework
|
|
130
|
-
# description: "Use the ALKiln testing framework to test interviews. See https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/automated_integrated_testing."
|
|
131
|
-
|
|
139
|
+
#
|
|
140
|
+
# name: Use the ALKiln testing framework v4 to run tests
|
|
132
141
|
# on:
|
|
133
142
|
# push:
|
|
134
143
|
# workflow_dispatch:
|
|
@@ -139,9 +148,9 @@ runs:
|
|
|
139
148
|
# tags:
|
|
140
149
|
# description: 'Optional. Use a "tag expression" specify which tagged tests to run. See https://cucumber.io/docs/cucumber/api/#tag-expressions for syntax.'
|
|
141
150
|
# default: ''
|
|
142
|
-
|
|
151
|
+
#
|
|
143
152
|
# jobs:
|
|
144
|
-
|
|
153
|
+
#
|
|
145
154
|
# interview-testing:
|
|
146
155
|
# runs-on: ubuntu-latest
|
|
147
156
|
# name: Run interview tests
|
|
@@ -151,8 +160,9 @@ runs:
|
|
|
151
160
|
# uses: suffolkLITLab/ALKiln@releases/v4
|
|
152
161
|
# with:
|
|
153
162
|
# SERVER_URL: "${{ secrets.SERVER_URL }}"
|
|
163
|
+
# DOCASSEMBLE_DEVELOPER_API_KEY: "${{ secrets.DOCASSEMBLE_DEVELOPER_API_KEY }}"
|
|
154
164
|
# PLAYGROUND_EMAIL: "${{ secrets.PLAYGROUND_EMAIL }}"
|
|
155
165
|
# PLAYGROUND_PASSWORD: "${{ secrets.PLAYGROUND_PASSWORD }}"
|
|
156
166
|
# PLAYGROUND_ID: "${{ secrets.PLAYGROUND_ID }}"
|
|
157
167
|
# EXTRA_LANGUAGES: "${{ secrets.EXTRA_LANGUAGES }}"
|
|
158
|
-
# - run: echo "Finished running ALKiln tests"
|
|
168
|
+
# - run: echo "Finished running ALKiln tests"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module.exports = async function wrapPromiseWithTimeout (
|
|
2
|
+
promise,
|
|
3
|
+
timeoutInMilliseconds,
|
|
4
|
+
timeoutMessage
|
|
5
|
+
) {
|
|
6
|
+
/** Race between a timeout and another function and clean up
|
|
7
|
+
* async afterwards.
|
|
8
|
+
*
|
|
9
|
+
* Taken from https://github.com/cucumber/cucumber-js/blob/main/src/time.ts#L42-L59
|
|
10
|
+
*/
|
|
11
|
+
if ( timeoutMessage === '' ) {
|
|
12
|
+
timeoutMessage = `Action did not complete within ${ timeoutInMilliseconds } milliseconds`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let timeoutId;
|
|
16
|
+
const timeoutPromise = new Promise((resolve, reject) => {
|
|
17
|
+
timeoutId = setTimeout(() => {
|
|
18
|
+
reject(new Error( timeoutMessage ))
|
|
19
|
+
}, timeoutInMilliseconds)
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return await Promise.race([ promise, timeoutPromise ]).finally(() =>
|
|
23
|
+
clearTimeout(timeoutId)
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const qs = require('qs');
|
|
3
|
+
|
|
4
|
+
const session_vars = require('../utils/session_vars' );
|
|
5
|
+
|
|
6
|
+
/* Requests to make to the developer's docassemble server.
|
|
7
|
+
* As close to plain requests as we can get so we don't have
|
|
8
|
+
* to think about this file again.
|
|
9
|
+
* Notes:
|
|
10
|
+
* - We are not using `.create()` because we want to get
|
|
11
|
+
* the environment variables fresh every time. */
|
|
12
|
+
|
|
13
|
+
let da = {};
|
|
14
|
+
module.exports = da;
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
// node -e 'require("./lib/docassemble/docassemble_api_REST.js").get_dev_id()'
|
|
18
|
+
da.get_dev_id = async function ( timeout ) {
|
|
19
|
+
/* Get docassemble developer id. */
|
|
20
|
+
let options = {
|
|
21
|
+
method: 'GET',
|
|
22
|
+
url: `${ session_vars.get_da_server_url() }/api/user`,
|
|
23
|
+
params: { key: session_vars.get_dev_api_key(), },
|
|
24
|
+
timeout: timeout,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return await axios.request( options );
|
|
28
|
+
}; // Ends da.get_dev_id()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
// node -e 'require("./lib/docassemble/docassemble_api_REST.js").create_project( "create1" )'
|
|
32
|
+
da.create_project = async function ( project_name, timeout ) {
|
|
33
|
+
/* Create a new project on the user's da server. */
|
|
34
|
+
let options = {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
url: `${ session_vars.get_da_server_url() }/api/playground/project`,
|
|
37
|
+
data: qs.stringify({
|
|
38
|
+
key: session_vars.get_dev_api_key(),
|
|
39
|
+
project: project_name,
|
|
40
|
+
}),
|
|
41
|
+
timeout: timeout,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return await axios.request( options );
|
|
45
|
+
|
|
46
|
+
}; // Ends da.create_project()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
// node -e 'require("./lib/docassemble/docassemble_api_REST.js").pull()'
|
|
50
|
+
da.pull = async function ( timeout ) {
|
|
51
|
+
/* Pull github code into an existing Project. */
|
|
52
|
+
let options = {
|
|
53
|
+
method: 'POST',
|
|
54
|
+
url: `${ session_vars.get_da_server_url() }/api/playground_pull`,
|
|
55
|
+
data: qs.stringify({
|
|
56
|
+
key: session_vars.get_dev_api_key(),
|
|
57
|
+
project: session_vars.get_project_name(),
|
|
58
|
+
github_url: session_vars.get_repo_url(),
|
|
59
|
+
branch: session_vars.get_branch_name(),
|
|
60
|
+
}),
|
|
61
|
+
timeout: timeout,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return await axios.request( options );
|
|
65
|
+
}; // Ends da.pull()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
// node -e 'require("./lib/docassemble/docassemble_api_REST.js").has_task_finished()'
|
|
69
|
+
da.has_task_finished = async function ( task_id, timeout ) {
|
|
70
|
+
/* Check task status based on `task_id`. */
|
|
71
|
+
let options = {
|
|
72
|
+
method: 'GET',
|
|
73
|
+
url: `${ session_vars.get_da_server_url() }/api/restart_status`,
|
|
74
|
+
params: {
|
|
75
|
+
key: session_vars.get_dev_api_key(),
|
|
76
|
+
task_id: task_id,
|
|
77
|
+
},
|
|
78
|
+
timeout: timeout,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return await axios.request( options );
|
|
82
|
+
}; // Ends da.has_task_finished()
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
// node -e 'require("./lib/docassemble/docassemble_api_REST.js").delete_project( "create1" )'
|
|
86
|
+
da.delete_project = async function ( timeout ) {
|
|
87
|
+
/* Delete a project on the user's da server. */
|
|
88
|
+
let options = {
|
|
89
|
+
method: 'DELETE',
|
|
90
|
+
url: `${ session_vars.get_da_server_url() }/api/playground/project`,
|
|
91
|
+
params: {
|
|
92
|
+
key: session_vars.get_dev_api_key(),
|
|
93
|
+
project: session_vars.get_project_name(),
|
|
94
|
+
},
|
|
95
|
+
timeout: timeout,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return await axios.request( options );
|
|
99
|
+
}; // Ends da.delete_project()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
// node -e 'require("./lib/docassemble/docassemble_api_REST.js").__delete_projects_starting_with( "testingdocassembleALAutomatedTestingTestsmain", 1, 1 )'
|
|
103
|
+
da.__delete_projects_starting_with = async function ( base_name, starting_num=1, ending_num ) {
|
|
104
|
+
/** FOR DEVELOPMENT ONLY. Deletes a set of Projects that start with a shared
|
|
105
|
+
* prefix. Useful for Projects created by an infinite loop. */
|
|
106
|
+
let name_incrementor = parseInt( starting_num );
|
|
107
|
+
ending_num = ending_num || starting_num; // Default to just delete one
|
|
108
|
+
let final_num = parseInt( ending_num );
|
|
109
|
+
while ( name_incrementor <= final_num ) {
|
|
110
|
+
try {
|
|
111
|
+
let project_name = base_name + name_incrementor;
|
|
112
|
+
console.log( `Deleting Project ${ project_name }` );
|
|
113
|
+
|
|
114
|
+
let options = {
|
|
115
|
+
method: 'DELETE',
|
|
116
|
+
url: `${ session_vars.get_da_server_url() }/api/playground/project`,
|
|
117
|
+
params: {
|
|
118
|
+
key: session_vars.get_dev_api_key(),
|
|
119
|
+
project: project_name,
|
|
120
|
+
},
|
|
121
|
+
timeout: 30 * 1000,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
await axios.request( options );
|
|
125
|
+
} catch ( error ) {
|
|
126
|
+
console.log( error )
|
|
127
|
+
}
|
|
128
|
+
name_incrementor++;
|
|
129
|
+
}
|
|
130
|
+
}; // Ends da_i.__delete_projects_starting_with()
|