diff --git a/.gitea/workflows/ci.yaml b/.forgejo/workflows/ci.yaml
similarity index 92%
rename from .gitea/workflows/ci.yaml
rename to .forgejo/workflows/ci.yaml
index 9f15571..65831ab 100644
--- a/.gitea/workflows/ci.yaml
+++ b/.forgejo/workflows/ci.yaml
@@ -72,9 +72,14 @@ jobs:
distribution: 'zulu'
java-version: '17'
+ # Fully qualified on purpose. Codeberg resolves bare `uses:` refs against
+ # data.forgejo.org, Forgejo's own action mirror — actions/checkout,
+ # setup-java and cache all exist there, but android-actions/setup-android
+ # does not, and the job dies with "repository not found". Gitea's instance
+ # defaults to GitHub, which is why this never surfaced before the split.
- name: Setup Android SDK
if: steps.scope.outputs.code == 'true'
- uses: android-actions/setup-android@v3
+ uses: https://github.com/android-actions/setup-android@v3
with:
# Default ("tools platform-tools") drags in the Android Emulator
# (~300 MB) which the build never uses.
diff --git a/.gitea/workflows/translations.yaml b/.forgejo/workflows/translations.yaml
similarity index 100%
rename from .gitea/workflows/translations.yaml
rename to .forgejo/workflows/translations.yaml
diff --git a/.gitea/workflows/release.yaml b/.gitea/workflows/release.yaml
index bf0f83e..17a4efd 100644
--- a/.gitea/workflows/release.yaml
+++ b/.gitea/workflows/release.yaml
@@ -27,6 +27,14 @@ jobs:
# whether this push actually cuts a new release (no tag for it yet). Keeps the
# heavy job from running on every merge to main.
detect:
+ # Gitea only. The workflow directory split already keeps this file invisible
+ # to Codeberg — Forgejo's lookup is first-match-wins, and .forgejo/workflows
+ # exists — but that only holds while .forgejo/ is non-empty. Move the last
+ # file out of it and Codeberg would fall back to .gitea/workflows and start
+ # running the release pipeline on the contributor-facing runner, with no
+ # secrets. repository_owner differs between the two forges regardless of
+ # URL, proxy or instance rename, so this closes it permanently.
+ if: github.repository_owner == 'makiolaj'
runs-on: docker
outputs:
is_release: ${{ steps.v.outputs.is_release }}
@@ -41,8 +49,16 @@ jobs:
- name: Resolve version and whether it is a new release
id: v
env:
- TOKEN: ${{ secrets.GITHUB_TOKEN }}
- API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
+ # Tags are read from Codeberg, which is canonical — deliberately NOT
+ # from the Gitea API this workflow runs on. The Codeberg -> Gitea sync
+ # is a push mirror, i.e. `git push --mirror`, which deletes refs the
+ # source does not have. A tag minted here on Gitea is therefore wiped
+ # by the next sync (Codeberg does not have it yet) and only reappears
+ # once the tag push at the end of this workflow propagates back.
+ # Asking Gitea inside that window would report "no tag" for a release
+ # that already shipped, and cut it a second time.
+ # Public repo, so this read needs no token.
+ TAG_API: https://codeberg.org/api/v1/repos/jlmakiola/calendula
run: |
set -e
VERSION=$(grep -oP 'versionName\s*=\s*"\K[^"]+' app/build.gradle.kts)
@@ -60,15 +76,28 @@ jobs:
fi
# A tag for this version already existing means the release shipped on
# an earlier push; do nothing. Absent => this merge cuts the release.
- STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
- -H "Authorization: token $TOKEN" "$API/git/refs/tags/v$VERSION")
- if [ "$STATUS" = "200" ]; then
- echo "Tag v$VERSION already exists — nothing to release."
- echo "is_release=false" >> "$GITHUB_OUTPUT"
- else
- echo "No tag for v$VERSION yet — cutting the release."
- echo "is_release=true" >> "$GITHUB_OUTPUT"
- fi
+ #
+ # Anything other than a clean 200/404 is treated as fatal rather than
+ # as "no tag". A Codeberg outage or a network blip would otherwise
+ # read as absent and re-cut a release that has already shipped —
+ # republishing to F-Droid and Play. Failing here is recoverable; a
+ # duplicate release is not.
+ STATUS=$(curl -s -o /dev/null -w '%{http_code}' "$TAG_API/git/refs/tags/v$VERSION" || echo 000)
+ case "$STATUS" in
+ 200)
+ echo "Tag v$VERSION already exists on Codeberg — nothing to release."
+ echo "is_release=false" >> "$GITHUB_OUTPUT"
+ ;;
+ 404)
+ echo "No tag for v$VERSION on Codeberg yet — cutting the release."
+ echo "is_release=true" >> "$GITHUB_OUTPUT"
+ ;;
+ *)
+ echo "Codeberg tag lookup for v$VERSION returned HTTP $STATUS." >&2
+ echo "Refusing to guess: treating this as 'no tag' could re-cut a shipped release." >&2
+ exit 1
+ ;;
+ esac
# Releases: build + sign + publish, then mint the tag and Gitea release.
# Also runs on manual dispatch, where it skips the build and just re-signs and
diff --git a/.gitea/workflows/renovate.yml b/.gitea/workflows/renovate.yml
index 5b5ebda..53f7a53 100644
--- a/.gitea/workflows/renovate.yml
+++ b/.gitea/workflows/renovate.yml
@@ -29,14 +29,30 @@ jobs:
- name: Run Renovate
run: renovate
env:
- # Self-hosted Gitea, not github.com.
- RENOVATE_PLATFORM: gitea
- RENOVATE_ENDPOINT: https://gitea.jeanlucmakiola.de/api/v1
- # Bot-account token (Gitea secret). Needs repo read/write + PR scope.
+ # Renovate targets Codeberg (canonical) while still RUNNING on the
+ # Gitea runner. Moving the job to Codeberg would put a repo-write
+ # token on the contributor-facing runner, which is exactly what the
+ # .forgejo/ vs .gitea/ split exists to prevent — so the token stays
+ # where the other secrets live and only the API calls cross over.
+ #
+ # Platform is `forgejo`, not `gitea`: Codeberg runs Forgejo, and the
+ # pinned image ships a distinct forgejo platform module.
+ RENOVATE_PLATFORM: forgejo
+ RENOVATE_ENDPOINT: https://codeberg.org/api/v1
+ # Codeberg bot-account token (Gitea secret). Needs repo read/write +
+ # PR scope on jlmakiola/calendula.
RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
# Scope to this repo only — no org-wide autodiscovery.
RENOVATE_AUTODISCOVER: 'false'
- RENOVATE_REPOSITORIES: '["makiolaj/calendula"]'
- # Commits/PRs authored as the bot, not a real maintainer.
+ RENOVATE_REPOSITORIES: '["jlmakiola/calendula"]'
+ # Commits/PRs authored as the bot, not a real maintainer. This address
+ # must be a verified email on the Codeberg bot account, otherwise the
+ # commits show up unattributed there.
RENOVATE_GIT_AUTHOR: 'Renovate Bot '
+ # Read-only github.com PAT (no scopes needed). Unaffected by the forge
+ # move — nearly every dependency is *released* on GitHub, and without
+ # this,
+ # changelog/release-note lookups hit the 60/h anonymous rate limit
+ # and PRs arrive with an empty "Release Notes" section.
+ RENOVATE_GITHUB_COM_TOKEN: ${{ secrets.GITHUB_COM_TOKEN }}
LOG_LEVEL: info
diff --git a/.gitmodules b/.gitmodules
index 103c066..b908ca7 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
[submodule "floret-kit"]
path = floret-kit
- url = https://gitea.jeanlucmakiola.de/makiolaj/floret-kit.git
+ url = https://codeberg.org/jlmakiola/floret-kit.git
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 17978a0..73cad12 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -29,6 +29,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
with a **"Missing a calendar?"** row that opens Settings → Calendars, where
those marks then explain why a calendar isn't offered ([#76]).
+### Changed
+- Calendula's source code now lives on **Codeberg**, where its issues already
+ were. The **Source code** and **License** links in Settings → About point
+ there, so reporting a bug and reading the code no longer land on two different
+ sites. Nothing about the app itself changes, and the F-Droid repository is
+ unaffected.
+
### Fixed
- Reminders now arrive for every calendar you have switched on. A calendar that
was hidden at system level — switched off in another calendar app, or never
diff --git a/README.md b/README.md
index f909377..f2e3b31 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
Reads, writes, and reminds — on top of the system calendar, with zero network access.
-
+
diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsScreen.kt
index c490375..c1efe32 100644
--- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsScreen.kt
+++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsScreen.kt
@@ -56,6 +56,7 @@ import androidx.compose.material.icons.filled.Keyboard
import androidx.compose.material.icons.filled.Language
import androidx.compose.material.icons.filled.Notifications
import androidx.compose.material.icons.filled.Palette
+import androidx.compose.material.icons.filled.PrivacyTip
import androidx.compose.material.icons.filled.Translate
import androidx.compose.material.icons.filled.Tune
import androidx.compose.material.icons.filled.UploadFile
@@ -408,7 +409,9 @@ private fun LanguageRow(position: Position) {
@Composable
private fun AboutCard() {
// The card layout lives in floret-kit (components.AboutCard); Calendula
- // supplies its own logo, author and the source / licence / support links.
+ // supplies its own logo, author and the source / licence / privacy / support
+ // links. The privacy policy has to be reachable from inside the app, not just
+ // from the store listing, because Calendula touches calendar and contact data.
AboutCard(
logo = { AppLogo() },
appName = stringResource(R.string.app_name),
@@ -424,6 +427,11 @@ private fun AboutCard() {
label = stringResource(R.string.settings_license),
url = stringResource(R.string.about_license_url),
),
+ AboutLink(
+ icon = Icons.Default.PrivacyTip,
+ label = stringResource(R.string.settings_about_privacy),
+ url = stringResource(R.string.about_privacy_url),
+ ),
),
highlightLink = AboutLink(
icon = Icons.Default.Favorite,
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index ce0c971..49c17a2 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -53,11 +53,11 @@
تعذّر مشاركة هذا الحدث.
حذف الحدث؟
الحدث أُزيل من تقويمك ومن كل جهاز تتم مزامنته معه.
- حذف الحدث المتكرر
+ حذف الحدث المتكرّر
فقط هذا الحدث
هذا وجميع الأحداث اللاحقة
جميع الأحداث في السلسلة
- تعديل الحدث المتكرر
+ تعديل الحدث المتكرّر
تعذّر حذف الحدث
Calendula يحتاج إلى صلاحية للكتابة لحذف الأحداث
إلغاء
@@ -108,7 +108,7 @@
الحدث يبقى كما هو الآن
هل تريد تطبيق تذكيرك الافتراضي؟
هذا الحدث حُذف في هذه الأثناء، على سبيل المثال على جهاز آخر. لم يعد من الممكن حفظ تغييراتك.
- المزيد من الخيارات
+ المزيد من الخانات
علني
الافتراضي
مشغول
@@ -153,7 +153,7 @@
%1$s حتى %2$s
%1$s، %2$d مرّات
طَبِّق الافتراضي
- حدث مُتكرر
+ حدث متكرّر
%1$s في %2$s
—
تم القُبول
@@ -166,7 +166,7 @@
ملغي
متاح
خاص
- سري
+ سرّي
المُنظِّم
اختياري
التذكير الافتراضي
@@ -180,7 +180,7 @@
Android لا يعرض تذكيرات الأحداث من نفسه — بل يجب أن يقوم تطبيق تقويم بذلك. دع Calendula يتولى هذه المهمة.
كل تذكير لأحداثك يصِل كإشعار، في الوقت المحدد تمامًا.
هل تستخدم تطبيق تقويم ثانٍ؟
- إذا كان تطبيق آخر أيضًا ينشر تذكيرات، فستراهم مرتين — قم بإيقاف تشغيلهم هناك أو هنا.
+ إذا تطبيق آخر أيضًا ينشر تذكيرات، فستراهم مرتين — قم بإيقاف تشغيلهم هناك أو هنا.
يمكنك تغييره في أي وقت
شَغِّل التذكيرات
ليس الآن
@@ -200,7 +200,7 @@
البحث عن الأحداث
مسح
لا مزيد من الأحداث اليوم
- لا توجد أحداث مطابقة ”%1$s“.
+ لا أحداث مطابقة ”%1$s“.
ابحث عن أحداثك بالعنوان، الموقع أو الملاحظات.
الرجوع
البحث
@@ -217,7 +217,7 @@
رجوع
المظهر
اللون الديناميكي
- يتطلب Android 12 أو أحدث
+ يتطلب أندرويد ١٢ أو أحدث
طريقة العرض الافتراضية
ألوان تقويم ناعمة
خفف ألوان التقويم والأحداث لتتناسب مع الثيم. قم بإيقافه لإظهار الألوان الخام من مصدر التقويم.
@@ -227,7 +227,7 @@
اختر ملفًا…
خط مخصص
تعذّر قراءة هذا الملف كخط
- يبدأ الأسبوع في
+ الأسبوع يبدأ في
تلقائي
تلقائي
تنسيق الوقت
@@ -243,4 +243,58 @@
إظهار
إخفاء
جدول
+ المنطقة الزمنية للجهاز
+ البحث عن المناطق الزمنية
+ جميع المناطق الزمنية
+ لا منطقة زمنية تطابق \"%1$s\"
+ %1$s توقيتك
+ الأحدث
+ أدخل رقمًا من ١ إلى ٩٩٩
+
+ - (%d) لا دقائق
+ - (%d) دقيقة واحده
+ - %d دقيقتان
+ - %d دقائق
+ - %d دقيقة
+ - %d دقيقة
+
+
+ - (%d) لا ساعات
+ - (%d) ساعة واحده
+ - %d ساعتان
+ - %d ساعات
+ - %d ساعة
+ - %d ساعة
+
+
+ - (%d) لا أيام
+ - (%d) يوم واحد
+ - %d يومان
+ - %d أيام
+ - %d يوم
+ - %d يوم
+
+
+ - (%d) لا أسابيع
+ - (%d) أسبوع واحد
+ - %d أسبوعان
+ - %d أسابيع
+ - %d أسبوع
+ - %d أسبوع
+
+ يبدأ %1$s
+ ينتهي %1$s
+ الانتقال إلى اليوم
+ تحديث
+ اسم التطبيق
+ تعتيم الأحداث المكتملة
+ تعتيم الأحداث التي انتهت بالفعل في عرض الشهر والأسبوع
+ زر اليوم في شريط الأدوات
+ إظهار زر الانتقال إلى اليوم في شريط الأدوات بدلاً من زر عائم
+ اعرض Calendula كـ \"Calendar\" في مشغّل التطبيقات الخاص بك. فقط الاسم في المشغّل يتغير؛ وقد ينتقل الرمز إلى مكان جديد بعد التبديل.
+ تعتيم
+ الأحداث السابقة
+ مدى الجدول
+ مخصص…
+ أيام
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 89b8563..629871c 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -354,7 +354,7 @@
Pomóż w tłumaczeniu
Dodaj lub ulepsz tłumaczenie w Weblate
Motyw, domyślny widok, pierwszy dzień tygodnia
- Kolejność przycisku szybkiego przełączania oraz menu
+ Układ widoku miesiąca, przycisk szybkiego przełączania, kolejność menu
Domyślne pola dla nowych wydarzeń
Przypomnienia o wydarzeniach
Urodziny i rocznice kontaktów
@@ -515,4 +515,32 @@
Zachowaj dzisiejszy dzień na górze agendy i widżetu, nawet gdy nie ma już na dziś żadnych zadań.
Urodziny
Rocznice
+ Strefa czasowa urządzenia
+ Podąża za Twoją lokalizacją
+ Znajdź strefę czasową
+ Ostatnie
+ Wszystkie strefy czasowe
+ Żadna strefa czasowa nie pasuje do „%1$s”
+ %1$s Twojego czasu
+ Wpisz liczbę od 1 do 999
+ Początek o %1$s
+ Koniec o %1$s
+ Dzisiaj
+ Przycisk „Dzisiaj” na pasku narzędzi
+ Pokaż przycisk skoku do dzisiaj na pasku narzędzi zamiast przycisku pływającego
+ Nazwa aplikacji
+ Wyświetlaj Calendula jako „Kalendarz” w menu aplikacji. Zmieni się tylko nazwa w menu; po przełączeniu ikona może pojawić się w innym miejscu.
+ Widok miesiąca
+ Styl widoku miesiąca
+ Strony
+ Jeden miesiąc wypełnia ekran. Przesuń w lewo lub w prawo, aby zmienić miesiąc.
+ Przewijanie miesięcy
+ Każdy miesiąc znajduje się pod własnym nagłówkiem, oddzielony od następnego niewielkim odstępem.
+ Tygodnie bez przerw
+ Tygodnie są ułożone jeden po drugim, każdy miesiąc płynnie łączy się z następnym, bez odstępu pomiędzy.
+ Podzielony
+ Zwięzła siatka wyróżnia dni z wydarzeniami a lista dla dnia wybranego dotknięciem wyświetla się poniżej.
+ Brak planów
+ Pokaż cały miesiąc
+ Pokaż wydarzenia dnia
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3e24629..21c16fc 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -462,6 +462,7 @@
MIT
by Jean-Luc Makiola
Source
+ Privacy policy
Support development
Version %1$s
Calendula app icon
@@ -579,8 +580,9 @@
Add Quick Settings tile
Add a “New event” tile to the Quick Settings panel.
- https://gitea.jeanlucmakiola.de/makiolaj/calendula
- https://gitea.jeanlucmakiola.de/makiolaj/calendula/src/branch/main/LICENSE
+ https://codeberg.org/jlmakiola/calendula
+ https://codeberg.org/jlmakiola/calendula/src/branch/main/LICENSE
+ https://jeanlucmakiola.de/calendula/privacy
https://ko-fi.com/jeanlucmakiola
https://weblate.dev.jeanlucmakiola.de/engage/calendula/
diff --git a/docs/RELEASING.md b/docs/RELEASING.md
index 4bd4f03..4426944 100644
--- a/docs/RELEASING.md
+++ b/docs/RELEASING.md
@@ -73,7 +73,8 @@ Published version codes so far: `v0.1.0`→100 … `v1.0.0`→10000 … `v2.0.0`
CI and release are split so a change is built once on its PR and only does
release work when a merge actually cuts a release:
-- **`ci.yaml`** (on `pull_request`) — lint + unit tests + a debug assemble (and
+- **`ci.yaml`** (`.forgejo/workflows/`, on `pull_request`, **Codeberg**) — lint +
+ unit tests + a debug assemble (and
a Trivy scan), once per PR. Docs/metadata-only PRs skip the Android build but
still report a green `CI` check.
- **`release.yaml`** (on push to `main`, plus `workflow_dispatch`) — a cheap
@@ -91,9 +92,9 @@ release work when a merge actually cuts a release:
Alongside F-Droid, each release is mirrored to the Codeberg repo
(`jlmakiola/calendula`) as a plain download for users who don't want F-Droid.
-Gitea already **push-mirrors** branches and tags to Codeberg, but releases
-aren't git objects and don't sync, so the pipeline creates the release over the
-Codeberg API and attaches `calendula_v.apk` + its `.sha256`. It's the
+Codeberg **push-mirrors** branches and tags to Gitea, but releases aren't git
+objects and don't sync in either direction, so the pipeline creates the release
+over the Codeberg API and attaches `calendula_v.apk` + its `.sha256`. It's the
same APK the F-Droid repo serves (same **app key**), so it adds no trust
surface. The step is best-effort: a Codeberg outage never fails an
already-published F-Droid release, and it skips cleanly if `CODEBERG_RELEASE_TOKEN` is
@@ -109,6 +110,39 @@ build, the version bump, and tag/release creation, and just re-signs the
existing F-Droid index with the configured repo key and re-uploads. Use this
for key rotation or repo recovery without publishing a new app version.
+## Two forges, one repo
+
+**Codeberg (`jlmakiola/calendula`) is canonical** — git, issues, PRs, tags and
+releases. The self-hosted Gitea instance is build infrastructure: it holds the
+signing key, publishes the F-Droid repo, and runs the release pipeline. Codeberg
+push-mirrors `main` and tags to Gitea, and a bumped `versionName` arriving there
+triggers `release.yaml` exactly as before.
+
+Workflows are separated by **directory**, not by conditionals. Forgejo looks in
+`.forgejo/workflows` → `.gitea/workflows` → `.github/workflows` and stops at the
+first that exists; Gitea doesn't know `.forgejo/` at all:
+
+| Directory | Runs on | Contains | Secrets |
+| --- | --- | --- | --- |
+| `.forgejo/workflows/` | Codeberg | `ci.yaml`, `translations.yaml` | **none** |
+| `.gitea/workflows/` | Gitea | `release.yaml`, `renovate.yml` | signing key, F-Droid, Play, bot tokens |
+
+The line is drawn at **secrets, not at CI-vs-release**. That's what makes fork
+PRs safe: everything a contributor can trigger lives in `.forgejo/` and can
+reference no secret. Renovate stays on the Gitea runner *even though it opens
+PRs on Codeberg* — it talks to Codeberg's API rather than moving its token onto
+the contributor-facing runner.
+
+Two consequences worth remembering:
+
+- **`detect` 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 would re-cut a shipped release.
+- **Any ref that exists only on Gitea gets deleted** by the mirror. That's
+ correct under Codeberg-canonical, but don't debug a "vanished" branch without
+ remembering it.
+
## Secrets (Gitea → repo Settings → Actions → Secrets)
| Secret | Purpose |
diff --git a/docs/fdroid-official/de.jeanlucmakiola.calendula.yml b/docs/fdroid-official/de.jeanlucmakiola.calendula.yml
index 86b95a7..aa9c737 100644
--- a/docs/fdroid-official/de.jeanlucmakiola.calendula.yml
+++ b/docs/fdroid-official/de.jeanlucmakiola.calendula.yml
@@ -18,9 +18,9 @@ Categories:
- Calendar & Agenda
License: MIT
AuthorName: Jean-Luc Makiola
-SourceCode: https://gitea.jeanlucmakiola.de/makiolaj/calendula
-IssueTracker: https://gitea.jeanlucmakiola.de/makiolaj/calendula/issues
-Changelog: https://gitea.jeanlucmakiola.de/makiolaj/calendula/src/branch/main/CHANGELOG.md
+SourceCode: https://codeberg.org/jlmakiola/calendula
+IssueTracker: https://codeberg.org/jlmakiola/calendula/issues
+Changelog: https://codeberg.org/jlmakiola/calendula/src/branch/main/CHANGELOG.md
Donate: https://ko-fi.com/jeanlucmakiola
AutoName: Calendula
diff --git a/fdroid-metadata/de.jeanlucmakiola.calendula.yml b/fdroid-metadata/de.jeanlucmakiola.calendula.yml
index 2f6581e..61c667b 100644
--- a/fdroid-metadata/de.jeanlucmakiola.calendula.yml
+++ b/fdroid-metadata/de.jeanlucmakiola.calendula.yml
@@ -6,6 +6,6 @@ Summary: A modern Material 3 Expressive calendar for Android.
Categories:
- Time
-SourceCode: https://gitea.jeanlucmakiola.de/makiolaj/calendula
-IssueTracker: https://gitea.jeanlucmakiola.de/makiolaj/calendula/issues
+SourceCode: https://codeberg.org/jlmakiola/calendula
+IssueTracker: https://codeberg.org/jlmakiola/calendula/issues
Donate: https://ko-fi.com/jeanlucmakiola
diff --git a/renovate.json5 b/renovate.json5
index 103bd3d..378bf07 100644
--- a/renovate.json5
+++ b/renovate.json5
@@ -7,6 +7,23 @@
":semanticCommits",
],
+ // `config:recommended` brings in mergeConfidence:age-confidence-badges, whose
+ // Age column is a Mend badge. Mend's Merge Confidence index only covers Maven
+ // Central: org.jetbrains.kotlin, junit, truth, turbine et al resolve, but
+ // every androidx/compose artifact lives on Google's Maven repo and comes back
+ // as a grey UNKNOWN — i.e. most of this project. Renovate already knows the
+ // real answer, since it derives release timestamps itself for the
+ // minimumReleaseAge rules below (Google Maven serves `last-modified` on its
+ // POMs), so take the age from there and leave Mend to the Confidence column,
+ // which still carries signal for the Maven Central half.
+ prBodyDefinitions: {
+ Age: "{{#if releaseTimestamp}}{{{newVersionAgeInDays}}} d{{else}}unknown{{/if}}",
+ },
+ // Default heading links to the Merge Confidence docs; this column is ours now.
+ prBodyHeadingDefinitions: {
+ Age: "Age",
+ },
+
// No automerge: a dependency bump goes through the same review (and, for
// anything touching the build, the same on-device check) as a feature
// before it can ride a release — see docs/RELEASING.md and the
@@ -15,6 +32,22 @@
// One reviewable surface; the dashboard issue lists everything pending.
dependencyDashboard: true,
+
+ // The cooling-off periods below are advisory, not a gate. "flexible" still
+ // prefers a version that has cleared its window, but when every candidate is
+ // too young it opens the PR at the newest one anyway, so merging early stays
+ // a judgement call. (The default, "strict", would suppress the PR entirely
+ // until a release aged in.) A still-young branch carries a yellow
+ // `renovate/stability-days` check so it's visible which side of the line
+ // it's on; with automerge off, nothing acts on that check by itself.
+ //
+ // NOT "none": that short-circuits the candidate loop in filter-checks.ts, and
+ // that loop is what calls postprocessRelease — the only thing that fetches a
+ // Maven artifact's Last-Modified header. Skipping it leaves releaseTimestamp
+ // unset, which empties the Age column and quietly makes minimumReleaseAge and
+ // the stability check no-ops, since both need that timestamp to compare.
+ internalChecksFilter: "flexible",
+
labels: ["dependencies"],
prConcurrentLimit: 5,
prHourlyLimit: 0,
@@ -25,11 +58,28 @@
// Gitea Actions workflows live under .gitea/workflows, not .github — extend
// the github-actions manager (same syntax) to watch them too.
+ // `fileMatch` is deprecated; the replacement takes the regex delimited, and
+ // Renovate's config migration was already rewriting this on every run.
"github-actions": {
- fileMatch: ["^\\.gitea/workflows/[^/]+\\.ya?ml$"],
+ managerFilePatterns: ["/^\\.gitea/workflows/[^/]+\\.ya?ml$/"],
},
packageRules: [
+ // Cooling-off period, scaled by blast radius: how long a release should
+ // have been out (and un-yanked, un-hotfixed) before it's considered
+ // settled. Advisory only — see `internalChecksFilter` above.
+ {
+ matchUpdateTypes: ["major"],
+ minimumReleaseAge: "30 days",
+ },
+ {
+ matchUpdateTypes: ["minor"],
+ minimumReleaseAge: "20 days",
+ },
+ {
+ matchUpdateTypes: ["patch", "digest", "pin", "rollback"],
+ minimumReleaseAge: "10 days",
+ },
// material3 is deliberately pinned to the 1.5 *alpha* line for the
// Expressive APIs (see gradle/libs.versions.toml). Follow the alpha train
// but keep it in its own PR, reviewed in isolation; revisit the pin when
@@ -52,5 +102,18 @@
],
groupName: "test dependencies",
},
+ // Last word on the PR table. The merge-confidence preset sets prBodyColumns
+ // from inside a packageRule of its own, and only for the datasources Mend
+ // supports — so a plain top-level prBodyColumns would lose to it for maven
+ // deps, and the Gradle wrapper / Actions / container bumps would keep the
+ // default columns and show no age at all. A rule declared after it wins,
+ // and gives every PR the same table.
+ // "Pending" earns its place under a flexible filter: when the bump lands on
+ // a version that has cleared its window but a newer one hasn't, that newer
+ // version is named here rather than silently withheld.
+ {
+ matchPackageNames: ["*"],
+ prBodyColumns: ["Package", "Type", "Change", "Age", "Pending", "Confidence"],
+ },
],
}