Bootstrap Pilgrims of Katan: rebrand, Gitea CI and OTA
Build and Release APK / Build APK and publish release (push) Canceled after 0s

Import of ProLibertateGames (upstream main, GPL-3.0) rebranded for
Wallacenet and repointed at git.wallacenet.ca.

- Identity: applicationId ca.wallacenet.pilgrimsofkatan (+ .dev for the dev
  channel), launcher names "Pilgrims of Katan" / "Pilgrims of Katan DEV",
  neutral hexagon branding replacing the Wallace tartan. Uncial Antiqua keeps
  its OFL licence, and the GPL-3.0 LICENSE plus upstream attribution stay.
- OTA: Updater.kt now reads this repo's own Gitea releases
  (/api/v1/repos/devadmin/PilgrimsOfKatan/releases...) and BuildConfig.
  OTA_ENABLED is on; Gitea answers the same JSON shape the code already parsed.
- Build numbers: versionCode = CI run number + plgVersionRunOffset (1000),
  with the tag and versionName derived from the same figure. The offset is
  permanent, because Gitea Actions restarts run numbers at 1 and a reset would
  otherwise make Android reject the next build as a downgrade.
- CI: ci.yml publishes a dev prerelease from dev, release.yml a production
  release from main, both through scripts/publish-release.sh (Gitea REST API,
  runnable by hand until an Actions runner is registered).
- Docs: docs/CI.md records the channel, numbering and runner decisions;
  docs/README.md seeds the per-game RULES-* conventions; CLAUDE.md carries the
  agent ground rules.

Verified: ./gradlew assembleDebug and testDebugUnitTest green on JDK 17 /
compileSdk 34, both variants stamped, installing side by side under the new
identity.

