Skip to content

Commit 32664fe

Browse files
authored
Merge branch 'main' into no-native-structures-validation
2 parents e4ed6cb + 929efea commit 32664fe

File tree

835 files changed

+77427
-11558
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

835 files changed

+77427
-11558
lines changed

.backportrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"repoOwner": "elastic",
33
"repoName": "elasticsearch-specification",
4-
"targetBranchChoices": ["9.0", "8.19", "8.18", "8.17"],
4+
"targetBranchChoices": ["9.1", "9.0", "8.19", "8.18"],
55
"fork": false
66
}

.github/validate-pr/index.js

Lines changed: 92 additions & 49 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,10 +82,13 @@ 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

89+
// Collect all APIs to validate
90+
const apisToValidate = new Set()
91+
8892
for (const file of specFiles) {
8993
if (file.startsWith('specification/_types')) continue
9094
if (file.startsWith('specification/_spec_utils')) continue
@@ -101,53 +105,62 @@ async function run() {
101105
.filter(endpoint => endpoint.name.split('.').filter(s => !privateNames.includes(s))[0] === getApi(file).split('.')[0])
102106
.map(endpoint => endpoint.name)
103107
for (const api of apis) {
104-
const report = await getReport({
105-
api,
106-
'generate-report': false,
107-
request: true,
108-
response: true,
109-
ci: false,
110-
verbose: false
111-
})
112-
table.push(buildTableLine(api, report))
108+
apisToValidate.add(api)
113109
}
114110
} else {
115-
const report = await getReport({
116-
api: getApi(file),
117-
'generate-report': false,
118-
request: true,
119-
response: true,
120-
ci: false,
121-
verbose: false
122-
})
123-
table.push(buildTableLine(getApi(file), report))
111+
const api = getApi(file)
112+
apisToValidate.add(api)
113+
}
114+
}
115+
116+
// Call getReport once with all APIs
117+
if (apisToValidate.size > 0) {
118+
const allApis = Array.from(apisToValidate).join(',')
119+
const report = await getReport({
120+
api: allApis,
121+
'generate-report': false,
122+
request: true,
123+
response: true,
124+
ci: false,
125+
verbose: false
126+
})
127+
128+
// Extract individual API reports from the combined result
129+
for (const api of apisToValidate) {
130+
const namespace = getNamespace(api)
131+
if (report.has(namespace)) {
132+
const namespaceReport = report.get(namespace).find(r => r.api === getName(api))
133+
if (namespaceReport) {
134+
reports.set(api, namespaceReport)
135+
}
136+
}
124137
}
125138
}
126139

127140
cd(path.join(__dirname, '..', '..'))
128141

129-
table.sort((a, b) => {
130-
if (a < b) return -1
131-
if (a > b) return 1
132-
return 0
133-
})
142+
// Compare current reports with baseline and find changes
143+
const changedApis = []
144+
for (const [apiName, report] of reports) {
145+
const baselineReport = findBaselineReport(apiName, baselineValidation)
146+
if (baselineReport && hasChanges(baselineReport, report, apiName)) {
147+
changedApis.push({ api: apiName, baseline: baselineReport, current: report })
148+
}
149+
}
150+
changedApis.sort((a, b) => a.api.localeCompare(b.api))
134151

