Read-only mirror — the public repositories of the Forgejo instance, refreshed every 10 minutes. The live instance (fg.dieschoenewolke.de) is reachable only over the VPN; clone here with https://git.dieschoenewolke.de/git/<owner>/<repo>.git.
summaryrefslogtreecommitdiff
path: root/src/misc/generate-docs.ts
blob: ada3acd14ccee4c136861bc4a967cb4ca24fdc70 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import * as fs from 'fs'
import * as os from 'os'
import * as path from 'path'
import * as yaml from 'js-yaml'
import {fileURLToPath} from 'url'

const __dirname = path.dirname(fileURLToPath(import.meta.url))

//
// 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@v6',
  path.join(__dirname, '..', '..', 'action.yml'),
  path.join(__dirname, '..', '..', 'README.md')
)