Co-Authored-By: Paperclip <[email protected]>
This commit is contained in:
adrianoftyriel
2026-10-13 22:03:27 +00:00
co-authored by Paperclip
parent d27c2db894
commit fad4778ad8
32 changed files with 760 additions and 773 deletions
+49 -26
View File
@@ -16,6 +16,20 @@ val buildChannel = System.getenv("PLG_CHANNEL").orEmpty()
val runNumber = (System.getenv("GITHUB_RUN_NUMBER") ?: "").toIntOrNull() ?: 0
val stampVersion = buildChannel.isNotEmpty() && runNumber > 0
// The fixed floor every stamped build number is measured from, in
// gradle.properties. Gitea Actions restarts its run numbers at 1 for each
// workflow, so an unstamped build (versionCode 1) and the first release of a
// fresh instance would otherwise collide — and once a phone has installed
// versionCode N, Android refuses anything smaller as a downgrade. Adding a
// permanent offset is what makes "the counter never resets" true by
// construction: it is read from one place, it never changes, and the tag,
// versionName and versionCode all get the same number (see docs/CI.md).
val runOffset = (project.findProperty("plgVersionRunOffset") as String?)?.toIntOrNull() ?: 0
// The stamped build number: what the release tag, the versionName and the
// versionCode are all named after.
val buildNumber = runNumber + runOffset
// The version series, from gradle.properties. Both workflows read the same
// property when they name a release tag, so the tag and the APK inside it
// cannot disagree about which series they belong to.
@@ -26,35 +40,40 @@ val versionSeries = (project.findProperty("plgVersionSeries") as String?) ?: "1.
//
// This one flag drives everything that makes a dev build a separate app rather
// than a replacement for the production one — its own applicationId, its own
// launcher name, and the hunting sett in place of the clan sett. They have to
// move together: a dev package wearing the production name and colours is
// exactly the confusion having both installed is meant to avoid.
// launcher name, and its own brand colour. They have to move together: a dev
// package wearing the production name and colours is exactly the confusion
// having both installed is meant to avoid.
val isDevBuild = buildChannel != "production"
android {
// Deliberately left at the upstream source package: R and BuildConfig stay
// in org.prolibertate.games for both channels, so no source file has to
// care which applicationId it ended up installed as. The *installed*
// identity is the applicationId below — that is what the rebrand changes
// (WALA-118), not the JVM package names.
namespace = "org.prolibertate.games"
compileSdk = 34
defaultConfig {
// A dev build installs under its own package, so a dev copy and a
// production copy can sit side by side on one device instead of one
// replacing the other. The namespace above is deliberately left alone:
// R and BuildConfig stay in org.prolibertate.games for both, so no
// source has to care which package it ended up installed as.
applicationId = if (isDevBuild) "org.prolibertate.games.dev" else "org.prolibertate.games"
// replacing the other.
applicationId = if (isDevBuild) "ca.wallacenet.pilgrimsofkatan.dev" else "ca.wallacenet.pilgrimsofkatan"
minSdk = 24
targetSdk = 34
// The -dev suffix in versionName is what the installed app reads to
// know its own channel, so it must survive into the shipped APK. It
// tracks isDevBuild rather than the stamp alone, so an unstamped local
// build cannot end up claiming a channel its applicationId contradicts.
// versionCode stays the run number and nothing else, so it keeps
// versionCode is the stamped build number and nothing else, so it keeps
// climbing across a change of series: bumping 1.0 to 1.1 must not make
// an update look like a downgrade to Android.
versionCode = if (stampVersion) runNumber else 1
// an update look like a downgrade to Android. An unstamped build is 1,
// below every release, which is the honest answer for a build nobody
// stamped.
versionCode = if (stampVersion) buildNumber else 1
versionName = when {
stampVersion && buildChannel == "production" -> "$versionSeries.$runNumber"
stampVersion -> "$versionSeries.$runNumber-dev"
stampVersion && buildChannel == "production" -> "$versionSeries.$buildNumber"
stampVersion -> "$versionSeries.$buildNumber-dev"
isDevBuild -> "$versionSeries.0-dev"
else -> "$versionSeries.0"
}
@@ -64,23 +83,27 @@ android {
resValue(
"string",
"app_name",
if (isDevBuild) "Pro Libertate Games DEV" else "Pro Libertate Games",
if (isDevBuild) "Pilgrims of Katan DEV" else "Pilgrims of Katan",
)
// The one colour that separates the two setts: Wallace red for
// production, Wallace Hunting green for dev. The icon vectors reference
// this rather than a literal, and Tartan.kt picks the matching Compose
// colour off DEV_BUILD below — the two have to stay in step or the
// launcher icon and the splash it opens on would be different cloth.
resValue("color", "tartan_field", if (isDevBuild) "#1E7A3C" else "#E01B24")
// Shades of the same field, so a launch does not flash the wrong colour
// before the tartan is drawn: splash_background is held behind the
// window for that instant, ic_launcher_background is the icon's flat
// fallback.
resValue("color", "splash_background", if (isDevBuild) "#0D2E17" else "#4A0B10")
resValue("color", "ic_launcher_background", if (isDevBuild) "#145C2D" else "#B3121B")
// The one colour that separates the two installs: slate blue on
// production, deep green on dev. The launcher icon and the splash are
// both built from it, so the drawer shows at a glance which of the two
// copies is which — the two have to stay in step or the icon and the
// splash it opens on would be different brands.
resValue("color", "brand_field", if (isDevBuild) "#2A6B54" else "#2B4A78")
// A darker shade of the same hue, held behind the window for the
// instant before the splash draws, so a launch never flashes the wrong
// colour.
resValue("color", "splash_background", if (isDevBuild) "#153B2F" else "#182A44")
buildConfigField("boolean", "DEV_BUILD", isDevBuild.toString())
// In-app OTA updates, pointed at this project's own Gitea releases
// (docs/CI.md). True in this build — the channel exists. Flipping it
// false is the kill switch: every check then reports that and fetches
// nothing, with the machinery and its tests still compiled.
buildConfigField("boolean", "OTA_ENABLED", "true")
}
signingConfigs {
@@ -108,7 +131,7 @@ android {
buildFeatures {
compose = true
// For DEV_BUILD, which is how the Compose tartan picks its sett.
// For DEV_BUILD, which is how the Compose splash picks its brand colour.
buildConfig = true
}