Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 14 additions & 16 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,25 @@ jobs:
- name: Checkout 🛎️
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

- name: Setup Python 🔧
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: 3.14.5

- name: Check workflow files
uses: docker://rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667
with:
args: -color

- name: Test 🔍
run: |
# nosemgrep: generic.ci.security.use-frozen-lockfile.use-frozen-lockfile-pip
pip install semgrep yamllint
semgrep --config=auto --error
yamllint .
# yamllint and semgrep run from their published images (no host Python),
# matching the actionlint step above. Renovate manages the tags + digests.
- name: Lint YAML 🔍
uses: docker://cytopia/yamllint:1@sha256:596fb19eb71e55ba5b2fa56d8c18a615ec82adc8d3bf2d73918cb78c8f3240fb
with:
args: .

- name: Security scan 🔒
uses: docker://semgrep/semgrep:1.167.0@sha256:06938c1f365d3f67b8cedd8bc117607ae64253f88a0e768e9da9408548927dd6
with:
# Set the entrypoint explicitly: this image has no ENTRYPOINT, and
# pinning it keeps the step correct if a digest bump reintroduces one.
entrypoint: semgrep
args: --config=auto --error

autodoc:
timeout-minutes: 5
Expand All @@ -44,11 +47,6 @@ jobs:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6

- name: Install uv
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: false

- name: Regenerate documentation
run: ./generate-doc.sh

Expand Down
74 changes: 0 additions & 74 deletions generate-doc.py

This file was deleted.

125 changes: 123 additions & 2 deletions generate-doc.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,128 @@
#!/bin/bash

# Generate the README Inputs table from action.yml.
#
# Replaces tj-actions/auto-doc: parses the action's inputs and rewrites the
# GitHub-flavoured Markdown table between the AUTO-DOC-INPUT markers in
# README.md. Pure bash + awk so the repo needs no Python/uv toolchain.

set -euo pipefail

command -v uv >/dev/null 2>&1 || { echo "uv is not installed: https://docs.astral.sh/uv/" >&2; exit 1; }
ROOT="$(cd "$(dirname "$0")" && pwd)"
ACTION="${ROOT}/action.yml"
README="${ROOT}/README.md"
START="<!-- AUTO-DOC-INPUT:START - Do not remove or modify this section -->"
END="<!-- AUTO-DOC-INPUT:END -->"

if ! grep -qF "${START}" "${README}" || ! grep -qF "${END}" "${README}"; then
echo "AUTO-DOC-INPUT markers not found in README.md" >&2
exit 1
fi

# Render the README inputs table from action.yml. awk emits one finished
# Markdown row per input; only the constrained GitHub Action inputs schema is
# handled (2-space input names, 4-space properties, optional `|`/`>`
# block-scalar descriptions).
rows="$(
awk '
function trim(s){ sub(/^[ \t]+/, "", s); sub(/[ \t]+$/, "", s); return s }
# unwrap a scalar: strip matching surrounding quotes (inside which "#" is
# literal), otherwise strip an inline " # comment" from a plain scalar.
function scalar(s){
s = trim(s)
if (s ~ /^".*"$/ || s ~ /^'"'"'.*'"'"'$/) return substr(s, 2, length(s) - 2)
sub(/[ \t]+#.*$/, "", s)
return trim(s)
}
# render a (newline-joined) description into a single Markdown table cell:
# wrapped prose joins with spaces; "* " lines become <br>-separated bullets.
function render(raw, nl, i, line, arr, parts, np, out){
np = 0; nl = split(raw, arr, "\n")
for (i = 1; i <= nl; i++) {
line = trim(arr[i])
if (line == "") continue
if (substr(line, 1, 2) == "* ") parts[++np] = "<br>\342\200\242 " trim(substr(line, 3))
else if (np > 0) parts[np] = parts[np] " " line
else parts[++np] = line
}
out = ""
for (i = 1; i <= np; i++) out = out parts[i]
return out
}
# emit the finished Markdown row; the downstream sort orders rows by the
# input name that follows the identical "| `" prefix.
function flush( defcell){
if (cur == "") return
defcell = (def == "") ? "" : "`" def "`"
printf "| `%s` | string | %s | %s | %s |\n", cur, req, defcell, render(desc)
}

BEGIN { in_inputs = 0; collecting = 0; cur = "" }
{
line = $0; sub(/\r$/, "", line)
p = match(line, /[^ ]/); ind = (p ? p - 1 : length(line))
blank = (line ~ /^[ \t]*$/)

if (collecting) {
if (blank) { desc = desc "\n"; next }
if (ind > blockind) { desc = desc (desc == "" ? "" : "\n") line; next }
collecting = 0 # dedent: fall through and reprocess this line
}

if (blank) next
if (line ~ /^[ \t]*#/) next # full-line comment

if (ind == 0) { # top-level key
flush(); cur = ""
in_inputs = (line ~ /^inputs:[ \t]*$/) ? 1 : 0
next
}
if (!in_inputs) next

if (ind == 2) { # new input name
flush()
key = line; sub(/:.*$/, "", key); cur = trim(key)
req = "false"; def = ""; desc = ""
next
}
if (ind >= 4 && cur != "") { # input property
prop = trim(line)
if (prop ~ /^description:/) {
val = prop; sub(/^description:[ \t]*/, "", val)
if (val ~ /^[|>]/) { collecting = 1; blockind = ind; desc = "" }
else desc = scalar(val)
} else if (prop ~ /^default:/) {
val = prop; sub(/^default:[ \t]*/, "", val); def = scalar(val)
} else if (prop ~ /^required:/) {
val = prop; sub(/^required:[ \t]*/, "", val); val = tolower(scalar(val))
req = (val == "true" || val == "yes" || val == "on") ? "true" : "false"
}
next
}
}
END { flush() }
' "${ACTION}" | LC_ALL=C sort
)"

# Assemble the table; the rows already carry their Markdown formatting.
table="| Input | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |"
if [ -n "${rows}" ]; then
table="${table}
${rows}"
fi

exec uv run "$(dirname "$0")/generate-doc.py"
# Splice the rendered block between the markers (inclusive). The block is read
# from a file rather than passed via `awk -v`, which rejects embedded newlines.
tmp="$(mktemp)"
blockfile="$(mktemp)"
trap 'rm -f "${tmp}" "${blockfile}"' EXIT
printf '%s\n\n%s\n\n%s\n' "${START}" "${table}" "${END}" > "${blockfile}"
awk -v start="${START}" -v end="${END}" -v blockfile="${blockfile}" '
index($0, start) { while ((getline l < blockfile) > 0) print l; close(blockfile); skip = 1; next }
skip && index($0, end) { skip = 0; next }
skip { next }
{ print }
' "${README}" > "${tmp}"
mv "${tmp}" "${README}"
# tmp + blockfile are cleaned by the EXIT trap above.