[OAS] Include alerting rule APIs (#189962)

## Summary

Includes alerting rule APIs in our OAS snapshots.

## How to test

Using bump CLI you can preview the output:

```sh
bump preview ./oas_docs/bundle.json
# or
bump preview ./oas_docs/bundle.serverless.json
```

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Jean-Louis Leysens 2024-08-13 17:21:10 +02:00 committed by GitHub
parent 7fb1577c1d
commit b85b1cb506
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 9535 additions and 23 deletions

View file

@ -5,7 +5,7 @@ set -euo pipefail
source .buildkite/scripts/common/util.sh
echo --- Capture OAS snapshot
cmd="node scripts/capture_oas_snapshot --include-path /api/status"
cmd="node scripts/capture_oas_snapshot --include-path /api/status --include-path /api/alerting/rule/ --include-path /api/alerting/rules"
if is_pr && ! is_auto_commit_disabled; then
cmd="$cmd --update"
fi

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -44,7 +44,7 @@ Object {
"paths": Object {
"/foo/{id}": Object {
"get": Object {
"operationId": "/foo/{id}#0",
"operationId": "%2Ffoo%2F%7Bid%7D#0",
"parameters": Array [
Object {
"description": "The version of the API to use",
@ -138,7 +138,7 @@ Object {
"/bar": Object {
"get": Object {
"deprecated": true,
"operationId": "/bar#0",
"operationId": "%2Fbar#0",
"parameters": Array [
Object {
"description": "The version of the API to use",
@ -229,7 +229,7 @@ OK response oas-test-version-2",
"/foo/{id}/{path*}": Object {
"delete": Object {
"description": "route description",
"operationId": "/foo/{id}/{path*}#2",
"operationId": "%2Ffoo%2F%7Bid%7D%2F%7Bpath*%7D#2",
"parameters": Array [
Object {
"description": "The version of the API to use",
@ -267,7 +267,7 @@ OK response oas-test-version-2",
},
"get": Object {
"description": "route description",
"operationId": "/foo/{id}/{path*}#0",
"operationId": "%2Ffoo%2F%7Bid%7D%2F%7Bpath*%7D#0",
"parameters": Array [
Object {
"description": "The version of the API to use",
@ -413,7 +413,7 @@ OK response oas-test-version-2",
},
"post": Object {
"description": "route description",
"operationId": "/foo/{id}/{path*}#1",
"operationId": "%2Ffoo%2F%7Bid%7D%2F%7Bpath*%7D#1",
"parameters": Array [
Object {
"description": "The version of the API to use",
@ -570,7 +570,7 @@ OK response oas-test-version-2",
},
"/no-xsrf/{id}/{path*}": Object {
"post": Object {
"operationId": "/no-xsrf/{id}/{path*}#1",
"operationId": "%2Fno-xsrf%2F%7Bid%7D%2F%7Bpath*%7D#1",
"parameters": Array [
Object {
"description": "The version of the API to use",
@ -721,7 +721,7 @@ Object {
"paths": Object {
"/recursive": Object {
"get": Object {
"operationId": "/recursive#0",
"operationId": "%2Frecursive#0",
"parameters": Array [
Object {
"description": "The version of the API to use",
@ -804,7 +804,7 @@ Object {
"paths": Object {
"/foo/{id}": Object {
"get": Object {
"operationId": "/foo/{id}#0",
"operationId": "%2Ffoo%2F%7Bid%7D#0",
"parameters": Array [
Object {
"description": "The version of the API to use",
@ -842,7 +842,7 @@ Object {
},
"/test": Object {
"get": Object {
"operationId": "/test#0",
"operationId": "%2Ftest#0",
"parameters": Array [
Object {
"description": "The version of the API to use",

View file

@ -33,7 +33,7 @@ export const sharedOas = {
'/bar': {
get: {
deprecated: true,
operationId: '/bar#0',
operationId: '%2Fbar#0',
parameters: [
{
description: 'The version of the API to use',
@ -152,7 +152,7 @@ export const sharedOas = {
'/foo/{id}/{path*}': {
get: {
description: 'route description',
operationId: '/foo/{id}/{path*}#0',
operationId: '%2Ffoo%2F%7Bid%7D%2F%7Bpath*%7D#0',
parameters: [
{
description: 'The version of the API to use',
@ -276,7 +276,7 @@ export const sharedOas = {
},
post: {
description: 'route description',
operationId: '/foo/{id}/{path*}#1',
operationId: '%2Ffoo%2F%7Bid%7D%2F%7Bpath*%7D#1',
parameters: [
{
description: 'The version of the API to use',

View file

@ -110,6 +110,39 @@ describe('processEnum', () => {
],
},
},
{
name: 'correctly transforms schema.nullable inputs',
input: {
anyOf: [
{
description: 'test',
type: 'object',
properties: {
test: {
type: 'string',
},
},
required: ['test'],
},
{
enum: [],
nullable: true,
type: undefined,
},
],
} as OpenAPIV3.SchemaObject,
expected: {
description: 'test',
type: 'object',
properties: {
test: {
type: 'string',
},
},
required: ['test'],
nullable: true,
},
},
])('$name', ({ input, expected }) => {
processEnum(input);
expect(input).toEqual(expected);

View file

@ -9,8 +9,38 @@
import type { OpenAPIV3 } from 'openapi-types';
import { isReferenceObject } from '../../../common';
export const processEnum = (schema: OpenAPIV3.SchemaObject) => {
if (!schema.anyOf) return;
/** Identify special case output of schema.nullable() */
const isNullableOutput = (schema: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject) => {
return (
!isReferenceObject(schema) &&
Object.keys(schema).length === 3 &&
schema.enum?.length === 0 &&
schema.nullable === true &&
schema.type === undefined
);
};
/**
* Handle special case output of schema.nullable()
*
* We go from:
* { anyOf: [ { type: 'string' }, { nullable: true, enum: [] } ] }
*
* To:
* { type: 'string', nullable: true }
*/
const processNullableOutput = (schema: OpenAPIV3.SchemaObject) => {
if (schema.anyOf!.length !== 2) return false;
const idx = schema.anyOf!.findIndex((item) => isNullableOutput(item));
if (idx === -1) return false;
const anyOf = schema.anyOf!;
delete schema.anyOf;
schema.nullable = true;
Object.assign(schema, anyOf[1 - idx]);
return true;
};
const prettifyEnum = (schema: OpenAPIV3.SchemaObject) => {
const result: unknown[] = [];
let type: OpenAPIV3.SchemaObject['type'];
for (const item of schema.anyOf!) {
@ -24,3 +54,9 @@ export const processEnum = (schema: OpenAPIV3.SchemaObject) => {
schema.enum = result;
delete schema.anyOf;
};
export const processEnum = (schema: OpenAPIV3.SchemaObject) => {
if (!schema.anyOf) return;
if (processNullableOutput(schema)) return;
prettifyEnum(schema);
};

View file

@ -11,13 +11,10 @@ import { joi2JsonInternal } from '../../parse';
import { processObject } from './object';
test.each([
[
schema.object({}),
{ type: 'object', properties: {}, additionalProperties: false, required: [] },
],
[schema.object({}), { type: 'object', properties: {}, additionalProperties: false }],
[
schema.object({ never: schema.never() }),
{ type: 'object', properties: {}, additionalProperties: false, required: [] },
{ type: 'object', properties: {}, additionalProperties: false },
],
[
schema.object(

View file

@ -38,7 +38,7 @@ const populateRequiredFields = (schema: OpenAPIV3.SchemaObject): void => {
}
}
schema.required = required;
if (required.length > 0) schema.required = required;
};
const removeNeverType = (schema: OpenAPIV3.SchemaObject): void => {

View file

@ -0,0 +1,31 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { createOperationIdCounter } from './operation_id_counter';
test('empty case', () => {
const opIdCounter = createOperationIdCounter();
expect(opIdCounter('')).toBe('#0');
});
test('other cases', () => {
const opIdCounter = createOperationIdCounter();
const tests = [
['/', '%2F#0'],
['/api/cool', '%2Fapi%2Fcool#0'],
['/api/cool', '%2Fapi%2Fcool#1'],
['/api/cool', '%2Fapi%2Fcool#2'],
['/api/cool/{variable}', '%2Fapi%2Fcool%2F%7Bvariable%7D#0'],
['/api/cool/{optionalVariable?}', '%2Fapi%2Fcool%2F%7BoptionalVariable%3F%7D#0'],
['/api/cool/{optionalVariable?}', '%2Fapi%2Fcool%2F%7BoptionalVariable%3F%7D#1'],
];
tests.forEach(([input, expected]) => {
expect(opIdCounter(input)).toBe(expected);
});
});

View file

@ -11,6 +11,7 @@ export type OperationIdCounter = (name: string) => string;
export const createOperationIdCounter = () => {
const operationIdCounters = new Map<string, number>();
return (name: string): string => {
name = encodeURIComponent(name);
// Aliases an operationId to ensure it is unique across
// multiple method+path combinations sharing a name.
// "search" -> "search#0", "search#1", etc.