From fe0078ff8d22de5eea48280e48d5798a782c7546 Mon Sep 17 00:00:00 2001 From: Franck Terray Date: Fri, 23 Feb 2024 17:40:56 +0000 Subject: [PATCH] implement test suites notification in Typescript --- hooks/command | 2 - package-lock.json | 279 ++++++++++++++++++++---- src/interfaces/junitResult.interface.ts | 1 + src/runner.ts | 26 ++- src/slackNotification.ts | 58 ++--- src/xmlParser.ts | 11 +- test/runner.test.ts | 2 + test/slackNotification.test.ts | 93 +++++++- test/testcaseStats.test.ts | 2 + test/xmlParser.test.ts | 2 +- 10 files changed, 390 insertions(+), 86 deletions(-) diff --git a/hooks/command b/hooks/command index bc710fa..cbed8f0 100755 --- a/hooks/command +++ b/hooks/command @@ -50,14 +50,12 @@ if [[ -n "$(plugin_read_list TEST_SUITES_0_ARTIFACTS)" ]] ; then i=0 while true; do var="TEST_SUITES_${i}_ARTIFACTS" - echo "$var=$(plugin_read_list $var)" if [[ -n "$(plugin_read_list $var)" ]] ; then buildkite-agent artifact download \ "$(plugin_read_config "${var}" "")" \ "$ARTIFACTS_DIR" i=$((i+1)) else - echo "!!! LEAVING on $var" break fi done diff --git a/package-lock.json b/package-lock.json index d9b3ed6..0313a68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "async": "^3.2.5", "fs": "0.0.1-security", "lodash": ">=4.17.21", + "minimatch": "^9.0.3", "xml2js": "^0.6.2" }, "devDependencies": { @@ -614,6 +615,16 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "13.10.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", @@ -630,6 +641,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -658,6 +681,28 @@ "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", @@ -2314,21 +2359,16 @@ } }, "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true, - "license": "MIT" + "version": "1.0.2", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", + "version": "2.0.1", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -2616,10 +2656,9 @@ }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true, - "license": "MIT" + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true }, "node_modules/concurrently": { "version": "8.2.2", @@ -3342,6 +3381,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -3432,6 +3481,18 @@ "node": ">= 0.8.0" } }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint/node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -4013,6 +4074,28 @@ "node": ">= 6" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -6770,15 +6853,14 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "version": "9.0.3", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" } }, "node_modules/mocked-env": { @@ -8050,6 +8132,28 @@ "node": ">=8" } }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -9134,6 +9238,16 @@ "strip-json-comments": "^3.1.1" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "globals": { "version": "13.10.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", @@ -9143,6 +9257,15 @@ "type-fest": "^0.20.2" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -9160,6 +9283,27 @@ "@humanwhocodes/object-schema": "^1.2.0", "debug": "^4.1.1", "minimatch": "^3.0.4" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "@humanwhocodes/object-schema": { @@ -10346,19 +10490,16 @@ } }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "version": "1.0.2", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "version": "2.0.1", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "braces": { @@ -10565,8 +10706,8 @@ }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "concurrently": { @@ -11050,6 +11191,16 @@ "color-convert": "^2.0.1" } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -11106,6 +11257,15 @@ "type-check": "~0.4.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -11531,6 +11691,27 @@ "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "glob-parent": { @@ -13450,12 +13631,11 @@ "dev": true }, "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "version": "9.0.3", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" } }, "mocked-env": { @@ -14346,6 +14526,27 @@ "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://artifactory.jfrog.iress.online/artifactory/api/npm/iress-npm/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "text-table": { diff --git a/src/interfaces/junitResult.interface.ts b/src/interfaces/junitResult.interface.ts index 32d3989..1065997 100644 --- a/src/interfaces/junitResult.interface.ts +++ b/src/interfaces/junitResult.interface.ts @@ -1,4 +1,5 @@ export interface JunitResult { + name: string | undefined, buildkite_pipeline: string, git_branch_name: string, build_id: number, diff --git a/src/runner.ts b/src/runner.ts index beecf85..a94d9b6 100644 --- a/src/runner.ts +++ b/src/runner.ts @@ -5,6 +5,7 @@ import {addStatsToCommit} from "./testcaseStats"; export const run = async () => { const commit: JunitResult = { + name: "", build_id: parseInt(process.env.BUILDKITE_BUILD_NUMBER, 10), build_url: process.env.BUILDKITE_BUILD_URL, buildkite_pipeline: process.env.BUILDKITE_PIPELINE_NAME, @@ -20,8 +21,27 @@ export const run = async () => { const SLACK_TOKEN = process.env.SLACK_TOKEN; const SLACK_CHANNEL = process.env.SLACK_CHANNEL; - const testsuites = await parseFiles(); - const result = await addStatsToCommit(testsuites, commit); - await sendResultToSlack(SLACK_TOKEN, SLACK_CHANNEL, result) + const results:JunitResult[] = []; + + const TEST_SUITES_0_ARTIFACTS = process.env.TEST_SUITES_0_ARTIFACTS || ""; + + if (TEST_SUITES_0_ARTIFACTS !== "") { + // loop until the string TEST_SUITES_0_ARTIFACTS is empty and 0 increase over each loop + let i = 0; + while (process.env[`TEST_SUITES_${i}_ARTIFACTS`] !== "") { + const testsuite = await parseFiles(process.env[`TEST_SUITES_${i}_ARTIFACTS`]); + const result = await addStatsToCommit(testsuite, commit); + result.name = process.env[`TEST_SUITES_${i}_NAME`] || ""; + results.push(result); + i++; + } + } else { + const ARTIFACTS = process.env.ARTIFACTS || "**/*.xml"; + const testsuite = await parseFiles(ARTIFACTS); + const result = await addStatsToCommit(testsuite, commit); + results.push(result); + } + + await sendResultToSlack(SLACK_TOKEN, SLACK_CHANNEL, results) .then(() => console.log("completed.")); }; diff --git a/src/slackNotification.ts b/src/slackNotification.ts index 755bd3b..b129071 100644 --- a/src/slackNotification.ts +++ b/src/slackNotification.ts @@ -1,23 +1,24 @@ import {JunitResult} from "./interfaces/junitResult.interface"; import {sendSlackMessage} from "./slack-web-api"; +import {flatten} from "lodash"; -export const getColor = (result: JunitResult): string => { - if (result.tests_failed > 0) { +export const getColor = (results: JunitResult[]): string => { + if (results.some(result => result.tests_failed > 0)) { return "#B94A48"; } - const summary = getSummary(result); - if (summary.length === 0) { + const summaries = results.map(result => getSummary(result)); + if (flatten(summaries).length === 0) { return "#B94A48"; } return "#69A76A"; }; -export const getEmoji = (result: JunitResult): string => { - if (result.tests_failed > 0) { +export const getEmoji = (results: JunitResult[]): string => { + if (results.some(result => result.tests_failed > 0)) { return ":-1: :-1:"; } - const summary = getSummary(result); - if (summary.length === 0) { + const summaries = results.map(result => getSummary(result)); + if (flatten(summaries).length === 0) { return ":-1:"; } return ":+1:"; @@ -39,26 +40,39 @@ export const getSummary = (result: JunitResult): string[] => { export const getTextSummaryLine = (result: JunitResult): string => { const summary = getSummary(result); - if (summary.length > 0) { - return `Tests ${summary.join(", ")}`; + const name = !result.name? "" : `*${result.name}*: `; + if (summary.length > 0 && result.name) { + return `${name}Tests ${summary.join(", ")}`; + } else if (summary.length > 0 && !result.name) { + return `*Tests ${summary.join(", ")}*`; } - return "No tests data generated!"; + return `${name}*No tests data generated!*`; }; -export const getCommitText = (result: JunitResult): string => { - return `${getEmoji(result)} *${result.buildkite_pipeline} (${result.git_branch_name}) #${result.build_id}*\n${result.git_comment} - ${result.git_username} (${result.git_log})`; +export const getCommitText = (results: JunitResult[]): string => { + return `${getEmoji(results)} *${results[0].buildkite_pipeline} (${results[0].git_branch_name}) #${results[0].build_id}*\n${results[0].git_comment} - ${results[0].git_username} (${results[0].git_log})`; }; -export const getSlackMessageAttachments = (result: JunitResult): unknown => { +export const getSlackMessageAttachments = (results: JunitResult[]): unknown => { + const details = results.map((result) => { + return { + "type": "section", + "text": { + "text": `${getTextSummaryLine(result)}`, + "type": "mrkdwn" + } + }; + }); + return [ { - "color": getColor(result), + "color": getColor(results), "blocks": [ { "type": "section", "text": { "type": "mrkdwn", - "text": getCommitText(result) + "text": getCommitText(results) }, "accessory": { "type": "button", @@ -66,22 +80,16 @@ export const getSlackMessageAttachments = (result: JunitResult): unknown => { "type": "plain_text", "text": "View build" }, - "url": result.build_url + "url": results[0].build_url } }, - { - "type": "section", - "text": { - "text": `*${getTextSummaryLine(result)}*`, - "type": "mrkdwn" - } - } + ...details ] } ]; }; -export const sendResultToSlack = async (slackToken: string, channel: string, junitResult: JunitResult): Promise => { +export const sendResultToSlack = async (slackToken: string, channel: string, junitResult: JunitResult[]): Promise => { let goodToken = ""; for (let i = 0; i < slackToken.length; i++) { if (checkChar(slackToken[i])) { diff --git a/src/xmlParser.ts b/src/xmlParser.ts index f72e56b..5a9904b 100644 --- a/src/xmlParser.ts +++ b/src/xmlParser.ts @@ -3,6 +3,7 @@ import {promisify} from "util"; import {join} from "path"; import {Parser} from "xml2js"; import {flattenDeep} from "lodash"; +import {minimatch} from "minimatch"; // Convert sync functions into async const fsReaddir = promisify(readdir); @@ -10,22 +11,22 @@ const fsReadFile = promisify(readFile); const fsStat = promisify(stat); const xmlParser = new Parser(); -export const parseFiles = async () => { +export const parseFiles = async (artifacts: string) => { const directoryPath = join(__dirname, "../reports"); - const allContents = await parseFolder(directoryPath); + const allContents = await parseFolder(directoryPath, artifacts); return flattenDeep(allContents); }; -export const parseFolder = async (baseDirectory: string): Promise => { +export const parseFolder = async (baseDirectory: string, artifacts: string): Promise => { const files: any[] = await fsReaddir(baseDirectory); return Promise.all(files.map(async fileName => { const fullPath = join(baseDirectory, fileName); const stats = await fsStat(fullPath); if (stats.isDirectory()) { // recursive - return parseFolder(fullPath); + return parseFolder(fullPath, artifacts); } - if (stats.isFile()) { + if (stats.isFile() && minimatch(fullPath, artifacts)) { console.log(`parsing ${fullPath}`); return parseFile(fullPath); } diff --git a/test/runner.test.ts b/test/runner.test.ts index 64be992..6601743 100644 --- a/test/runner.test.ts +++ b/test/runner.test.ts @@ -64,6 +64,7 @@ line 3`, "git_comment": "line 1", "git_log": "0123456", "git_username": "the-author", + "name": "", "tests_failed": 0, "tests_ignored": 0, "tests_passed": 0 @@ -83,6 +84,7 @@ line 3`, "git_comment": "msg", "git_log": "0123456", "git_username": "the-author", + "name": "", "tests_failed": 0, "tests_ignored": 0, "tests_passed": 0 diff --git a/test/slackNotification.test.ts b/test/slackNotification.test.ts index 9494a1c..f7d9f01 100644 --- a/test/slackNotification.test.ts +++ b/test/slackNotification.test.ts @@ -23,6 +23,7 @@ beforeEach(() => { describe("Failed test", () => { const result: JunitResult = { + name: "", tests_failed: 3, build_id: 123, build_url: "https://www.iress.com/mybuild", @@ -36,21 +37,21 @@ describe("Failed test", () => { }; it("should return red", () => { - const actual = getColor(result); + const actual = getColor([result]); expect(actual).toBe("#B94A48"); }); it("should return negative emoij", () => { - const actual = getEmoji(result); + const actual = getEmoji([result]); expect(actual).toBe(":-1: :-1:"); }); it("should return summary slack message", () => { - const actual = getSlackMessageAttachments(result); + const actual = getSlackMessageAttachments([result]); expect(actual).toStrictEqual([ { @@ -88,7 +89,7 @@ describe("Failed test", () => { const SLACK_TOKEN = "xoxb-00000000000-0000000000000-xxxxxxxxxxxxxxxxxxxxxxxx\t"; const SLACK_CHANNEL = "hac-483_testing"; - await sendResultToSlack(SLACK_TOKEN, SLACK_CHANNEL, result); + await sendResultToSlack(SLACK_TOKEN, SLACK_CHANNEL, [result]); expect(mockToken).toEqual("xoxb-00000000000-0000000000000-xxxxxxxxxxxxxxxxxxxxxxxx"); @@ -98,6 +99,7 @@ describe("Failed test", () => { describe("Passed test", () => { const result: JunitResult = { + name: "", tests_failed: 0, build_id: 456, build_url: "https://www.iress.com/myotherbuild", @@ -110,16 +112,44 @@ describe("Passed test", () => { tests_ignored: 0 }; + const unitTestResult: JunitResult = { + name: "Unit tests", + tests_failed: 0, + build_id: 456, + build_url: "https://www.iress.com/myotherbuild", + buildkite_pipeline: "My Build other pipeline", + git_branch_name: "hac-483_other_branch", + git_comment: "Second commit", + git_log: "a1b2c3d4", + git_username: "Frankly Chilled", + tests_passed: 300, + tests_ignored: 0 + }; + + const verificationTestResult: JunitResult = { + name: "Verification tests", + tests_failed: 0, + build_id: 456, + build_url: "https://www.iress.com/myotherbuild", + buildkite_pipeline: "My Build other pipeline", + git_branch_name: "hac-483_other_branch", + git_comment: "Second commit", + git_log: "a1b2c3d4", + git_username: "Frankly Chilled", + tests_passed: 20, + tests_ignored: 0 + }; + it("should return green", () => { - const actual = getColor(result); + const actual = getColor([result]); expect(actual).toBe("#69A76A"); }); it("should return summary slack message", () => { - const actual = getSlackMessageAttachments(result); + const actual = getSlackMessageAttachments([result]); expect(actual).toStrictEqual([ { @@ -153,18 +183,59 @@ describe("Passed test", () => { }); + it("should return summary slack message of multiple test suites", () => { + const actual = getSlackMessageAttachments([unitTestResult, verificationTestResult]); + + expect(actual).toStrictEqual([ + { + "blocks": [ + { + "accessory": { + "text": { + "text": "View build", + "type": "plain_text" + }, + "type": "button", + "url": "https://www.iress.com/myotherbuild" + }, + "text": { + "text": ":+1: *My Build other pipeline (hac-483_other_branch) #456*\nSecond commit - Frankly Chilled (a1b2c3d4)", + "type": "mrkdwn" + }, + "type": "section" + }, + { + "text": { + "text": "*Unit tests*: Tests passed: 300", + "type": "mrkdwn" + }, + "type": "section" + }, + { + "text": { + "text": "*Verification tests*: Tests passed: 20", + "type": "mrkdwn" + }, + "type": "section" + } + ], + "color": "#69A76A" + } + ]); + + }); + it("send message to slack channel", async () => { const SLACK_TOKEN = "xoxb-00000000000-0000000000000-xxxxxxxxxxxxxxxxxxxxxxxx"; const SLACK_CHANNEL = "hac-483_testing"; - await sendResultToSlack(SLACK_TOKEN, SLACK_CHANNEL, result); - - + await sendResultToSlack(SLACK_TOKEN, SLACK_CHANNEL, [result]); }); }); describe("No tests", () => { const result: JunitResult = { + name: "", tests_failed: 0, build_id: 789, build_url: "https://www.iress.com/myotherbuild", @@ -178,7 +249,7 @@ describe("No tests", () => { }; it("should return summary slack message", () => { - const actual = getSlackMessageAttachments(result); + const actual = getSlackMessageAttachments([result]); expect(actual).toStrictEqual([ { @@ -216,7 +287,7 @@ describe("No tests", () => { const SLACK_TOKEN = "xoxb-00000000000-0000000000000-xxxxxxxxxxxxxxxxxxxxxxxx"; const SLACK_CHANNEL = "hac-483_testing"; - await sendResultToSlack(SLACK_TOKEN, SLACK_CHANNEL, result); + await sendResultToSlack(SLACK_TOKEN, SLACK_CHANNEL, [result]); // verify call to chat const attachments = [ diff --git a/test/testcaseStats.test.ts b/test/testcaseStats.test.ts index a20cba1..b87a24a 100644 --- a/test/testcaseStats.test.ts +++ b/test/testcaseStats.test.ts @@ -681,6 +681,7 @@ describe("Add Statistic to Commit", () => { git_comment: "bk_MESSAGE", git_log: "asdfff012", git_username: "bk_BUILD_AUTHOR", + name: "", tests_failed: 0, tests_passed: 0, tests_ignored: 0 @@ -948,6 +949,7 @@ describe("Add Statistic to Commit", () => { git_comment: "bk_MESSAGE", git_log: "asdfff012", git_username: "bk_BUILD_AUTHOR", + name: "", tests_failed: 1, tests_ignored: 11, tests_passed: 1 diff --git a/test/xmlParser.test.ts b/test/xmlParser.test.ts index a6c9dcc..99c2a92 100644 --- a/test/xmlParser.test.ts +++ b/test/xmlParser.test.ts @@ -3,7 +3,7 @@ import {describe, expect} from "@jest/globals"; describe("Parser test read slack-notification/reports folder", () => { it("should parse XML files with testcase results", async () => { - const actual = await parseFiles(); + const actual = await parseFiles("**/*.xml"); expect(actual).toEqual([ { "testsuite": {