Skip to content

Commit 4cd7a7d

Browse files
validate-pr: report diff instead of current status (#4642) (#4645)
* validate-pr: report diff instead of current status * Introduce a few errors on purpose * Revert "Introduce a few errors on purpose" This reverts commit 3e5d7e1. (cherry picked from commit 73d7cb4) Co-authored-by: Quentin Pradet <[email protected]>
1 parent 68d4489 commit 4cd7a7d

File tree

1 file changed

+70
-28
lines changed

1 file changed

+70
-28
lines changed

.github/validate-pr/index.js

Lines changed: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import * as core from '@actions/core'
2727
import { copyFile } from 'fs/promises'
2828
import * as github from '@actions/github'
2929
import specification from '../../output/schema/schema.json' with { type: 'json' }
30+
import baselineValidation from '../../../clients-flight-recorder/recordings/types-validation/types-validation.json' with { type: 'json' }
3031
import { run as getReport } from '../../../clients-flight-recorder/scripts/types-validator/index.js'
3132
import {
3233
getNamespace,
@@ -81,7 +82,7 @@ async function run() {
8182
const specFiles = files.filter(
8283
(file) => file.includes('specification') && !file.includes('compiler/test')
8384
)
84-
const table = []
85+
const reports = new Map()
8586

8687
cd(tsValidationPath)
8788

@@ -104,37 +105,47 @@ async function run() {
104105
ci: false,
105106
verbose: false
106107
})
107-
table.push(buildTableLine(api, report))
108+
const [namespace, _method] = api.split('.')
109+
// Asked to validate a specific API, so we only store that one
110+
reports.set(api, report.get(namespace)[0])
108111
}
109112
} else {
113+
const api = getApi(file)
110114
const report = await getReport({
111-
api: getApi(file),
115+
api,
112116
'generate-report': false,
113117
request: true,
114118
response: true,
115119
ci: false,
116120
verbose: false
117121
})
118-
table.push(buildTableLine(getApi(file), report))
122+
123+
const [namespace, _method] = api.split('.')
124+
// Asked to validate a specific API, so we only store that one
125+
reports.set(api, report.get(namespace)[0])
119126
}
120127
}
121128

122129
cd(path.join(__dirname, '..', '..'))
123130

124-
table.sort((a, b) => {
125-
if (a < b) return -1
126-
if (a > b) return 1
127-
return 0
128-
})
131+
// Compare current reports with baseline and find changes
132+
const changedApis = []
133+
for (const [apiName, report] of reports) {
134+
const baselineReport = findBaselineReport(apiName, baselineValidation)
135+
if (baselineReport && hasChanges(baselineReport, report, apiName)) {
136+
changedApis.push({ api: apiName, baseline: baselineReport, current: report })
137+
}
138+
}
139+
changedApis.sort((a, b) => a.api.localeCompare(b.api))
129140

