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:
parent
261fa74ac9
commit
6f7686ba34
2 changed files with 130 additions and 30 deletions
88
README.md
88
README.md
|
@ -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 -->
|
|
@ -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}`)
|
||||
|
|
Loading…
Reference in a new issue