checkout/src/misc/generate-docs.ts
Salman Chishti 08c6903cd8
Some checks failed
Build and Test / test (macos-latest) (push) Waiting to run
Build and Test / test (windows-latest) (push) Waiting to run
Licensed / Check licenses (push) Successful in 46s
CodeQL / Analyze (javascript) (push) Failing after 1m41s
Build and Test / test (ubuntu-latest) (push) Failing after 8s
Build and Test / test-proxy (push) Failing after 6s
Build and Test / build (push) Failing after 1m32s
Build and Test / test-git-container (push) Failing after 5s
Build and Test / test-output (push) Failing after 5s
Build and Test / test-bypass-proxy (push) Failing after 37s
Check dist / check-dist (push) Successful in 3m24s
Prepare v5.0.0 release (#2238)
2025-08-11 13:35:28 +01:00

127 lines
3.4 KiB
TypeScript

import * as fs from 'fs'
import * as os from 'os'
import * as path from 'path'
import * as yaml from 'js-yaml'
//
// SUMMARY
//
// This script rebuilds the usage section in the README.md to be consistent with the action.yml
function updateUsage(
actionReference: string,
actionYamlPath = 'action.yml',
readmePath = 'README.md',
startToken = '<!-- start usage -->',
endToken = '<!-- end usage -->'
): void {
if (!actionReference) {
throw new Error('Parameter actionReference must not be empty')
}
// Load the action.yml
const actionYaml = yaml.load(fs.readFileSync(actionYamlPath).toString())
// Load the README
const originalReadme = fs.readFileSync(readmePath).toString()
// Find the start token
const startTokenIndex = originalReadme.indexOf(startToken)
if (startTokenIndex < 0) {
throw new Error(`Start token '${startToken}' not found`)
}
// Find the end token
const endTokenIndex = originalReadme.indexOf(endToken)
if (endTokenIndex < 0) {
throw new Error(`End token '${endToken}' not found`)
} else if (endTokenIndex < startTokenIndex) {
throw new Error('Start token must appear before end token')
}
// Build the new README
const newReadme: string[] = []
// Append the beginning
newReadme.push(originalReadme.substr(0, startTokenIndex + startToken.length))
// Build the new usage section
newReadme.push('```yaml', `- uses: ${actionReference}`, ' with:')
const inputs = actionYaml.inputs
let firstInput = true
for (const key of Object.keys(inputs)) {
const input = inputs[key]
// Line break between inputs
if (!firstInput) {
newReadme.push('')
}
// Constrain the width of the description
const width = 80
let description = (input.description as string)
.trimRight()
.replace(/\r\n/g, '\n') // Convert CR to LF
.replace(/ +/g, ' ') // Squash consecutive spaces
.replace(/ \n/g, '\n') // Squash space followed by newline
while (description) {
// Longer than width? Find a space to break apart
let segment: string = description
if (description.length > width) {
segment = description.substr(0, width + 1)
while (!segment.endsWith(' ') && !segment.endsWith('\n') && segment) {
segment = segment.substr(0, segment.length - 1)
}
// Trimmed too much?
if (segment.length < width * 0.67) {
segment = description
}
} else {
segment = description
}
// Check for newline
const newlineIndex = segment.indexOf('\n')
if (newlineIndex >= 0) {
segment = segment.substr(0, newlineIndex + 1)
}
// Append segment
newReadme.push(` # ${segment}`.trimRight())
// Remaining
description = description.substr(segment.length)
}
if (input.default !== undefined) {
// Append blank line if description had paragraphs
if ((input.description as string).trimRight().match(/\n[ ]*\r?\n/)) {
newReadme.push(` #`)
}
// Default
newReadme.push(` # Default: ${input.default}`)
}
// Input name
newReadme.push(` ${key}: ''`)
firstInput = false
}
newReadme.push('```')
// Append the end
newReadme.push(originalReadme.substr(endTokenIndex))
// Write the new README
fs.writeFileSync(readmePath, newReadme.join(os.EOL))
}
updateUsage(
'actions/checkout@v5',
path.join(__dirname, '..', '..', 'action.yml'),
path.join(__dirname, '..', '..', 'README.md')
)