ci: the full release pipeline, Codeberg-canonical from commit one
Both siblings' pipelines are near-identical; the real difference between them is which forge is canonical. This is Agendula's spine — it pushes the tag to Codeberg itself and flags pre-1.0 releases as pre-releases — with Calendula's `play` job grafted on unchanged. Taking Agendula's spine means there is no Gitea-canonical phase to migrate out of later, which is the one thing Agendula had to unwind. The Codeberg publish step stays NOT continue-on-error, inherited that way deliberately: in Agendula it reported green through five consecutive releases while never once publishing, which is how a crash-fix release reached F-Droid but not the users who needed it. Comments that recount that history now name Agendula, so an inherited scar isn't misread as ours. The `play` job runs last and isolated, and skips cleanly until PLAY_SERVICE_ACCOUNT_JSON exists — so it stays dormant through the whole pre-1.0 run, which is the correct behaviour anyway. Templates, the contributing guide and verify-release.sh are rewritten for this app's domain rather than renamed: the architectural rule here is that Room types stay in the data layer, and the on-device release check is an alarm that survives a lock screen and a reboot, not a task list that loads. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L94fydiJC37LtxVusNQBDy
This commit is contained in:
co-authored by
Claude Opus 5
parent
5ddec0f248
commit
97ed6cf6f5
@@ -0,0 +1,7 @@
|
||||
# fastlane is used in this repo ONLY as a Google Play Developer API client
|
||||
# (see fastlane/Fastfile). It never builds and never signs.
|
||||
|
||||
# Reconstructed in CI from the PLAY_SERVICE_ACCOUNT_JSON secret; gitignored.
|
||||
json_key_file(ENV["SUPPLY_JSON_KEY"] || "play-service-account.json")
|
||||
|
||||
package_name("de.jeanlucmakiola.clockula")
|
||||
@@ -0,0 +1,87 @@
|
||||
# Google Play publishing only.
|
||||
#
|
||||
# Building and signing are deliberately NOT fastlane's job: release.yaml drives
|
||||
# Gradle directly so the release build stays F-Droid-reproducible (`vcsInfo`,
|
||||
# `dependenciesInfo` and the AGP metadata block are disabled in
|
||||
# app/build.gradle.kts and guarded by scripts/check_reproducible_release.sh).
|
||||
# Interposing fastlane there would add a layer that can inject Gradle flags into
|
||||
# the one build whose byte-for-byte output is verified by a third party.
|
||||
#
|
||||
# What fastlane IS here for is `supply` — the Play Developer API client — because
|
||||
# the store listing already lives in fastlane/metadata/android, which the
|
||||
# official F-Droid repo harvests from the tagged source tree. One metadata tree,
|
||||
# two stores.
|
||||
|
||||
default_platform(:android)
|
||||
|
||||
# fastlane runs a lane body with the working directory set to `fastlane/`, not
|
||||
# the project root, so a relative artifact path from the caller has to be
|
||||
# resolved explicitly. Absolute paths pass through untouched.
|
||||
def project_path(path)
|
||||
File.expand_path(path, File.expand_path("..", FastlaneCore::FastlaneFolder.path || "."))
|
||||
end
|
||||
|
||||
platform :android do
|
||||
desc "Upload an already-built, already-signed AAB to Play"
|
||||
lane :deploy do |options|
|
||||
aab = project_path(options[:aab] || "app/build/outputs/bundle/release/app-release.aab")
|
||||
UI.user_error!("AAB not found at #{aab}") unless File.exist?(aab)
|
||||
|
||||
supply(
|
||||
aab: aab,
|
||||
track: options[:track] || "production",
|
||||
release_status: options[:release_status] || "completed",
|
||||
|
||||
# The APK belongs to F-Droid and the Codeberg download; Play only ever
|
||||
# gets the bundle. Never let the uploader reach for the other artifact.
|
||||
skip_upload_apk: true,
|
||||
|
||||
# Listing text is synced deliberately via the `listing` lane, not on every
|
||||
# release. Overwriting a live listing by accident triggers a Play policy
|
||||
# review, which is not a quick revert.
|
||||
skip_upload_metadata: true,
|
||||
|
||||
# "What's New" DOES track every release.
|
||||
# scripts/sync_changelog_to_fastlane.sh writes
|
||||
# fastlane/metadata/android/en-US/changelogs/<versionCode>.txt from
|
||||
# CHANGELOG.md, so Play shows exactly the text F-Droid does.
|
||||
skip_upload_changelogs: false,
|
||||
|
||||
# See the `listing` lane for why the committed images can't go to Play yet.
|
||||
skip_upload_images: true,
|
||||
skip_upload_screenshots: true,
|
||||
|
||||
# Dry run: validate the edit against the API and roll it back instead of
|
||||
# committing it. Used for the first end-to-end rehearsal.
|
||||
validate_only: options[:dry_run].to_s == "true",
|
||||
)
|
||||
end
|
||||
|
||||
desc "Sync the store listing text (and, once the assets qualify, the images)"
|
||||
lane :listing do |options|
|
||||
# Deliberate and manual: `bundle exec fastlane listing`. Not wired into the
|
||||
# release pipeline.
|
||||
#
|
||||
# Images stay off by default because the committed assets do not satisfy
|
||||
# Play today, even though F-Droid accepts all of them:
|
||||
#
|
||||
# * phoneScreenshots are 1280x2856. Play caps the long edge at twice the
|
||||
# short edge (2560 here), so every screenshot is rejected.
|
||||
# * those PNGs are 32-bit RGBA. Play wants 24-bit PNG, no alpha.
|
||||
# * icon.png is 512x512 but 24-bit RGB. Play's icon wants 32-bit PNG.
|
||||
# * there is no featureGraphic.png. Play requires one, exactly 1024x500.
|
||||
#
|
||||
# Until that is fixed, the Play listing's graphics are managed by hand in the
|
||||
# console. Pass images:true once the assets qualify.
|
||||
upload_images = options[:images].to_s == "true"
|
||||
|
||||
supply(
|
||||
skip_upload_aab: true,
|
||||
skip_upload_apk: true,
|
||||
skip_upload_metadata: false,
|
||||
skip_upload_changelogs: true,
|
||||
skip_upload_images: !upload_images,
|
||||
skip_upload_screenshots: !upload_images,
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
Clockula is a Material 3 Expressive clock app for Android: alarms, timers, a stopwatch and a world clock, in one app that looks like it belongs on a modern phone.
|
||||
|
||||
It is the third app in the Floret family, after Calendula (calendar) and Agendula (tasks).
|
||||
|
||||
<b>Alarms that actually ring</b>
|
||||
|
||||
An alarm app is only worth having if you can trust it. Clockula schedules alarms the way Android intends — as real alarm clocks, exempt from battery saving, visible to the system lock screen and status bar. When something on your device would stop an alarm from ringing, Clockula tells you which setting it is and takes you there, instead of failing silently at 7am.
|
||||
|
||||
<b>Everything you expect</b>
|
||||
|
||||
• Alarms with repeat schedules, snooze, your own ringtones and per-alarm settings
|
||||
• Several timers at once, with controls from the notification shade
|
||||
• A stopwatch with laps
|
||||
• World clocks over the standard IANA time-zone database
|
||||
|
||||
A running timer or stopwatch stays reachable from every tab, so you never lose track of one.
|
||||
|
||||
<b>Open, and yours</b>
|
||||
|
||||
Clockula speaks Android's standard alarm intents, so your assistant and your automation apps can set alarms and timers in it like any other clock app. Your alarms, timers and clocks export to a documented JSON file whenever you want them, because data you cannot take with you is not really yours.
|
||||
|
||||
No account. No tracking. No ads. Free software under the MIT licence.
|
||||
@@ -0,0 +1 @@
|
||||
Alarms, timers, stopwatch and world clock. Material 3 Expressive, open source, no account.
|
||||
@@ -0,0 +1 @@
|
||||
Clockula
|
||||
Reference in New Issue
Block a user