refactor(ci): extract inline scripts to ci/scripts/

- ci/scripts/read_meta.py     legge version|build_from da config.yaml/json
- ci/scripts/update_repo.py   upserta repository.json
- ci/scripts/lint_addon.sh    hadolint + yaml/json + shellcheck
- ci/scripts/git_push_repo.sh  commit e push di repository.json

Rimuove writeFile /tmp/ dal Jenkinsfile

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Martin Tahiraj
2026-04-02 14:46:17 +02:00
parent 88fe792ca0
commit c8dbd399ce
5 changed files with 197 additions and 138 deletions

View File

@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# git_push_repo.sh <gitea_user> <gitea_base_url>
#
# Committa repository.json (se modificato) e lo pusha su main.
# Il messaggio include [skip ci] per evitare loop webhook.
#
# Variabili d'ambiente richieste:
# GITEA_PUSH_PSW — password/token Gitea (iniettata da withCredentials)
set -euo pipefail
GITEA_USER=${1:?Uso: git_push_repo.sh <gitea_user> <gitea_base_url>}
GITEA_BASE_URL=${2:?Uso: git_push_repo.sh <gitea_user> <gitea_base_url>}
GITEA_PSW=${GITEA_PUSH_PSW:?GITEA_PUSH_PSW non impostata}
git config user.email "jenkins@pipelines.mt-home.uk"
git config user.name "Jenkins CI"
git add repository.json
if git diff --staged --quiet; then
echo "[INFO] Nessuna modifica a repository.json — niente da committare"
exit 0
fi
git commit -m "chore: update repository.json [skip ci]"
# Rimuove schema (https://) per costruire l'URL con credenziali
GITEA_HOST=${GITEA_BASE_URL#https://}
GITEA_HOST=${GITEA_HOST#http://}
git push \
"https://oauth2:${GITEA_PSW}@${GITEA_HOST}/${GITEA_USER}/HomeAssistantAddons.git" \
HEAD:main
echo "[OK] repository.json pushato su main"

38
ci/scripts/lint_addon.sh Normal file
View File

@@ -0,0 +1,38 @@
#!/usr/bin/env bash
# lint_addon.sh <addon_dir>
#
# Esegue tre check su un addon HA:
# 1. hadolint — Dockerfile best practices
# 2. yaml/json — config.yaml o config.json valido
# 3. shellcheck — tutti gli *.sh nella directory
#
# Esce con codice 0 se tutti i check passano, 1 altrimenti.
set -euo pipefail
ADDON=${1:?Uso: lint_addon.sh <addon_dir>}
echo "[INFO] === Lint: ${ADDON} ==="
# ── 1. hadolint ────────────────────────────────────────────────────────────────
echo "[INFO] hadolint: ${ADDON}/Dockerfile"
docker run --rm -i hadolint/hadolint < "${ADDON}/Dockerfile"
# ── 2. Config valida ───────────────────────────────────────────────────────────
if [ -f "${ADDON}/config.yaml" ]; then
python3 -c "import yaml,sys; yaml.safe_load(open(sys.argv[1]))" "${ADDON}/config.yaml"
echo "[OK] ${ADDON}/config.yaml valido"
elif [ -f "${ADDON}/config.json" ]; then
python3 -c "import json,sys; json.load(open(sys.argv[1]))" "${ADDON}/config.json"
echo "[OK] ${ADDON}/config.json valido"
else
echo "[WARN] Nessuna config trovata in ${ADDON}/"
fi
# ── 3. shellcheck ──────────────────────────────────────────────────────────────
find "${ADDON}/" -name '*.sh' | while read -r f; do
echo "[INFO] shellcheck: ${f}"
docker run --rm -v "$PWD:/mnt" koalaman/shellcheck:stable "/mnt/${f}"
done
echo "[OK] ${ADDON}: lint completato"

32
ci/scripts/read_meta.py Normal file
View File

@@ -0,0 +1,32 @@
#!/usr/bin/env python3
"""
Legge version e build_from.amd64 dalla config di un addon HA.
Uso: python3 read_meta.py <addon_dir>
Output su stdout: version|build_from_amd64
"""
import json
import os
import sys
try:
import yaml
HAS_YAML = True
except ImportError:
HAS_YAML = False
addon = sys.argv[1]
for filename in ('config.yaml', 'config.json'):
path = os.path.join(addon, filename)
if not os.path.exists(path):
continue
with open(path) as f:
cfg = yaml.safe_load(f) if (filename.endswith('.yaml') and HAS_YAML) else json.load(f)
version = str(cfg.get('version', 'latest'))
build_from = (cfg.get('build_from') or {}).get('amd64', '')
print(f'{version}|{build_from}')
sys.exit(0)
# Nessuna config trovata
print('latest|')

87
ci/scripts/update_repo.py Normal file
View File

@@ -0,0 +1,87 @@
#!/usr/bin/env python3
"""
Aggiorna repository.json con i metadati degli addon buildati con successo.
Upserta ogni addon (match su slug). Il file viene creato se non esiste.
Uso: python3 update_repo.py <gitea_user> <addon1> [addon2 ...]
Variabili d'ambiente richieste:
REGISTRY es. registry.mt-home.uk
GITEA_BASE_URL es. https://git.mt-home.uk
"""
import json
import os
import sys
try:
import yaml
HAS_YAML = True
except ImportError:
HAS_YAML = False
REGISTRY = os.environ['REGISTRY']
GITEA_BASE_URL = os.environ['GITEA_BASE_URL']
GITEA_USER = sys.argv[1]
addons_arg = sys.argv[2:]
REPO_FILE = 'repository.json'
skeleton = {
'name': f'HA Add-ons by {GITEA_USER}',
'url': f'{GITEA_BASE_URL}/{GITEA_USER}/HomeAssistantAddons',
'maintainer': GITEA_USER,
'addons': [],
}
repo = skeleton.copy()
if os.path.exists(REPO_FILE):
with open(REPO_FILE) as f:
repo = json.load(f)
repo.setdefault('addons', [])
def load_cfg(addon_dir):
for name, use_yaml in [('config.yaml', True), ('config.json', False)]:
p = os.path.join(addon_dir, name)
if not os.path.exists(p):
continue
with open(p) as f:
return yaml.safe_load(f) if (use_yaml and HAS_YAML) else json.load(f)
return {}
changed = False
for addon in addons_arg:
cfg = load_cfg(addon)
if not cfg:
print(f'[WARN] Nessuna config trovata per {addon}, skip', flush=True)
continue
slug = cfg.get('slug', addon)
version = str(cfg.get('version', 'latest'))
entry = {
'slug': slug,
'name': cfg.get('name', addon),
'description': cfg.get('description', ''),
'version': version,
'url': cfg.get('url', ''),
'arch': cfg.get('arch', ['amd64']),
'image': f'{REGISTRY}/hassio-addons/{slug}:{version}',
}
idx = next((i for i, a in enumerate(repo['addons']) if a.get('slug') == slug), None)
if idx is not None:
old_ver = repo['addons'][idx].get('version', '?')
repo['addons'][idx] = entry
print(f'[UPDATE] {slug}: {old_ver}{version}', flush=True)
else:
repo['addons'].append(entry)
print(f'[ADD] {slug} v{version}', flush=True)
changed = True
if changed:
with open(REPO_FILE, 'w') as f:
json.dump(repo, f, indent=2, ensure_ascii=False)
f.write('\n')
print('[OK] repository.json aggiornato', flush=True)
else:
print('[INFO] Nessuna modifica a repository.json', flush=True)