Skip to content

Commit c96e3ed

Browse files
committed
Updated the webhook to record test cases
1 parent 90b45d4 commit c96e3ed

File tree

7 files changed

+196
-5
lines changed

7 files changed

+196
-5
lines changed

src/config.service.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ import * as path from 'path';
88

99
import { zencrepesConfig, defaultConfig } from '@bit/zencrepes.zindexer.config';
1010

11+
// Since bit is not working anymore, adding this extra interface manually
12+
interface zencrepesConfigAppend {
13+
elasticsearch: {
14+
dataIndices: {
15+
testingCases: string;
16+
}
17+
}
18+
}
19+
1120
export interface EnvConf {
1221
[key: string]: string;
1322
}
@@ -19,7 +28,7 @@ export class ConfigService {
1928
APP_VERSION: string;
2029

2130
private readonly envConfig: EnvConf;
22-
private userConfig: zencrepesConfig;
31+
private userConfig: zencrepesConfig & zencrepesConfigAppend;
2332

2433
constructor() {
2534
// Initialize config directory:
@@ -74,11 +83,11 @@ export class ConfigService {
7483
return this.envConfig[key];
7584
}
7685

77-
getUserConfig(): zencrepesConfig {
86+
getUserConfig(): zencrepesConfig & zencrepesConfigAppend {
7887
return this.userConfig;
7988
}
8089

81-
setUserConfig(userConfig: zencrepesConfig) {
90+
setUserConfig(userConfig: zencrepesConfig & zencrepesConfigAppend) {
8291
this.userConfig = userConfig;
8392
}
8493
}

src/testing/cases/esMapping.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
const yaml = `
2+
#https://www.elastic.co/guide/en/elasticsearch/plugins/current/mapper-size-usage.html
3+
_source:
4+
enabled: true
5+
properties:
6+
id:
7+
type: keyword
8+
name:
9+
type: text
10+
fields:
11+
keyword:
12+
type: keyword
13+
ignore_above: 256
14+
suite:
15+
type: text
16+
fields:
17+
keyword:
18+
type: keyword
19+
ignore_above: 256
20+
project:
21+
type: text
22+
fields:
23+
keyword:
24+
type: keyword
25+
ignore_above: 256
26+
jahia:
27+
type: text
28+
fields:
29+
keyword:
30+
type: keyword
31+
ignore_above: 256
32+
module:
33+
type: text
34+
fields:
35+
keyword:
36+
type: keyword
37+
ignore_above: 256
38+
full:
39+
type: text
40+
fields:
41+
keyword:
42+
type: keyword
43+
ignore_above: 256
44+
createdAt:
45+
type: date
46+
state:
47+
type: keyword
48+
caseTotal:
49+
type: integer
50+
caseSuccess:
51+
type: integer
52+
caseSuccessRate:
53+
type: integer
54+
caseFailure:
55+
type: integer
56+
caseFailureRate:
57+
type: integer
58+
duration:
59+
type: keyword
60+
url:
61+
type: keyword
62+
`;
63+
export default yaml;

src/testing/cases/esSettings.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const yaml = `
2+
analysis:
3+
analyzer:
4+
autocomplete_analyzed:
5+
filter:
6+
- lowercase
7+
- edge_ngram
8+
tokenizer: standard
9+
autocomplete_prefix:
10+
filter:
11+
- lowercase
12+
- edge_ngram
13+
tokenizer: keyword
14+
lowercase_keyword:
15+
filter:
16+
- lowercase
17+
tokenizer: keyword
18+
filter:
19+
edge_ngram:
20+
max_gram: '20'
21+
min_gram: '1'
22+
side: front
23+
type: edge_ngram
24+
index.mapping.nested_fields.limit: 100
25+
number_of_shards: 1
26+
`;
27+
export default yaml;

src/testing/cases/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export { default as esMapping } from './esMapping';
2+
export { default as esSettings } from './esSettings';
3+
export { getId, getCaseId } from './utils';
4+
export { CaseNode, Dependency } from './node.type'

src/testing/cases/node.type.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
export interface Dependency {
3+
id: string;
4+
name: string;
5+
version: string;
6+
full: string;
7+
url?: string;
8+
}
9+
10+
export interface CaseNode {
11+
id: string;
12+
name: string;
13+
suite: string;
14+
project: string;
15+
version: string;
16+
full: string;
17+
dependencies: Dependency[]
18+
createdAt: string;
19+
state: string;
20+
duration: number;
21+
url: string;
22+
}

src/testing/cases/utils.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {v5 as uuidv5} from 'uuid'
2+
import {CaseNode} from './node.type'
3+
4+
interface Dependency {
5+
name: string;
6+
version: string;
7+
}
8+
9+
const prepString = (s: string) => {
10+
return s.replace(/[^0-9a-zA-Z]/g, '').toLowerCase()
11+
}
12+
13+
// We want the run ID to be unique as we want to record all runs
14+
export const getCaseId = (testCase: CaseNode) => {
15+
const idStr = prepString(testCase.id) + prepString(testCase.createdAt)
16+
const UUID_NAMESPACE = 'c72d8f12-1818-4cb9-bead-44634c441c11'
17+
return uuidv5(idStr, UUID_NAMESPACE)
18+
}
19+
20+
21+
// This generate an unique id based on the combination the component and its dependencies
22+
// The ID is simply a UUID genreated from the concatenation of all elements
23+
// Note that the dependencies are sorted and all string are cleaned (lower case and stripped from non alphanumerical characters)
24+
export const getId = (dependency: Dependency) => {
25+
const idStr = prepString(dependency.name) + prepString(dependency.version)
26+
const UUID_NAMESPACE = 'c72d8f12-1818-4cb9-bead-44634c441c11'
27+
return uuidv5(idStr, UUID_NAMESPACE)
28+
}

src/testing/testingStorePayload.processor.ts

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Job } from 'bull';
44

55
import { esMapping, esSettings, StateNode, getId } from '@bit/zencrepes.zindexer.testing-states';
66
import { esMapping as esMappingRuns, esSettings as esSettingsRuns, RunNode, getRunId} from '@bit/zencrepes.zindexer.testing-runs';
7+
import { esMapping as esMappingCases, esSettings as esSettingsCases, CaseNode, getCaseId} from './cases';
78
import { checkEsIndex, pushEsNodes } from '@bit/zencrepes.zindexer.es-utils';
89

910
import { ConfigService } from '../config.service';
@@ -31,7 +32,7 @@ export class TestingStorePayloadProcessor {
3132
await checkEsIndex(esClient, userConfig.elasticsearch.dataIndices.testingStates, esMapping, esSettings, console.log);
3233

3334
// Transforming the object, objective is just to match to GitHub's to be consistent with the rest of the app
34-
const state: StateNode = {
35+
let state: StateNode = {
3536
...job.data,
3637
full: job.data.name + '_' + job.data.version,
3738
dependencies: {
@@ -48,6 +49,12 @@ export class TestingStorePayloadProcessor {
4849
}
4950
}
5051

52+
// Cases is a more recent addition, it should not be present in the state, not to pollute the index
53+
// with unnecessary data
54+
if ((state as any).cases !== undefined) {
55+
delete (state as any).cases;
56+
}
57+
5158
// Push single document to Elasticsearch
5259
await pushEsNodes(esClient, userConfig.elasticsearch.dataIndices.testingStates, [state], console.log);
5360

@@ -58,7 +65,7 @@ export class TestingStorePayloadProcessor {
5865
await checkEsIndex(esClient, userConfig.elasticsearch.dataIndices.testingRuns, esMappingRuns, esSettingsRuns, console.log);
5966

6067
// Transforming the object, objective is just to match to GitHub's to be consistent with the rest of the app
61-
const run: RunNode = {
68+
let run: RunNode = {
6269
...job.data,
6370
id: getRunId(job.data),
6471
full: job.data.name + '_' + job.data.version,
@@ -78,8 +85,39 @@ export class TestingStorePayloadProcessor {
7885
}
7986
}
8087

88+
// Cases is a more recent addition, it should not be present in the state, not to pollute the index
89+
// with unnecessary data
90+
if ((run as any).cases !== undefined) {
91+
delete (run as any).cases;
92+
}
93+
8194
// Push single document to Elasticsearch
8295
await pushEsNodes(esClient, userConfig.elasticsearch.dataIndices.testingRuns, [run], console.log);
8396

97+
if (job.data.cases !== undefined && job.data.cases.length > 0) {
98+
// Check if the index exists, create it if it does not
99+
await checkEsIndex(esClient, userConfig.elasticsearch.dataIndices.testingCases, esMappingCases, esSettingsCases, console.log);
100+
101+
// Populating testing Cases
102+
this.logger.log(`Event for: ${job.data.name}, version: ${job.data.version} - Pushing ${job.data.cases.length} Cases`);
103+
104+
const cases: CaseNode[] = job.data.cases.map((c) => {
105+
const caseObj = {
106+
...c,
107+
id: getCaseId(c),
108+
full: c.suite + ' - ' + c.name,
109+
runId: run.id,
110+
url: run.url,
111+
caseSuccessRate: Math.round(c.caseSuccess * 100 / c.caseTotal),
112+
caseFailureRate: Math.round(c.caseFailure * 100 / c.caseTotal),
113+
project: run.name
114+
}
115+
return caseObj
116+
})
117+
118+
// Push single document to Elasticsearch
119+
await pushEsNodes(esClient, userConfig.elasticsearch.dataIndices.testingCases, cases, console.log);
120+
121+
}
84122
}
85123
}

0 commit comments

Comments
 (0)