Commit Graph

16 Commits

Author SHA1 Message Date
Jean-Luc Makiola
217d5d7afd Move the canonical forge to Codeberg, and add Renovate + Weblate (#2)
Some checks failed
Release — F-Droid repo + Gitea/Codeberg release / release (push) Has been skipped
Release — F-Droid repo + Gitea/Codeberg release / detect (push) Successful in 7s
Renovate / renovate (push) Failing after 43s
Makes Codeberg canonical for git, issues, PRs, tags and releases. The self-hosted Gitea instance stays build infrastructure: signing key, F-Droid publishing, release pipeline. Ports the setup Calendula already runs on, adapted where Agendula genuinely differs.

**This PR is its own test.** It is the first PR opened on Codeberg, so a green `CI` check proves the new runner works *and* that the submodule resolves from its new home.

### 1 · Workflows split by directory

Forgejo's lookup is first-match-wins across `.forgejo/` → `.gitea/` → `.github/`, and Gitea cannot see `.forgejo/` at all. So each forge sees exactly one set, with no duplicated files and no expression to keep in sync:

| Directory | Runs on | Contains | Secrets |
| --- | --- | --- | --- |
| `.forgejo/workflows/` | Codeberg | `ci.yaml`, `translations.yaml` | **none** |
| `.gitea/workflows/` | Gitea | `release.yaml`, `renovate.yml` | all of them |

The line is drawn at **secrets, not CI-vs-release** — that is what makes fork PRs safe. Renovate deliberately does *not* move despite opening PRs here; it keeps running where its token already lives and merely talks to Codeberg's API.

CI also gains three fixes: an explicit `SKIP_RE` skip-list that names the build-relevant files in the log, base-ref normalisation, and a fully-qualified `android-actions/setup-android` — Codeberg resolves bare `uses:` refs against `data.forgejo.org`, which does not carry that action.

### 2 · Three release-pipeline safety changes

- `detect` and the Renovate job get an explicit `repository_owner` guard. The directory split only holds while `.forgejo/` is non-empty; empty it and Codeberg would fall back to `.gitea/` and start running these on the contributor-facing runner, without secrets.
- `detect` now reads tags from **Codeberg**, not from the Gitea instance it runs on. Push mirroring is `git push --mirror`, so a tag minted on Gitea is deleted by the next sync until the Codeberg tag push propagates back — asking Gitea inside that window reports "no tag" for an already-shipped release and would cut it twice. It also now fails on any status other than 200/404 rather than reading a transient error as "no tag": a failed job is recoverable, a duplicate release is not.
- **The Codeberg publish step pushes the tag itself** instead of waiting for it to arrive by mirror. That wait was correct while Gitea mirrored *to* Codeberg; under Codeberg-canonical the mirror runs the other way and it would never resolve. Attaching the release to an already-pushed ref (no `target_commitish`) is what avoids the empty-bodied 500s, and the create call retries with backoff because Codeberg 500s on a tag it has only just received. The step stays **fail-loud**, not `continue-on-error` — it reported green through 0.2.1–0.3.2 while never once publishing, and that must not be possible again.

### 3 · Renovate

`renovate.json5` plus a Gitea-side job targeting Codeberg's API. `managerFilePatterns` covers **both** workflow directories, so the pinned Renovate image tag and the action versions in either file keep getting bumped.

Needs two new Gitea secrets: `RENOVATE_TOKEN` (Codeberg bot, repo read/write + PR scope) and `GITHUB_COM_TOKEN` (read-only github.com PAT, for changelog lookups).

### 4 · Weblate

A parity check (`scripts/check_translations.py`) runs on every PR without a path filter, so the required `Translations` status is always reported. Partial translations are expected, so `MissingTranslation` and `MissingQuantity` become informational — `ExtraTranslation` stays fatal. Agendula had no `lint` block at all, so the first locale to land would otherwise have failed the build.

**Settings → App language** now opens a picker carrying a "Help translate" header. That is why it drops floret-kit's `LanguagePickerRow` for a local row: the shared recipe has no `header` slot, and the framing is app-specific rather than a family primitive.

### 5 · Links repointed

In-app Source / License / report-issue URLs, F-Droid metadata, README (now with a Codeberg CI badge), and the docs.

`floret-kit` follows suit — `.gitmodules` points at `codeberg.org/jlmakiola/floret-kit`, so a clone no longer needs to reach the personal Gitea instance to resolve it. The Gitea copy is **kept**: every existing tag records the old submodule URL, so rebuilds of past releases still resolve.

### 6 · Housekeeping

Drops `release-notes.md` — a release-pipeline scratch file that got committed — and gitignores the five others the release job writes into the workspace.

### Not in this PR

The Codeberg → Gitea push mirror, the Weblate component, and the Codeberg bot account (all browser-side). Until the mirror is flipped, merging this does **not** reach the Gitea runner.

Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/agendula/pulls/2
2026-08-01 16:34:20 +02:00
3f166ef5f0 release: cut 0.3.2 — get the crash fix onto Codeberg
No app-code change from 0.3.1: this exists to re-run the release pipeline
now that the Codeberg publish step is fixed. 0.3.1's APK reached F-Droid but
its Codeberg release 500'd, so anyone installing from Codeberg or Obtainium
is still on the crashing 0.3.0 — cutting 0.3.2 gets them the fix and proves
the workflow fix in the only way that counts, a real release.

Chosen over hand-patching the 0.3.1 release onto Codeberg: same outcome for
users, minus a manual APK upload, and it actually exercises the pipeline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 19:11:48 +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
a9843e25b7 release: cut 0.3.0
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 12m27s
Ships the M5 reminders onboarding + Settings screen alongside the reworked
overview (Today progress ring, live Upcoming preview, unfurling search) and
the real launcher mark.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 22:25:14 +02:00
8f6b85008c release: cut 0.2.2
Some checks failed
Release — F-Droid repo + Gitea/Codeberg release / detect (push) Successful in 6s
Release — F-Droid repo + Gitea/Codeberg release / release (push) Has been cancelled
Re-cut after 0.2.1's Codeberg publish failed (500 on pre-synced tag,
fixed in the previous commit). Validates the fix end to end and ships
the Codeberg direct-download channel (signed APK + SHA-256).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 22:14:57 +02:00
7516972e9f release: cut 0.2.1
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) Successful in 12m13s
Publish releases to the Codeberg mirror (signed APK + SHA-256 checksum)
as a direct-download channel. Bumps versionName to 0.2.1; the pipeline
mints the v0.2.1 tag on merge to main.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 21:53:49 +02:00
7f58f81fe1 ci: adopt the modern calendula pipeline + Codeberg mirror
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>
2026-07-19 21:53:13 +02:00
4994f5ec2c reminders + locale: draw prefs/reminders and language plumbing from floret-kit
Consume two newly extracted floret-kit modules and drop the in-app copies:

