Commit c362da58 authored by xuwang's avatar xuwang
Browse files

feat(renovate): root-controlled admin scans via RENOVATE_ADMIN_CONFIG



Add a single root config file (RENOVATE_ADMIN_CONFIG, default renovate-admin.json)
passed to Renovate as its global config, so renovate-admin runs are driven from
one place. It can hold an explicit `repositories` list (no instance-wide scan —
e.g. derived from repos.txt) or `autodiscover` + filter. renovate-run.sh only
forces --autodiscover when no admin config is present, and passes the file via
RENOVATE_CONFIG_FILE (npx + docker).

Changelog: added
Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
parent dd5353fa
Loading
Loading
Loading
Loading
+27 −5
Original line number Diff line number Diff line
@@ -150,16 +150,38 @@ include ${OTICA_DIR}/makefiles/renovate-admin.mk

| Target | What it does |
| --- | --- |
| `renovate-admin-dryrun` | Autodiscover dry-run across every repo the token can see |
| `renovate-admin-run` | Autodiscover real run across matching repos (`confirm.sh`-guarded) |
| `renovate-admin-dryrun` | Admin dry-run across the controlled repo set |
| `renovate-admin-run` | Admin real run across the controlled repo set (`confirm.sh`-guarded) |

Both runs are driven by a single **root config file**, `RENOVATE_ADMIN_CONFIG`
(default `renovate-admin.json`), passed to Renovate as its global config — the one
place that controls which repos run. Two ways to scope it:

