Release — F-Droid repo + Gitea/Codeberg release + Play / detect (push) Successful in 8s
Renovate / renovate (push) Successful in 1m11s
Release — F-Droid repo + Gitea/Codeberg release + Play / release (push) Successful in 18m4s
Release — F-Droid repo + Gitea/Codeberg release + Play / play (push) Failing after 1m33s
Beta — Codeberg pre-release / detect (push) Successful in 5s
Beta — Codeberg pre-release / beta (push) Skipped
Stable 1.2.0, after 1.2.0-beta.1 and beta.2. - Version bumped to 1.2.0 (1020099); the CHANGELOG entries moved from Unreleased to 1.2.0. - What's New for every shipped locale, now including cs-CZ. - Full store listing (title, short and full description) for every locale; new for cs-CZ, ar and fr-FR. Play only gets these through the `listing` lane. - `main` is merged in with the branch side kept. #81 and the Weblate updates already came in through the #88 squash, and the only lines unique to `main` were string keys that #88 removed. The #75 fix landed after beta.2, so no reporter has tested it yet. Closes #72, closes #78, closes #75, closes #92 Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de> Reviewed-on: https://codeberg.org/jlmakiola/agendula/pulls/103
56 lines
2.1 KiB
Python
Executable File
56 lines
2.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Fail when R8 keeps one of our classes by name but strips its no-arg constructor.
|
|
|
|
A keep rule that names a class but no members keeps the class and lets R8 drop
|
|
the constructor nothing calls directly. Anything that then instantiates it by
|
|
reflection (Room, Glance's ActionCallback, WorkManager) fails at runtime only,
|
|
in release builds only (#1, #75). R8 reports both halves: seeds.txt lists what
|
|
keep rules pinned, usage.txt what it removed.
|
|
|
|
scripts/check_r8_keeps.py [mapping dir] default: fullReleaseTest's
|
|
"""
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
DEFAULT_DIR = ROOT / "app/build/outputs/mapping/fullReleaseTest"
|
|
PACKAGES = ("de.jeanlucmakiola.",)
|
|
|
|
|
|
def kept_classes(seeds: Path) -> set[str]:
|
|
return {
|
|
line.strip()
|
|
for line in seeds.read_text().splitlines()
|
|
if line.startswith(PACKAGES) and ":" not in line
|
|
}
|
|
|
|
|
|
def classes_without_default_ctor(usage: Path) -> set[str]:
|
|
stripped, current = set(), None
|
|
for line in usage.read_text().splitlines():
|
|
if not line.startswith(" "):
|
|
current = line.rstrip(":") if line.endswith(":") else None
|
|
elif current and line.strip().endswith(" <init>()"):
|
|
stripped.add(current)
|
|
return stripped
|
|
|
|
|
|
def main() -> int:
|
|
mapping = Path(sys.argv[1]) if len(sys.argv) > 1 else DEFAULT_DIR
|
|
seeds, usage = mapping / "seeds.txt", mapping / "usage.txt"
|
|
if not seeds.exists() or not usage.exists():
|
|
print(f"ERROR: no seeds.txt/usage.txt in {mapping}; build a minified variant first.", file=sys.stderr)
|
|
return 1
|
|
broken = sorted(kept_classes(seeds) & classes_without_default_ctor(usage))
|
|
for name in broken:
|
|
print(f"ERROR: {name} is kept by a rule but R8 removed its no-arg constructor.", file=sys.stderr)
|
|
if broken:
|
|
print("Keep the constructor too: -keep class ... { <init>(); }", file=sys.stderr)
|
|
return 1
|
|
print(f"OK: every kept class under {', '.join(PACKAGES)} still has its no-arg constructor.")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|