Aller au contenu

Renovate : valider la config et son silence sur les forks

Une renovate.json invalide ne se signale pas toujours. Certaines erreurs font ouvrir une issue et arrêtent toutes les PR, d'autres sont ignorées en silence et sur un fork Renovate peut ne jamais rien faire sans que ça apparaisse nulle part. Les 3 cas sont arrivés sur 2 repos le même après-midi. Le validateur en attrape une partie et il faut savoir laquelle.

Valider avant de pousser

Renovate publie son validateur dans le paquet npm, donc pas besoin d'attendre un cycle sur la plateforme :

cd /le/repo
npx --yes --package renovate@latest -- renovate-config-validator

Sortie sur une config saine :

 INFO: Validating renovate.json
 INFO: Config validated successfully against 1 file(s)

2 détails de l'invocation valent le détour.

Épingler la version

--package renovate sans tag, qui est la forme de la doc officielle, laisse npx servir ce qu'il a en cache. Le cache local datait de plusieurs majeures et refusait une config que la 44 accepte, ce qui suffit à conclure l'inverse de la réalité sur le point qu'on cherchait à vérifier.

Savoir dans quel mode il tourne

Passer un chemin en argument fait valider le fichier comme config globale, celle d'une instance self-hosted et pas comme config de repo. --no-global force le mode repo, et la ligne de sortie annonce alors le mode :

 INFO: Validating renovate.json as global config
 INFO: Validating renovate.json as repo config

Le suffixe as <mode> config n'apparaît que quand on passe un fichier en argument. Sans argument, le validateur découvre les emplacements par défaut, valide en mode repo et se contente de INFO: Validating renovate.json, comme dans la sortie plus haut.

Le mode n'est pas cosmétique, contrairement à ce qu'on croit en voyant qu'une clé inconnue est refusée dans les 2. En mode global, les options réservées à la config globale passent en silence ; en mode repo elles sont rejetées. Testé sur {"autodiscover": true, "binarySource": "install"} avec la 44 :

$ renovate-config-validator c.json
 INFO: Config validated successfully against 1 file(s)

$ renovate-config-validator --no-global c.json
       "message": "The \"autodiscover\" option is a global option reserved only for Renovate's
                    global configuration and cannot be configured within a repository's config file"

Valider une config de repo en mode global laisse donc passer exactement ce que le vrai run refusera. C'est la raison d'être de --no-global, pas une préférence.

--strict fait en plus échouer la validation quand une migration de config est nécessaire, ce que Renovate propose sinon via une case à cocher dans le dependency dashboard.

Épingler la version avec le hook pre-commit

Renovate publie ses hooks et leur rev est la version de Renovate. Le problème de cache npx disparaît, puisque le hook installe renovate@<rev> en dépendance :

.pre-commit-config.yaml
repos:
  - repo: https://github.com/renovatebot/pre-commit-hooks
    rev: 44.39.2
    hooks:
      - id: renovate-config-validator

Le hook matche renovate.json, .renovaterc, renovate.json5 et leurs variantes et demande pre-commit 3.6.0 au minimum. Comme pre-commit passe les fichiers matchés en arguments, il valide en mode global : ajouter args: [--no-global] remet le mode repo.

Renovate ne met pas ce rev à jour tout seul : son manager pre-commit est livré avec enabled: false. Sans opt-in explicite le rev reste figé indéfiniment, ce qui vide de son sens l'argument « le validateur suit la version qui tourne ». Il faut l'activer :

renovate.json
{
  "extends": [":enablePreCommit"]
}

Ou l'équivalent {"pre-commit": {"enabled": true}}. À noter que ce manager n'est pas supporté par les mainteneurs de pre-commit, Renovate le rappelle dans le corps de ses PR.

Documenter une config sans la casser

La convention "// commentaire" marche dans plusieurs outils qui manipulent du JSON. Renovate valide strictement et refuse toute clé qu'il ne connaît pas :

