@redpanda-data/docs-extensions-and-macros 5.31.0 → 5.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/doc-tools-mcp.js +1 -1
- package/bin/doc-tools.js +9 -7
- package/bin/mcp-tools/lint-doc-strings.js +2 -1
- package/cli-utils/enterprise-sources.js +3 -3
- package/cli-utils/github-token.js +53 -13
- package/cli-utils/octokit-client.js +2 -2
- package/cli-utils/self-managed-docs-branch.js +2 -2
- package/extensions/version-fetcher/set-latest-version.js +6 -3
- package/package.json +1 -1
- package/tools/get-redpanda-version.js +2 -2
- package/tools/lint-strings/diff.js +15 -1
- package/tools/lint-strings/fixtures/api/lint_admin_v2.proto +114 -0
- package/tools/lint-strings/fixtures/api/lint_api.proto +123 -0
- package/tools/lint-strings/fixtures/connect/lint_connect.go +1 -1
- package/tools/lint-strings/fixtures/crd/lint_types.go +70 -0
- package/tools/lint-strings/fixtures/helm/lint_values.yaml +16 -3
- package/tools/lint-strings/index.js +2 -1
- package/tools/lint-strings/rules/common.js +87 -1
- package/tools/lint-strings/surfaces/api.js +786 -0
- package/tools/lint-strings/surfaces/crd.js +204 -7
- package/tools/lint-strings/surfaces/helm.js +338 -12
- package/tools/property-extractor/rp-util-fetch.js +2 -2
- package/tools/rpk-docs/rpk-docs-handler.js +2 -2
package/bin/doc-tools-mcp.js
CHANGED
|
@@ -446,7 +446,7 @@ const tools = [
|
|
|
446
446
|
},
|
|
447
447
|
surface: {
|
|
448
448
|
type: 'string',
|
|
449
|
-
description:
|
|
449
|
+
description: `Comma-separated surfaces to lint: ${Object.keys(require('../tools/lint-strings').SURFACES).join(', ')} (optional, defaults to all)`
|
|
450
450
|
},
|
|
451
451
|
diff: {
|
|
452
452
|
type: 'string',
|
package/bin/doc-tools.js
CHANGED
|
@@ -122,9 +122,9 @@ programCli
|
|
|
122
122
|
* - A GitHub token with access to redpanda-data/streaming-enterprise, which is
|
|
123
123
|
* private. Redpanda releases are published there now, and the old public repo
|
|
124
124
|
* is frozen, so this command exits rather than report a stale version when it
|
|
125
|
-
* has no token. Resolved from
|
|
126
|
-
*
|
|
127
|
-
*
|
|
125
|
+
* has no token. Resolved from REDPANDA_GITHUB_TOKEN, ACTIONS_BOT_TOKEN,
|
|
126
|
+
* GITHUB_TOKEN, VBOT_GITHUB_API_TOKEN, GH_TOKEN, or GIT_CREDENTIALS, in that
|
|
127
|
+
* priority order (an API call, so the git credential is the last resort)
|
|
128
128
|
*/
|
|
129
129
|
programCli
|
|
130
130
|
.command('get-redpanda-version')
|
|
@@ -1908,7 +1908,7 @@ automation
|
|
|
1908
1908
|
*
|
|
1909
1909
|
* @requirements
|
|
1910
1910
|
* - GitHub token with access to redpanda-data/cloudv2-infra repository
|
|
1911
|
-
* - Token is resolved from
|
|
1911
|
+
* - Token is resolved from REDPANDA_GITHUB_TOKEN, ACTIONS_BOT_TOKEN, GITHUB_TOKEN, VBOT_GITHUB_API_TOKEN, GH_TOKEN, or GIT_CREDENTIALS, in that priority order (an API call, so the git credential is the last resort)
|
|
1912
1912
|
* - Internet connection to access GitHub API
|
|
1913
1913
|
*/
|
|
1914
1914
|
automation
|
|
@@ -1925,7 +1925,7 @@ automation
|
|
|
1925
1925
|
.option('--dry-run', 'Print output to stdout instead of writing file')
|
|
1926
1926
|
.action(async (options, command) => {
|
|
1927
1927
|
const { generateCloudRegions } = require('../tools/cloud-regions/generate-cloud-regions.js')
|
|
1928
|
-
const {
|
|
1928
|
+
const { getGitHubApiToken } = require('../cli-utils/github-token')
|
|
1929
1929
|
|
|
1930
1930
|
try {
|
|
1931
1931
|
// The default output path holds the unfiltered table, so a filtered run
|
|
@@ -1947,7 +1947,7 @@ automation
|
|
|
1947
1947
|
const absOutput = options.dryRun
|
|
1948
1948
|
? undefined
|
|
1949
1949
|
: resolveInsideRepo(repoRoot, options.output, '--output')
|
|
1950
|
-
const token =
|
|
1950
|
+
const token = getGitHubApiToken()
|
|
1951
1951
|
if (!token) {
|
|
1952
1952
|
throw new Error('GitHub token is required to fetch from private cloudv2-infra repo.')
|
|
1953
1953
|
}
|
|
@@ -2622,7 +2622,9 @@ programCli
|
|
|
2622
2622
|
.command('lint-strings')
|
|
2623
2623
|
.description('Lint user-facing doc strings embedded in engineering source code (properties, metrics, ...)')
|
|
2624
2624
|
.requiredOption('--repo <path>', 'Path to an existing engineering checkout (for example, a local redpanda clone). Nothing is cloned.')
|
|
2625
|
-
|
|
2625
|
+
// Read off the registry rather than restated here: a hardcoded list silently
|
|
2626
|
+
// went stale the moment a surface was added.
|
|
2627
|
+
.option('--surface <list>', `Comma-separated surfaces to lint (default: all registered). Registered: ${Object.keys(require('../tools/lint-strings').SURFACES).join(', ')}`)
|
|
2626
2628
|
.option('--diff <base>', 'Declaration-anchored diff mode: lint only declarations whose full span intersects lines changed in <base>...HEAD')
|
|
2627
2629
|
.option('--format <format>', 'Output format: human or json', 'human')
|
|
2628
2630
|
.option('--skip-rules <list>', 'Comma-separated rule ids to skip')
|
|
@@ -16,7 +16,8 @@ const DOC_TOOLS_BIN = path.resolve(__dirname, '..', 'doc-tools.js');
|
|
|
16
16
|
* Lint user-facing doc strings embedded in engineering source code
|
|
17
17
|
* @param {Object} args - Arguments
|
|
18
18
|
* @param {string} args.repo - Path to the engineering checkout (required)
|
|
19
|
-
* @param {string} [args.surface] - Comma-separated surfaces
|
|
19
|
+
* @param {string} [args.surface] - Comma-separated surfaces; see the SURFACES
|
|
20
|
+
* registry in tools/lint-strings/index.js for the current list
|
|
20
21
|
* @param {string} [args.diff] - Base ref for declaration-anchored diff mode
|
|
21
22
|
* @param {string} [args.skip_rules] - Comma-separated rule ids to skip
|
|
22
23
|
* @param {string} [args.only_rules] - Comma-separated rule ids to run exclusively
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
const fs = require('fs')
|
|
14
14
|
const path = require('path')
|
|
15
|
-
const {
|
|
15
|
+
const { getGitHubApiToken } = require('./github-token')
|
|
16
16
|
|
|
17
17
|
const RAW = 'https://raw.githubusercontent.com'
|
|
18
18
|
|
|
@@ -62,7 +62,7 @@ async function discardBody (resp) {
|
|
|
62
62
|
* check runs on a weekly cron where nobody is watching live.
|
|
63
63
|
*
|
|
64
64
|
* @param {object} [deps]
|
|
65
|
-
* @param {string|null} [deps.token] - GitHub token (defaults to
|
|
65
|
+
* @param {string|null} [deps.token] - GitHub token (defaults to getGitHubApiToken())
|
|
66
66
|
* @param {Function} [deps.fetchImpl] - fetch implementation (defaults to global fetch)
|
|
67
67
|
* @param {Function} [deps.warn] - warning sink (defaults to console.warn)
|
|
68
68
|
* @param {Function} [deps.sleep] - delay implementation, for tests
|
|
@@ -72,7 +72,7 @@ async function discardBody (resp) {
|
|
|
72
72
|
* check that never ran. Failures without a sourceName throw instead.
|
|
73
73
|
*/
|
|
74
74
|
function createSourceFetcher (deps = {}) {
|
|
75
|
-
const ghToken = deps.token !== undefined ? deps.token :
|
|
75
|
+
const ghToken = deps.token !== undefined ? deps.token : getGitHubApiToken()
|
|
76
76
|
const fetchImpl = deps.fetchImpl || ((...args) => fetch(...args))
|
|
77
77
|
const warn = deps.warn || ((msg) => console.warn(msg))
|
|
78
78
|
const sleep = deps.sleep || ((ms) => new Promise((resolve) => setTimeout(resolve, ms)))
|
|
@@ -47,9 +47,25 @@ function getTokenFromGitCredentials(credentials = process.env.GIT_CREDENTIALS) {
|
|
|
47
47
|
return null;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
const API_TOKEN_VARS = [
|
|
51
|
+
'REDPANDA_GITHUB_TOKEN',
|
|
52
|
+
'ACTIONS_BOT_TOKEN',
|
|
53
|
+
'GITHUB_TOKEN',
|
|
54
|
+
'VBOT_GITHUB_API_TOKEN',
|
|
55
|
+
'GH_TOKEN'
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
function firstApiTokenVar() {
|
|
59
|
+
for (const name of API_TOKEN_VARS) {
|
|
60
|
+
if (process.env[name]) return process.env[name];
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
50
65
|
/**
|
|
51
|
-
* Get GitHub token
|
|
52
|
-
*
|
|
66
|
+
* Get the GitHub token for git operations (clone, fetch, authenticated URLs).
|
|
67
|
+
*
|
|
68
|
+
* Checks, in priority order:
|
|
53
69
|
* 1. GIT_CREDENTIALS - Antora's credential store contents (github.com entry)
|
|
54
70
|
* 2. REDPANDA_GITHUB_TOKEN - Custom Redpanda token
|
|
55
71
|
* 3. ACTIONS_BOT_TOKEN - GitHub Actions bot token
|
|
@@ -57,21 +73,44 @@ function getTokenFromGitCredentials(credentials = process.env.GIT_CREDENTIALS) {
|
|
|
57
73
|
* 5. VBOT_GITHUB_API_TOKEN - Legacy bot token
|
|
58
74
|
* 6. GH_TOKEN - GitHub CLI default
|
|
59
75
|
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
76
|
+
* GIT_CREDENTIALS wins here on purpose: it is the credential Antora itself
|
|
77
|
+
* clones the content repos with, so anything else that clones in the same
|
|
78
|
+
* build should use the same identity. It is a git credential, not an API
|
|
79
|
+
* one; for REST calls use getGitHubApiToken().
|
|
64
80
|
*
|
|
65
81
|
* @returns {string|null} GitHub token or null if not found
|
|
66
82
|
*/
|
|
67
83
|
function getGitHubToken() {
|
|
68
|
-
return getTokenFromGitCredentials() ||
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
84
|
+
return getTokenFromGitCredentials() || firstApiTokenVar();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get the GitHub token for REST API calls (Octokit, api.github.com,
|
|
89
|
+
* raw.githubusercontent.com).
|
|
90
|
+
*
|
|
91
|
+
* Same variables as getGitHubToken(), but GIT_CREDENTIALS comes LAST:
|
|
92
|
+
*
|
|
93
|
+
* 1. REDPANDA_GITHUB_TOKEN
|
|
94
|
+
* 2. ACTIONS_BOT_TOKEN
|
|
95
|
+
* 3. GITHUB_TOKEN
|
|
96
|
+
* 4. VBOT_GITHUB_API_TOKEN
|
|
97
|
+
* 5. GH_TOKEN
|
|
98
|
+
* 6. GIT_CREDENTIALS
|
|
99
|
+
*
|
|
100
|
+
* Why the different order: on the Netlify Antora sites GIT_CREDENTIALS holds
|
|
101
|
+
* a token scoped only to cloning the private docs content repos. Letting it
|
|
102
|
+
* outrank REDPANDA_GITHUB_TOKEN meant the release lookup against the private
|
|
103
|
+
* streaming-enterprise repo authenticated with a token that cannot see that
|
|
104
|
+
* repo, got a 404, and every latest-redpanda-* attribute went unset in the
|
|
105
|
+
* production build even though a token with access was sitting right there.
|
|
106
|
+
* An explicitly named API token always beats the git credential; the git
|
|
107
|
+
* credential remains a fallback so a build with only GIT_CREDENTIALS still
|
|
108
|
+
* authenticates.
|
|
109
|
+
*
|
|
110
|
+
* @returns {string|null} GitHub token or null if not found
|
|
111
|
+
*/
|
|
112
|
+
function getGitHubApiToken() {
|
|
113
|
+
return firstApiTokenVar() || getTokenFromGitCredentials();
|
|
75
114
|
}
|
|
76
115
|
|
|
77
116
|
/**
|
|
@@ -106,6 +145,7 @@ function hasGitHubToken() {
|
|
|
106
145
|
|
|
107
146
|
module.exports = {
|
|
108
147
|
getGitHubToken,
|
|
148
|
+
getGitHubApiToken,
|
|
109
149
|
getTokenFromGitCredentials,
|
|
110
150
|
getAuthenticatedGitHubUrl,
|
|
111
151
|
hasGitHubToken
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { Octokit } = require('@octokit/rest')
|
|
4
|
-
const {
|
|
4
|
+
const { getGitHubApiToken } = require('./github-token')
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Shared Octokit client instance for GitHub API access
|
|
@@ -14,7 +14,7 @@ const { getGitHubToken } = require('./github-token')
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
// Get authentication token from environment
|
|
17
|
-
const token =
|
|
17
|
+
const token = getGitHubApiToken()
|
|
18
18
|
|
|
19
19
|
// Configure Octokit options
|
|
20
20
|
const octokitOptions = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const yaml = require('js-yaml');
|
|
2
2
|
const { spawnSync } = require('child_process');
|
|
3
|
-
const {
|
|
3
|
+
const { getGitHubApiToken } = require('./github-token');
|
|
4
4
|
|
|
5
5
|
const ANTORA_URL = 'https://raw.githubusercontent.com/redpanda-data/docs/main/antora.yml'
|
|
6
6
|
|
|
@@ -23,7 +23,7 @@ const REJECTED_HINT = ' A GitHub token was sent but rejected, so it may be expir
|
|
|
23
23
|
*/
|
|
24
24
|
async function fetchRemoteAntoraVersion(deps = {}) {
|
|
25
25
|
const fetchImpl = deps.fetchImpl || fetch
|
|
26
|
-
const ghToken = 'token' in deps ? deps.token :
|
|
26
|
+
const ghToken = 'token' in deps ? deps.token : getGitHubApiToken()
|
|
27
27
|
|
|
28
28
|
let resp = await fetchImpl(ANTORA_URL, ghToken ? { headers: { Authorization: `Bearer ${ghToken}` } } : undefined)
|
|
29
29
|
const hint = ghToken ? REJECTED_HINT : TOKEN_HINT
|
|
@@ -10,10 +10,13 @@ module.exports.register = function ({ config }) {
|
|
|
10
10
|
const GetLatestConnectVersion = require('./get-latest-connect');
|
|
11
11
|
const logger = this.getLogger('set-latest-version-extension');
|
|
12
12
|
|
|
13
|
-
const {
|
|
13
|
+
const { getGitHubApiToken } = require('../../cli-utils/github-token');
|
|
14
14
|
// Shared with tools/bundle-openapi.js so there is one major.minor derivation.
|
|
15
15
|
const { toShortVersion } = require('../../cli-utils/version');
|
|
16
|
-
|
|
16
|
+
// API token, not the git one: GIT_CREDENTIALS (Antora's clone credential)
|
|
17
|
+
// is only a last resort here, because on Netlify it is scoped to the docs
|
|
18
|
+
// content repos and cannot see streaming-enterprise.
|
|
19
|
+
const token = getGitHubApiToken();
|
|
17
20
|
|
|
18
21
|
if (!token) {
|
|
19
22
|
// Unauthenticated requests still work for the public repos this
|
|
@@ -21,7 +24,7 @@ module.exports.register = function ({ config }) {
|
|
|
21
24
|
// version now comes from the private streaming-enterprise repo, whose
|
|
22
25
|
// API 404s without a token -- the latest-redpanda-* attributes are then
|
|
23
26
|
// left unset and pages fall back to their antora.yml values.
|
|
24
|
-
logger.warn('GitHub token not set (
|
|
27
|
+
logger.warn('GitHub token not set (REDPANDA_GITHUB_TOKEN, GITHUB_TOKEN, GH_TOKEN, or GIT_CREDENTIALS). The Redpanda version lookup against the private streaming-enterprise repo will fail and leave latest-redpanda-* attributes unset; other lookups proceed unauthenticated.');
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
this.on('contentClassified', async ({ contentCatalog }) => {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const GetLatestRedpandaVersion = require('../extensions/version-fetcher/get-latest-redpanda-version.js');
|
|
4
4
|
const { getPrereleaseFromAntora } = require('../cli-utils/antora-utils.js');
|
|
5
|
-
const {
|
|
5
|
+
const { getGitHubApiToken } = require('../cli-utils/github-token');
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Fetches and prints the latest Redpanda version and Docker repository.
|
|
@@ -20,7 +20,7 @@ module.exports = async function getRedpandaVersion({ beta = false, fromAntora =
|
|
|
20
20
|
const owner = 'redpanda-data';
|
|
21
21
|
const repo = 'streaming-enterprise';
|
|
22
22
|
|
|
23
|
-
if (!
|
|
23
|
+
if (!getGitHubApiToken()) {
|
|
24
24
|
console.error(`❌ redpanda-data/${repo} is a private repository.`);
|
|
25
25
|
console.error(' Set GH_TOKEN, REDPANDA_GITHUB_TOKEN, or GITHUB_TOKEN to a token with access.');
|
|
26
26
|
process.exit(1);
|
|
@@ -26,7 +26,21 @@ const SURFACE_ROUTES = [
|
|
|
26
26
|
// console) and charts/<name>/values.yaml (connectors).
|
|
27
27
|
{ surface: 'helm', pattern: /^charts\/[^/]+\/(chart\/)?values\.yaml$/ },
|
|
28
28
|
{ surface: 'crd', pattern: /^operator\/api\// },
|
|
29
|
-
{ surface: 'connect', pattern: /^internal\/impl\// }
|
|
29
|
+
{ surface: 'connect', pattern: /^internal\/impl\// },
|
|
30
|
+
// API protos, whose comments and openapiv2 option strings reach readers as
|
|
31
|
+
// OpenAPI descriptions. console holds the data plane and Console APIs under
|
|
32
|
+
// proto/redpanda/api/; cloudv2's control plane lives under proto/public/.
|
|
33
|
+
// Anchored on the api/ segment so cloudv2's proto/descriptors/ tree (private
|
|
34
|
+
// and internal) and every vendored proto/public/**/wellknown/ path stay out.
|
|
35
|
+
{ surface: 'api', pattern: /^proto\/(?:redpanda\/api|public\/[^/]+\/redpanda\/api)\/.*\.proto$/ },
|
|
36
|
+
// Admin API v2, in the redpanda/streaming-enterprise repo. A different
|
|
37
|
+
// generator (protoc-gen-connect-openapi) and a third string form; see
|
|
38
|
+
// surfaces/api.js. These two directories are exactly what the api-docs
|
|
39
|
+
// bundler feeds into the published spec (tools/bundle-openapi.js):
|
|
40
|
+
// `admin/internal` and `core/testing` are excluded by that repo's buf.yaml
|
|
41
|
+
// and generate nothing, and `core/rest` generates a fragment that is never
|
|
42
|
+
// bundled, so none of them reach readers.
|
|
43
|
+
{ surface: 'api', pattern: /^proto\/redpanda\/core\/(?:admin\/v2|common)\/.*\.proto$/ }
|
|
30
44
|
]
|
|
31
45
|
|
|
32
46
|
/**
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Copyright 2026 Redpanda Data, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
//
|
|
6
|
+
// A license header is a leading comment on nothing. It must not attach itself
|
|
7
|
+
// to the first declaration in the file.
|
|
8
|
+
|
|
9
|
+
syntax = "proto3";
|
|
10
|
+
|
|
11
|
+
package redpanda.core.admin.v2;
|
|
12
|
+
|
|
13
|
+
import "proto/redpanda/core/pbgen/rpc.proto";
|
|
14
|
+
|
|
15
|
+
option (pbgen.cpp_namespace) = "proto::fixture";
|
|
16
|
+
|
|
17
|
+
service FixtureService {
|
|
18
|
+
// GetFixture
|
|
19
|
+
//
|
|
20
|
+
// Returns a single fixture.
|
|
21
|
+
rpc GetFixture(GetFixtureRequest) returns (GetFixtureResponse) {
|
|
22
|
+
option (pbgen.rpc) = {
|
|
23
|
+
authz: SUPERUSER
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// CreateFixture
|
|
28
|
+
//
|
|
29
|
+
// Creates a fixture. The description can run over several comment
|
|
30
|
+
// lines, and the resolved prose joins them.
|
|
31
|
+
//
|
|
32
|
+
// A blank comment line inside the description is a paragraph break and
|
|
33
|
+
// stays part of the description.
|
|
34
|
+
rpc CreateFixture(CreateFixtureRequest)
|
|
35
|
+
returns (CreateFixtureResponse) {
|
|
36
|
+
option (pbgen.rpc) = {
|
|
37
|
+
authz: SUPERUSER
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Reports the collapsed case: with no blank line the generator uses this
|
|
42
|
+
// whole comment as BOTH the summary and the description, so the API
|
|
43
|
+
// reference's nav item becomes a paragraph.
|
|
44
|
+
rpc CollapsedFixture(CollapsedFixtureRequest)
|
|
45
|
+
returns (CollapsedFixtureResponse) {
|
|
46
|
+
option (pbgen.rpc) = {
|
|
47
|
+
authz: SUPERUSER
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// DeleteFixture.
|
|
52
|
+
//
|
|
53
|
+
// Deletes a fixture.
|
|
54
|
+
rpc DeleteFixture(DeleteFixtureRequest) returns (DeleteFixtureResponse) {
|
|
55
|
+
option (pbgen.rpc) = {
|
|
56
|
+
authz: SUPERUSER
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ListFixtures
|
|
61
|
+
// over two lines
|
|
62
|
+
//
|
|
63
|
+
// Lists every fixture.
|
|
64
|
+
rpc ListFixtures(ListFixturesRequest) returns (ListFixturesResponse) {
|
|
65
|
+
option (pbgen.rpc) = {
|
|
66
|
+
authz: SUPERUSER
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// BodylessFixture
|
|
71
|
+
//
|
|
72
|
+
// A body-less rpc opens no block, so it must not swallow the
|
|
73
|
+
// declarations that follow it.
|
|
74
|
+
rpc BodylessFixture(BodylessFixtureRequest) returns (BodylessFixtureResponse);
|
|
75
|
+
|
|
76
|
+
// WatchFixture
|
|
77
|
+
//
|
|
78
|
+
// Confirms the rpc after a body-less one is still found.
|
|
79
|
+
rpc WatchFixture(WatchFixtureRequest) returns (WatchFixtureResponse) {
|
|
80
|
+
option (pbgen.rpc) = {
|
|
81
|
+
authz: SUPERUSER
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// The request for a single fixture.
|
|
87
|
+
message GetFixtureRequest {
|
|
88
|
+
// The node ID for the fixture. If unset, the broker handling the RPC
|
|
89
|
+
// returns information about itself.
|
|
90
|
+
optional int32 node_id = 1;
|
|
91
|
+
|
|
92
|
+
// Fixture name
|
|
93
|
+
string name = 2;
|
|
94
|
+
|
|
95
|
+
int32 undocumented = 3;
|
|
96
|
+
|
|
97
|
+
// Partition ID
|
|
98
|
+
int32 partition_id = 4;
|
|
99
|
+
|
|
100
|
+
// The protocol versions the fixture supports. See
|
|
101
|
+
// https://kafka.apache.org/protocol.html#protocol_compatibility
|
|
102
|
+
repeated int32 api_versions = 5;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Fixture mode
|
|
106
|
+
//
|
|
107
|
+
// - Not specified
|
|
108
|
+
// - Runs fast
|
|
109
|
+
enum FixtureMode {
|
|
110
|
+
FIXTURE_MODE_UNSPECIFIED = 0;
|
|
111
|
+
// Per-value comments are discarded by protoc-gen-connect-openapi, so they
|
|
112
|
+
// are not extracted and must not be reported as declarations.
|
|
113
|
+
FIXTURE_MODE_FAST = 1;
|
|
114
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package redpanda.api.fixture.v1;
|
|
4
|
+
|
|
5
|
+
import "google/protobuf/descriptor.proto";
|
|
6
|
+
import "protoc-gen-openapiv2/options/annotations.proto";
|
|
7
|
+
|
|
8
|
+
// Extension fields are wire metadata, never published schema. The field
|
|
9
|
+
// inside this block must not be extracted.
|
|
10
|
+
extend google.protobuf.MethodOptions {
|
|
11
|
+
string fixture_extension = 60002;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// FixtureMode selects how the fixture behaves.
|
|
15
|
+
enum FixtureMode {
|
|
16
|
+
FIXTURE_MODE_UNSPECIFIED = 0;
|
|
17
|
+
FIXTURE_MODE_FAST = 1;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// A fixture topic.
|
|
21
|
+
message FixtureTopic {
|
|
22
|
+
// A topic-level config key (e.g. `segment.bytes`).
|
|
23
|
+
string name = 1;
|
|
24
|
+
|
|
25
|
+
// Whether the config is read-only, or is dynamic and can be altered.
|
|
26
|
+
bool read_only = 2;
|
|
27
|
+
|
|
28
|
+
// Wrapped option lists must be covered by the declaration span, so a
|
|
29
|
+
// suggestion block can replace the whole statement.
|
|
30
|
+
string wrapped = 3 [
|
|
31
|
+
(buf.validate.field).string.min_len = 1,
|
|
32
|
+
(buf.validate.field).string.max_len = 255
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
// Sets default_topic_partitions when the topic is created.
|
|
36
|
+
int32 partitions = 4;
|
|
37
|
+
|
|
38
|
+
// A comment can wrap over several lines, and the resolved prose joins them
|
|
39
|
+
// rather than keeping only the first.
|
|
40
|
+
string wrapped_comment = 5;
|
|
41
|
+
|
|
42
|
+
string undocumented = 6;
|
|
43
|
+
|
|
44
|
+
// An openapiv2_field description OVERRIDES this comment, so the comment is
|
|
45
|
+
// dead text and the option's string is what must be linted.
|
|
46
|
+
string option_documented = 9 [
|
|
47
|
+
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
|
48
|
+
description: "The string the generator actually publishes."
|
|
49
|
+
example: "\"ignored\""
|
|
50
|
+
}
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
* A field documented ONLY by an openapiv2_field option is not an
|
|
55
|
+
* undocumented field. 73 of console's fields are this shape and every one
|
|
56
|
+
* of them used to be reported as having no description.
|
|
57
|
+
*
|
|
58
|
+
* This note is a detached block comment, separated by a blank line, so that
|
|
59
|
+
* option_only genuinely has no leading comment of its own.
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
string option_only = 10 [
|
|
63
|
+
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
|
64
|
+
description: "Documented by the option alone."
|
|
65
|
+
}
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
// A oneof moves the brace depth without opening a message. Matching a bare
|
|
69
|
+
// closing brace here popped FixtureTopic and reported the sibling message
|
|
70
|
+
// below as nested inside it.
|
|
71
|
+
oneof selector {
|
|
72
|
+
// Selects by name.
|
|
73
|
+
string by_name = 7;
|
|
74
|
+
// Selects by id.
|
|
75
|
+
string by_id = 8;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Nested messages are genuinely nested and should report a dotted path.
|
|
79
|
+
message Nested {
|
|
80
|
+
// The nested value.
|
|
81
|
+
string value = 1;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// A sibling of FixtureTopic, not a child of it.
|
|
86
|
+
message FixtureSibling {
|
|
87
|
+
// The sibling name.
|
|
88
|
+
string name = 1;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
service FixtureService {
|
|
92
|
+
rpc CreateFixture(FixtureTopic) returns (FixtureTopic) {
|
|
93
|
+
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
|
94
|
+
summary: "Create fixture."
|
|
95
|
+
description: "Create a [fixture](https://docs.redpanda.com/fixture/) with a `{prefix}` path."
|
|
96
|
+
responses: {
|
|
97
|
+
key: "200"
|
|
98
|
+
value: {description: "OK"}
|
|
99
|
+
}
|
|
100
|
+
responses: {
|
|
101
|
+
key: "201"
|
|
102
|
+
value: {description: "Fixture created"}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
rpc ListFixtures(FixtureTopic) returns (FixtureTopic) {
|
|
108
|
+
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
|
109
|
+
summary: "List fixtures"
|
|
110
|
+
description: "Short one"
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
rpc JoinFixtures(FixtureTopic) returns (FixtureTopic) {
|
|
115
|
+
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
|
116
|
+
summary: "Join fixtures"
|
|
117
|
+
// Proto concatenates adjacent string literals like C++, so the resolved
|
|
118
|
+
// description is both halves, not just the first.
|
|
119
|
+
description: "Joins two fixtures together "
|
|
120
|
+
"and returns the result."
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -28,7 +28,7 @@ This fixture exercises the ` + "`raw` + interpreted + `raw`" + ` concatenation i
|
|
|
28
28
|
This heading and the table below are legitimate AsciiDoc:
|
|
29
29
|
|
|
30
30
|
|===
|
|
31
|
-
| kafka_key | The record key
|
|
31
|
+
| `+"`kafka_key`"+` | The record key
|
|
32
32
|
|===
|
|
33
33
|
`).
|
|
34
34
|
Fields(fixtureConfigFields()...)
|
|
@@ -4,6 +4,7 @@ package v1alpha2
|
|
|
4
4
|
|
|
5
5
|
import (
|
|
6
6
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
7
|
+
"k8s.io/apimachinery/pkg/runtime"
|
|
7
8
|
)
|
|
8
9
|
|
|
9
10
|
// WidgetSpec defines the configuration of a fixture widget.
|
|
@@ -35,6 +36,75 @@ type WidgetReference struct {
|
|
|
35
36
|
Version int `json:"version"`
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
// EmptyOnOneLine opens and closes on a single line. Assuming it opened a
|
|
40
|
+
// struct body left the parser inside a type that had already ended, which
|
|
41
|
+
// dropped every declaration below it in the file.
|
|
42
|
+
type EmptyOnOneLine struct{}
|
|
43
|
+
|
|
44
|
+
// ValueSource represents where a value can be pulled from.
|
|
45
|
+
type ValueSource struct {
|
|
46
|
+
// The literal value.
|
|
47
|
+
Value string `json:"value,omitempty"`
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// UndocumentedType has no doc comment of its own, so a field referencing it
|
|
51
|
+
// has nothing to inherit and genuinely ships blank.
|
|
52
|
+
type undocumentedTypeMarker int
|
|
53
|
+
|
|
54
|
+
type UndocumentedTarget struct {
|
|
55
|
+
// The only field.
|
|
56
|
+
Only string `json:"only,omitempty"`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// InlinedValues is +hidefromdoc, but it is embedded with `json:",inline"`
|
|
60
|
+
// below, so crd-ref-docs flattens its fields into the embedding type and
|
|
61
|
+
// publishes every one of them. The marker suppresses this type's own section,
|
|
62
|
+
// not its fields.
|
|
63
|
+
// +hidefromdoc
|
|
64
|
+
type InlinedValues struct {
|
|
65
|
+
ReplicaCount *int32 `json:"replicaCount,omitempty"`
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// HiddenNotInlined is +hidefromdoc and embedded nowhere, so nothing it
|
|
69
|
+
// declares is ever published.
|
|
70
|
+
// +hidefromdoc
|
|
71
|
+
type HiddenNotInlined struct {
|
|
72
|
+
NeverPublished string `json:"neverPublished,omitempty"`
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// EmbeddingSpec inlines a hidden type.
|
|
76
|
+
type EmbeddingSpec struct {
|
|
77
|
+
InlinedValues `json:",inline"`
|
|
78
|
+
// The name of the thing.
|
|
79
|
+
Name string `json:"name,omitempty"`
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// StructuralSpec covers external types that controller-gen publishes with no
|
|
83
|
+
// description of their own.
|
|
84
|
+
type StructuralSpec struct {
|
|
85
|
+
// +optional
|
|
86
|
+
Config *runtime.RawExtension `json:"config,omitempty"`
|
|
87
|
+
// +optional
|
|
88
|
+
Expiration *metav1.Time `json:"expiration,omitempty"`
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// FallbackSpec covers what an uncommented field actually publishes.
|
|
92
|
+
type FallbackSpec struct {
|
|
93
|
+
// +optional
|
|
94
|
+
Inherited *ValueSource `json:"inherited,omitempty"`
|
|
95
|
+
// +optional
|
|
96
|
+
FromUndocumented *UndocumentedTarget `json:"fromUndocumented,omitempty"`
|
|
97
|
+
// +optional
|
|
98
|
+
Primitive string `json:"primitive,omitempty"`
|
|
99
|
+
// +optional
|
|
100
|
+
SliceOfDocumented []ValueSource `json:"sliceOfDocumented,omitempty"`
|
|
101
|
+
// +optional
|
|
102
|
+
External *metav1.Duration `json:"external,omitempty"`
|
|
103
|
+
// How long to wait before giving up on the widget.
|
|
104
|
+
// +optional
|
|
105
|
+
Both *ValueSource `json:"both,omitempty"`
|
|
106
|
+
}
|
|
107
|
+
|
|
38
108
|
// WidgetList is ignored via the config's ignoreTypes ('List$').
|
|
39
109
|
type WidgetList struct {
|
|
40
110
|
metav1.TypeMeta `json:",inline"`
|