mirror of
https://github.com/spantaleev/matrix-docker-ansible-deploy.git
synced 2026-08-29 12:03:14 +00:00
Automerge patch bumps of components whose role has a Molecule scenario
A component bump touches that role's defaults/main.yml, which is on the Molecule workflow's path filter, so the change-detection job runs that role's scenario. The bump therefore only merges once the new version has actually been started on the configuration the role renders. That is a real gate, and a stronger one than a human reading a version number in a diff. Patch only. A minor carries behaviour changes that no static rule can judge - the MASH fleet tried a minor-automerge preset across 21 stateless roles and reverted all of them, because reading a given release's notes is what decides it, and that is a job for a human or an agent rather than a config file. Branch push rather than a PR, as with the other automerge rules here. The list has to stay in step with the roles that actually have a scenario, so bin/check-molecule-automerge-list.py enforces it from prek. The direction that matters is a role keeping automerge after losing its scenario: bumps would then merge with nothing exercising them. It reports the harmless direction too, since a role gaining a scenario without being listed is usually an oversight. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SEH3vxYSQ5SV4N5z61eyGT
This commit is contained in:
co-authored by
Claude Opus 5
parent
8e53dbf940
commit
2d258cf0e0
@@ -79,6 +79,24 @@
|
||||
],
|
||||
"automerge": true,
|
||||
"automergeType": "branch"
|
||||
},
|
||||
{
|
||||
"description": "Automerge patch bumps of components whose role has a Molecule scenario (via branch push - no PR). A bump touches that role's defaults/main.yml, which makes the Molecule workflow run that role's scenario, so the update only merges once the component has been started on the configuration the role renders. Patch only: a minor carries behaviour changes no static rule can judge, and reading the release notes to decide is a job for a human or an agent. Keep this list in step with the roles that have a scenario - bin/check-molecule-automerge-list.py enforces that.",
|
||||
"matchFileNames": [
|
||||
"roles/custom/matrix-alertmanager-receiver/defaults/main.yml",
|
||||
"roles/custom/matrix-bot-baibot/defaults/main.yml",
|
||||
"roles/custom/matrix-bot-matrix-reminder-bot/defaults/main.yml",
|
||||
"roles/custom/matrix-bridge-heisenbridge/defaults/main.yml",
|
||||
"roles/custom/matrix-bridge-hookshot/defaults/main.yml",
|
||||
"roles/custom/matrix-bridge-mautrix-discord/defaults/main.yml",
|
||||
"roles/custom/matrix-bridge-mautrix-meta-messenger/defaults/main.yml",
|
||||
"roles/custom/matrix-bridge-mautrix-whatsapp/defaults/main.yml"
|
||||
],
|
||||
"matchUpdateTypes": [
|
||||
"patch"
|
||||
],
|
||||
"automerge": true,
|
||||
"automergeType": "branch"
|
||||
}
|
||||
],
|
||||
"pre-commit": {
|
||||
|
||||
@@ -38,3 +38,9 @@ repos:
|
||||
language: script
|
||||
files: '(examples/vars\.yml|roles/custom/matrix_playbook_migration/defaults/main\.yml)'
|
||||
pass_filenames: false
|
||||
- id: check-molecule-automerge-list
|
||||
name: Check the Molecule automerge list matches the roles that have a scenario
|
||||
entry: bin/check-molecule-automerge-list.py
|
||||
language: script
|
||||
files: '(\.github/renovate\.json|roles/custom/[^/]+/molecule/default/molecule\.yml)'
|
||||
pass_filenames: false
|
||||
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Keeps the Molecule patch-automerge rule in step with the roles that have a scenario.
|
||||
|
||||
.github/renovate.json automerges patch bumps for roles listed by file name, on the grounds that
|
||||
the bump runs that role's Molecule scenario before merging. That reasoning only holds while the
|
||||
role actually has one.
|
||||
|
||||
The dangerous direction is a role keeping automerge after losing its scenario: bumps would then
|
||||
merge with nothing exercising them. The harmless direction - a role gaining a scenario without
|
||||
being added - only means a missed opportunity, but it is reported too, since it is usually an
|
||||
oversight rather than a decision.
|
||||
"""
|
||||
|
||||
import json
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
REPO = pathlib.Path(__file__).resolve().parent.parent
|
||||
RENOVATE = REPO / ".github" / "renovate.json"
|
||||
MARKER = "bin/check-molecule-automerge-list.py"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
with_scenario = {
|
||||
p.parts[-4] for p in (REPO / "roles" / "custom").glob("*/molecule/default/molecule.yml")
|
||||
}
|
||||
|
||||
config = json.loads(RENOVATE.read_text())
|
||||
rules = [r for r in config.get("packageRules", []) if MARKER in r.get("description", "")]
|
||||
|
||||
if len(rules) != 1:
|
||||
print(f"Expected exactly one rule mentioning {MARKER}, found {len(rules)}.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
listed = set()
|
||||
for name in rules[0].get("matchFileNames", []):
|
||||
parts = pathlib.PurePosixPath(name).parts
|
||||
if parts[:2] == ("roles", "custom") and parts[3:] == ("defaults", "main.yml"):
|
||||
listed.add(parts[2])
|
||||
else:
|
||||
print(f"Unexpected entry in the automerge rule: {name}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
automerged_without_scenario = sorted(listed - with_scenario)
|
||||
scenario_without_automerge = sorted(with_scenario - listed)
|
||||
|
||||
if automerged_without_scenario:
|
||||
print(
|
||||
"These roles automerge patch bumps but have no Molecule scenario, so nothing would\n"
|
||||
"exercise the bump before it merges. Remove them from the rule in\n"
|
||||
".github/renovate.json, or give them a scenario:",
|
||||
file=sys.stderr,
|
||||
)
|
||||
for role in automerged_without_scenario:
|
||||
print(f" {role}", file=sys.stderr)
|
||||
|
||||
if scenario_without_automerge:
|
||||
print(
|
||||
"These roles have a Molecule scenario but are not in the automerge rule in\n"
|
||||
".github/renovate.json, so their patch bumps still need a button press:",
|
||||
file=sys.stderr,
|
||||
)
|
||||
for role in scenario_without_automerge:
|
||||
print(f" {role}", file=sys.stderr)
|
||||
|
||||
return 1 if (automerged_without_scenario or scenario_without_automerge) else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,3 @@
|
||||
SPDX-FileCopyrightText: 2026 Slavi Pantaleev
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
Reference in New Issue
Block a user