3 Commits

Author SHA1 Message Date
cfa25b9730 release: cut 0.3.1 — fix the launch crash in minified builds (#1)
All checks were successful
Release — F-Droid repo + Gitea/Codeberg release / detect (push) Successful in 7s
Release — F-Droid repo + Gitea/Codeberg release / release (push) Successful in 11m31s
2026-07-20 18:36:47 +02:00
9d7fc64b0b release: cut 0.3.1 — fix the launch crash in minified builds
R8 kept androidx.work.impl.WorkDatabase_Impl but pruned its no-arg
constructor: nothing calls it directly, Room only reaches it reflectively.
Room then threw InstantiationException, surfacing as "Failed to create an
instance of androidx.work.impl.WorkDatabase". WorkManager builds that
database from a startup ContentProvider, so 0.3.0 died before any of our
code ran — every install, every launch.

We don't depend on WorkManager directly; it arrives via Glance. AGP 9's
stricter R8 is what tipped this over, which is why 0.3.0 was the first
release to hit it.

Keep the Room no-arg constructor, and the ListenableWorker constructor
alongside it — same pruning hazard on the path WorkManager uses to
instantiate workers by name, which would have bitten once a Glance widget
update actually ran.

Reproduced the reporter's stack trace frame-for-frame on a releaseTest
build, then confirmed it launches clean afterwards. Fixes #1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 18:35:41 +02:00
4aa65edb45 ci(release): push tag to Codeberg before creating the release
All checks were successful
Release — F-Droid repo + Gitea/Codeberg release / detect (push) Successful in 6s
Release — F-Droid repo + Gitea/Codeberg release / release (push) Has been skipped
The first fix didn't help: the pipeline creates the tag via the Gitea
API, and the push mirror (sync_on_commit only fires on real git pushes)
doesn't propagate an API-created tag promptly. So the Codeberg release
POST still raced the mirror and 500'd on a commit/tag Codeberg hadn't
received (0.2.1 and 0.3.0 both shipped everywhere but Codeberg).

Push the tag straight to Codeberg from the runner (guaranteed present),
then attach the release to that existing tag with no target_commitish —
which is what Forgejo 500s on. Race-free.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 22:48:29 +02:00
5 changed files with 43 additions and 16 deletions

View File

@@ -399,27 +399,27 @@ jobs:
sed -i -e '/./,$!d' release-notes.md sed -i -e '/./,$!d' release-notes.md
fi fi
[ -s release-notes.md ] || echo "_See CHANGELOG.md for ${VERSION}._" > release-notes.md [ -s release-notes.md ] || echo "_See CHANGELOG.md for ${VERSION}._" > release-notes.md
# The push mirror (sync_on_commit) usually syncs the tag to Codeberg # The pipeline creates the tag via the Gitea API, which the push mirror
# before this step runs. Forgejo 500s on POST /releases with a # (sync_on_commit only fires on real git pushes) doesn't propagate
# target_commitish when the tag already exists — so only pass # promptly — so a release POST that carries a target_commitish can
# target_commitish when we actually need the API to create the tag. # outrun the mirror and 500 on a commit/tag Codeberg hasn't received.
TAG_CODE=$(curl -s -o /dev/null -w '%{http_code}' \ # Push the tag straight to Codeberg so it's guaranteed present, then
-H "Authorization: token $TOKEN" "$API/git/refs/tags/$TAG") # attach the release to that existing tag with NO target_commitish
python3 - "$TAG" "$SHA" "$PRERELEASE" "$TAG_CODE" <<'PY' > cb-payload.json # (which is what triggered the 500).
git tag -f "$TAG" "$SHA"
git push -f "https://jlmakiola:${TOKEN}@codeberg.org/jlmakiola/agendula.git" \
"refs/tags/$TAG"
python3 - "$TAG" "$PRERELEASE" <<'PY' > cb-payload.json
import json, sys import json, sys
tag, sha, pre, tag_code = sys.argv[1:5] tag, pre = sys.argv[1:3]
payload = { print(json.dumps({
"tag_name": tag, "tag_name": tag,
"name": tag, "name": tag,
"body": open("release-notes.md").read(), "body": open("release-notes.md").read(),
"draft": False, "draft": False,
# Pre-1.0 releases are flagged as pre-releases (see detect job). # Pre-1.0 releases are flagged as pre-releases (see detect job).
"prerelease": pre == "true", "prerelease": pre == "true",
} }))
# Only create the tag via the release when it isn't mirrored yet.
if tag_code != "200":
payload["target_commitish"] = sha
print(json.dumps(payload))
PY PY
# Upsert (re-run safe). # Upsert (re-run safe).
ID=$(curl -s -H "Authorization: token $TOKEN" "$API/releases/tags/$TAG" | jq -r '.id // empty') ID=$(curl -s -H "Authorization: token $TOKEN" "$API/releases/tags/$TAG" | jq -r '.id // empty')

View File

@@ -7,6 +7,13 @@ All notable changes to this project are documented here. The format follows
## [Unreleased] ## [Unreleased]
## [0.3.1] - 2026-07-20
### Fixed
- Agendula no longer crashes on launch. Every 0.3.0 install was affected: the
release build stripped a constructor that the background-work scheduler needs
to open its database, and that happens before the app draws anything.
## [0.3.0] - 2026-07-19 ## [0.3.0] - 2026-07-19
### Added ### Added

View File

@@ -29,8 +29,8 @@ android {
// release itself (versionCode is pinned to MAJOR*10000 + MINOR*100 + // release itself (versionCode is pinned to MAJOR*10000 + MINOR*100 +
// PATCH from versionName, e.g. 0.2.0 -> 200). The Gitea release is marked // PATCH from versionName, e.g. 0.2.0 -> 200). The Gitea release is marked
// as a pre-release while MAJOR is 0. See docs/RELEASING.md. // as a pre-release while MAJOR is 0. See docs/RELEASING.md.
versionCode = 300 versionCode = 301
versionName = "0.3.0" versionName = "0.3.1"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }

View File

@@ -2,5 +2,20 @@
-keep class dagger.hilt.** { *; } -keep class dagger.hilt.** { *; }
-keep @dagger.hilt.android.HiltAndroidApp class * -keep @dagger.hilt.android.HiltAndroidApp class *
# Room instantiates its generated <Database>_Impl reflectively through a no-arg
# constructor. R8 under AGP 9 keeps the class but prunes that constructor, since
# nothing calls it directly Room then throws InstantiationException, reported
# as "Failed to create an instance of ...". We pull Room in transitively via
# Glance -> WorkManager, whose WorkDatabase is built by WorkManagerInitializer
# at startup, so the app died on launch in every minified build (issue #1).
-keep class * extends androidx.room.RoomDatabase { <init>(); }
# WorkManager likewise looks its workers up by name and calls this constructor
# reflectively same pruning, but it only bites once a worker actually runs
# (Glance's widget updates), so keep it explicitly rather than wait for it.
-keep class * extends androidx.work.ListenableWorker {
<init>(android.content.Context, androidx.work.WorkerParameters);
}
# Compose Compiler may keep its own; defaults are fine # Compose Compiler may keep its own; defaults are fine
-dontwarn org.jetbrains.annotations.** -dontwarn org.jetbrains.annotations.**

View File

@@ -0,0 +1,5 @@
### Fixed
- Agendula no longer crashes on launch. Every 0.3.0 install was affected: the
release build stripped a constructor that the background-work scheduler needs
to open its database, and that happens before the app draws anything.