Cut 2.18.0. Adds the retroactive entries for #114 and #70, whose PRs
landed on main directly rather than on this branch.

The fastlane changelog is now hand-written and capped at 500 chars —
Play rejects longer "What's New" text and F-Droid truncates it, while
copying the CHANGELOG.md section produced up to 8k chars. The sync
script keeps a committed file and only falls back to CHANGELOG.md when
one is missing.
This commit is contained in:
2026-07-31 22:14:48 +02:00
parent c09fd5198a
commit 51dba1959a
6 changed files with 84 additions and 34 deletions

View File

@@ -264,9 +264,10 @@ jobs:
cp app/build/outputs/apk/release/app-release.apk "fdroid/repo/calendula_v${VERSION}.apk" cp app/build/outputs/apk/release/app-release.apk "fdroid/repo/calendula_v${VERSION}.apk"
# Per-version "What's New": ensure this version's changelog exists in the # Per-version "What's New": ensure this version's changelog exists in the
# fastlane tree (committed at release-cut time for the official repo; this # fastlane tree. The committed hand-written summary (kept under Play's
# regenerates it from CHANGELOG.md so the self-hosted repo never depends on # 500-char cap) is used as-is; only if it is missing does the script fall
# the commit having happened). The transform below then carries it across. # back to CHANGELOG.md, so the self-hosted repo never depends on the
# commit having happened. The transform below then carries it across.
- name: Ensure this version's changelog is in the fastlane tree - name: Ensure this version's changelog is in the fastlane tree
if: env.IS_RELEASE == 'true' if: env.IS_RELEASE == 'true'
run: bash scripts/sync_changelog_to_fastlane.sh run: bash scripts/sync_changelog_to_fastlane.sh

View File

