mcdev 5.0.2 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/.coverage-comment-template.svelte +177 -161
  2. package/.github/ISSUE_TEMPLATE/bug.yml +1 -0
  3. package/.github/dependabot.yml +8 -0
  4. package/.github/workflows/coverage-base-update.yml +6 -2
  5. package/.github/workflows/coverage-develop-branch.yml +7 -6
  6. package/.github/workflows/coverage-main-branch.yml +7 -6
  7. package/.github/workflows/coverage.yml +7 -2
  8. package/.husky/post-checkout +3 -2
  9. package/docs/dist/documentation.md +162 -47
  10. package/lib/Deployer.js +3 -3
  11. package/lib/cli.js +28 -0
  12. package/lib/index.js +173 -2
  13. package/lib/metadataTypes/Automation.js +400 -193
  14. package/lib/metadataTypes/DataExtension.js +5 -5
  15. package/lib/metadataTypes/MetadataType.js +42 -15
  16. package/lib/metadataTypes/Query.js +26 -0
  17. package/lib/metadataTypes/definitions/Asset.definition.js +1 -0
  18. package/lib/metadataTypes/definitions/Automation.definition.js +52 -6
  19. package/lib/metadataTypes/definitions/DataExtension.definition.js +1 -0
  20. package/lib/metadataTypes/definitions/DataExtract.definition.js +1 -0
  21. package/lib/metadataTypes/definitions/EmailSend.definition.js +1 -0
  22. package/lib/metadataTypes/definitions/Event.definition.js +1 -0
  23. package/lib/metadataTypes/definitions/Filter.definition.js +1 -0
  24. package/lib/metadataTypes/definitions/ImportFile.definition.js +1 -0
  25. package/lib/metadataTypes/definitions/MobileKeyword.definition.js +1 -0
  26. package/lib/metadataTypes/definitions/Query.definition.js +1 -0
  27. package/lib/metadataTypes/definitions/Role.definition.js +1 -0
  28. package/lib/metadataTypes/definitions/TriggeredSend.definition.js +1 -0
  29. package/lib/metadataTypes/definitions/User.definition.js +1 -0
  30. package/lib/util/devops.js +13 -11
  31. package/lib/util/util.js +152 -129
  32. package/package.json +5 -5
  33. package/test/general.test.js +26 -0
  34. package/test/mockRoot/.mcdevrc.json +1 -1
  35. package/test/mockRoot/deploy/testInstance/testBU/automation/testExisting_automation.automation-meta.json +53 -0
  36. package/test/mockRoot/deploy/testInstance/testBU/automation/testNew_automation.automation-meta.json +46 -0
  37. package/test/mockRoot/deploy/testInstance/testBU/query/{testExistingQuery.query-meta.json → testExisting_query.query-meta.json} +2 -2
  38. package/test/mockRoot/deploy/testInstance/testBU/query/{testNewQuery.query-meta.json → testNew_query.query-meta.json} +2 -2
  39. package/test/resourceFactory.js +64 -21
  40. package/test/resources/9999999/automation/build-expected.json +58 -0
  41. package/test/resources/9999999/automation/create-expected.json +46 -0
  42. package/test/resources/9999999/automation/create-testNew_automation-expected.md +28 -0
  43. package/test/resources/9999999/automation/delete-response.xml +40 -0
  44. package/test/resources/9999999/automation/retrieve-expected.json +58 -0
  45. package/test/resources/9999999/automation/retrieve-testExisting_automation-expected.md +30 -0
  46. package/test/resources/9999999/automation/template-expected.json +58 -0
  47. package/test/resources/9999999/automation/update-expected.json +46 -0
  48. package/test/resources/9999999/automation/update-testExisting_automation-expected.md +28 -0
  49. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json +85 -0
  50. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/patch-response.json +85 -0
  51. package/test/resources/9999999/automation/v1/automations/a8afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json +85 -0
  52. package/test/resources/9999999/automation/v1/automations/post-response.json +85 -0
  53. package/test/resources/9999999/automation/v1/dataextracts/56c5370a-f988-4f36-b0ee-0f876573f6d7/get-response.json +38 -0
  54. package/test/resources/9999999/automation/v1/dataextracts/get-response.json +20 -0
  55. package/test/resources/9999999/automation/v1/filetransfers/72c328ac-f5b0-4e37-91d3-a775666f15a6/get-response.json +18 -0
  56. package/test/resources/9999999/automation/v1/filetransfers/get-response.json +15 -0
  57. package/test/resources/9999999/automation/v1/imports/get-response.json +38 -0
  58. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/actions/start/post-response.txt +1 -0
  59. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/get-response.json +2 -2
  60. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json +2 -2
  61. package/test/resources/9999999/automation/v1/queries/get-response.json +4 -4
  62. package/test/resources/9999999/automation/v1/queries/post-response.json +2 -2
  63. package/test/resources/9999999/automation/v1/scripts/get-response.json +17 -0
  64. package/test/resources/9999999/dataFolder/retrieve-ContentType=automations-response.xml +48 -0
  65. package/test/resources/9999999/dataFolder/retrieve-ContentType=queryactivity-response.xml +48 -0
  66. package/test/resources/9999999/dataFolder/retrieve-response.xml +22 -0
  67. package/test/resources/9999999/emailSendDefinition/retrieve-response.xml +85 -0
  68. package/test/resources/9999999/legacy/v1/beta/automations/notifications/RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow/get-response.json +21 -0
  69. package/test/resources/9999999/legacy/v1/beta/automations/notifications/RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow/post-response.json +0 -0
  70. package/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/get-response.json +30 -0
  71. package/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation-response.xml +30 -0
  72. package/test/resources/9999999/program/retrieve-CustomerKey=testNew_automation-response.xml +30 -0
  73. package/test/resources/9999999/program/retrieve-Name=testExisting_automation-response.xml +31 -0
  74. package/test/resources/9999999/program/retrieve-response.xml +32 -0
  75. package/test/resources/9999999/query/build-expected.json +2 -2
  76. package/test/resources/9999999/query/get-expected.json +2 -2
  77. package/test/resources/9999999/query/get2-expected.json +2 -2
  78. package/test/resources/9999999/query/patch-expected.json +2 -2
  79. package/test/resources/9999999/query/post-expected.json +2 -2
  80. package/test/resources/9999999/query/template-expected.json +2 -2
  81. package/test/type.automation.test.js +259 -0
  82. package/test/type.dataExtension.test.js +3 -0
  83. package/test/type.query.test.js +39 -26
  84. package/test/type.user.test.js +17 -3
  85. package/test/utils.js +7 -6
  86. package/.coverage-comment-template.md +0 -20
  87. /package/test/mockRoot/deploy/testInstance/testBU/query/{testExistingQuery.query-meta.sql → testExisting_query.query-meta.sql} +0 -0
  88. /package/test/mockRoot/deploy/testInstance/testBU/query/{testNewQuery.query-meta.sql → testNew_query.query-meta.sql} +0 -0
