Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 60 additions & 18 deletions renovate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,19 @@ The org default carries:
- **JS lint stack grouping** — `eslint`, `prettier`, `jshint`, plus
glob-matched `@eslint/*`, `eslint-config-*`, `eslint-plugin-*`.
One coordinated PR instead of one-per-plugin.
- **Weekly Monday batch** for minor + major. Patches don't wait.
- **Patch automerge** on green CI. See **Patch automerge contract**
below.
- **Soak windows** (`minimumReleaseAge`) before automerge: patch/digest
2 days, minor 5 days, major 7 days. The soak catches a yanked or
hotfixed release before it lands unattended.
- **PRs are created immediately** (`internalChecksFilter: "none"`), even
while soaking — so every update is visible and a human can manually
merge early (e.g. a hotfix). The soak only gates **automerge**: a
pending `renovate/stability-days` check holds the auto-merge until the
window passes, but it isn't a required branch-protection check, so
manual merge still works.
- **Automerge** on green CI after soak for **patch + digest** and
**minor**. **Majors never automerge** — always human-reviewed (see the
**Major-bump SOP** below). Minor automerge raises the CI bar; see the
**Automerge contract** below.

Things that belong **per-repo**, not in the default:

Expand Down Expand Up @@ -92,37 +102,69 @@ Three ways to unlock auto-merge on the private repos:
minor friction. The patch automerge rule remains in the org default;
it just no-ops on the private repos.

## Patch + digest automerge contract
## Automerge contract (patch + digest + minor)

The org default automerges patch-level **and digest-pin** updates
once CI passes. (Digest updates refresh the upstream image's content
hash without changing its tag — same code, freshly-rebuilt base
layer for CVEs — so they're inherently no-op-risk.) **A repo
extending this default must satisfy these conditions** or automerge
will silently land unreviewed code:
The org default automerges **patch**, **digest-pin**, and **minor**
updates once CI passes **and** the release has soaked
(`minimumReleaseAge`: patch/digest 2 days, minor 5 days) — long enough
for the ecosystem to surface a yanked or hotfixed release before it
lands unattended, short enough not to delay routine fixes. (Digest
updates refresh the upstream image's content hash without changing its
tag — same code, freshly-rebuilt base layer for CVEs — so they're
inherently no-op-risk.) **A repo extending this default must satisfy
these conditions** or automerge will silently land unreviewed code:

1. **PR-triggered CI must exist.** A workflow on `pull_request` (not
just `workflow_dispatch` or `push`). Renovate's PRs run it; a
missing workflow means no gate — Renovate would merge with no
signal. Every existing jellyrock repo satisfies this today.
2. **CI must exercise the dependency surface.** "Build + lint" is
the baseline. "Build + lint + unit tests" is better. The
stronger the CI, the higher the confidence in patches. The
contract is intentionally fuzzy — repos with high test coverage
inherit higher safety than repos with just a build check.
3. **If a repo can't meet (1) or (2), override per-repo:**
2. **CI must exercise the dependency surface.** "Build + lint" is the
floor for patch/digest. **Minor automerge raises the bar:** a
breaking minor can pass a build but fail at runtime, so a repo that
automerges minors should have CI that exercises runtime behavior
(unit/integration/smoke tests), not just build+lint. The stronger
the CI, the higher the confidence.
3. **If a repo can't meet the bar, override per-repo.** Disable minor
automerge (keep patch) when CI is build+lint only:
```jsonc
{
"extends": ["github>jellyrock/.github//renovate/default"],
"packageRules": [
{
"description": "This repo doesn't have CI strong enough for blind patch automerge",
"matchUpdateTypes": ["patch", "digest"],
"description": "CI is build+lint only — minors need human review",
"matchUpdateTypes": ["minor"],
"automerge": false
}
]
}
```
Or disable all automerge (patch + minor) for a repo with no real CI:
```jsonc
{
"matchUpdateTypes": ["patch", "digest", "minor"],
"automerge": false
}
```

## Major-bump SOP

Majors never automerge. When a major PR appears, before merging:

1. **Read the upstream changelog / migration guide** for the version
range (the PR body links the release notes).
2. **Pull the branch and run the repo's full gate locally** — build +
lint + the complete test suite (on JellyRock that includes the
on-device BS unit tests and the RTA functional pass, which CI's
PR-triggered run may not cover end-to-end).
3. **Grep for breaking-API usage** the changelog flags; migrate code in
the same PR.
4. **For runtime deps bundled into the app** (e.g. the Roku BS libs),
verify on a real device, not just a green build.
5. Merge only when the gate is green and any required migration is in
the PR.

Repos may wrap this in a local script or skill so the steps run the same
way every time, rather than doing the checklist by hand.

## Adding a new repo

Expand Down
19 changes: 14 additions & 5 deletions renovate/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"ignorePaths": ["**/node_modules/**"],
"timezone": "America/New_York",
"separateMinorPatch": true,
"internalChecksFilter": "none",
"packageRules": [
{
"description": "Group GitHub Actions updates together; pin to SHA digests so version tags can't be silently re-pointed by upstream.",
Expand Down Expand Up @@ -38,14 +39,22 @@
"addLabels": ["javascript"]
},
{
"description": "Minor + major updates land on a weekly Monday review batch. Reduces PR noise; patches still fire immediately so security fixes aren't delayed.",
"matchUpdateTypes": ["minor", "major"],
"schedule": ["before 6am on monday"]
"description": "Minor updates automerge once CI is green AND the release has soaked 5 days. The PR is created immediately (internalChecksFilter:none) so it's visible and a human can manually merge early if needed (e.g. a hotfix); the renovate/stability-days pending check holds AUTOMERGE until the soak passes. Minor automerge raises the CI bar — the repo's PR-triggered CI must exercise runtime behavior, not just build+lint (a breaking minor can pass a build but fail at runtime). A repo whose CI can't meet that should override this rule to automerge:false. See renovate/README.md.",
"matchUpdateTypes": ["minor"],
"minimumReleaseAge": "5 days",
"automerge": true
},
{
"description": "Major updates soak 7 days and NEVER automerge — a major is always human-reviewed regardless of CI. The PR is created immediately (internalChecksFilter:none) so it's visible during the soak; the soak gives the ecosystem time to surface a yanked or hotfixed release before a human picks it up. Follow the major-bump SOP (renovate/README.md) before merging.",
"matchUpdateTypes": ["major"],
"minimumReleaseAge": "7 days",
"automerge": false
},
{
"description": "Patch + digest updates automerge once CI is green. Digest pins refresh the base layer for CVEs without changing the underlying version — same code, just a freshly-rebuilt upstream image — so they're inherently low-risk and don't need human review. Contract: every repo that extends this default must have PR-triggered CI that exercises the dependency surface (lint+build at minimum). See renovate/README.md.",
"description": "Patch + digest updates automerge once CI is green AND the release has soaked 2 days (minimumReleaseAge) — long enough to catch a yanked or hotfixed patch before it lands unattended, short enough not to delay routine fixes. Digest pins refresh the base layer for CVEs without changing the underlying version — same code, just a freshly-rebuilt upstream image — so they're inherently low-risk and don't need human review. Contract: every repo that extends this default must have PR-triggered CI that exercises the dependency surface (lint+build at minimum). See renovate/README.md.",
"matchUpdateTypes": ["patch", "digest"],
"minimumReleaseAge": "2 days",
"automerge": true
}
]
}
}
Loading