- core-reminders: ReminderUnit / decomposeReminderMinutes, the ReminderOverride
  model and the override codec. SettingsPrefs keeps its own DataStore wiring and
  Agendula's ':' codec dialect; ReminderFormatting/ReminderLeadPicker keep the
  app's R.string labels and presets.
- core-locale: AppLanguage. Deleted the app copy; SettingsScreen now passes
  R.xml.locales_config to supportedTags().

Bumps the floret-kit submodule to include both modules.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 14:12:50 +02:00
a5ddf16537 components: draw the shared Compose vocabulary from floret-kit
Some checks failed
CI / ci (push) Has been cancelled
Phase 4 (components). Agendula now sources its grouped-row primitive
(GroupedSurface/GroupedRow + Position/positionOf), InlineTextField, OptionCard,
and pastelize() from the kit's components module instead of its own ui/common
copies. These were Agendula's versions, taken as the canonical family reference
(design sign-off); Agendula keeps its own identity chips (ListColorChip/
ListNameChip task glyph, PriorityChip) which now import the shared pastelize.

- Delete app copies of GroupedList/InlineTextField/OptionCard; drop the local
  pastelize from ListChip. Repoint all imports (cross-package + same-package +
  one inline FQN) to de.jeanlucmakiola.floret.components. Submodule re-pinned.