**Explicit list (recommended for a multi-repo project)** — process exactly the
repos you own, with **no instance-wide scan**. Pair with `onboarding: false` +
`requireConfig: required` so only repos that already have their own
`renovate.json` are touched (others are skipped, never onboarding-PR'd):

```json
{
  "repositories": ["ns/repo-a", "ns/repo-b"],
  "onboarding": false,
  "requireConfig": "required"
}
```

Narrow the scope with `RENOVATE_AUTODISCOVER_FILTER` (a glob, e.g. `mygroup/**`):
A natural source for that list is the project's `repos.txt`:

```bash
make renovate-admin-dryrun RENOVATE_AUTODISCOVER_FILTER='iac/**'
grep -vE '^\s*#|^\s*$' repos.txt | awk '{print $2}' | sed -E 's#^git@[^:]+:##; s#\.git$##'
```

This needs a **group or instance** token that can see the target repos.
**Autodiscover** — set `"autodiscover": true` (+ optional `autodiscoverFilter`) in
the admin config, or omit the file and use `RENOVATE_AUTODISCOVER_FILTER`. Note
autodiscover enumerates the **whole instance** before filtering, so the explicit
list is far cheaper.

Either way the admin run needs a token that can see the target repos.

## Scheduled runs in GitLab CI (`.gitlab/renovate-ci.yml`)

+8 −1
Original line number Diff line number Diff line
@@ -13,6 +13,12 @@ unexport RENOVATE_ADMIN_MK_INCLUDED
# optionally narrowed by RENOVATE_AUTODISCOVER_FILTER (e.g. "mygroup/**"). Needs
# a group/instance token: read_api for dry-runs, api for real runs.
#
# Centralize control in one place with RENOVATE_ADMIN_CONFIG: a global config
# file (default renovate-admin.json) holding autodiscover / autodiscoverFilter /
# onboarding / requireConfig. Keep onboarding=false + requireConfig=required so
# only repos that already have their own renovate.json are managed — editing this
# one file (or onboarding a repo) controls the whole fleet.
#
# Targets:
#   renovate-admin-dryrun  autodiscover dry-run across accessible repos
#   renovate-admin-run     autodiscover real run across accessible repos (confirm)
@@ -26,7 +32,8 @@ include $(dir $(lastword $(MAKEFILE_LIST)))renovate.mk
endif

RENOVATE_AUTODISCOVER_FILTER ?=
export RENOVATE_AUTODISCOVER_FILTER
RENOVATE_ADMIN_CONFIG        ?= renovate-admin.json
export RENOVATE_AUTODISCOVER_FILTER RENOVATE_ADMIN_CONFIG

.PHONY: renovate-admin-dryrun
renovate-admin-dryrun: renovate-check ## autodiscover dry-run across accessible repos (read_api)
+24 −17
Original line number Diff line number Diff line
@@ -15,6 +15,9 @@
#   RENOVATE_REPO         namespace/project (default: derived from git remote)
#   RENOVATE_ARGS         extra args appended to the Renovate invocation
#   RENOVATE_AUTODISCOVER_FILTER  optional autodiscover glob (autodiscover modes)
#   RENOVATE_ADMIN_CONFIG  global config file for autodiscover modes (passed to
#                          Renovate as RENOVATE_CONFIG_FILE) — the one place that
#                          controls which repos get scanned
#   RENOVATE_DOCKER_IMAGE default: renovate/renovate
#   RENOVATE_TOKEN        GitLab token for the repo's server (scope: 'api' real,
#                         'read_api' dry-run). Precedence:
@@ -40,6 +43,7 @@ RENOVATE_PLATFORM="${RENOVATE_PLATFORM:-gitlab}"
RENOVATE_CONFIG="${RENOVATE_CONFIG:-renovate.json}"
RENOVATE_ARGS="${RENOVATE_ARGS:-}"
RENOVATE_AUTODISCOVER_FILTER="${RENOVATE_AUTODISCOVER_FILTER:-}"
RENOVATE_ADMIN_CONFIG="${RENOVATE_ADMIN_CONFIG:-}"
RENOVATE_DOCKER_IMAGE="${RENOVATE_DOCKER_IMAGE:-renovate/renovate}"

# Parse the origin remote (https, scp-style, or ssh://) once.
@@ -126,10 +130,9 @@ run_renovate() {
    elif command -v npx >/dev/null 2>&1; then
        base=(npx --yes renovate)
    elif command -v docker >/dev/null 2>&1; then
        base=(docker run --rm \
              -e RENOVATE_TOKEN -e RENOVATE_PLATFORM -e RENOVATE_ENDPOINT \
              -v "${PWD}:/usr/src/app" -w /usr/src/app \
              "${RENOVATE_DOCKER_IMAGE}")
        base=(docker run --rm -e RENOVATE_TOKEN -e RENOVATE_PLATFORM -e RENOVATE_ENDPOINT)
        [ -n "${RENOVATE_CONFIG_FILE:-}" ] && base+=(-e RENOVATE_CONFIG_FILE)
        base+=(-v "${PWD}:/usr/src/app" -w /usr/src/app "${RENOVATE_DOCKER_IMAGE}")
    else
        err "No Renovate runtime found. Install Node 20+ (renovate/npx) or Docker, or set RENOVATE_CMD."
    fi
@@ -176,19 +179,23 @@ case "${MODE}" in
        log_context; echo "renovate: repo=${REPO}" >&2
        run_renovate ${RENOVATE_ARGS} "${REPO}"
        ;;
    autodiscover-dryrun)
        require_token read_api
        log_context; echo "renovate: autodiscover (dry-run)${RENOVATE_AUTODISCOVER_FILTER:+ filter=${RENOVATE_AUTODISCOVER_FILTER}}" >&2
        run_renovate --autodiscover=true \
            ${RENOVATE_AUTODISCOVER_FILTER:+--autodiscover-filter="${RENOVATE_AUTODISCOVER_FILTER}"} \
            --dry-run=full ${RENOVATE_ARGS}
        ;;
    autodiscover-run)
        require_token api
        log_context; echo "renovate: autodiscover${RENOVATE_AUTODISCOVER_FILTER:+ filter=${RENOVATE_AUTODISCOVER_FILTER}}" >&2
        run_renovate --autodiscover=true \
            ${RENOVATE_AUTODISCOVER_FILTER:+--autodiscover-filter="${RENOVATE_AUTODISCOVER_FILTER}"} \
            ${RENOVATE_ARGS}
    autodiscover-dryrun|autodiscover-run)
        [ "${MODE}" = autodiscover-run ] && require_token api || require_token read_api
        admin_args=()
        # A root admin config (renovate-admin.json) is passed to Renovate as its
        # global config and is the single place that controls which repos run —
        # e.g. an explicit `repositories` list (no instance-wide scan) or
        # `autodiscover` + filter. Without it, fall back to instance autodiscover.
        if [ -n "${RENOVATE_ADMIN_CONFIG}" ] && [ -f "${RENOVATE_ADMIN_CONFIG}" ]; then
            export RENOVATE_CONFIG_FILE="${RENOVATE_ADMIN_CONFIG}"
            echo "renovate: admin config=${RENOVATE_ADMIN_CONFIG}" >&2
        else
            admin_args+=(--autodiscover=true)
            [ -n "${RENOVATE_AUTODISCOVER_FILTER}" ] && admin_args+=(--autodiscover-filter="${RENOVATE_AUTODISCOVER_FILTER}")
        fi
        [ "${MODE}" = autodiscover-dryrun ] && admin_args+=(--dry-run=full)
        log_context; echo "renovate: admin run (${MODE#autodiscover-})" >&2
        run_renovate ${admin_args[@]+"${admin_args[@]}"} ${RENOVATE_ARGS}
        ;;
    *)
        err "Unknown mode '${MODE}'. Use validate|dryrun|run|autodiscover-dryrun|autodiscover-run."