From 021c7b56bd7ea45c8e63c26765fdfbb8b5ac5293 Mon Sep 17 00:00:00 2001 From: Christian Bush Date: Fri, 19 Jun 2026 13:30:40 -0700 Subject: [PATCH] Add Renovate to sync linkedin/iceberg 1.2.x and 1.5.x lines Self-hosted Renovate (GitHub Actions, hourly) keeps the com.linkedin.iceberg fork pinned to the newest release within each line. A regex customManager updates the source-of-truth version strings directly (iceberg_1_2_version, iceberg_1_5_version), and per-line matchCurrentVersion / allowedVersions rules give the 1.2.x and 1.5.x pins independent ceilings on the shared artifacts -- something native Dependabot's per-artifact ignore rules cannot express. Scoped via enabledManagers to only these version strings; opens one PR per line. --- .github/renovate.json | 38 ++++++++++++ .github/workflows/renovate.yml | 74 +++++++++++++++++++++++ docs/development/renovate-iceberg-sync.md | 70 +++++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 .github/renovate.json create mode 100644 .github/workflows/renovate.yml create mode 100644 docs/development/renovate-iceberg-sync.md diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 000000000..1b07f711a --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ], + "enabledManagers": [ + "custom.regex" + ], + "customManagers": [ + { + "customType": "regex", + "fileMatch": [ + "^build\\.gradle$" + ], + "matchStrings": [ + "iceberg_1_[25]_version\\s*=\\s*\"(?[^\"]+)\"" + ], + "depNameTemplate": "com.linkedin.iceberg:iceberg-core", + "datasourceTemplate": "maven" + } + ], + "packageRules": [ + { + "matchPackageNames": [ + "com.linkedin.iceberg:iceberg-core" + ], + "matchCurrentVersion": "/^1\\.2\\./", + "allowedVersions": "/^1\\.2\\./" + }, + { + "matchPackageNames": [ + "com.linkedin.iceberg:iceberg-core" + ], + "matchCurrentVersion": "/^1\\.5\\./", + "allowedVersions": "/^1\\.5\\./" + } + ] +} diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml new file mode 100644 index 000000000..4c281d981 --- /dev/null +++ b/.github/workflows/renovate.yml @@ -0,0 +1,74 @@ +# Self-hosted Renovate that constantly syncs the linkedin/iceberg fork +# (com.linkedin.iceberg) within its 1.2.x and 1.5.x lines. +# +# Behavior is defined in .github/renovate.json: +# - iceberg_1_2_version (root build.gradle) -> capped to 1.2.x +# - iceberg_1_5_version (root build.gradle) -> capped to 1.5.x +# Only the custom regex manager is enabled, so Renovate touches nothing else. +# +# ── One-time setup ─────────────────────────────────────────────────────────── +# Create a repo (or org) secret named RENOVATE_TOKEN so Renovate can open PRs +# AND so CI runs on those PRs (PRs opened with the default GITHUB_TOKEN do NOT +# trigger other workflows). Use either: +# - a classic PAT with `repo` + `workflow` scope, or +# - a fine-grained PAT / GitHub App installation token with read+write on +# Contents and Pull requests. +# If RENOVATE_TOKEN is absent the run falls back to GITHUB_TOKEN: PRs are still +# created, but CI will not auto-run on them. +name: Renovate (linkedin/iceberg sync) + +on: + schedule: + # Hourly — "constantly" sync. Renovate is idempotent: a run is a no-op when + # the pinned versions are already the newest within their line. + - cron: '0 * * * *' + workflow_dispatch: + inputs: + logLevel: + description: Renovate log level + required: false + default: info + type: choice + options: + - info + - debug + dryRun: + description: Dry run (extract & log only, open no PRs) + required: false + default: false + type: boolean + +# When a dedicated RENOVATE_TOKEN is set, Renovate uses it and these job-token +# permissions are unused. They exist so the GITHUB_TOKEN fallback can still +# create branches and PRs (CI just won't auto-run on those PRs). +permissions: + contents: write + pull-requests: write + +concurrency: + group: renovate + cancel-in-progress: false + +jobs: + renovate: + name: Renovate + runs-on: ubuntu-latest + steps: + # Set RENOVATE_DRY_RUN only when explicitly requested; leaving it unset on + # scheduled runs avoids a config-validation warning for an invalid value. + - name: Enable dry run + if: ${{ inputs.dryRun }} + run: echo "RENOVATE_DRY_RUN=full" >> "$GITHUB_ENV" + + - name: Run Renovate + # renovatebot/github-action publishes only full vX.Y.Z tags (no moving + # major tag); the github-actions Dependabot updater keeps this current. + uses: renovatebot/github-action@v46.1.15 + with: + token: ${{ secrets.RENOVATE_TOKEN || secrets.GITHUB_TOKEN }} + env: + # Only operate on this repository; do not crawl the whole org. + RENOVATE_REPOSITORIES: ${{ github.repository }} + RENOVATE_AUTODISCOVER: 'false' + # Per-repo config lives in .github/renovate.json (auto-detected). + LOG_LEVEL: ${{ inputs.logLevel || 'info' }} diff --git a/docs/development/renovate-iceberg-sync.md b/docs/development/renovate-iceberg-sync.md new file mode 100644 index 000000000..ae3739fd4 --- /dev/null +++ b/docs/development/renovate-iceberg-sync.md @@ -0,0 +1,70 @@ +# Renovate: linkedin/iceberg version sync + +OpenHouse depends on the LinkedIn Iceberg fork (`com.linkedin.iceberg`, published +to Maven Central) and deliberately pins **two minor lines at once**: + +| Source of truth | Line | Drives | +| --- | --- | --- | +| `iceberg_1_2_version` in `build.gradle` | `1.2.x` | Spark 3.1 stack, `iceberg-1.2` integrations, `datalayout` | +| `iceberg_1_5_version` in `build.gradle` | `1.5.x` | Spark 3.5 stack, `iceberg-1.5` integrations, services | + +Renovate ([`.github/renovate.json`](../../.github/renovate.json)) keeps each pin at +the newest release **within its own line** and opens a PR per line when a newer +version exists. It runs hourly via the self-hosted +[`renovate.yml`](../../.github/workflows/renovate.yml) workflow. + +## Why Renovate (and not native Dependabot) + +Native Dependabot cannot express this repo's setup: + +1. **Two minor lines of the same artifacts.** `iceberg-core`, `iceberg-common`, + `iceberg-data`, and `iceberg-bundled-guava` are each pinned at both `1.2.x` + and `1.5.x`. Dependabot's `ignore` rules are keyed per-artifact, so it would + try to converge both pins onto a single latest version, breaking one line. + Renovate's `matchCurrentVersion` evaluates each occurrence against its own + current value, so the `1.2.0.x` pin and the `1.5.2.x` pin get independent + ceilings. +2. **Cross-file `ext` indirection.** Versions are defined once in the root + `build.gradle` and read elsewhere via `rootProject.ext.…` and `buildSrc` + convention plugins. Instead of relying on a parser to follow that chain, a + Renovate `customManager` (regex) updates the source-of-truth lines directly. + +`enabledManagers: ["custom.regex"]` scopes Renovate to **only** these three +version strings — it does not touch any other dependency. GitHub Actions updates +remain handled by the existing [`dependabot.yml`](../../.github/dependabot.yml). + +## How the line caps work + +Each line is held by a `packageRule` keyed on the current version, e.g. for the +1.5 line: + +```json +{ + "matchPackageNames": ["com.linkedin.iceberg:iceberg-core"], + "matchCurrentVersion": "/^1\\.5\\./", + "allowedVersions": "/^1\\.5\\./" +} +``` + +The 4-part LinkedIn versions (`1.5.2.11`) are compared with Renovate's `maven` +versioning, and release candidates (`1.5.2.0-rc1`) are skipped as unstable. + +## One-time setup + +Create a repository (or org) secret named **`RENOVATE_TOKEN`** so Renovate can +open PRs **and** so CI runs on them — PRs opened with the default `GITHUB_TOKEN` +do not trigger other workflows. Use one of: + +- a classic PAT with `repo` + `workflow` scope, or +- a fine-grained PAT / GitHub App installation token with read+write on + **Contents** and **Pull requests**. + +Without `RENOVATE_TOKEN` the workflow falls back to `GITHUB_TOKEN`: PRs are still +created, but their CI must be re-run manually. + +## Verifying / running on demand + +- Trigger **Actions → "Renovate (linkedin/iceberg sync)" → Run workflow** with + the `Dry run` option to see what Renovate would do without opening PRs. +- Validate config changes locally: + `npx --yes --package renovate -- renovate-config-validator .github/renovate.json`