mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-07-28 00:40:31 +02:00
Refactor README generation workflow
Updated the GitHub Actions workflow to enhance README generation with improved error handling and structure.
This commit is contained in:
310
.github/workflows/daily_README.yaml
vendored
310
.github/workflows/daily_README.yaml
vendored
@@ -1,131 +1,243 @@
|
|||||||
#!/usr/bin/env bash
|
# yamllint disable rule:line-length
|
||||||
|
---
|
||||||
|
name: Generate README
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: 0 17 * * *
|
||||||
|
workflow_dispatch: null
|
||||||
|
|
||||||
set -euo pipefail
|
jobs:
|
||||||
|
README_updater:
|
||||||
|
if: github.repository_owner == 'alexbelgium'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repo
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
# Ensure yq is installed (mikefarah/yq v4+)
|
- name: Install jq + yq (v4)
|
||||||
if ! command -v yq &>/dev/null; then
|
run: |
|
||||||
echo "yq is required (https://github.com/mikefarah/yq), please install it in your CI or local environment"
|
set -euo pipefail
|
||||||
exit 1
|
if ! command -v jq >/dev/null 2>&1; then
|
||||||
fi
|
sudo apt-get update -y
|
||||||
|
sudo apt-get install -y jq
|
||||||
echo "Starting"
|
fi
|
||||||
|
if ! command -v yq >/dev/null 2>&1; then
|
||||||
cp .templates/.README.md README2.md
|
sudo wget -qO /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_linux_amd64"
|
||||||
ADDONSLINE="$(sed -n '/%%ADDONS_LIST%%/=' README2.md)"
|
sudo chmod +x /usr/local/bin/yq
|
||||||
sed -i "/%%ADDONS_LIST%%/d" README2.md
|
|
||||||
|
|
||||||
# Step 1: Rename folders by name field in config
|
|
||||||
for f in $(find . -maxdepth 1 -type d ! -name '.' | sort -r); do
|
|
||||||
CONFIG=""
|
|
||||||
[ -f "$f/config.json" ] && CONFIG="$f/config.json"
|
|
||||||
[ -z "$CONFIG" ] && [ -f "$f/config.yaml" ] && CONFIG="$f/config.yaml"
|
|
||||||
[ -z "$CONFIG" ] && continue
|
|
||||||
|
|
||||||
if [[ "$CONFIG" == *.json ]]; then
|
|
||||||
NAME=$(jq -r '.name // empty' "$CONFIG")
|
|
||||||
else
|
|
||||||
NAME=$(yq -r '.name // empty' "$CONFIG")
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "$NAME" && "$f" != "./$NAME" ]]; then
|
- name: Create README file
|
||||||
echo "${f#./}" > "$f/oldname"
|
shell: bash
|
||||||
mv "$f" "./$NAME"
|
run: |
|
||||||
fi
|
set -euo pipefail
|
||||||
done
|
|
||||||
|
|
||||||
# Step 2: Populate README with addons list
|
echo "Starting"
|
||||||
find . -maxdepth 1 -type d ! -name '.' | sort -r | while read -r f; do
|
|
||||||
CONFIG=""
|
|
||||||
[ -f "$f/config.json" ] && CONFIG="$f/config.json"
|
|
||||||
[ -z "$CONFIG" ] && [ -f "$f/config.yaml" ] && CONFIG="$f/config.yaml"
|
|
||||||
[ -z "$CONFIG" ] && continue
|
|
||||||
|
|
||||||
# Helper functions
|
# ---------------------------
|
||||||
get_field() {
|
# Helper functions (JSON/YAML)
|
||||||
local field="$1"
|
# ---------------------------
|
||||||
if [[ "$CONFIG" == *.json ]]; then
|
get_config() {
|
||||||
jq -r "$field // empty" "$CONFIG"
|
# Echos "<path>|<type>" where type is json|yaml, or "|" if none found
|
||||||
|
local dir="$1"
|
||||||
|
if [ -f "$dir/config.json" ]; then
|
||||||
|
echo "$dir/config.json|json"
|
||||||
|
elif [ -f "$dir/config.yaml" ]; then
|
||||||
|
echo "$dir/config.yaml|yaml"
|
||||||
|
elif [ -f "$dir/config.yml" ]; then
|
||||||
|
echo "$dir/config.yml|yaml"
|
||||||
else
|
else
|
||||||
yq -r "$field // empty" "$CONFIG"
|
echo "|"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
get_array() {
|
get_raw() {
|
||||||
local field="$1"
|
# Print raw scalar or list items (newline-separated)
|
||||||
if [[ "$CONFIG" == *.json ]]; then
|
# $1 = jq/yq expr, $2 = type (json|yaml), $3 = path
|
||||||
jq -r "$field // empty | @sh" "$CONFIG" | tr -d "'"
|
local expr="$1" type="$2" file="$3"
|
||||||
|
if [ "$type" = "json" ]; then
|
||||||
|
jq -r "$expr" "$file" 2>/dev/null || true
|
||||||
else
|
else
|
||||||
yq -r "$field // empty | @sh" "$CONFIG" | tr -d "'"
|
yq -r "$expr" "$file" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Info extraction
|
get_jsonc() {
|
||||||
if [ -f "$f/oldname" ]; then FOLDERNAME="$(cat "$f/oldname")"; else FOLDERNAME="${f#./}"; fi
|
# Print compact JSON form of a subnode (for substring checks)
|
||||||
NAME="$(get_field '.name')"
|
# $1 = expr, $2 = type, $3 = path
|
||||||
DESCRIPTION="$(get_field '.description')"
|
local expr="$1" type="$2" file="$3"
|
||||||
|
if [ "$type" = "json" ]; then
|
||||||
|
jq -c "$expr" "$file" 2>/dev/null || true
|
||||||
|
else
|
||||||
|
yq -o=json -c "$expr" "$file" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# Prepare template
|
||||||
|
# ---------------------------
|
||||||
|
cp .templates/.README.md README2.md
|
||||||
|
ADDONSLINE="$(sed -n '/%%ADDONS_LIST%%/=' README2.md)"
|
||||||
|
# Keep the placeholder line so INSERT index stays stable
|
||||||
|
# sed -i '/%%ADDONS_LIST%%/d' README2.md
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# Sort folders by addon name (supports config.json & config.yaml/.yml)
|
||||||
|
# ---------------------------
|
||||||
|
for f in $( find -- * -maxdepth 0 -type d | sort -r ); do
|
||||||
|
IFS='|' read -r CONFIG TYPE <<<"$(get_config "$f")"
|
||||||
|
if [ -n "$CONFIG" ]; then
|
||||||
|
NAME="$(get_raw '.name' "$TYPE" "$CONFIG")"
|
||||||
|
if [ -n "${NAME:-}" ] && [ "$f" != "$NAME" ]; then
|
||||||
|
echo "$f" > "$f/oldname"
|
||||||
|
mv "$f" "$NAME"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# Populate template
|
||||||
|
# ---------------------------
|
||||||
|
find -- * -maxdepth 0 -type d | sort -r | while read -r f; do
|
||||||
|
IFS='|' read -r CONFIG TYPE <<<"$(get_config "$f")"
|
||||||
|
if [ -n "$CONFIG" ]; then
|
||||||
|
echo "Project $f"
|
||||||
|
|
||||||
|
# Get variables
|
||||||
|
if [ -f "$f/oldname" ]; then FOLDERNAME="$(cat "$f/oldname")"; else FOLDERNAME="$f"; fi
|
||||||
|
NAME="$(get_raw '.name' "$TYPE" "$CONFIG")"
|
||||||
|
DESCRIPTION="$(get_raw '.description' "$TYPE" "$CONFIG")"
|
||||||
|
|
||||||
# Icon
|
# Icon
|
||||||
ICON_RAW="$(get_field '.panel_icon')"
|
PANEL_ICON_RAW="$(get_raw '.panel_icon' "$TYPE" "$CONFIG")"
|
||||||
if [[ "$ICON_RAW" != "null" && -n "$ICON_RAW" ]]; then
|
if [ -n "$PANEL_ICON_RAW" ] && [ "$PANEL_ICON_RAW" != "null" ]; then
|
||||||
ICON="${ICON_RAW#*:}"
|
ICON="${PANEL_ICON_RAW#*:}"
|
||||||
ICON=""
|
ICON=""
|
||||||
else
|
else
|
||||||
ICON=""
|
ICON=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Insert new line for this addon
|
# Derived / checks
|
||||||
|
SCHEMA_JSON="$(get_jsonc '.schema' "$TYPE" "$CONFIG")"
|
||||||
|
SERVICES_LIST="$(get_raw '.services[]' "$TYPE" "$CONFIG")"
|
||||||
|
ARCH_LIST="$(get_raw '.arch[]' "$TYPE" "$CONFIG")"
|
||||||
|
FULL_ACCESS="$(get_raw '.full_access' "$TYPE" "$CONFIG")"
|
||||||
|
INGRESS="$(get_raw '.ingress' "$TYPE" "$CONFIG")"
|
||||||
|
|
||||||
|
# Write infos
|
||||||
|
echo "Writing infos"
|
||||||
sed -i "$ADDONSLINE"'{G;}' README2.md
|
sed -i "$ADDONSLINE"'{G;}' README2.md
|
||||||
|
|
||||||
# Badges
|
if [[ "$SCHEMA_JSON" == *"localdisks"* ]]; then sed -i "$ADDONSLINE"'a ![localdisks][localdisks-badge]' README2.md; fi
|
||||||
[[ "$(get_field '.schema')" == *"localdisks"* ]] && sed -i "$ADDONSLINE"'a ![localdisks][localdisks-badge]' README2.md
|
if [[ "$SCHEMA_JSON" == *"networkdisks"* ]]; then sed -i "$ADDONSLINE"'a ![smb][smb-badge]' README2.md; fi
|
||||||
[[ "$(get_field '.schema')" == *"networkdisks"* ]] && sed -i "$ADDONSLINE"'a ![smb][smb-badge]' README2.md
|
if [[ "$FULL_ACCESS" == "true" ]]; then sed -i "$ADDONSLINE"'a ![full_access][full_access-badge]' README2.md; fi
|
||||||
[[ "$(get_field '.full_access')" == "true" ]] && sed -i "$ADDONSLINE"'a ![full_access][full_access-badge]' README2.md
|
if [[ "$SERVICES_LIST" == *"mqtt"* ]]; then sed -i "$ADDONSLINE"'a ![mqtt][mqtt-badge]' README2.md; fi
|
||||||
|
if [[ "$SERVICES_LIST" == *"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
|
||||||
|
|
||||||
SERVICES="$(get_array '.services[]')"
|
if [[ "$ARCH_LIST" == *"armv7"* ]]; then
|
||||||
[[ "$SERVICES" == *"mqtt"* ]] && sed -i "$ADDONSLINE"'a ![mqtt][mqtt-badge]' README2.md
|
sed -i "$ADDONSLINE"'a ![armv7][armv7-badge]' README2.md
|
||||||
[[ "$SERVICES" == *"mysql"* ]] && sed -i "$ADDONSLINE"'a ![MariaDB][mariadb-badge]' README2.md
|
|
||||||
|
|
||||||
[[ "$(get_field '.ingress')" == "true" ]] && sed -i "$ADDONSLINE"'a ![ingress][ingress-badge]' README2.md
|
|
||||||
|
|
||||||
ARCHS="$(get_array '.arch[]')"
|
|
||||||
[[ "$ARCHS" == *"armv7"* ]] && sed -i "$ADDONSLINE"'a ![armv7][armv7-badge]' README2.md || sed -i "$ADDONSLINE"'a ![armv7no][armv7no-badge]' README2.md
|
|
||||||
[[ "$ARCHS" == *"amd64"* ]] && sed -i "$ADDONSLINE"'a ![amd64][amd64-badge]' README2.md || sed -i "$ADDONSLINE"'a ![amd64no][amd64no-badge]' README2.md
|
|
||||||
[[ "$ARCHS" == *"aarch64"* ]] && sed -i "$ADDONSLINE"'a ![aarch64][aarch64-badge]' README2.md || sed -i "$ADDONSLINE"'a ![aarch64no][aarch64no-badge]' README2.md
|
|
||||||
|
|
||||||
[ -f "$f/updater.json" ] && sed -i "$ADDONSLINE"'a ' README2.md
|
|
||||||
|
|
||||||
if [[ "$CONFIG" == *.json ]]; then
|
|
||||||
sed -i "$ADDONSLINE"'a   ' README2.md
|
|
||||||
else
|
else
|
||||||
sed -i "$ADDONSLINE"'a   ' README2.md
|
sed -i "$ADDONSLINE"'a ![armv7no][armv7no-badge]' README2.md
|
||||||
|
fi || true
|
||||||
|
|
||||||
|
if [[ "$ARCH_LIST" == *"amd64"* ]]; then
|
||||||
|
sed -i "$ADDONSLINE"'a ![amd64][amd64-badge]' README2.md
|
||||||
|
else
|
||||||
|
sed -i "$ADDONSLINE"'a ![amd64no][amd64no-badge]' README2.md
|
||||||
|
fi || true
|
||||||
|
|
||||||
|
if [[ "$ARCH_LIST" == *"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 ' README2.md
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Version badge: JSON vs YAML endpoint
|
||||||
|
if [ "$TYPE" = "json" ]; then
|
||||||
|
sed -i "$ADDONSLINE"'a   ' README2.md || true
|
||||||
|
else
|
||||||
|
sed -i "$ADDONSLINE"'a   ' README2.md || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sed -i "$ADDONSLINE"'a ✓ '"$ICON"' ['"$NAME"']('"$FOLDERNAME"'/) : '"$DESCRIPTION\\n" README2.md
|
sed -i "$ADDONSLINE"'a ✓ '"$ICON"' ['"$NAME"']('"$FOLDERNAME"'/) : '"$DESCRIPTION\\n" README2.md
|
||||||
done
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# Step 3: Restore folder names if changed
|
# ---------------------------
|
||||||
echo "Restore structure..."
|
# Restore folders name
|
||||||
find . -maxdepth 1 -type d ! -name '.' | sort -r | while read -r f; do
|
# ---------------------------
|
||||||
[ -f "$f/oldname" ] && NAME="$(cat "$f/oldname")" && rm "$f/oldname" && mv "$f" "./$NAME"
|
echo "Restore structure..."
|
||||||
done
|
find -- * -maxdepth 0 -type d | sort -r | while read -r f; do
|
||||||
echo "... done"
|
if [ -f "$f/oldname" ]; then
|
||||||
|
NAME="$(cat "$f/oldname")"
|
||||||
|
rm "$f/oldname"
|
||||||
|
mv "$f" "$NAME"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "... done"
|
||||||
|
|
||||||
# Step 4: Stats (count both config.json and config.yaml)
|
# ---------------------------
|
||||||
echo "Global stats..."
|
# Global stats
|
||||||
STATS_DOWNLOADS="$(awk 'NR==2{print $1}' Stats)"
|
# ---------------------------
|
||||||
TOTAL_ADDONS=$(find . -type f \( -name "config.json" -o -name "config.yaml" \) | wc -l)
|
echo "Global stats..."
|
||||||
sed -i "s|%%STATS_DOWNLOADS%%|$STATS_DOWNLOADS|g" README2.md
|
# shellcheck disable=SC2002
|
||||||
sed -i "s|%%STATS_ADDONS%%|$TOTAL_ADDONS|g" README2.md
|
STATS_DOWNLOADS="$(awk 'NR==2{print $1}' Stats)"
|
||||||
STATS_ONE="$(awk 'NR==3{print $(NF)}' Stats)"
|
sed -i "s|%%STATS_DOWNLOADS%%|$STATS_DOWNLOADS|g" README2.md && \
|
||||||
STATS_TWO="$(awk 'NR==4{print $(NF)}' Stats)"
|
# Count addons having either config.json or config.yaml/.yml (unique folders)
|
||||||
STATS_THREE="$(awk 'NR==5{print $(NF)}' Stats)"
|
sed -i "s|%%STATS_ADDONS%%|$(find . -type f \( -name 'config.json' -o -name 'config.yaml' -o -name 'config.yml' \) -printf '%h\n' | sort -u | wc -l)|g" README2.md && \
|
||||||
sed -i "s|%%STATS_ONE%%|${STATS_ONE^}|g" README2.md
|
STATS_ONE="$(awk 'NR==3{print $(NF)}' Stats)" && \
|
||||||
sed -i "s|%%STATS_TWO%%|${STATS_TWO^}|g" README2.md
|
STATS_TWO="$(awk 'NR==4{print $(NF)}' Stats)" && \
|
||||||
sed -i "s|%%STATS_THREE%%|${STATS_THREE^}|g" README2.md
|
STATS_THREE="$(awk 'NR==5{print $(NF)}' Stats)"
|
||||||
echo "... done"
|
echo "Best addon is $STATS_ONE"
|
||||||
|
sed -i "s|%%STATS_ONE%%|${STATS_ONE^}|g" README2.md
|
||||||
|
sed -i "s|%%STATS_TWO%%|${STATS_TWO^}|g" README2.md
|
||||||
|
sed -i "s|%%STATS_THREE%%|${STATS_THREE^}|g" README2.md
|
||||||
|
echo "... done"
|
||||||
|
|
||||||
# Add any additional stats or breakdowns here as in your original
|
# ---------------------------
|
||||||
|
# Breakdown per arch
|
||||||
|
# ---------------------------
|
||||||
|
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_ARMV7="$(awk -v t1="$STATS_ARMV7" -v t4="$STATS_DOWNLOADS" 'BEGIN{printf "%.0f", (t4==0?0:t1/t4*100)}')"
|
||||||
|
STATS_AMD64="$(awk -v t2="$STATS_AMD64" -v t4="$STATS_DOWNLOADS" 'BEGIN{printf "%.0f", (t4==0?0:t2/t4*100)}')"
|
||||||
|
STATS_AARCH64="$(awk -v t3="$STATS_AARCH64" -v t4="$STATS_DOWNLOADS" 'BEGIN{printf "%.0f", (t4==0?0: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 "... done"
|
||||||
|
|
||||||
# Final: Replace template if changed
|
for var in "$STATS_ONE" "$STATS_TWO" "$STATS_THREE"; do
|
||||||
mv README2.md README.md
|
i=0
|
||||||
echo "... done"
|
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" ] 2>/dev/null && [ "$i" -gt "$j" ]; then j="$i"; fi
|
||||||
|
done
|
||||||
|
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"
|
||||||
|
|
||||||
|
- name: Commit if needed
|
||||||
|
uses: EndBug/add-and-commit@v9
|
||||||
|
with:
|
||||||
|
message: "GitHub bot : README updated"
|
||||||
|
default_author: github_actions
|
||||||
|
|||||||
Reference in New Issue
Block a user