From e57ad2c1ba41912384c198eba7032f4a1799bf0f Mon Sep 17 00:00:00 2001 From: Jonathan Miller <1+jmiller@noreply.git.mokoconsulting.tech> Date: Wed, 20 May 2026 02:04:16 +0000 Subject: [PATCH 1/3] fix(ci): replace python -c with bash printf for JSON report Avoid YAML quoting issues with embedded python. Authored-by: Moko Consulting --- .gitea/workflows/repo-health.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.gitea/workflows/repo-health.yml b/.gitea/workflows/repo-health.yml index 482ee1a..079d2b6 100644 --- a/.gitea/workflows/repo-health.yml +++ b/.gitea/workflows/repo-health.yml @@ -477,14 +477,7 @@ jobs: export MISSING_OPTIONAL="$(printf '%s\n' "${missing_optional[@]:-}")" export CONTENT_WARNINGS="$(printf '%s\n' "${content_warnings[@]:-}")" - report_json="$(python3 -c " -import json, os -profile = os.environ.get('PROFILE_RAW') or 'all' -mr = [x for x in os.environ.get('MISSING_REQUIRED', '').splitlines() if x] -mo = [x for x in os.environ.get('MISSING_OPTIONAL', '').splitlines() if x] -cw = [x for x in os.environ.get('CONTENT_WARNINGS', '').splitlines() if x] -print(json.dumps({'profile': profile, 'missing_required': mr, 'missing_optional': mo, 'content_warnings': cw}, indent=2)) -")" + report_json=$(printf '{"profile":"%s","missing_required":%d,"missing_optional":%d,"content_warnings":%d}' "$profile" "${#missing_required[@]}" "${#missing_optional[@]}" "${#content_warnings[@]}") { printf '%s\n' '### Repository health' From 3ac3abc7d11bbc5cdce6c0ed114417a3c1585dcf Mon Sep 17 00:00:00 2001 From: Jonathan Miller <1+jmiller@noreply.git.mokoconsulting.tech> Date: Wed, 20 May 2026 02:09:45 +0000 Subject: [PATCH 2/3] fix(ci): replace missing_links python heredoc with bash loop Second heredoc also incompatible with act runner. Authored-by: Moko Consulting --- .gitea/workflows/repo-health.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/repo-health.yml b/.gitea/workflows/repo-health.yml index 079d2b6..5c6a513 100644 --- a/.gitea/workflows/repo-health.yml +++ b/.gitea/workflows/repo-health.yml @@ -608,8 +608,24 @@ jobs: fi if [ -f "${DOCS_INDEX}" ]; then - missing_links="$(python3 - <<'PY' - import os + missing_links="" + if [ -f "${DOCS_INDEX}" ]; then + while IFS= read -r line; do + for link in $(echo "$line" | grep -oP '\]\(\K[^)]+' || true); do + case "$link" in http://*|https://*|\#*|mailto:*) continue ;; esac + linkpath="${link%%#*}" + linkpath="${linkpath%%\?*}" + [ -z "$linkpath" ] && continue + if [ "${linkpath:0:1}" = "/" ]; then + testpath="${linkpath#/}" + else + testpath="$(dirname "${DOCS_INDEX}")/${linkpath}" + fi + [ ! -e "$testpath" ] && missing_links="${missing_links}${testpath} +" + done + done < "${DOCS_INDEX}" + fi import re idx = os.environ.get('DOCS_INDEX', 'docs/docs-index.md') From 7bd4ede1196aefd94d7ecf91b8f664d12e1059ec Mon Sep 17 00:00:00 2001 From: Jonathan Miller <1+jmiller@noreply.git.mokoconsulting.tech> Date: Wed, 20 May 2026 02:13:12 +0000 Subject: [PATCH 3/3] fix(ci): clean up docs-index link check (remove broken heredoc remnants) Authored-by: Moko Consulting --- .gitea/workflows/repo-health.yml | 46 ++++++-------------------------- 1 file changed, 8 insertions(+), 38 deletions(-) diff --git a/.gitea/workflows/repo-health.yml b/.gitea/workflows/repo-health.yml index 5c6a513..5392de3 100644 --- a/.gitea/workflows/repo-health.yml +++ b/.gitea/workflows/repo-health.yml @@ -608,11 +608,10 @@ jobs: fi if [ -f "${DOCS_INDEX}" ]; then - missing_links="" - if [ -f "${DOCS_INDEX}" ]; then - while IFS= read -r line; do - for link in $(echo "$line" | grep -oP '\]\(\K[^)]+' || true); do - case "$link" in http://*|https://*|\#*|mailto:*) continue ;; esac + missing_links="" + while IFS= read -r docline; do + for link in $(echo "$docline" | grep -oE '\]\([^)]+\)' | sed 's/\](//' | sed 's/)$//' || true); do + case "$link" in http://*|https://*|"#"*|mailto:*) continue ;; esac linkpath="${link%%#*}" linkpath="${linkpath%%\?*}" [ -z "$linkpath" ] && continue @@ -621,46 +620,17 @@ jobs: else testpath="$(dirname "${DOCS_INDEX}")/${linkpath}" fi - [ ! -e "$testpath" ] && missing_links="${missing_links}${testpath} -" + [ ! -e "$testpath" ] && missing_links="${missing_links}${testpath} " done done < "${DOCS_INDEX}" - fi - import re - - idx = os.environ.get('DOCS_INDEX', 'docs/docs-index.md') - base = os.getcwd() - - bad = [] - pat = re.compile(r'\[[^\]]+\]\(([^)]+)\)') - - with open(idx, 'r', encoding='utf-8') as f: - for line in f: - for m in pat.findall(line): - link = m.strip() - if link.startswith('http://') or link.startswith('https://') or link.startswith('#') or link.startswith('mailto:'): - continue - if link.startswith('/'): - rel = link.lstrip('/') - else: - rel = os.path.normpath(os.path.join(os.path.dirname(idx), link)) - rel = rel.split('#', 1)[0] - rel = rel.split('?', 1)[0] - if not rel: - continue - p = os.path.join(base, rel) - if not os.path.exists(p): - bad.append(rel) - - print('\n'.join(sorted(set(bad)))) - PY - )" if [ -n "${missing_links}" ]; then extended_findings+=("docs/docs-index.md contains broken relative links") { printf '%s\n' '### Docs index link integrity' printf '%s\n' 'Broken relative links:' - while IFS= read -r l; do [ -n "${l}" ] && printf '%s\n' "- ${l}"; done <<< "${missing_links}" + for bl in ${missing_links}; do + printf '%s\n' "- ${bl}" + done printf '\n' } >> "${GITHUB_STEP_SUMMARY}" fi