135-
if (table.length > 0) {
136-
let comment = `Following you can find the validation results for the API${table.length === 1 ? '' : 's'} you have changed.\n\n`
152+
let comment = `Following you can find the validation changes against the target branch for the API${changedApis.length === 1 ? '' : 's'}.\n\n`
153+
if (changedApis.length > 0) {
137154
comment += '| API | Status | Request | Response |\n'
138155
comment += '| --- | --- | --- | --- |\n'
139-
for (const line of [...new Set(table)]) {
140-
comment += line
156+
for (const change of changedApis) {
157+
comment += buildDiffTableLine(change)
141158
}
142-
comment += `\nYou can validate ${table.length === 1 ? 'this' : 'these'} API${table.length === 1 ? '' : 's'} yourself by using the ${tick}make validate${tick} target.\n`
143-
144-
await octokit.rest.issues.createComment({
145-
owner: 'elastic',
146-
repo: 'elasticsearch-specification',
147-
issue_number: context.payload.pull_request.number,
148-
body: comment
149-
})
159+
} else {
160+
comment += '**No changes detected**.\n'
150161
}
162+
comment += `\nYou can validate ${changedApis.length === 1 ? 'this' : 'these'} API${changedApis.length === 1 ? '' : 's'} yourself by using the ${tick}make validate${tick} target.\n`
163+
core.setOutput('comment_body', comment)
151164

152165
core.info('Done!')
153166
}
@@ -156,35 +169,65 @@ function getApi (file) {
156169
return file.split('/').slice(1, 3).filter(s => !privateNames.includes(s)).filter(Boolean).join('.')
157170
}
158171

159-
function buildTableLine (api, report) {
160-
const apiReport = report.get(getNamespace(api)).find(r => r.api === getName(api))
161-
return `| ${tick}${api}${tick} | ${generateStatus(apiReport)} | ${generateRequest(apiReport)} | ${generateResponse(apiReport)} |\n`
172+
function findBaselineReport(apiName, baselineValidation) {
173+
const [namespace, method] = apiName.split('.')
174+
175+
if (!baselineValidation.namespaces[namespace]) {
176+
return null
177+
}
178+
179+
return baselineValidation.namespaces[namespace].apis.find(api => api.api === method)
162180
}
163181

164-
function generateStatus (report) {
165-
if (!report.diagnostics.hasRequestType || !report.diagnostics.hasResponseType) {
182+
function hasChanges(baselineReport, report) {
183+
if (!report) return false
184+
185+
return baselineReport.status !== report.status ||
186+
baselineReport.passingRequest !== report.passingRequest ||
187+
baselineReport.passingResponse !== report.passingResponse
188+
}
189+
190+
function buildDiffTableLine(change) {
191+
const { api, baseline, current } = change
192+
193+
const status = generateStatus(current.status)
194+
const request = generateRequest(current)
195+
const response = generateResponse(current)
196+
197+
const baselineStatus = generateStatus(baseline.status)
198+
const baselineRequest = generateRequest(baseline)
199+
const baselineResponse = generateResponse(baseline)
200+
201+
const statusDiff = status !== baselineStatus ? `${baselineStatus}${status}` : status
202+
const requestDiff = request !== baselineRequest ? `${baselineRequest}${request}` : request
203+
const responseDiff = response !== baselineResponse ? `${baselineResponse}${response}` : response
204+
205+
return `| ${tick}${api}${tick} | ${statusDiff} | ${requestDiff} | ${responseDiff} |\n`
206+
}
207+
208+
209+
function generateStatus (status) {
210+
if (status === 'missing_types' || status === 'missing_request_type' || status === 'missing_response_type') {
166211
return ':orange_circle:'
167212
}
168-
if (report.totalRequest <= 0 || report.totalResponse <= 0) {
213+
if (status === 'missing_test') {
169214
return ':white_circle:'
170215
}
171-
if (report.diagnostics.request.length === 0 && report.diagnostics.response.length === 0) {
216+
if (status === 'passing') {
172217
return ':green_circle:'
173218
}
174219
return ':red_circle:'
175220
}
176221

177222
function generateRequest (r) {
178-
if (r.totalRequest === -1) return 'Missing recording'
179-
if (!r.diagnostics.hasRequestType) return 'Missing type'
180-
if (r.totalRequest === 0) return 'Missing test'
223+
if (r.status === 'missing_test') return 'Missing test'
224+
if (r.status === 'missing_types' || r.status == 'missing_request_type') return 'Missing type'
181225
return `${r.passingRequest}/${r.totalRequest}`
182226
}
183227

184228
function generateResponse (r) {
185-
if (r.totalResponse === -1) return 'Missing recording'
186-
if (!r.diagnostics.hasResponseType) return 'Missing type'
187-
if (r.totalResponse === 0) return 'Missing test'
229+
if (r.status === 'missing_test') return 'Missing test'
230+
if (r.status === 'missing_types' || r.status == 'missing_response_type') return 'Missing type'
188231
return `${r.passingResponse}/${r.totalResponse}`
189232
}
190233

.github/workflows/update-rest-api-json.yml

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
strategy:
1414
fail-fast: false
1515
matrix:
16-
branch: ['main', '9.0', '8.19', '8.18', '8.17', '8.16', '7.17']
16+
branch: ['main', '9.1', '9.0', '8.19', '8.18']
1717

1818
steps:
1919
- uses: actions/checkout@v4
@@ -28,8 +28,7 @@ jobs:
2828
- name: Install deps
2929
run: |
3030
npm install --prefix .github/download-artifacts
31-
npm install --prefix compiler
32-
npm install --prefix typescript-generator
31+
make setup
3332
3433
- name: Download artifacts
3534
run: |
@@ -53,12 +52,3 @@ jobs:
5352
delete-branch: true
5453
reviewers: Anaethelion,ezimuel,flobernd,JoshMock,l-trotta,miguelgrinberg,picandocodigo,pquentin,swallez,technige
5554
branch: automated/rest-api-spec-update-${{ matrix.branch }}
56-
57-
- name: Open an issue if the action fails
58-
if: ${{ failure() }}
59-
uses: nashmaniac/[email protected]
60-
with:
61-
title: rest-api-spec update failed
62-
token: ${{ secrets.GITHUB_TOKEN }}
63-
labels: bug
64-
body: The rest-api-spec action is currently failing, see [here](https://github.com/elastic/elasticsearch-specification/actions/workflows/update-rest-api-json.yml).

.github/workflows/validate-pr.yml

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,25 @@ jobs:
6060
fi
6161
node scripts/upload-recording/download.js --branch $branch --git
6262
node scripts/clone-elasticsearch/index.js --branch $branch
63-
env:
64-
GCS_CREDENTIALS: ${{ secrets.GCS_CREDENTIALS }}
65-
66-
- name: Remove previous comment
67-
uses: maheshrayas/action-pr-comment-delete@v1
68-
with:
69-
github_token: ${{ secrets.GITHUB_TOKEN }}
70-
org: elastic
71-
repo: elasticsearch-specification
72-
user: github-actions[bot]
73-
issue: ${{ github.event.number }}
7463
7564
- name: Run validation
65+
id: validation
7666
working-directory: ./elasticsearch-specification
7767
run: node .github/validate-pr --token ${{ secrets.GITHUB_TOKEN }}
68+
69+
- name: Find existing comment
70+
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
71+
id: find-comment
72+
with:
73+
issue-number: ${{ github.event.pull_request.number }}
74+
comment-author: 'github-actions[bot]'
75+
body-includes: 'Following you can find the validation changes'
76+
77+
- name: Create or update comment
78+
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
79+
with:
80+
token: ${{ secrets.GITHUB_TOKEN }}
81+
comment-id: ${{ steps.find-comment.outputs.comment-id }}
82+
issue-number: ${{ github.event.pull_request.number }}
83+
body: ${{ steps.validation.outputs.comment_body }}
84+
edit-mode: replace

.gitignore

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,7 @@ output/schema/schema
6565
# Test suite outputs
6666
compiler/test/**/output/
6767

68-
# Temporary openAPI files
69-
output/openapi/elasticsearch-serverless-openapi.tmp*.json
70-
output/openapi/elasticsearch-serverless-openapi.examples.json
71-
output/openapi/elasticsearch-openapi.tmp*.json
72-
output/openapi/elasticsearch-openapi.examples.json
73-
output/openapi/elasticsearch-serverless-openapi-docs.json
74-
output/openapi/elasticsearch-openapi-docs.json
68+
# Temporary openAPI documentation files
69+
output/openapi/elasticsearch-serverless-openapi-docs*.json
70+
output/openapi/elasticsearch-openapi-docs*.json
71+
output/openapi/elasticsearch*.redirects.csv

CONTRIBUTING.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Documents under the docs/ directory will help you to change the specification. T
3939
* [Fixing a definition, the complete story](docs/validation-example.md)
4040

4141

42-
## Send your pull request
42+
## Send your pull request from a branch
4343

4444
To fix any style issues and generate the outputs (that we store in git), please run:
4545

@@ -56,5 +56,4 @@ Then, follow those steps:
5656
- If the API is unusable without the change -> every supported version
5757
- If the API is usable, but fix is on the response side -> every supported version
5858
- If the API is usable, but fix is on the request side -> no backport, unless the API is _partially_ usable and the fix unlocks a missing feature that has no workaround
59-
60-
59+
- Send the pull request from a branch, **not a fork**

Makefile

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ setup: ## Install dependencies for contrib target
4343
@npm install --prefix validator
4444
@npm install --prefix specification
4545
@npm install @redocly/cli
46+
@npm install --prefix docs/examples
4647

4748
clean-dep: ## Clean npm dependencies
4849
@rm -rf compiler/node_modules
@@ -56,8 +57,10 @@ transform-to-openapi: ## Generate the OpenAPI definition from the compiled schem
5657
@npm run transform-to-openapi -- --schema output/schema/schema.json --flavor serverless --output output/openapi/elasticsearch-serverless-openapi.json
5758

5859
transform-to-openapi-for-docs: ## Generate the OpenAPI definition tailored for API docs generation
59-
@npm run transform-to-openapi -- --schema output/schema/schema.json --flavor stack --lift-enum-descriptions --merge-multipath-endpoints --multipath-redirects --output output/openapi/elasticsearch-openapi-docs.json
60-
@npm run transform-to-openapi -- --schema output/schema/schema.json --flavor serverless --lift-enum-descriptions --merge-multipath-endpoints --multipath-redirects --output output/openapi/elasticsearch-serverless-openapi-docs.json
60+
@make generate-language-examples
61+
@make generate
62+
@npm run transform-to-openapi -- --schema output/schema/schema.json --flavor stack --lift-enum-descriptions --merge-multipath-endpoints --multipath-redirects --include-language-examples --output output/openapi/elasticsearch-openapi-docs.json
63+
@npm run transform-to-openapi -- --schema output/schema/schema.json --flavor serverless --lift-enum-descriptions --merge-multipath-endpoints --multipath-redirects --include-language-examples --output output/openapi/elasticsearch-serverless-openapi-docs.json
6164

6265
filter-for-serverless: ## Generate the serverless version from the compiled schema
6366
@npm run --prefix compiler filter-by-availability -- --serverless --visibility=public --input ../output/schema/schema.json --output ../output/output/openapi/elasticsearch-serverless-openapi.json
@@ -66,23 +69,31 @@ dump-routes: ## Create a new schema with all generics expanded
6669
@npm run dump-routes --prefix compiler
6770

6871
overlay-docs: ## Apply overlays to OpenAPI documents
69-
@npx bump overlay "output/openapi/elasticsearch-serverless-openapi.json" "docs/overlays/elasticsearch-serverless-openapi-overlays.yaml" > "output/openapi/elasticsearch-serverless-openapi.tmp1.json"
70-
@npx bump overlay "output/openapi/elasticsearch-serverless-openapi.tmp1.json" "docs/overlays/elasticsearch-shared-overlays.yaml" > "output/openapi/elasticsearch-serverless-openapi.tmp2.json"
71-
@npx @redocly/cli bundle output/openapi/elasticsearch-serverless-openapi.tmp2.json --ext json -o output/openapi/elasticsearch-serverless-openapi.examples.json
72-
@npx bump overlay "output/openapi/elasticsearch-openapi.json" "docs/overlays/elasticsearch-openapi-overlays.yaml" > "output/openapi/elasticsearch-openapi.tmp1.json"
73-
@npx bump overlay "output/openapi/elasticsearch-openapi.tmp1.json" "docs/overlays/elasticsearch-shared-overlays.yaml" > "output/openapi/elasticsearch-openapi.tmp2.json"
74-
@npx @redocly/cli bundle output/openapi/elasticsearch-openapi.tmp2.json --ext json -o output/openapi/elasticsearch-openapi.examples.json
75-
rm output/openapi/elasticsearch-serverless-openapi.tmp*.json
76-
rm output/openapi/elasticsearch-openapi.tmp*.json
72+
@npx bump overlay "output/openapi/elasticsearch-serverless-openapi-docs.json" "docs/overlays/elasticsearch-serverless-openapi-overlays.yaml" > "output/openapi/elasticsearch-serverless-openapi-docs.tmp1.json"
73+
@npx bump overlay "output/openapi/elasticsearch-serverless-openapi-docs.tmp1.json" "docs/overlays/elasticsearch-shared-overlays.yaml" > "output/openapi/elasticsearch-serverless-openapi-docs.tmp2.json"
74+
@npx @redocly/cli bundle output/openapi/elasticsearch-serverless-openapi-docs.tmp2.json --ext json -o output/openapi/elasticsearch-serverless-openapi-docs-final.json
75+
@npx bump overlay "output/openapi/elasticsearch-openapi-docs.json" "docs/overlays/elasticsearch-openapi-overlays.yaml" > "output/openapi/elasticsearch-openapi-docs.tmp1.json"
76+
@npx bump overlay "output/openapi/elasticsearch-openapi-docs.tmp1.json" "docs/overlays/elasticsearch-shared-overlays.yaml" > "output/openapi/elasticsearch-openapi-docs.tmp2.json"
77+
@npx @redocly/cli bundle output/openapi/elasticsearch-openapi-docs.tmp2.json --ext json -o output/openapi/elasticsearch-openapi-docs-final.json
78+
rm output/openapi/elasticsearch-serverless-openapi-docs.tmp*.json
79+
rm output/openapi/elasticsearch-openapi-docs.tmp*.json
80+
81+
generate-language-examples:
82+
@node docs/examples/generate-language-examples.js
83+
@npm run format:fix-examples --prefix compiler
84+
85+
generate-language-examples-with-java:
86+
@node docs/examples/generate-language-examples.js java
87+
@npm run format:fix-examples --prefix compiler
7788

7889
lint-docs: ## Lint the OpenAPI documents after overlays
7990
@npx @redocly/cli lint "output/openapi/elasticsearch-*.json" --config "docs/linters/redocly.yaml" --format stylish --max-problems 500
8091

81-
lint-docs-stateful: ## Lint only the elasticsearch-openapi.examples.json file
82-
@npx @redocly/cli lint "output/openapi/elasticsearch-openapi.examples.json" --config "docs/linters/redocly.yaml" --format stylish --max-problems 500
92+
lint-docs-stateful: ## Lint only the elasticsearch-openapi-docs-final.json file
93+
@npx @redocly/cli lint "output/openapi/elasticsearch-openapi-docs-final.json" --config "docs/linters/redocly.yaml" --format stylish --max-problems 500
8394

8495
lint-docs-serverless: ## Lint only the serverless OpenAPI document after overlays
85-
@npx @redocly/cli lint "output/openapi/elasticsearch-serverless-openapi.examples.json" --config "docs/linters/redocly.yaml" --format stylish --max-problems 500
96+
@npx @redocly/cli lint "output/openapi/elasticsearch-serverless-openapi-docs-final.json" --config "docs/linters/redocly.yaml" --format stylish --max-problems 500
8697

8798
contrib: | generate license-check spec-format-fix transform-to-openapi filter-for-serverless lint-docs ## Pre contribution target
8899

0 commit comments

Comments
 (0)