Improve README updater workflow with yq

Refactor README updater workflow to use yq for YAML processing and simplify config handling.
This commit is contained in:
Alexandre
2025-11-10 21:41:29 +01:00
committed by GitHub
parent 3370af2060
commit 279b0320b7

View File

@@ -5,6 +5,7 @@ on:
schedule:
- cron: 0 17 * * *
workflow_dispatch: null
jobs:
README_updater:
if: github.repository_owner == 'alexbelgium'
@@ -12,135 +13,112 @@ jobs:
steps:
- name: Checkout Repo
uses: actions/checkout@v5
- name: Install yq (and jq)
run: |
sudo apt-get update
sudo apt-get install -y jq
YQ_VERSION="v4.44.3"
sudo wget -qO /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_amd64"
sudo chmod +x /usr/local/bin/yq
- name: Create README file
run: |
# Init
echo "Starting"
# Ensure dependencies available
echo "Installing PyYAML"
python3 -m pip install --user --quiet PyYAML
export PATH="$HOME/.local/bin:$PATH"
get_config_file() {
if [ -f "$1/config.json" ]; then
echo "$1/config.json"
elif [ -f "$1/config.yaml" ]; then
echo "$1/config.yaml"
else
echo ""
fi
}
convert_config_to_json() {
local source="$1"
if [[ "$source" == *.yaml ]]; then
local temp_file
temp_file="$(mktemp)"
python3 - <<'PY' "$source" "$temp_file"
import json
import sys
from pathlib import Path
import yaml
source = Path(sys.argv[1])
target = Path(sys.argv[2])
with source.open("r", encoding="utf-8") as fp:
data = yaml.safe_load(fp)
with target.open("w", encoding="utf-8") as fp:
json.dump(data, fp)
PY
echo "$temp_file"
else
echo "$source"
fi
}
# Prepare template
cp .templates/.README.md README2.md
ADDONSLINE="$(sed -n '/%%ADDONS_LIST%%/=' README2.md)"
sed -i "/%%ADDONS_LIST%%/d" README2.md
sed -i "/**ADDONS_LIST%%/d" README2.md
# Helper to find a config file (json/yaml/yml)
get_cfg() {
local dir="$1"
for ext in json yaml yml; do
if [ -f "$dir/config.$ext" ]; then
echo "$dir/config.$ext"
return 0
fi
done
return 1
}
# Sort folders by addon name
# shellcheck disable=SC2086
# Sort folders by addon name (support json & yaml)
# shellcheck disable=SC2046
for f in $( find -- * -maxdepth 0 -type d | sort -r ); do
CONFIG_SRC="$(get_config_file "$f")"
if [ -n "$CONFIG_SRC" ]; then
CONFIG_FILE="$(convert_config_to_json "$CONFIG_SRC")"
NAME=$(jq -r '.name' "$CONFIG_FILE")
if [[ "$f" != "$NAME" ]]; then
echo "$f" > "$f"/oldname
CFG="$(get_cfg "$f" || true)"
if [ -n "${CFG:-}" ]; then
NAME="$(yq -r '.name // ""' "$CFG")"
if [ -n "$NAME" ] && [ "$f" != "$NAME" ]; then
echo "$f" > "$f/oldname"
mv "$f" "$NAME"
fi
if [[ "$CONFIG_FILE" != "$CONFIG_SRC" ]]; then rm "$CONFIG_FILE"; fi
fi
done
# Populate template
find -- * -maxdepth 0 -type d | sort -r | while read -r f; do
# $f is an addon directory
CONFIG_SRC="$(get_config_file "$f")"
if [ -n "$CONFIG_SRC" ]; then
CFG="$(get_cfg "$f" || true)"
[ -n "${CFG:-}" ] || continue
CONFIG_FILE="$(convert_config_to_json "$CONFIG_SRC")"
echo "Project $f"
echo "Project $f"
# Folder name in repo root (for links/badges)
if [ -f "$f/oldname" ]; then FOLDERNAME="$(cat "$f/oldname")"; else FOLDERNAME="$f"; fi
# Get variables
if [ -f "$f/oldname" ]; then FOLDERNAME="$(cat "$f/oldname")"; else FOLDERNAME="$f"; fi
NAME="$(jq -r '.name' "$CONFIG_FILE")"
DESCRIPTION="$(jq -r '.description' "$CONFIG_FILE")"
# Get icon
if [ "$(jq '.panel_icon' "$CONFIG_FILE")" != null ]; then
ICON="$(jq -r '.panel_icon' "$CONFIG_FILE")"
ICON="${ICON#*:}"
ICON="![image](https://api.iconify.design/mdi/$ICON.svg)"
else
ICON=""
fi
# Choose badge type & extension for Shields
EXT="${CFG##*.}"
BADGE_KIND="json"
case "$EXT" in
yaml|yml) BADGE_KIND="yaml" ;;
esac
# Write infos
echo "Writing infos"
sed -i "$ADDONSLINE"'{G;}' README2.md
if [[ "$(jq '.schema' "$CONFIG_FILE" 2>/dev/null)" == *"localdisks"* ]]; then sed -i "$ADDONSLINE"'a ![localdisks][localdisks-badge]' README2.md; fi
if [[ "$(jq '.schema' "$CONFIG_FILE" 2>/dev/null)" == *"networkdisks"* ]]; then sed -i "$ADDONSLINE"'a ![smb][smb-badge]' README2.md; fi
if [[ "$(jq '.full_access' "$CONFIG_FILE" 2>/dev/null)" == "true" ]]; then sed -i "$ADDONSLINE"'a ![full_access][full_access-badge]' README2.md; fi
if [[ "$(jq '.services[]' "$CONFIG_FILE" 2>/dev/null)" == *"mqtt"* ]]; then sed -i "$ADDONSLINE"'a ![mqtt][mqtt-badge]' README2.md; fi
if [[ "$(jq '.services[]' "$CONFIG_FILE" 2>/dev/null)" == *"mysql"* ]]; then sed -i "$ADDONSLINE"'a ![MariaDB][mariadb-badge]' README2.md; fi
if [[ "$(jq '.ingress' "$CONFIG_FILE" 2>/dev/null)" == "true" ]]; then sed -i "$ADDONSLINE"'a ![ingress][ingress-badge]' README2.md; fi
if [[ "$(jq '.arch[]' "$CONFIG_FILE")" == *"armv7"* ]]; then
sed -i "$ADDONSLINE"'a ![armv7][armv7-badge]' README2.md
else sed -i "$ADDONSLINE"'a ![armv7no][armv7no-badge]' README2.md; fi || true
if [[ "$(jq '.arch[]' "$CONFIG_FILE")" == *"amd64"* ]]; then
sed -i "$ADDONSLINE"'a ![amd64][amd64-badge]' README2.md
else sed -i "$ADDONSLINE"'a ![amd64no][amd64no-badge]' README2.md; fi || true
if [[ "$(jq '.arch[]' "$CONFIG_FILE")" == *"aarch64"* ]]; then
sed -i "$ADDONSLINE"'a ![aarch64][aarch64-badge]' README2.md
else sed -i "$ADDONSLINE"'a ![aarch64no][aarch64no-badge]' README2.md; fi || true
if [[ -f "$f/updater.json" ]]; then sed -i "$ADDONSLINE"'a ![Update](https://img.shields.io/badge/dynamic/json?label=Updated&query=%24.last_update&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2F'"$FOLDERNAME"'%2Fupdater.json)' README2.md; fi
if [[ "$CONFIG_SRC" == *.yaml ]]; then
sed -i "$ADDONSLINE"'a &emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2F'"$FOLDERNAME"'%2Fconfig.yaml)' README2.md || true
else
sed -i "$ADDONSLINE"'a &emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/json?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2F'"$FOLDERNAME"'%2Fconfig.json)' README2.md || true
fi
sed -i "$ADDONSLINE"'a &#10003; '"$ICON"' ['"$NAME"']('"$FOLDERNAME"'/) : '"$DESCRIPTION\\n" README2.md
if [[ "$CONFIG_FILE" != "$CONFIG_SRC" ]]; then rm "$CONFIG_FILE"; fi
# Read fields using yq (works for both JSON & YAML)
NAME="$(yq -r '.name // ""' "$CFG")"
DESCRIPTION="$(yq -r '.description // ""' "$CFG")"
PANEL_ICON="$(yq -r '.panel_icon // ""' "$CFG")"
# Icon (mdi:foo)
if [ -n "$PANEL_ICON" ] && [ "$PANEL_ICON" != "null" ]; then
ICON_NAME="${PANEL_ICON#*:}"
ICON="![image](https://api.iconify.design/mdi/$ICON_NAME.svg)"
else
ICON=""
fi
# Derived strings for checks
SCHEMA_STR="$(yq -o=json '.schema // {}' "$CFG" | tr -d '\n' || true)"
SERVICES="$(yq -r '.services[]? // empty' "$CFG" | tr '\n' ' ' || true)"
ARCHS="$(yq -r '.arch[]? // empty' "$CFG" | tr '\n' ' ' || true)"
FULL_ACCESS="$(yq -r '.full_access // false' "$CFG" || true)"
INGRESS="$(yq -r '.ingress // false' "$CFG" || true)"
# Write infos
echo "Writing infos"
sed -i "$ADDONSLINE"'{G;}' README2.md
if [[ "$SCHEMA_STR" == *"localdisks"* ]]; then sed -i "$ADDONSLINE"'a ![localdisks][localdisks-badge]' README2.md; fi
if [[ "$SCHEMA_STR" == *"networkdisks"* ]]; then sed -i "$ADDONSLINE"'a ![smb][smb-badge]' README2.md; fi
if [[ "$FULL_ACCESS" == "true" ]]; then sed -i "$ADDONSLINE"'a ![full_access][full_access-badge]' README2.md; fi
if [[ "$SERVICES" == *"mqtt"* ]]; then sed -i "$ADDONSLINE"'a ![mqtt][mqtt-badge]' README2.md; fi
if [[ "$SERVICES" == *"mysql"* ]]; then sed -i "$ADDONSLINE"'a ![MariaDB][mariadb-badge]' README2.md; fi
if [[ "$INGRESS" == "true" ]]; then sed -i "$ADDONSLINE"'a ![ingress][ingress-badge]' README2.md; fi
if [[ " $ARCHS " == *" armv7 "* ]]; then sed -i "$ADDONSLINE"'a ![armv7][armv7-badge]' README2.md; else sed -i "$ADDONSLINE"'a ![armv7no][armv7no-badge]' README2.md; fi || true
if [[ " $ARCHS " == *" amd64 "* ]]; then sed -i "$ADDONSLINE"'a ![amd64][amd64-badge]' README2.md; else sed -i "$ADDONSLINE"'a ![amd64no][amd64no-badge]' README2.md; fi || true
if [[ " $ARCHS " == *" aarch64 "* ]]; then sed -i "$ADDONSLINE"'a ![aarch64][aarch64-badge]' README2.md; else sed -i "$ADDONSLINE"'a ![aarch64no][aarch64no-badge]' README2.md; fi || true
if [[ -f "$f/updater.json" ]]; then
sed -i "$ADDONSLINE"'a ![Update](https://img.shields.io/badge/dynamic/json?label=Updated&query=%24.last_update&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2F'"$FOLDERNAME"'%2Fupdater.json)' README2.md
fi
# Version badge: picks dynamic/json for JSON, dynamic/yaml for YAML
sed -i "$ADDONSLINE"'a &emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/'"$BADGE_KIND"'?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2F'"$FOLDERNAME"'%2Fconfig.'"$EXT"')' README2.md || true
sed -i "$ADDONSLINE"'a &#10003; '"$ICON"' ['"$NAME"']('"$FOLDERNAME"'/) : '"$DESCRIPTION\\n" README2.md
done
# Restore folders name
echo "Restore structure..."
find -- * -maxdepth 0 -type d | sort -r | while read -r f; do
if [ -f "$f/oldname" ]; then
@@ -152,13 +130,10 @@ PY
echo "... done"
# Write stats
# shellcheck disable=SC2002
echo "Global stats..."
STATS_DOWNLOADS="$(awk 'NR==2{print $1}' Stats)"
sed -i "s|%%STATS_DOWNLOADS%%|$STATS_DOWNLOADS|g" README2.md && \
ADDONS_COUNT="$(find -- * -maxdepth 1 -type f \( -name "config.json" -o -name "config.yaml" \) -printf '%h\n' 2>/dev/null | sort -u | wc -l)" && \
sed -i "s|%%STATS_ADDONS%%|$ADDONS_COUNT|g" README2.md && \
sed -i "s|%%STATS_ADDONS%%|$(find . -type f \( -name 'config.json' -o -name 'config.yaml' -o -name 'config.yml' \) | wc -l)|g" README2.md && \
STATS_ONE="$(awk 'NR==3{print $(NF)}' Stats)" && \
STATS_TWO="$(awk 'NR==4{print $(NF)}' Stats)" && \
STATS_THREE="$(awk 'NR==5{print $(NF)}' Stats)"
@@ -168,44 +143,41 @@ PY
sed -i "s|%%STATS_THREE%%|${STATS_THREE^}|g" README2.md
echo "... done"
# Breakdown per arch
# Breakdown per arch (unchanged)
echo "Breakdown per arch..."
STATS_ARMV7="$(awk '{SUM+=$3}END{print SUM}' Stats2)"
STATS_AMD64="$(awk '{SUM+=$4}END{print SUM}' Stats2)"
STATS_AARCH64="$(awk '{SUM+=$5}END{print SUM}' Stats2)"
STATS_DOWNLOADS="$(( "$STATS_ARMV7" + "$STATS_AMD64" + "$STATS_AARCH64" ))"
STATS_DOWNLOADS="$(( STATS_ARMV7 + STATS_AMD64 + STATS_AARCH64 ))"
STATS_ARMV7="$(awk -v t1="$STATS_ARMV7" -v t2="$STATS_AMD64" -v t3="$STATS_AARCH64" -v t4="$STATS_DOWNLOADS" 'BEGIN{printf "%.0f", t1/t4 * 100}')"
STATS_AMD64="$(awk -v t1="$STATS_ARMV7" -v t2="$STATS_AMD64" -v t3="$STATS_AARCH64" -v t4="$STATS_DOWNLOADS" 'BEGIN{printf "%.0f", t2/t4 * 100}')"
STATS_AARCH64="$(awk -v t1="$STATS_ARMV7" -v t2="$STATS_AMD64" -v t3="$STATS_AARCH64" -v t4="$STATS_DOWNLOADS" 'BEGIN{printf "%.0f", t3/t4 * 100}')"
sed -i "s|%%STATS_ARMV7%%|armv7: ${STATS_ARMV7}%|g" README2.md
sed -i "s|%%STATS_AMD64%%|amd64: ${STATS_AMD64}%|g" README2.md
sed -i "s|%%STATS_AARCH64%%|aarch64: ${STATS_AARCH64}%|g" README2.md
#echo $((100*$STATS_THREE/($STATS_ONE+$STATS_TWO+$STATS_THREE)))
echo "... done"
for var in "$STATS_ONE" "$STATS_TWO" "$STATS_THREE"; do
i=0
j=0
k=0
i=0
j=0
k=0
# shellcheck disable=SC2013
for i in $(sed -n "/$var/p" Stats); do
k="$((k+1))"
if [ "$k" -eq 3 ]; then break; fi
if [ "$i" -eq "$i" ] && [ "$i" -gt "$j" ]; then j="$i"; fi
done
sed -i "s|${var^}|${var^} (${j}x)|g" README2.md
echo "$STATS_ONE has $j downloads"
sed -i "s|${var^}|${var^} (${j}x)|g" README2.md
echo "$STATS_ONE has $j downloads"
done
echo "... done"
# Replace template if change
echo "Replace template..."
mv README2.md README.md
echo "... done"
shell: bash
- name: Commit if needed
uses: EndBug/add-and-commit@v9
with: