Skip to content

ekino/Drunovate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Drunovate

Self-hosted Renovate for Drupal — with drush updatedb and config:export baked into every MR.

License: MIT Docker Image Renovate


The problem

Renovate handles composer.json and composer.lock updates out of the box. Drupal does not care.

When a contrib module is updated, several side effects must be committed alongside the lockfile:

  • Schema updateshook_update_N and hook_post_update_NAME implementations modify the active configuration and sometimes the database schema. They must be run via drush updatedb and their output captured.
  • Configuration drift — module updates frequently ship new or altered config entities. Without a drush config:export after the update, config/sync/ diverges from the active config. The next deployment will either fail or silently override changes.
  • Scaffold filesdrupal/core-composer-scaffold may regenerate web/sites/default/default.settings.php, drush.yml, or other managed files. These changes need to be committed as well.

Standard Renovate produces a MR with a correct lockfile and nothing else. Deploying it to a Drupal site without the accompanying config export is a reliability hazard.

Drunovate closes this gap.


How it works

Drunovate is a GitLab CI orchestrator built around a custom Docker image and a set of Renovate presets. It runs as a scheduled pipeline and produces MRs that are complete and deployment-ready.

  Drunovate/renovate-drupal
  ├── docker/Dockerfile      ──►  ghcr.io/ekino/drunovate-runner:latest
  ├── scripts/*.sh                (PHP 8.4 + Composer + Drush + Renovate)
  ├── renovate/presets/      ──►  extended by each target project's renovate.json
  └── .gitlab-ci.yml         ──►  one scheduled job per target Drupal project
                                           │
                          ┌────────────────┼────────────────┐
                          ▼                ▼                ▼
                   project-a          project-b        project-c
                          │
                          │  for each updated package, Renovate runs
                          │  postUpgradeTasks inside a disposable container:
                          │
                          ▼
              ┌───────────────────────────────┐
              │  1. drush site:install         │
              │       --existing-config        │
              │  2. drush updatedb --yes       │
              │  3. drush config:export --yes  │
              │  4. capture scaffold changes   │
              └──────────────┬────────────────┘
                             │
                             ▼
              MR opened on the target project
              ├── composer.json / composer.lock
              ├── config/sync/*.yml
              └── web/sites/default/* (if scaffold changed)

Each MR produced by Drunovate contains:

File(s) Why
composer.json, composer.lock Standard Renovate output
config/sync/*.yml Config export after drush updatedb
web/sites/default/* Scaffold changes, if any

Requirements

Dependency Version Notes
GitLab 16+ GitLab.com or self-managed
GitLab CI runners Docker executor required
PHP 8.4 Runtime inside the Docker image
Composer 2.x Bundled in the image
Drush 13 Via Drush launcher; resolved from each project's vendor
Renovate 37 Self-hosted, bundled in the image
SQLite 3.x Disposable database for postUpgradeTasks

Drunovate does not require a running database server or a web server. The Drupal bootstrap for drush updatedb runs entirely on SQLite in an ephemeral CI container.


Quickstart

1. Fork or clone this repository

git clone https://github.com/ekino/Drunovate.git
cd Drunovate

Alternatively, use the pre-built Docker image directly without cloning:

ghcr.io/ekino/drunovate-runner:latest

2. Add renovate.json to your Drupal project root

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "github>ekino/Drunovate//renovate/base-config"
  ]
}

That is the only change required in the target project.

3. Create a Project Access Token on the target project

In your Drupal project: Settings → Access Tokens

Field Value
Name renovate-bot
Role Developer
Scopes api, read_repository, write_repository

Store the generated token as a masked + protected CI variable in Drunovate:

RENOVATE_TOKEN_YOUR_PROJECT = glpat-xxxxxxxxxxxx

4. Add a job in .gitlab-ci.yml

renovate-your-project:
  extends: .renovate-job
  script:
    - renovate your-group/your-drupal-project
  variables:
    RENOVATE_TOKEN: "${RENOVATE_TOKEN_YOUR_PROJECT}"
    DRUPAL_ROOT: "web"
    CONFIG_SYNC_DIR: "../config/sync"

5. Run manually to verify

Trigger the pipeline from CI/CD → Pipelines → Run pipeline.

Check that:

  • Renovate can read the target repository
  • A Dependency Dashboard issue is created in the target project
  • If updates exist, a MR is opened with composer.lock and config/sync/ changes if needed.

Token architecture

Drunovate uses GitLab Project Access Tokens (not a single shared bot PAT) so that each target project retains full control over its own access grants.

Token Created in Stored in Used for
PAT — service account GitLab service account Drunovate CI vars Read Drunovate presets
PROJECT_TOKEN_A projet-drupal-A Drunovate CI vars Read/write project A
PROJECT_TOKEN_B projet-drupal-B Drunovate CI vars Read/write project B
COMPOSER_AUTH Packagist Drunovate CI vars Private package access
CI_JOB_TOKEN GitLab (automatic) Pull/push Docker image

Full documentation is in progress. See the README for current setup instructions.


Renovate presets

The three presets in renovate/presets/ can be used independently or extended:

  • drupal-core.json — groups all drupal/core-* packages into a single MR, enforces a stabilityDays window, adds drupal-core label
  • drupal-modules.json — per-module MRs, conservative stabilityDays, adds changelog body notes with Drupal.org SA links
  • automerge.json — explicitly disables automerge for all drupal/* packages regardless of semver range

Building the Docker image locally

docker build -f docker/Dockerfile -t drunovate-runner:local .

# Verify installed toolchain
docker run --rm drunovate-runner:local php --version
docker run --rm drunovate-runner:local composer --version
docker run --rm drunovate-runner:local renovate --version
docker run --rm drunovate-runner:local drush --version

The CI pipeline automatically rebuilds and pushes ghcr.io/ekino/drunovate-runner:latest whenever docker/Dockerfile or scripts/** are modified.


Contributing

Contributions are welcome. Please read CONTRIBUTING.md before opening a pull request.

Areas where contributions are most valuable:

  • Support for PostgreSQL or MySQL as an alternative to the SQLite disposable database
  • Support for Drupal multisite configurations
  • Additional presets for specific distributions (Commerce, GovCMS, Lightning)
  • GitHub Actions equivalent of the CI templates

License

MIT — see LICENSE.


Built and maintained by ekino. Battle-tested on a fleet of Drupal projects in production.

Roadmap

The following components are in progress and will be added in upcoming commits:

  • ci/ — GitLab CI job templates (generic .renovate-job, scheduled pipeline)
  • docs/ — getting started guide, token setup, architecture walkthrough

About

Drupal integration for Renovate

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors