Auto-generate configuration documentation in README (#26)

Auto-generate the documentation of the configuration options in
`README.md` from `config.schema.json`.
This commit is contained in:
Lars Strojny 2022-11-17 13:19:22 +01:00 committed by GitHub
parent 261fa74ac9
commit 6f7686ba34
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 130 additions and 30 deletions

View file

@ -116,51 +116,81 @@ Once *Prometheus* is restarted, metrics with the `homebridge_` prefix should sta
*homebridge-prometheus-exporter* offers a few advanced settings to customize its behavior.
```json lines
<!-- AUTOGENERATED CONFIG DOCS BEGIN -->
```json5
{
//
// ...
"platforms": [
{
"platform": "PrometheusExporter",
// Homebridge PIN for service authentication. String of digits, format XXX-XX-XXX. Required
"pin": string,
// Toggle debug mode. Run homebridge with -D if you want to see the debug output. Default: false
"debug": boolean,
// Prefix for all metrics. Default: "homebridge"
"prefix": string,
// Pin
//
// Homebridge PIN for service authentication
"pin": "<string>",
// TCP port where the Prometheus metrics server listens. Default: 36123
"port": number,
// Interface where the Prometheus metrics server listens. Default: "::" which means "any interface".
// Can be an IP, a hostname, "0.0.0.0" for all IPv4 interfaces, "::1" for all IPv6 interfaces.
// Default is "::" which means any interface
"interface": string,
// Debug
"debug": "<boolean>",
// How frequently the services should be rediscovered (in seconds). Default: 60
"refresh_interval": number,
// Timeout for the HTTP request that retrieves the homekit devices (in seconds). Default: 10
"request_timeout": number,
// Metrics prefix
"prefix": "<string>",
// Timeout for the service discovery (in seconds). Default: 20
"discovery_timeout": number,
// Metrics server port
//
// TCP port where the Prometheus metrics server listens
"port": "<integer>",
// Metrics server interface
//
// Interface where the Prometheus metrics server listens. Can be an IP, a
// hostname, "0.0.0.0" for all IPv4 interfaces, "::1" for all IPv6 interfaces.
// Default is "::" which means "any interface"
"interface": "<string>",
// Service refresh interval
//
// Discover new services every <interval> seconds
"refresh_interval": "<integer>",
// Request timeout
//
// Request timeout when interacting with homebridge instances
"request_timeout": "<integer>",
// Service discovery timeout
//
// Discovery timeout after which the current discovery is considered failed
"discovery_timeout": "<integer>",
// TLS cert file
//
// Path to TLS certificate file (in PEM format)
"tls_cert_file": string,
"tls_cert_file": "<string>",
// TLS key file
//
// Path to TLS key file
"tls_key_file": string,
"tls_key_file": "<string>",
// Usernames and passwords for basic auth. Key is the username, value is the password.
// Password must be encoded with bcrypt
"basic_auth": {
"username": "<password encoded with bcrypt>"
}
},
// …
// Basic auth username/password pairs
//
// Usernames and passwords for basic auth. Object key is the username, object
// value is the password. Password must be encoded with bcrypt. Example:
// {"joanna": "$2a$12$5/mmmRB28wg9yzaXhee5Iupq3UrFr/qMgAe9LvAxGoY5jLcfVGTUq"}
"basic_auth": "<object>"
}
]
}
```
<!-- AUTOGENERATED CONFIG DOCS END -->

View file

@ -5,7 +5,7 @@ const { schema } = require('../config.schema.json')
const { format } = require('prettier')
const { join, basename } = require('path')
const prettierConfig = require('../prettier.config')
const { writeFileSync } = require('fs')
const { writeFileSync, readFileSync } = require('fs')
const file = join(__dirname, '../src/generated/config_boundary.ts')
@ -26,4 +26,74 @@ export const ConfigBoundary = ${zodSchema}
writeFileSync(file, code)
const note = 'AUTOGENERATED CONFIG DOCS'
const comment = (...strings) => `<!-- ${strings.join(' ')} -->`
const readmePath = join(__dirname, '../README.md')
const readme = readFileSync(readmePath).toString()
const regex = new RegExp(`${comment(note, 'BEGIN')}.*${comment(note, 'END')}`, 'mgs')
if (!readme.match(regex)) {
console.log('Could not update README.md')
process.exit(1)
}
writeFileSync(
readmePath,
readme.replace(
regex,
`${comment(note, 'BEGIN')}\n\`\`\`json5\n${generateDocs(schema)}\n\`\`\`\n${comment(note, 'END')}`,
),
)
function generateDocs(schema) {
const doc = indent(
Object.entries(schema.properties)
.map(([property, definition]) => {
const lines = []
if (definition.title) {
lines.push(`// ${definition.title}`)
}
if (definition.description) {
lines.push(`//\n// ${wordwrap(definition.description, 80, '\n// ')}`)
}
lines.push(`${JSON.stringify(property)}: ${JSON.stringify('<' + definition.type + '>')}`)
return lines.join('\n')
})
.join(',\n\n\n'),
6,
)
return `{
// ...
"platforms": [
{
"platform": "PrometheusExporter",
${doc}
}
]
}`
}
function wordwrap(word, length, wrap = '\n') {
const wrapped = []
while (word.length > length) {
const cut = word.substring(0, length)
const pos = cut.lastIndexOf(' ')
wrapped.push(cut.substring(0, pos))
word = word.substring(pos + 1)
}
wrapped.push(word)
return wrapped.join(wrap)
}
function indent(string, indent) {
return string.replace(/^(.+)$/gm, `${' '.repeat(indent)}$1`)
}
console.log(`Finished code generation for ${file}`)