Eliminating Tech Debt: Automated Dependency Updates & Code Refactoring

1 minute read

Published:

Keeping base images and application dependencies fresh is a never-ending chore.
This post shows how to wire up Renovate for quarterly dependency updates (especially Dockerfiles) on GitLab, where OpenRewrite fits for Java code changes.


Why Automate? (Golden Images, Security, SCA Noise)

  • Golden base images drift, accumulating CVEs over time.
  • Manually bumping tags across many repos is painful and inconsistent.
  • Quarterly, curated updates reduce alert fatigue while keeping compliance intact.

Quickstart: Self-Hosted Renovate on GitLab (Quarterly Cadence)

Repo structure for a renovate-bot project:

.
├── .gitlab-ci.yml
├── renovate.json5
└── templates/
    └── renovate.gitlab-ci.yml

renovate.json5

{
  "platform": "gitlab",
  "endpoint": "https://gitlab.com/api/v4",
  "autodiscover": true,
  "extends": ["config:base"],
  "docker": { "enabled": true },
  "packageRules": [
    {
      "managers": ["dockerfile"],
      "groupName": "Base image updates",
      "schedule": ["on the first day of the month"],
      "automerge": false
    },
    {
      "matchPackageNames": ["renovate/renovate"],
      "matchUpdateTypes": ["minor", "patch"],
      "automerge": true,
      "automergeType": "branch"
    }
  ],
  "onboarding": true,
  "requireConfig": "optional"
}

Private registries? Add hostRules

"hostRules": [
  {
    "hostType": "docker",
    "matchHost": "registry.example.com",
    "username": "CI_DOCKER_USER",
    "password": "CI_DOCKER_PASS"
  }
] 

.gitlab-ci.yml

include:
  - 'templates/renovate.gitlab-ci.yml'

stages: [renovate]

variables:
  RENOVATE_CONFIG_FILE: 'renovate.json5'

renovate:
  stage: renovate
  image: renovate/renovate:latest
  script: [ "renovate" ]
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
      when: always
    - when: never

templates/renovate.gitlab-ci.yml

variables:
  GIT_DEPTH: 0

before_script:
  - echo "Starting Renovate"

renovate:
  script:
    - npx renovate

CI/CD Variables

RENOVATE_TOKEN — GitLab PAT (scopes: api, read_user, write_repository)

Optional: GITHUB_COM_TOKEN — for GitHub package lookups

Schedule It Quarterly In GitLab: CI/CD → Schedules → New schedule

Description: Quarterly Renovate Run
Cron: 0 2 1 1,4,7,10 *
Target branch: main
Timezone: match your ops window

OpenRewrite vs Renovate — Why Use Both?

AspectRenovateOpenRewrite
Primary jobBump dependency versions (Maven, npm, Docker tags, etc.)Refactor source code for API changes
OutputMRs updating version declarationsMRs with code changes
ScopeMany ecosystems (npm, pip, Maven/Gradle, Dockerfile, Helm, Terraform, etc.)Strong for Java/JVM; also YAML/XML/props
Breaking change handlingNo (build may break)Yes (recipes handle API migration)

Workflow example

  1. Renovate raises an MR to move spring-boot 2.x → 3.x.
  2. OpenRewrite applies Java refactors (Jakarta namespace, etc.).
  3. CI tests run; reviewers merge when green.