@@ -32,16 +32,16 @@ describe('type: query', () => {
32
32
  );
33
33
  // normal test
34
34
  assert.deepEqual(
35
- await testUtils.getActualJson('testExistingQuery', 'query'),
35
+ await testUtils.getActualJson('testExisting_query', 'query'),
36
36
  await testUtils.getExpectedJson('9999999', 'query', 'get'),
37
37
  'returned metadata with correct key was not equal expected'
38
38
  );
39
- expect(file(testUtils.getActualFile('testExistingQuery', 'query', 'sql'))).to.equal(
39
+ expect(file(testUtils.getActualFile('testExisting_query', 'query', 'sql'))).to.equal(
40
40
  file(testUtils.getExpectedFile('9999999', 'query', 'get', 'sql'))
41
41
  );
42
42
  // check if targetKey was overwritten
43
43
  assert.deepEqual(
44
- await testUtils.getActualJson('testExistingQuery2', 'query'),
44
+ await testUtils.getActualJson('testExisting_query2', 'query'),
45
45
  await testUtils.getExpectedJson('9999999', 'query', 'get2'),
46
46
  'returned metadata with wrong key was not equal expected'
47
47
  );
@@ -55,7 +55,7 @@ describe('type: query', () => {
55
55
  });
56
56
  it('Should retrieve one specific query', async () => {
57
57
  // WHEN
58
- await handler.retrieve('testInstance/testBU', ['query'], ['testExistingQuery']);
58
+ await handler.retrieve('testInstance/testBU', ['query'], ['testExisting_query']);
59
59
  // THEN
60
60
  assert.equal(process.exitCode, false, 'retrieve should not have thrown an error');
61
61
  // get results from cache
@@ -66,11 +66,11 @@ describe('type: query', () => {
66
66
  'only one query expected'
67
67
  );
68
68
  assert.deepEqual(
69
- await testUtils.getActualJson('testExistingQuery', 'query'),
69
+ await testUtils.getActualJson('testExisting_query', 'query'),
70
70
  await testUtils.getExpectedJson('9999999', 'query', 'get'),
71
71
  'returned metadata was not equal expected'
72
72
  );
73
- expect(file(testUtils.getActualFile('testExistingQuery', 'query', 'sql'))).to.equal(
73
+ expect(file(testUtils.getActualFile('testExisting_query', 'query', 'sql'))).to.equal(
74
74
  file(testUtils.getExpectedFile('9999999', 'query', 'get', 'sql'))
75
75
  );
76
76
  assert.equal(
@@ -99,20 +99,20 @@ describe('type: query', () => {
99
99
  );
100
100
  // confirm created item
101
101
  assert.deepEqual(
102
- await testUtils.getActualJson('testNewQuery', 'query'),
102
+ await testUtils.getActualJson('testNew_query', 'query'),
103
103
  await testUtils.getExpectedJson('9999999', 'query', 'post'),
104
104
  'returned metadata was not equal expected for insert query'
105
105
  );
106
- expect(file(testUtils.getActualFile('testNewQuery', 'query', 'sql'))).to.equal(
106
+ expect(file(testUtils.getActualFile('testNew_query', 'query', 'sql'))).to.equal(
107
107
  file(testUtils.getExpectedFile('9999999', 'query', 'post', 'sql'))
108
108
  );
109
109
  // confirm updated item
110
110
  assert.deepEqual(
111
- await testUtils.getActualJson('testExistingQuery', 'query'),
111
+ await testUtils.getActualJson('testExisting_query', 'query'),
112
112
  await testUtils.getExpectedJson('9999999', 'query', 'patch'),
113
113
  'returned metadata was not equal expected for insert query'
114
114
  );
115
- expect(file(testUtils.getActualFile('testExistingQuery', 'query', 'sql'))).to.equal(
115
+ expect(file(testUtils.getActualFile('testExisting_query', 'query', 'sql'))).to.equal(
116
116
  file(testUtils.getExpectedFile('9999999', 'query', 'patch', 'sql'))
117
117
  );
118
118
  // check number of API calls
@@ -131,7 +131,7 @@ describe('type: query', () => {
131
131
  const result = await handler.retrieveAsTemplate(
132
132
  'testInstance/testBU',
133
133
  'query',
134
- ['testExistingQuery'],
134
+ ['testExisting_query'],
135
135
  'testSourceMarket'
136
136
  );
137
137
  // WHEN
@@ -146,18 +146,18 @@ describe('type: query', () => {
146
146
  'only one query expected'
147
147
  );
148
148
  assert.deepEqual(
149
- await testUtils.getActualTemplateJson('testExistingQuery', 'query'),
149
+ await testUtils.getActualTemplateJson('testExisting_query', 'query'),
150
150
  await testUtils.getExpectedJson('9999999', 'query', 'template'),
151
151
  'returned template JSON of retrieveAsTemplate was not equal expected'
152
152
  );
153
153
  expect(
154
- file(testUtils.getActualTemplateFile('testExistingQuery', 'query', 'sql'))
154
+ file(testUtils.getActualTemplateFile('testExisting_query', 'query', 'sql'))
155
155
  ).to.equal(file(testUtils.getExpectedFile('9999999', 'query', 'template', 'sql')));
156
156
  // THEN
157
157
  await handler.buildDefinition(
158
158
  'testInstance/testBU',
159
159
  'query',
160
- 'testExistingQuery',
160
+ 'testExisting_query',
161
161
  'testTargetMarket'
162
162
  );
163
163
  assert.equal(
@@ -167,13 +167,14 @@ describe('type: query', () => {
167
167
  );
168
168
 
169
169
  assert.deepEqual(
170
- await testUtils.getActualDeployJson('testExistingQuery', 'query'),
170
+ await testUtils.getActualDeployJson('testTemplated_query', 'query'),
171
171
  await testUtils.getExpectedJson('9999999', 'query', 'build'),
172
172
  'returned deployment JSON was not equal expected'
173
173
  );
174
174
  expect(
175
- file(testUtils.getActualDeployFile('testExistingQuery', 'query', 'sql'))
175
+ file(testUtils.getActualDeployFile('testTemplated_query', 'query', 'sql'))
176
176
  ).to.equal(file(testUtils.getExpectedFile('9999999', 'query', 'build', 'sql')));
177
+
177
178
  assert.equal(
178
179
  testUtils.getAPIHistoryLength(),
179
180
  6,
@@ -188,7 +189,7 @@ describe('type: query', () => {
188
189
  const result = await handler.buildTemplate(
189
190
  'testInstance/testBU',
190
191
  'query',
191
- ['testExistingQuery'],
192
+ ['testExisting_query'],
192
193
  'testSourceMarket'
193
194
  );
194
195
  // WHEN
@@ -200,18 +201,18 @@ describe('type: query', () => {
200
201
  'only one query expected'
201
202
  );
202
203
  assert.deepEqual(
203
- await testUtils.getActualTemplateJson('testExistingQuery', 'query'),
204
+ await testUtils.getActualTemplateJson('testExisting_query', 'query'),
204
205
  await testUtils.getExpectedJson('9999999', 'query', 'template'),
205
206
  'returned template JSON of buildTemplate was not equal expected'
206
207
  );
207
208
  expect(
208
- file(testUtils.getActualTemplateFile('testExistingQuery', 'query', 'sql'))
209
+ file(testUtils.getActualTemplateFile('testExisting_query', 'query', 'sql'))
209
210
  ).to.equal(file(testUtils.getExpectedFile('9999999', 'query', 'template', 'sql')));
210
211
  // THEN
211
212
  await handler.buildDefinition(
212
213
  'testInstance/testBU',
213
214
  'query',
214
- 'testExistingQuery',
215
+ 'testExisting_query',
215
216
  'testTargetMarket'
216
217
  );
217
218
  assert.equal(
@@ -221,12 +222,12 @@ describe('type: query', () => {
221
222
  );
222
223
 
223
224
  assert.deepEqual(
224
- await testUtils.getActualDeployJson('testExistingQuery', 'query'),
225
+ await testUtils.getActualDeployJson('testTemplated_query', 'query'),
225
226
  await testUtils.getExpectedJson('9999999', 'query', 'build'),
226
227
  'returned deployment JSON was not equal expected'
227
228
  );
228
229
  expect(
229
- file(testUtils.getActualDeployFile('testExistingQuery', 'query', 'sql'))
230
+ file(testUtils.getActualDeployFile('testTemplated_query', 'query', 'sql'))
230
231
  ).to.equal(file(testUtils.getExpectedFile('9999999', 'query', 'build', 'sql')));
231
232
 
232
233
  assert.equal(
@@ -241,7 +242,7 @@ describe('type: query', () => {
241
242
  it('Should delete the item', async () => {
242
243
  // WHEN
243
244
  const result = await handler.deleteByKey('testInstance/testBU', 'query', [
244
- 'testExistingQuery',
245
+ 'testExisting_query',
245
246
  ]);
246
247
  // THEN
247
248
  assert.equal(process.exitCode, false, 'delete should not have thrown an error');
@@ -254,7 +255,7 @@ describe('type: query', () => {
254
255
  it('Should return a list of files based on their type and key', async () => {
255
256
  // WHEN
256
257
  const fileList = await handler.getFilesToCommit('testInstance/testBU', 'query', [
257
- 'testExistingQuery',
258
+ 'testExisting_query',
258
259
  ]);
259
260
  // THEN
260
261
  assert.equal(
@@ -266,15 +267,27 @@ describe('type: query', () => {
266
267
 
267
268
  assert.equal(
268
269
  fileList[0].split('\\').join('/'),
269
- 'retrieve/testInstance/testBU/query/testExistingQuery.query-meta.json',
270
+ 'retrieve/testInstance/testBU/query/testExisting_query.query-meta.json',
270
271
  'wrong JSON path'
271
272
  );
272
273
  assert.equal(
273
274
  fileList[1].split('\\').join('/'),
274
- 'retrieve/testInstance/testBU/query/testExistingQuery.query-meta.sql',
275
+ 'retrieve/testInstance/testBU/query/testExisting_query.query-meta.sql',
275
276
  'wrong JSON path'
276
277
  );
277
278
  return;
278
279
  });
279
280
  });
281
+ describe('Execute ================', () => {
282
+ it('Should start executing a query', async () => {
283
+ const execute = await handler.execute(
284
+ 'testInstance/testBU',
285
+ ['query'],
286
+ ['testExisting_query']
287
+ );
288
+ assert.equal(process.exitCode, false, 'execute should not have thrown an error');
289
+ assert.equal(execute, true, 'query was supposed to be executed');
290
+ return;
291
+ });
292
+ });
280
293
  });
@@ -7,6 +7,7 @@ const file = chaiFiles.file;
7
7
  const cache = require('../lib/util/cache');
8
8
  const testUtils = require('./utils');
9
9
  const handler = require('../lib/index');
10
+ const File = require('../lib/util/file');
10
11
 
11
12
  describe('type: user', () => {
12
13
  beforeEach(() => {
@@ -35,9 +36,22 @@ describe('type: user', () => {
35
36
  'returned metadata was not equal expected'
36
37
  );
37
38
  // check if MD file was created and equals expectations
38
- expect(file(`./docs/user/testInstance.users.md`)).to.equal(
39
- file(testUtils.getExpectedFile('1111111', 'user', 'retrieve', 'md'))
40
- );
39
+ // ! this test needs to update the lastLoginDate counter because it changes with every passing day
40
+ const expectedFile = await File.readFile(
41
+ testUtils.getExpectedFile('1111111', 'user', 'retrieve', 'md'),
42
+ { encoding: 'utf8' }
43
+ );
44
+ const regexFindDaysSinceLogin =
45
+ /\| (\d*) (seconds|minutes|days|weeks|months|years){1} \|/gm;
46
+ // fetch expected time since last login
47
+ const expectedDaysSinceLogin = expectedFile.match(regexFindDaysSinceLogin);
48
+ // load actual file and replace days since last login with expected value
49
+ const actualFile = (
50
+ await File.readFile(`./docs/user/testInstance.users.md`, {
51
+ encoding: 'utf8',
52
+ })
53
+ ).replaceAll(regexFindDaysSinceLogin, expectedDaysSinceLogin);
54
+ expect(actualFile).to.equal(expectedFile);
41
55
 
42
56
  assert.equal(
43
57
  testUtils.getAPIHistoryLength(),
package/test/utils.js CHANGED
@@ -4,6 +4,7 @@ const axios = require('axios');
4
4
  const MockAdapter = require('axios-mock-adapter');
5
5
  const auth = require('../lib/util/auth');
6
6
  const Util = require('../lib/util/util');
7
+ const handler = require('../lib/index');
7
8
 
8
9
  // for some reason doesnt realize below reference
9
10
  // eslint-disable-next-line no-unused-vars
@@ -28,7 +29,7 @@ exports.getActualJson = (customerKey, type, buName = 'testBU') =>
28
29
  * @param {string} customerKey of metadata
29
30
  * @param {string} type of metadata
30
31
  * @param {string} [buName] used when we need to test on ParentBU
31
- * @returns {Promise.<string>} file in string form
32
+ * @returns {string} file path
32
33
  */
33
34
  exports.getActualDoc = (customerKey, type, buName = 'testBU') =>
34
35
  `./retrieve/testInstance/${buName}/${type}/${customerKey}.${type}-doc.md`;
@@ -38,7 +39,7 @@ exports.getActualDoc = (customerKey, type, buName = 'testBU') =>
38
39
  * @param {string} customerKey of metadata
39
40
  * @param {string} type of metadata
40
41
  * @param {string} ext file extension
41
- * @returns {Promise.<string>} file in string form
42
+ * @returns {string} file path
42
43
  */
43
44
  exports.getActualFile = (customerKey, type, ext) =>
44
45
  `./retrieve/testInstance/testBU/${type}/${customerKey}.${type}-meta.${ext}`;
@@ -58,7 +59,7 @@ exports.getActualDeployJson = (customerKey, type, buName = 'testBU') =>
58
59
  * @param {string} customerKey of metadata
59
60
  * @param {string} type of metadata
60
61
  * @param {string} ext file extension
61
- * @returns {Promise.<string>} file in string form
62
+ * @returns {string} file path
62
63
  */
63
64
  exports.getActualDeployFile = (customerKey, type, ext) =>
64
65
  `./deploy/testInstance/testBU/${type}/${customerKey}.${type}-meta.${ext}`;
@@ -77,7 +78,7 @@ exports.getActualTemplateJson = (customerKey, type) =>
77
78
  * @param {string} customerKey of metadata
78
79
  * @param {string} type of metadata
79
80
  * @param {string} ext file extension
80
- * @returns {Promise.<string>} file in string form
81
+ * @returns {string} file path
81
82
  */
82
83
  exports.getActualTemplateFile = (customerKey, type, ext) =>
83
84
  `./template/${type}/${customerKey}.${type}-meta.${ext}`;
@@ -99,7 +100,7 @@ exports.getExpectedJson = (mid, type, action) =>
99
100
  * @param {string} type of metadata
100
101
  * @param {string} action of SOAP request
101
102
  * @param {string} ext file extension
102
- * @returns {Promise.<string>} file in string form
103
+ * @returns {string} file path
103
104
  */
104
105
  exports.getExpectedFile = (mid, type, action, ext) =>
105
106
  path.join('test', 'resources', mid, type, action + '-expected.' + ext);
@@ -111,7 +112,7 @@ exports.getExpectedFile = (mid, type, action, ext) =>
111
112
  */
112
113
 
113
114
  exports.mockSetup = (isDeploy) => {
114
- Util.setLoggingLevel({ debug: true });
115
+ handler.setOptions({ debug: true, noLogFile: true });
115
116
  apimock = new MockAdapter(axios, { onNoMatch: 'throwException' });
116
117
  // set access_token to mid to allow for autorouting of mock to correct resources
117
118
  apimock.onPost(authResources.success.url).reply((config) => {
@@ -1,20 +0,0 @@
1
- ## Coverage Report
2
-
3
- Commit: [{{short_commit_sha}}]({{commit_link}})
4
- Base: [{{base_ref}}@{{base_short_commit_sha}}]({{base_commit_link}})
5
-
6
- | Type | Base | This PR |
7
- | ------------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------- |
8
- | Total Statements Coverage | {{base_total_statements_coverage_percent}} | {{total_statements_coverage_percent}} ({{total_statements_coverage_percent_diff}}) |
9
- | Total Branches Coverage | {{base_total_branches_coverage_percent}} | {{total_branches_coverage_percent}} ({{total_branches_coverage_percent_diff}}) |
10
- | Total Functions Coverage | {{base_total_functions_coverage_percent}} | {{total_functions_coverage_percent}} ({{total_functions_coverage_percent_diff}}) |
11
- | Total Lines Coverage | {{base_total_lines_coverage_percent}} | {{total_lines_coverage_percent}} ({{total_lines_coverage_percent_diff}}) |
12
-
13
- <details>
14
- <summary>Details (changed files)</summary>
15
- {{changed_files_coverage_table}}
16
- </details>
17
- <details>
18
- <summary>Details (all files)</summary>
19
- {{files_coverage_table}}
20
- </details>