130-
if (table.length > 0) {
131-
let comment = `Following you can find the validation results for the API${table.length === 1 ? '' : 's'} you have changed.\n\n`
141+
if (changedApis.length > 0) {
142+
let comment = `Following you can find the validation changes for the API${changedApis.length === 1 ? '' : 's'} you have modified.\n\n`
132143
comment += '| API | Status | Request | Response |\n'
133144
comment += '| --- | --- | --- | --- |\n'
134-
for (const line of [...new Set(table)]) {
135-
comment += line
145+
for (const change of changedApis) {
146+
comment += buildDiffTableLine(change)
136147
}
137-
comment += `\nYou can validate ${table.length === 1 ? 'this' : 'these'} API${table.length === 1 ? '' : 's'} yourself by using the ${tick}make validate${tick} target.\n`
148+
comment += `\nYou can validate ${changedApis.length === 1 ? 'this' : 'these'} API${changedApis.length === 1 ? '' : 's'} yourself by using the ${tick}make validate${tick} target.\n`
138149

139150
await octokit.rest.issues.createComment({
140151
owner: 'elastic',
@@ -151,39 +162,70 @@ function getApi (file) {
151162
return file.split('/').slice(1, 3).filter(s => !privateNames.includes(s)).filter(Boolean).join('.')
152163
}
153164

154-
function buildTableLine (api, report) {
155-
const apiReport = report.get(getNamespace(api)).find(r => r.api === getName(api))
156-
return `| ${tick}${api}${tick} | ${generateStatus(apiReport)} | ${generateRequest(apiReport)} | ${generateResponse(apiReport)} |\n`
165+
166+
function findBaselineReport(apiName, baselineValidation) {
167+
const [namespace, method] = apiName.split('.')
168+
169+
if (!baselineValidation.namespaces[namespace]) {
170+
return null
171+
}
172+
173+
return baselineValidation.namespaces[namespace].apis.find(api => api.api === method)
157174
}
158175

159-
function generateStatus (report) {
160-
if (!report.diagnostics.hasRequestType || !report.diagnostics.hasResponseType) {
176+
function hasChanges(baselineReport, report) {
177+
if (!report) return false
178+
179+
return baselineReport.status !== report.status ||
180+
baselineReport.passingRequest !== report.passingRequest ||
181+
baselineReport.passingResponse !== report.passingResponse
182+
}
183+
184+
function buildDiffTableLine(change) {
185+
const { api, baseline, current } = change
186+
187+
const status = generateStatus(current.status)
188+
const request = generateRequest(current)
189+
const response = generateResponse(current)
190+
191+
const baselineStatus = generateStatus(baseline.status)
192+
const baselineRequest = generateRequest(baseline)
193+
const baselineResponse = generateResponse(baseline)
194+
195+
const statusDiff = status !== baselineStatus ? `${baselineStatus}${status}` : status
196+
const requestDiff = request !== baselineRequest ? `${baselineRequest}${request}` : request
197+
const responseDiff = response !== baselineResponse ? `${baselineResponse}${response}` : response
198+
199+
return `| ${tick}${api}${tick} | ${statusDiff} | ${requestDiff} | ${responseDiff} |\n`
200+
}
201+
202+
203+
function generateStatus (status) {
204+
if (status === 'missing_types' || status === 'missing_request_type' || status === 'missing_response_type') {
161205
return ':orange_circle:'
162206
}
163-
if (report.totalRequest <= 0 || report.totalResponse <= 0) {
207+
if (status === 'missing_test') {
164208
return ':white_circle:'
165209
}
166-
if (report.diagnostics.request.length === 0 && report.diagnostics.response.length === 0) {
210+
if (status === 'passing') {
167211
return ':green_circle:'
168212
}
169213
return ':red_circle:'
170214
}
171215

172216
function generateRequest (r) {
173-
if (r.totalRequest === -1) return 'Missing recording'
174-
if (!r.diagnostics.hasRequestType) return 'Missing type'
175-
if (r.totalRequest === 0) return 'Missing test'
217+
if (r.status === 'missing_test') return 'Missing test'
218+
if (r.status === 'missing_types' || r.status == 'missing_request_type') return 'Missing type'
176219
return `${r.passingRequest}/${r.totalRequest}`
177220
}
178221

179222
function generateResponse (r) {
180-
if (r.totalResponse === -1) return 'Missing recording'
181-
if (!r.diagnostics.hasResponseType) return 'Missing type'
182-
if (r.totalResponse === 0) return 'Missing test'
223+
if (r.status === 'missing_test') return 'Missing test'
224+
if (r.status === 'missing_types' || r.status == 'missing_response_type') return 'Missing type'
183225
return `${r.passingResponse}/${r.totalResponse}`
184226
}
185227

186228
run().catch((err) => {
187229
core.error(err)
188230
process.exit(1)
189-
})
231+
})

0 commit comments

Comments
 (0)