renovate.json, ce qui casse
{
  "// forkProcessing": "ce repo est un fork, renovate saute les forks par défaut",
  "forkProcessing": "enabled"
}

Renovate ouvre alors une issue Action Required: Fix Renovate Configuration et arrête d'ouvrir des PR jusqu'à correction. Le champ prévu pour documenter est description, valable au niveau racine comme dans une packageRule :

renovate.json, ce qui passe
{
  "description": "ce repo est un fork, renovate saute les forks par défaut",
  "forkProcessing": "enabled"
}

github-runners : une datasource, pas un manager

github-runners suit les labels de runner (ubuntu-24.04, macos-15). C'est une datasource, il n'existe pas de page de manager pour elle et les labels sont détectés par le manager github-actions qui lit les workflows. Donc une règle sur github-actions seul les couvre déjà.

Ce qu'on veut La clé
Tout ce que le manager github-actions détecte, actions et labels de runner "matchManagers": ["github-actions"]
Seulement les labels de runner "matchDatasources": ["github-runners"]

Et c'est là que le validateur ne sert à rien. Renovate 44 accepte n'importe quelle chaîne dans matchManagers, y compris ceci-nexiste-absolument-pas et sort en succès. Une version plus ancienne refusait, avec la liste des managers valides dans le message :

ERROR: Found errors in configuration
  "message": "packageRules: You have included an unsupported manager in a
  package rule. Your list: github-actions,github-runners.
  Supported managers are: (ansible, ..., github-actions, gitlabci, ...)"

Ce contrôle a disparu, donc sur ce point c'est la doc qui tranche, pas l'outil. Une règle qui cible un manager inexistant ne matche rien et ne le dit pas : elle a l'air de fonctionner et le semanticCommitType ou le groupName qu'elle porte ne s'applique jamais.

Le silence de Renovate sur les forks

forkProcessing vaut auto par défaut, et auto veut dire « sauter les forks en mode autodiscover ». C'est le cas de l'app Mend installée sur « All repositories », et d'une instance self-hosted lancée en autodiscover. Renovate n'ouvre alors sur un fork ni PR d'onboarding, ni dependency dashboard, ni issue de config, et c'est le défaut le plus coûteux à diagnostiquer parce qu'il ne produit aucun signal.

En dehors de l'autodiscover, quand les repos sont listés explicitement, les forks sont traités normalement. Le comportement dépend donc du mode d'exécution, ce qui explique qu'on lise des retours contradictoires dessus.

Sur un repo créé par fork, sans savoir que l'option existe, on regarde une config correcte en se demandant pourquoi rien ne bouge.

renovate.json
{
  "description": "ce repo est un fork, renovate saute les forks par défaut",
  "forkProcessing": "enabled"
}

Vérifier si un repo est un fork tient en une commande :

gh api repos/OWNER/REPO --jq '{fork: .fork, parent: .parent.full_name}'

Un fork naît aussi avec ses issues désactivées, quel que soit l'état du parent : ce n'est pas de l'héritage, c'est GitHub qui les désactive sur tout nouveau fork. Renovate y met son dependency dashboard, donc tant qu'elles sont fermées il n'a nulle part où lister ce qu'il retient. Ça n'empêche pas les PR, mais on perd la vue d'ensemble et la case « lancer maintenant ».

Attraper l'erreur avant que Renovate la trouve

Le validateur tient dans un job, ce qui évite de découvrir l'erreur par une issue que Renovate ouvre 6 heures plus tard :

.github/workflows/renovate-config.yml
name: renovate-config

on:
  pull_request:
    paths: ['renovate.json*', '.renovaterc*', '.github/renovate.json*']

permissions:
  contents: read

jobs:
  validate:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false
      - run: npx --yes --package renovate@latest -- renovate-config-validator

Aller plus loin

Le durcissement de la CI et les presets Renovate qui vont avec, helpers:pinGitHubActionDigests, minimumReleaseAge et l'automerge, sont détaillés dans Durcir une CI GitHub Actions.