The Codeberg publish has never once succeeded — 0.2.1, 0.2.2, 0.3.0, 0.3.1
and 0.3.2 all failed, and 0.3.0 was published by hand. Neither previous fix
could have worked, because the cause isn't in this file: ref writes to
jlmakiola/agendula on Codeberg fail. A tag push returns "cannot lock
references" and POST /tags returns an empty-bodied 500, while the identical
calls succeed on jlmakiola/calendula with the same token. Creating a release
mints a tag, so it inherited the same failure.
Attaching a release to a tag that is ALREADY there needs no ref write and
returns 201. So split the responsibility the way it should have been: the
push mirror owns delivering the tag, this step only attaches to it. Poll for
the tag, then POST with no target_commitish so the API attaches rather than
resolves a commit and mints one. If the tag never lands, fail with a pointer
at the mirror instead of trying to create it.
Drop continue-on-error. It reported green across five releases that never
published, which is how 0.3.1's crash fix reached F-Droid while the Codeberg
and Obtainium users who hit the crash got nothing.
Tested against the live API before committing (unlike its predecessors):
tag-present attaches 201, tag-absent exits 1 with the diagnostic. Note this
does not by itself restore publishing — the mirror cannot write the v0.3.2
tag either, so Codeberg must repair the repo's ref store first.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Revert 4aa65ed's approach. It read the Forgejo 500 as being caused by
target_commitish, and pushed the tag to Codeberg first so the release could
attach to an existing tag without one. That inverted the actual failure:
Forgejo 500s on POST /releases precisely WHEN the tag already exists, so
pre-pushing it guarantees the error it was meant to avoid.
The second half then can't recover — a bare tag is not a release, so
GET /releases/tags 404s and the upsert has no id, which is the
"Could not resolve Codeberg release id" that ended the 0.3.1 run.
0.3.0 published fine because it POSTed while the tag was still unsynced and
let the API mint tag + release together. Do that deliberately instead of by
luck: if no release owns the tag, delete the mirrored tag, then POST with
target_commitish. Branches mirror reliably (main was already at the release
commit when 0.3.1 failed), so the commit is present and only the raced-in
tag was in the way. Deleting it is safe exactly because no release owns it.
An existing release still takes the PATCH path and skips the delete, so
re-runs never disturb something already published.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
The push mirror (sync_on_commit) syncs the tag to Codeberg before the
publish step runs, and Forgejo returns HTTP 500 on POST /releases with a
target_commitish when the tag already exists — so the release was never
created (v0.2.1 shipped to Gitea/F-Droid but not Codeberg). Only pass
target_commitish when the tag isn't mirrored yet; otherwise attach the
release to the existing tag.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Port Calendula's current CI/release pipeline:
- ci.yaml: pull_request-triggered, change-scope classification
(docs/metadata-only PRs skip the Android build but still report a
green CI), and a reproducible-release invariant guard.
- release.yaml: the committed versionName is the source of truth — a
bump reaching main triggers the release, which builds, signs,
publishes to the F-Droid repo, then mints the vX.Y.Z tag + Gitea
release and mirrors it to Codeberg with the signed APK + SHA-256
checksum. workflow_dispatch runs the re-sign-only recovery path.
- Gitea releases are flagged as pre-releases while MAJOR is 0.
- build.gradle.kts: reproducible-release invariants (vcsInfo,
dependenciesInfo) + a releaseTest variant for the on-device gate.
- fastlane/ becomes the single source of truth for store metadata;
the localized F-Droid layout is generated from it at release time.
- Port scripts/, .gitea/ISSUE_TEMPLATE/, and rewrite docs/RELEASING.md
for the versionName-in-main model; fix stale references elsewhere.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds crash reporting to Agendula by drawing the kit's new core-crash module
(first Android-library module in floret-kit), and finishes the core-time wiring
that a Phase 0 staging slip left uncommitted on main.
core-crash (NEW capability — Agendula had none):
- CrashReporter.install() in AgendulaApp captures uncaught exceptions on-device
(allowlist-only report, chains to the platform handler, uploads nothing).
- MainActivity routes to a standalone CrashReportActivity on a startup crash-loop,
and surfaces a single captured crash as a dialog on next launch; markHealthy on
resume. App label + issue-tracker URL flow in via CrashConfig.
- Thin app-side CrashReportActivity uses AgendulaTheme; the reusable machinery
(reporter, dialog, submit, config) lives in the kit. Submodule re-pinned to the
core-crash kit commit.
Completes Phase 0 (was only partially committed in ec7b696):
- Repoint DayWindow + Instant formatting imports to de.jeanlucmakiola.floret.time
(the app copies were deleted in ec7b696 but the imports/includeBuild/dependency
were never staged, leaving main non-building).
- settings.gradle.kts includeBuild("floret-kit"); app depends on core-time.
Also fixes the CI checkout YAML: the submodules block was mis-indented under
'uses:' (invalid step mapping) — dedented to a proper sibling.
Clean composite build + unit tests + lintDebug + debug assemble green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Floret is promoted to the family / design-language (shared-kit) name; the
tasks app itself becomes Agendula (de.jeanlucmakiola.agendula) — agenda
('things to be done') + Calendula's -ula, a twin of the Calendula name.
Renames the package, namespace, applicationId, rootProject.name, app_name,
FloretApp/FloretNavHost/FloretTransitions classes, theme, F-Droid metadata
dir, CI artifact name, and docs. The botanical word 'florets' is preserved in
the name-origin prose, which is rewritten to Agendula's etymology. Clean
build + unit tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sibling to Calendula. Pure front-end posture; TaskContract data layer,
task screens and reminder engine to follow (see docs/PLAN.md).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>