Clean composite build + tests + lintDebug + debug assemble green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 13:09:37 +02:00
18e03e27b6 identity: draw the M3 Expressive theme factory + nav slide from floret-kit
All checks were successful
CI / ci (push) Successful in 7m0s
Phase 3 (identity layer). AgendulaTheme is now a thin wrapper over the kit's
FloretExpressiveTheme(lightScheme, darkScheme, …): the shared mechanics
(dynamic colour, light/dark, standard motion scheme) live in floret-kit, while
Agendula keeps its own identity — the seed-derived AgendulaLight/DarkFallback
schemes and AgendulaTypography (unchanged in Color.kt/Type.kt). rememberNavSlideSpec
now comes from the kit; the app's AgendulaTransitions.kt is removed and the
NavHost import repointed. Submodule re-pinned to the identity kit commit.

Clean composite build + tests + lintDebug + debug assemble green; substitution
confirmed (de.jeanlucmakiola.floret:identity -> project :floret-kit:identity).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 12:59:56 +02:00
152226c1b2 Phase 2: core-crash from floret-kit; complete the core-time wiring
All checks were successful
CI / ci (push) Successful in 9m16s
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>
2026-06-28 12:24:49 +02:00
76a0139fda Rename app Floret → Agendula
All checks were successful
CI / ci (push) Successful in 8m33s
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>
2026-06-27 23:10:24 +02:00
2c457f3915 release: 0.2.0
All checks were successful
CI / ci (push) Successful in 6m18s
Release — F-Droid repo + Gitea release / ci (push) Successful in 7m21s
Release — F-Droid repo + Gitea release / gitea-release (push) Successful in 5s
Release — F-Droid repo + Gitea release / build-and-deploy (push) Successful in 6m14s
Promote [Unreleased] → [0.2.0] in the changelog (M2 UI + M3/M4 + fixes) and
bump the dev-default version to 0.2.0 / 200. The pushed tag drives the released
version per docs/RELEASING.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 21:27:06 +02:00
b196d9ebe0 M2: wire navigation host + base screen scaffolds
Replace the RootScreen nav stubs with a real NavHost. Each destination
binds its existing M1 ViewModel from route args.

- ui/navigation: Dest route table (string-based; no serialization plugin)
  + FloretNavHost (lists -> task list -> detail / edit).
- Base scaffolds for TaskListScreen, TaskDetailScreen, TaskEditScreen,
  wired to their ViewModels — skeletons for the rich M2/M3 UI.
- RootScreen READY branch now hands off to FloretNavHost.
- Add navigation-compose 2.9.0; supporting strings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 09:44:18 +02:00
Jean-Luc Makiola
6e1c9bec79 UI: lists in grouped surface cards; debug demo seeder
Some checks failed
CI / ci (push) Has been cancelled
- Per-account lists now render inside rounded surfaceContainer cards
  (grouped-list pattern) with inset dividers and transparent rows, instead
  of bare ListItems on the background — surfaces-first per design feedback.
- Add debug-only DemoSeeder (local, non-syncing 'Floret Demo' list) behind
  BuildConfig.DEBUG + an intent extra, to populate the UI for design review.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 22:53:18 +02:00
Jean-Luc Makiola
01d1f558b8 M0: Floret skeleton — Material 3 Expressive scaffold over OpenTasks (planned)
All checks were successful
CI / ci (push) Successful in 6m39s
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>
2026-06-17 19:40:53 +02:00