Files
plex-playlist/.gitea/workflows/renovate.yml
copilotcoder e4925e2023
Some checks failed
CICD / Build CICD Image Failure Postmortem (push) Has been cancelled
CICD / Source Checks (push) Has been cancelled
CICD / Dependency Audits (Informational) (push) Has been cancelled
CICD / CICD Tests Complete (push) Has been cancelled
CICD / Build Release Images (push) Has been cancelled
CICD / Build Tester Images (push) Has been cancelled
CICD / Production Images Complete (push) Has been cancelled
CICD / Production Image Failures Postmortem (push) Has been cancelled
CICD / Source Lanes Failure Postmortem (push) Has been cancelled
CICD / Runtime Black-Box Integration Tests (push) Has been cancelled
CICD / Integration Tests Failure Postmortem (push) Has been cancelled
CICD / End-to-End Tests (push) Has been cancelled
CICD / E2E Tests Failure Postmortem (push) Has been cancelled
CICD / Promote Staging Images To Release (push) Has been cancelled
CICD / Build and Push CICD Images (push) Has been cancelled
ci(renovate): force manual runs outside schedule
2026-07-21 15:52:58 -04:00

543 lines
25 KiB
YAML

name: Renovate Dependency Updates
on:
schedule:
# Run Renovate every weekday at 8 AM UTC
- cron: '0 8 * * 1-5'
workflow_dispatch: # Allow manual triggering
inputs:
dry_run:
description: 'Run in dry-run mode (no changes made)'
required: false
default: 'false'
type: boolean
jobs:
renovate:
name: Renovate Dependencies
# Renovate is npm/registry heavy; restrict to 8GB-capacity runners.
runs-on: ubuntu-act-8gb
timeout-minutes: 90
steps:
- name: Prepare Renovate container image
env:
RENOVATE_IMAGE_PRIMARY: kankali.darkhelm.lan:3001/darkhelm.org/renovate:41
RENOVATE_IMAGE_FALLBACK: ghcr.io/renovatebot/renovate:41
GITEA_REGISTRY_HOST: kankali.darkhelm.lan
GITEA_REGISTRY_IP: 10.18.75.2
PACKAGE_ACCESS_TOKEN: ${{ secrets.PACKAGE_ACCESS_TOKEN }}
REGISTRY_USER: ${{ github.actor }}
run: |
set -euo pipefail
retry_cmd() {
attempts="${1:-3}"
backoff="${2:-10}"
shift 2
attempt=1
while [ "${attempt}" -le "${attempts}" ]; do
if "$@"; then
return 0
fi
if [ "${attempt}" -lt "${attempts}" ]; then
sleep_seconds=$((backoff * attempt))
echo "Command failed (attempt ${attempt}/${attempts}): $*" >&2
echo "Retrying in ${sleep_seconds}s" >&2
sleep "${sleep_seconds}"
fi
attempt=$((attempt + 1))
done
echo "Command failed after ${attempts} attempts: $*" >&2
return 1
}
echo "=== Preparing Renovate container ==="
free -h || true
if ! grep -q "${GITEA_REGISTRY_HOST}" /etc/hosts; then
echo "${GITEA_REGISTRY_IP} ${GITEA_REGISTRY_HOST}" >> /etc/hosts
fi
if [ -n "${PACKAGE_ACCESS_TOKEN:-}" ] && [ -n "${REGISTRY_USER:-}" ]; then
echo "${PACKAGE_ACCESS_TOKEN}" | docker login "http://${GITEA_REGISTRY_HOST}:3001" -u "${REGISTRY_USER}" --password-stdin >/dev/null || true
fi
extract_remote_digest_buildx() {
image_ref="$1"
digest="$(docker buildx imagetools inspect "${image_ref}" --format '{{json .Manifest.Digest}}' 2>/dev/null || true)"
digest="${digest//\"/}"
digest="${digest//$'\n'/}"
digest="${digest//$'\r'/}"
digest="${digest// /}"
if [[ "${digest}" == sha256:* ]]; then
printf '%s\n' "${digest}"
return 0
fi
return 1
}
extract_remote_digest_manifest() {
image_ref="$1"
digest="$(docker manifest inspect "${image_ref}" 2>/dev/null | sed -n 's/.*"digest"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1 || true)"
if [[ "${digest}" == sha256:* ]]; then
printf '%s\n' "${digest}"
return 0
fi
return 1
}
remote_digest() {
image_ref="$1"
if [[ "${image_ref}" == *@sha256:* ]]; then
printf '%s\n' "${image_ref##*@}"
return 0
fi
extract_remote_digest_buildx "${image_ref}" || extract_remote_digest_manifest "${image_ref}"
}
local_digest_matches() {
image_ref="$1"
digest="$2"
docker image inspect --format '{{range .RepoDigests}}{{println .}}{{end}}' "${image_ref}" 2>/dev/null | grep -q "@${digest}$"
}
resolve_candidate() {
image_ref="$1"
if docker image inspect "${image_ref}" >/dev/null 2>&1; then
if digest="$(remote_digest "${image_ref}")"; then
if local_digest_matches "${image_ref}" "${digest}"; then
echo "Using cached current image: ${image_ref}" >&2
printf '%s\n' "${image_ref}"
return 0
fi
echo "Cached image is stale for ${image_ref}; refreshing" >&2
else
echo "Remote digest unavailable for ${image_ref}; attempting refresh pull" >&2
fi
fi
if retry_cmd 3 15 docker pull "${image_ref}" >/dev/null; then
printf '%s\n' "${image_ref}"
return 0
fi
return 1
}
pick_renovate_image() {
for candidate in "${RENOVATE_IMAGE_PRIMARY}" "${RENOVATE_IMAGE_FALLBACK}"; do
echo "Trying Renovate image candidate: ${candidate}" >&2
if resolve_candidate "${candidate}" >/dev/null; then
printf '%s\n' "${candidate}"
return 0
fi
echo "⚠ Renovate image candidate failed: ${candidate}" >&2
done
return 1
}
if ! RENOVATE_IMAGE="$(pick_renovate_image)"; then
echo "❌ Unable to prepare Renovate image from local mirror or GHCR"
echo "Tried: ${RENOVATE_IMAGE_PRIMARY}"
echo "Tried: ${RENOVATE_IMAGE_FALLBACK}"
exit 1
fi
echo "Using Renovate image: ${RENOVATE_IMAGE}"
docker run --rm "${RENOVATE_IMAGE}" --version
echo "RENOVATE_IMAGE=${RENOVATE_IMAGE}" >> "$GITHUB_ENV"
- name: Run Renovate
env:
# Prefer dedicated Renovate token, then fall back to existing CI tokens.
RENOVATE_TOKEN_SECRET: ${{ secrets.RENOVATE_TOKEN }}
RENOVATE_GITHUB_COM_TOKEN: ${{ secrets.RENOVATE_GITHUB_COM_TOKEN }}
ACTIONS_TRIGGER_TOKEN: ${{ secrets.ACTIONS_TRIGGER_TOKEN }}
PACKAGE_ACCESS_TOKEN: ${{ secrets.PACKAGE_ACCESS_TOKEN }}
RENOVATE_DRY_RUN: ${{ inputs.dry_run }}
RENOVATE_PLATFORM: gitea
RENOVATE_ENDPOINT_INTERNAL: http://kankali.darkhelm.lan:3001/api/v1
RENOVATE_ENDPOINT_EXTERNAL: https://dogar.darkhelm.org/api/v1
RENOVATE_GIT_HOST: dogar.darkhelm.org
RENOVATE_GIT_USERNAME: ${{ github.actor }}
RENOVATE_ENDPOINT_IP: 10.18.75.2
RENOVATE_ALLOW_INSECURE_TLS: "true"
RENOVATE_GIT_AUTHOR: Renovate Bot <renovate@darkhelm.org>
RENOVATE_ONBOARDING: "false"
RENOVATE_REQUIRE_CONFIG: required
RENOVATE_PR_CONCURRENT_LIMIT: "3"
RENOVATE_BRANCH_CONCURRENT_LIMIT: "5"
RENOVATE_NODE_ARGS: --max-old-space-size=768
RENOVATE_OSV_VULNERABILITY_ALERTS: "false"
RENOVATE_FETCH_CHANGELOGS: "off"
LOG_LEVEL: debug
run: |
set -euo pipefail
echo "=== Running Renovate Bot ==="
TARGET_REPO="DarkHelm.org/plex-playlist"
TARGET_ORG="${TARGET_REPO%%/*}"
CURL_INSECURE_FLAG=""
if [ "${RENOVATE_ALLOW_INSECURE_TLS:-false}" = "true" ]; then
echo "⚠ Renovate insecure TLS mode enabled for self-signed certificate endpoint"
CURL_INSECURE_FLAG="--insecure"
export NODE_TLS_REJECT_UNAUTHORIZED=0
fi
configure_endpoint() {
endpoint_input="${1%/}"
endpoint_ip_fallback="${2:-}"
if [[ "${endpoint_input}" == */api/v1 ]]; then
API_ENDPOINT="${endpoint_input}"
BASE_ENDPOINT="${endpoint_input%/api/v1}"
else
API_ENDPOINT="${endpoint_input}/api/v1"
BASE_ENDPOINT="${endpoint_input}"
fi
ENDPOINT_AUTHORITY="$(printf '%s' "${BASE_ENDPOINT}" | sed -E 's#^https?://([^/]+).*$#\1#')"
ENDPOINT_HOST="${ENDPOINT_AUTHORITY%%:*}"
ENDPOINT_IP="$(getent hosts "${ENDPOINT_HOST}" | awk '{print $1; exit}' || true)"
if [ -z "${ENDPOINT_IP}" ] && [ -n "${endpoint_ip_fallback}" ]; then
ENDPOINT_IP="${endpoint_ip_fallback}"
echo "Using configured Renovate endpoint IP fallback: ${ENDPOINT_HOST} -> ${ENDPOINT_IP}"
if ! grep -q "${ENDPOINT_HOST}" /etc/hosts; then
echo "${ENDPOINT_IP} ${ENDPOINT_HOST}" >> /etc/hosts
fi
fi
DOCKER_ADD_HOST_ARG=""
if [ -n "${ENDPOINT_IP}" ]; then
DOCKER_ADD_HOST_ARG="--add-host ${ENDPOINT_HOST}:${ENDPOINT_IP}"
echo "Renovate container host mapping: ${ENDPOINT_HOST} -> ${ENDPOINT_IP}"
else
echo "⚠ Unable to resolve ${ENDPOINT_HOST} on runner; proceeding without explicit --add-host"
fi
}
select_reachable_endpoint() {
for candidate in "${RENOVATE_ENDPOINT_INTERNAL}" "${RENOVATE_ENDPOINT_EXTERNAL}"; do
fallback_ip=""
if [ "${candidate}" = "${RENOVATE_ENDPOINT_INTERNAL}" ]; then
fallback_ip="${RENOVATE_ENDPOINT_IP:-}"
fi
configure_endpoint "${candidate}" "${fallback_ip}"
echo "Testing Renovate endpoint candidate: ${API_ENDPOINT}"
version_status=$(curl -sS -o /tmp/renovate-version-check.json -w "%{http_code}" \
${CURL_INSECURE_FLAG} \
"${API_ENDPOINT}/version" || true)
if [ "${version_status}" = "200" ]; then
SELECTED_ENDPOINT_INPUT="${candidate}"
VERSION_STATUS="${version_status}"
return 0
fi
echo "⚠ Endpoint candidate failed version preflight: ${API_ENDPOINT} (status=${version_status})"
if [ -s /tmp/renovate-version-check.json ]; then
cat /tmp/renovate-version-check.json || true
fi
done
return 1
}
if ! select_reachable_endpoint; then
echo "❌ Unable to reach either configured Renovate endpoint"
echo "Tried internal: ${RENOVATE_ENDPOINT_INTERNAL}"
echo "Tried external: ${RENOVATE_ENDPOINT_EXTERNAL}"
exit 1
fi
# Force git clone base URL to the selected endpoint host/port.
# This avoids relying on platform-advertised clone URLs that may point to an unreachable external proxy.
export RENOVATE_GIT_URL="${BASE_ENDPOINT}/"
export RENOVATE_ENDPOINT="${BASE_ENDPOINT}"
echo "Renovate endpoint (primary): ${RENOVATE_ENDPOINT}"
echo "Renovate endpoint (fallback): ${RENOVATE_ENDPOINT_EXTERNAL}"
echo "Renovate git base URL override: ${RENOVATE_GIT_URL}"
echo "Preflight API endpoint: ${API_ENDPOINT}"
PLATFORM_VERSION=""
if [ "${VERSION_STATUS}" = "200" ]; then
PLATFORM_VERSION=$(sed -n 's/.*"version":"\([^"]*\)".*/\1/p' /tmp/renovate-version-check.json | head -n 1)
if [ -n "${PLATFORM_VERSION}" ]; then
export RENOVATE_X_PLATFORM_VERSION="${PLATFORM_VERSION}"
echo "✓ Gitea version preflight passed: ${RENOVATE_X_PLATFORM_VERSION}"
else
echo "⚠ Gitea version preflight returned 200 but version could not be parsed"
cat /tmp/renovate-version-check.json || true
fi
else
echo "⚠ Gitea version preflight failed with status ${VERSION_STATUS}"
if [ -s /tmp/renovate-version-check.json ]; then
cat /tmp/renovate-version-check.json || true
fi
fi
select_token_with_repo_access() {
for candidate_name in RENOVATE_TOKEN_SECRET ACTIONS_TRIGGER_TOKEN PACKAGE_ACCESS_TOKEN; do
candidate_value="${!candidate_name:-}"
if [ -z "${candidate_value}" ]; then
continue
fi
USER_STATUS=$(curl -sS -o /tmp/renovate-auth-check-user.json -w "%{http_code}" \
${CURL_INSECURE_FLAG} \
-H "Authorization: token ${candidate_value}" \
"${API_ENDPOINT}/user" || true)
REPO_STATUS=$(curl -sS -o /tmp/renovate-auth-check-repo.json -w "%{http_code}" \
${CURL_INSECURE_FLAG} \
-H "Authorization: token ${candidate_value}" \
"${API_ENDPOINT}/repos/${TARGET_REPO}" || true)
ORG_STATUS=$(curl -sS -o /tmp/renovate-auth-check-org.json -w "%{http_code}" \
${CURL_INSECURE_FLAG} \
-H "Authorization: token ${candidate_value}" \
"${API_ENDPOINT}/orgs/${TARGET_ORG}" || true)
if [ "${REPO_STATUS}" = "200" ]; then
if [ "${USER_STATUS}" != "200" ] || [ "${ORG_STATUS}" != "200" ]; then
echo "⚠ Token candidate ${candidate_name} has repo access but limited user/org scopes (user=${USER_STATUS}, repo=${REPO_STATUS}, org=${ORG_STATUS})"
fi
echo "${candidate_name}:${candidate_value}"
return 0
fi
echo "⚠ Token candidate ${candidate_name} rejected (user=${USER_STATUS}, repo=${REPO_STATUS}, org=${ORG_STATUS})"
done
return 1
}
if ! SELECTED_TOKEN_RESULT="$(select_token_with_repo_access)"; then
echo "❌ No token available for Renovate authentication with repository access"
echo "Configure RENOVATE_TOKEN with at least repository read/write access; user/org read scopes are optional for this workflow."
echo "Token preflight checks attempted: ${API_ENDPOINT}/user, ${API_ENDPOINT}/repos/${TARGET_REPO}, and ${API_ENDPOINT}/orgs/${TARGET_ORG}"
if [ -s /tmp/renovate-auth-check-user.json ]; then
echo "Last user endpoint response body:"
cat /tmp/renovate-auth-check-user.json || true
fi
if [ -s /tmp/renovate-auth-check-repo.json ]; then
echo "Last repo endpoint response body:"
cat /tmp/renovate-auth-check-repo.json || true
fi
if [ -s /tmp/renovate-auth-check-org.json ]; then
echo "Last org endpoint response body:"
cat /tmp/renovate-auth-check-org.json || true
fi
exit 1
fi
SELECTED_TOKEN_SOURCE="${SELECTED_TOKEN_RESULT%%:*}"
SELECTED_TOKEN="${SELECTED_TOKEN_RESULT#*:}"
export RENOVATE_TOKEN="${SELECTED_TOKEN}"
RENOVATE_HOST_RULES_PAYLOAD="[{\"matchHost\":\"${ENDPOINT_AUTHORITY}\",\"token\":\"${SELECTED_TOKEN}\",\"authType\":\"Token-Only\",\"timeout\":180000,\"concurrentRequestLimit\":2},{\"matchHost\":\"registry.npmjs.org\",\"timeout\":90000,\"concurrentRequestLimit\":1},{\"matchHost\":\"pypi.org\",\"timeout\":90000,\"concurrentRequestLimit\":2},{\"matchHost\":\"files.pythonhosted.org\",\"timeout\":90000,\"concurrentRequestLimit\":2},{\"matchHost\":\"mcr.microsoft.com\",\"timeout\":90000,\"concurrentRequestLimit\":2}]"
# Authenticate GitHub datasource calls to avoid anonymous GraphQL rate limiting.
if [ -n "${RENOVATE_GITHUB_COM_TOKEN:-}" ]; then
RENOVATE_HOST_RULES_PAYLOAD="${RENOVATE_HOST_RULES_PAYLOAD%]}"
RENOVATE_HOST_RULES_PAYLOAD="${RENOVATE_HOST_RULES_PAYLOAD},{\"matchHost\":\"api.github.com\",\"hostType\":\"github\",\"token\":\"${RENOVATE_GITHUB_COM_TOKEN}\"}]"
echo "✓ Using RENOVATE_GITHUB_COM_TOKEN for GitHub datasource requests"
else
echo "⚠ RENOVATE_GITHUB_COM_TOKEN is not set; GitHub datasource may hit anonymous rate limits"
fi
export RENOVATE_HOST_RULES="${RENOVATE_HOST_RULES_PAYLOAD}"
# Rewrite external clone URLs to local-network git transport.
export RENOVATE_GIT_REWRITE_FROM="https://dogar.darkhelm.org/"
export RENOVATE_GIT_REWRITE_TO="http://${RENOVATE_GIT_USERNAME}:${SELECTED_TOKEN}@kankali.darkhelm.lan:3001/"
# Prefer local SSH for git on kankali:2222 when keys are available in the container.
if docker run --rm ${DOCKER_ADD_HOST_ARG} \
--entrypoint /bin/sh \
"${RENOVATE_IMAGE}" \
-lc 'GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no -o BatchMode=yes -o ConnectTimeout=5" git ls-remote --heads "ssh://git@kankali.darkhelm.lan:2222/'"${TARGET_REPO}"'.git" >/dev/null 2>&1'; then
export RENOVATE_GIT_REWRITE_TO="ssh://git@kankali.darkhelm.lan:2222/"
echo "✓ Renovate git rewrite transport: local SSH (kankali:2222)"
else
echo "⚠ Local SSH git auth unavailable in Renovate container; using internal HTTP token fallback"
fi
unset SELECTED_TOKEN RESULT_TOKEN
echo "✓ Renovate auth preflight passed with ${SELECTED_TOKEN_SOURCE}"
echo "=== Renovate container connectivity preflight ==="
# Prove whether the same image/container path Renovate uses can reach Gitea.
# If this fails, the problem is container network/TLS resolution, not Renovate config.
# shellcheck disable=SC2086
docker run --rm ${DOCKER_ADD_HOST_ARG} \
-e API_ENDPOINT="${API_ENDPOINT}" \
-e TARGET_REPO="${TARGET_REPO}" \
-e RENOVATE_TOKEN \
-e NODE_TLS_REJECT_UNAUTHORIZED \
"${RENOVATE_IMAGE}" \
node -e 'const endpoints = [["version", `${process.env.API_ENDPOINT}/version`, {}], ["repo", `${process.env.API_ENDPOINT}/repos/${process.env.TARGET_REPO}`, { headers: { Authorization: `token ${process.env.RENOVATE_TOKEN}` } }], ["user", `${process.env.API_ENDPOINT}/user`, { headers: { Authorization: `token ${process.env.RENOVATE_TOKEN}` }, optional: true }]]; let failed = false; (async () => { for (const [name, url, rawOptions] of endpoints) { const optional = Boolean(rawOptions.optional); const options = { ...rawOptions }; delete options.optional; try { const response = await fetch(url, options); console.log(`container_${name}_status=${response.status}`); if (!response.ok && !optional) { failed = true; console.log(`container_${name}_body_start`); console.log((await response.text()).slice(0, 1000)); console.log(`container_${name}_body_end`); } else if (!response.ok && optional) { console.log(`container_${name}_optional_scope_missing=true`); } } catch (error) { if (!optional) { failed = true; console.log(`container_${name}_error=${error instanceof Error ? error.message : String(error)}`); } else { console.log(`container_${name}_optional_probe_error=${error instanceof Error ? error.message : String(error)}`); } } } if (failed) { process.exit(1); } })();'
# Run Renovate with configuration
if [ "${RENOVATE_DRY_RUN}" = "true" ]; then
export RENOVATE_DRY_RUN="full"
echo "🔍 Running in DRY-RUN mode (no changes will be made)"
else
unset RENOVATE_DRY_RUN
fi
# Manual workflow dispatch should execute immediately, regardless of repository schedule windows.
if [ "${GITHUB_EVENT_NAME:-}" = "workflow_dispatch" ]; then
export RENOVATE_FORCE='{"schedule":["at any time"]}'
echo "✓ Manual run detected: forcing Renovate outside schedule windows"
else
unset RENOVATE_FORCE
fi
# Multi-batch runs must not prune branches created by earlier batches.
export RENOVATE_PRUNE_STALE_BRANCHES="false"
run_renovate_with_endpoint() {
endpoint="$1"
enabled_managers="$2"
single_pass_node_args="${RENOVATE_NODE_ARGS}"
single_pass_pr_limit="${RENOVATE_PR_CONCURRENT_LIMIT}"
single_pass_branch_limit="${RENOVATE_BRANCH_CONCURRENT_LIMIT}"
export RENOVATE_ENDPOINT="${endpoint}"
echo "Running Renovate single pass with endpoint: ${RENOVATE_ENDPOINT}"
echo "Enabled managers: ${enabled_managers}"
echo "Node args: ${single_pass_node_args}"
echo "PR/branch limits: ${single_pass_pr_limit}/${single_pass_branch_limit}"
# shellcheck disable=SC2086
docker run --rm ${DOCKER_ADD_HOST_ARG} \
-e LOG_LEVEL \
-e NODE_TLS_REJECT_UNAUTHORIZED \
-e GIT_SSL_NO_VERIFY=1 \
-e GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=no' \
-e RENOVATE_TOKEN \
-e RENOVATE_GIT_USERNAME \
-e RENOVATE_GIT_REWRITE_FROM \
-e RENOVATE_GIT_REWRITE_TO \
-e RENOVATE_GIT_URL \
-e RENOVATE_HOST_RULES \
-e RENOVATE_X_PLATFORM_VERSION \
-e RENOVATE_PLATFORM \
-e RENOVATE_ENDPOINT \
-e RENOVATE_DRY_RUN \
-e RENOVATE_GIT_AUTHOR \
-e RENOVATE_ONBOARDING \
-e RENOVATE_REQUIRE_CONFIG \
-e RENOVATE_PR_CONCURRENT_LIMIT="${single_pass_pr_limit}" \
-e RENOVATE_BRANCH_CONCURRENT_LIMIT="${single_pass_branch_limit}" \
-e RENOVATE_NODE_ARGS="${single_pass_node_args}" \
-e RENOVATE_OSV_VULNERABILITY_ALERTS \
-e RENOVATE_FETCH_CHANGELOGS \
-e RENOVATE_FORCE \
-e RENOVATE_PRUNE_STALE_BRANCHES \
-e RENOVATE_ENABLED_MANAGERS="${enabled_managers}" \
--entrypoint /bin/sh \
"${RENOVATE_IMAGE}" \
-lc 'set -e
git config --global "url.${RENOVATE_GIT_REWRITE_TO}.insteadOf" "https://dogar.darkhelm.org/"
git config --global --add "url.${RENOVATE_GIT_REWRITE_TO}.insteadOf" "http://dogar.darkhelm.org/"
git config --global --add "url.${RENOVATE_GIT_REWRITE_TO}.insteadOf" "https://${RENOVATE_GIT_USERNAME}@dogar.darkhelm.org/"
git config --global --add "url.${RENOVATE_GIT_REWRITE_TO}.insteadOf" "https://${RENOVATE_TOKEN}@dogar.darkhelm.org/"
git config --global --add "url.${RENOVATE_GIT_REWRITE_TO}.insteadOf" "https://x-access-token:${RENOVATE_TOKEN}@dogar.darkhelm.org/"
git config --global --add "url.${RENOVATE_GIT_REWRITE_TO}.insteadOf" "${RENOVATE_GIT_REWRITE_FROM}"
echo "Configured git dogar->kankali rewrite rules"
renovate --platform "${RENOVATE_PLATFORM}" --endpoint "${RENOVATE_ENDPOINT}" --git-url "${RENOVATE_GIT_URL}" --git-author "${RENOVATE_GIT_AUTHOR}" --onboarding="${RENOVATE_ONBOARDING}" --pr-concurrent-limit "${RENOVATE_PR_CONCURRENT_LIMIT}" --branch-concurrent-limit "${RENOVATE_BRANCH_CONCURRENT_LIMIT}" --osv-vulnerability-alerts="${RENOVATE_OSV_VULNERABILITY_ALERTS}" --enabled-managers "${RENOVATE_ENABLED_MANAGERS}" DarkHelm.org/plex-playlist'
}
run_single_pass_with_fallback() {
enabled_managers="$1"
if run_renovate_with_endpoint "${BASE_ENDPOINT}" "${enabled_managers}" 2>&1 | tee -a /tmp/renovate.log; then
return 0
fi
primary_status=$?
if [ "${primary_status}" -eq 137 ] || tail -n 400 /tmp/renovate.log | grep -qE '(^|[[:space:]])Killed($|[[:space:]])|exitcode '\''137'\''' ; then
echo "❌ Renovate single pass terminated by OOM/kill signal on primary endpoint; skipping endpoint retry"
return "${primary_status}"
fi
echo "⚠ Renovate single pass failed with primary endpoint. Retrying with API endpoint form..."
run_renovate_with_endpoint "${API_ENDPOINT}" "${enabled_managers}" 2>&1 | tee -a /tmp/renovate.log
}
: > /tmp/renovate.log
# Run Renovate once across all enabled managers.
run_single_pass_with_fallback "docker-compose,dockerfile,github-actions,npm,pep621"
echo "✓ Renovate execution completed"
- name: Failure diagnostics
if: failure()
run: |
echo "=== Failure Diagnostics ==="
date -u '+timestamp_utc=%Y-%m-%dT%H:%M:%SZ'
echo "runner_name=${RUNNER_NAME:-unknown}"
echo "runner_hostname=${HOSTNAME:-unknown}"
uname -a || true
cat /etc/os-release 2>/dev/null || true
df -h || true
free -h || true
ps aux --sort=-%mem | head -n 30 || true
if command -v docker >/dev/null 2>&1; then
echo "=== Docker Diagnostics ==="
docker version || true
docker info || true
docker ps -a || true
docker images --digests | head -n 50 || true
else
echo "docker not available on this runner"
fi
echo "=== Kernel Tail ==="
dmesg | tail -n 120 || true
- name: Upload Renovate logs
if: always()
run: |
if [ -f "/tmp/renovate.log" ]; then
echo "=== Renovate Log Output ==="
echo "Last 50 lines of Renovate log:"
tail -50 /tmp/renovate.log
# Save log as artifact (if GitHub Actions artifact support exists)
mkdir -p /tmp/artifacts
cp /tmp/renovate.log /tmp/artifacts/renovate-$(date +%Y%m%d-%H%M%S).log
else
echo "No Renovate log file found"
fi
- name: Report Results
if: always()
run: |
echo "=== Renovate Execution Summary ==="
echo "Repository: DarkHelm.org/plex-playlist"
echo "Execution time: $(date)"
echo "Dry run mode: ${RENOVATE_DRY_RUN:-false}"
echo ""
echo "Check the Dependency Dashboard issue in your repository for detailed results:"
echo "https://dogar.darkhelm.org/DarkHelm.org/plex-playlist/issues"
echo ""
echo "Next scheduled run: Next weekday at 8 AM UTC"