@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [2.18.0] — 2026-07-31
### Added ### Added
- A new event no longer always lasts an hour. **Settings → New event form → - A new event no longer always lasts an hour. **Settings → New event form →
Default duration** sets how long one opens, and each calendar may keep its own Default duration** sets how long one opens, and each calendar may keep its own
@@ -57,6 +59,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
is now called **Harmonise calendar colours**; turning it off still shows the is now called **Harmonise calendar colours**; turning it off still shows the
raw colours from your calendar source ([#21], [#36]). raw colours from your calendar source ([#21], [#36]).
### Fixed
- The back gesture closes the sidebar instead of the app. With the drawer open,
swiping back left Calendula altogether rather than putting the sidebar away
([#114]).
- The sidebar lines up. "Calendula", "View" and "Calendars" now share the left
edge of the rows under them, and the view, jump-to-date, Settings and calendar
rows sit on one vertical axis instead of each icon finding its own — the same
alignment the Settings screens use ([#114]).
- The status- and navigation-bar icons follow Calendula's own light/dark choice.
Setting the app dark while the system stayed light — or the other way round —
left the clock and battery drawn for the system's theme, so they could sit
near-invisible against the app's own bar ([#70]).
## [2.17.1] — 2026-07-30 ## [2.17.1] — 2026-07-30
### Added ### Added

View File

@@ -28,8 +28,8 @@ android {
// which builds this version and then creates the matching vX.Y.Z tag + // which builds this version and then creates the matching vX.Y.Z tag +
// 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. 2.7.2 -> 20702). See docs/RELEASING.md. // PATCH from versionName, e.g. 2.7.2 -> 20702). See docs/RELEASING.md.
versionCode = 21701 versionCode = 21800
versionName = "2.17.1" versionName = "2.18.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }

View File

@@ -33,15 +33,27 @@ Published version codes so far: `v0.1.0`→100 … `v1.0.0`→10000 … `v2.0.0`
the F-Droid per-version changelog. the F-Droid per-version changelog.
3. Bump the committed `versionName` (and `versionCode`) in 3. Bump the committed `versionName` (and `versionCode`) in
`app/build.gradle.kts` to the new version. **This bump is what triggers the `app/build.gradle.kts` to the new version. **This bump is what triggers the
release** when the branch merges to `main`. Then run release** when the branch merges to `main`. Then write the per-version
"What's New" by hand to
`fastlane/metadata/android/en-US/changelogs/<versionCode>.txt` and commit it.
**Keep it under 500 characters.** That one file is what both the **official**
F-Droid repo (which reads it from the tagged source tree) and **Google Play**
publish, and Play caps "What's New" at 500 characters while F-Droid truncates
long entries in-client. So it is a short summary — a handful of bullets
naming the headline changes — not a copy of the CHANGELOG.md section, which
runs to thousands of characters. `CHANGELOG.md` stays the full account and is
what the Gitea/Codeberg release notes use.
Then run
```bash ```bash
scripts/sync_changelog_to_fastlane.sh scripts/sync_changelog_to_fastlane.sh
``` ```
and commit the generated to check it. The script **keeps** a committed file untouched and only warns
`fastlane/metadata/android/en-US/changelogs/<versionCode>.txt`. This is what if it is over the limit; it extracts the CHANGELOG.md section as a fallback
makes the **official** F-Droid repo show this version's changelog (it reads solely when the file is missing, so the self-hosted pipeline always has
the changelog from the tagged source tree). The self-hosted pipeline something to publish. The pipeline runs the same script, so forgetting to
regenerates it regardless, so forgetting only affects the official listing. write the file yields a long auto-generated changelog rather than none.
4. **Verify the release build on a real device** — the mandatory gate. The 4. **Verify the release build on a real device** — the mandatory gate. The
shipped APK is R8-shrunk/obfuscated, and bugs that only appear there, or shipped APK is R8-shrunk/obfuscated, and bugs that only appear there, or
only on first run, never show up in the debug build or on a device that only on first run, never show up in the debug build or on a device that
@@ -142,8 +154,9 @@ because the store listing already lives in `fastlane/metadata/android/` — the
same tree the official F-Droid repo harvests. One metadata source, two stores. same tree the official F-Droid repo harvests. One metadata source, two stores.
**What gets uploaded per release:** the AAB, plus the per-version "What's New" **What gets uploaded per release:** the AAB, plus the per-version "What's New"
from `fastlane/metadata/android/en-US/changelogs/<versionCode>.txt` (generated from `fastlane/metadata/android/en-US/changelogs/<versionCode>.txt` — the
from `CHANGELOG.md` by `scripts/sync_changelog_to_fastlane.sh`). Listing text is hand-written summary from step 3, which is why it must stay **under 500
characters**: Play rejects a longer one. Listing text is
**not** touched — an accidental overwrite of a live listing triggers a Play **not** touched — an accidental overwrite of a live listing triggers a Play
policy review. Sync it deliberately with `bundle exec fastlane listing`. policy review. Sync it deliberately with `bundle exec fastlane listing`.

View File

@@ -0,0 +1,12 @@
New
• Default event duration — how long a new event opens, per calendar.
• Week & day: choose an hour height, or pinch to zoom. "Fit whole day" shows all 24 hours at once.
• Tap the date in the top bar to jump to another day.
Changed
• Calendar colours reworked so event text is always readable.
• Reminders now carry Calendula's own status-bar icon.
Fixed
• Back closes the sidebar instead of the app, and its rows line up.
• Status-bar icons follow the app's light/dark choice.

View File

@@ -1,19 +1,24 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Write the current version's CHANGELOG.md section into the fastlane changelog # Ensure the current version's "What's New" exists at
# file that F-Droid harvests: fastlane/metadata/android/en-US/changelogs/<code>.txt # fastlane/metadata/android/en-US/changelogs/<code>.txt — the one file both the
# (en-US is F-Droid's fallback locale, so it covers every language). # official F-Droid repo and Google Play read (en-US is F-Droid's fallback
# locale, so it covers every language).
# #
# Run this when cutting a release (after editing CHANGELOG.md and bumping # A COMMITTED file wins and is never rewritten. Play caps "What's New" at 500
# versionName in app/build.gradle.kts) and COMMIT the result, so the OFFICIAL # characters and F-Droid truncates long entries in-client, so this file is a
# F-Droid repo — which reads the changelog from the tagged source treeshows # hand-written summary, not a copy of the CHANGELOG.md sectionthose run to
# this version's "What's New". The self-hosted release pipeline also runs it so # thousands of characters. Write it when cutting a release, keep it under 500,
# its changelog never depends on the file having been committed. Idempotent. # and commit it.
# #
# Extraction matches the awk used for the Gitea release notes so all three # Only when the file is missing does this fall back to extracting the
# (release notes, self-hosted changelog, official changelog) stay in sync. # CHANGELOG.md section, so the self-hosted release pipeline always has
# something to publish. The extraction matches the awk used for the Gitea
# release notes.
set -euo pipefail set -euo pipefail
cd "$(dirname "$0")/.." # repo root cd "$(dirname "$0")/.." # repo root
LIMIT=500
VERSION=$(grep -oP 'versionName\s*=\s*"\K[^"]+' app/build.gradle.kts) VERSION=$(grep -oP 'versionName\s*=\s*"\K[^"]+' app/build.gradle.kts)
[ -n "$VERSION" ] || { echo "No versionName in app/build.gradle.kts" >&2; exit 1; } [ -n "$VERSION" ] || { echo "No versionName in app/build.gradle.kts" >&2; exit 1; }
MAJOR=${VERSION%%.*}; rest=${VERSION#*.}; MINOR=${rest%%.*}; PATCH=${rest##*.} MAJOR=${VERSION%%.*}; rest=${VERSION#*.}; MINOR=${rest%%.*}; PATCH=${rest##*.}
@@ -24,18 +29,22 @@ CL_DIR="fastlane/metadata/android/en-US/changelogs"
mkdir -p "$CL_DIR" mkdir -p "$CL_DIR"
OUT="$CL_DIR/${VERSION_CODE}.txt" OUT="$CL_DIR/${VERSION_CODE}.txt"
awk -v ver="$VERSION" ' if [ -s "$OUT" ]; then
ACTION="Kept"
else
ACTION="Generated"
awk -v ver="$VERSION" '
$0 ~ "^## \\[" ver "\\]" { flag = 1; next } $0 ~ "^## \\[" ver "\\]" { flag = 1; next }
/^## \[/ { flag = 0 } /^## \[/ { flag = 0 }
flag' CHANGELOG.md > "$OUT" flag' CHANGELOG.md > "$OUT"
# Trim leading blank lines (same as the pipeline did). # Trim leading blank lines (same as the pipeline did).
sed -i -e '/./,$!d' "$OUT" sed -i -e '/./,$!d' "$OUT"
if [ ! -s "$OUT" ]; then [ -s "$OUT" ] || echo "See CHANGELOG.md for $VERSION." > "$OUT"
echo "See CHANGELOG.md for $VERSION." > "$OUT"
fi fi
CHARS=$(wc -m < "$OUT" | tr -d ' ') CHARS=$(wc -m < "$OUT" | tr -d ' ')
echo "Wrote $OUT (version $VERSION, code $VERSION_CODE, ${CHARS} chars)" echo "$ACTION $OUT (version $VERSION, code $VERSION_CODE, ${CHARS} chars)"
if [ "$CHARS" -gt 500 ]; then if [ "$CHARS" -gt "$LIMIT" ]; then
echo " note: >500 chars — F-Droid may truncate this changelog in-client." >&2 echo " warning: >${LIMIT} chars — Play rejects this and F-Droid truncates it." >&2
echo " Replace $OUT with a hand-written summary under ${LIMIT} chars." >&2
fi fi