Merge pull request #11: move to the 1.1 series
Verified green on the feature branch before merging: build, unit tests and Android lint (ci.yml run 59).
This commit is contained in:
@@ -34,7 +34,7 @@ jobs:
|
|||||||
# Stamp the APK as a dev-channel build exactly when it is a build of the
|
# Stamp the APK as a dev-channel build exactly when it is a build of the
|
||||||
# dev branch, which is exactly when it can be published below. Pull
|
# dev branch, which is exactly when it can be published below. Pull
|
||||||
# request builds run against refs/pull/N/merge, so they stay unstamped at
|
# request builds run against refs/pull/N/merge, so they stay unstamped at
|
||||||
# 1.0.0-dev: they are never published and must not claim a channel
|
# <series>.0-dev: they are never published and must not claim a channel
|
||||||
# version.
|
# version.
|
||||||
#
|
#
|
||||||
# This condition has to stay in step with the publish steps' own. Stamping
|
# This condition has to stay in step with the publish steps' own. Stamping
|
||||||
@@ -96,7 +96,12 @@ jobs:
|
|||||||
if: github.ref == 'refs/heads/dev'
|
if: github.ref == 'refs/heads/dev'
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
version="v1.0.${{ github.run_number }}-dev"
|
# The series comes from gradle.properties, which is the same file the
|
||||||
|
# build read when it stamped the APK — so the tag and what is inside
|
||||||
|
# it cannot name different versions.
|
||||||
|
series="$(sed -n 's/^plgVersionSeries=//p' gradle.properties)"
|
||||||
|
test -n "$series"
|
||||||
|
version="v${series}.${{ github.run_number }}-dev"
|
||||||
src="app/build/outputs/apk/debug/app-debug.apk"
|
src="app/build/outputs/apk/debug/app-debug.apk"
|
||||||
dest="ProLibertateGames-${version}.apk"
|
dest="ProLibertateGames-${version}.apk"
|
||||||
cp "$src" "$dest"
|
cp "$src" "$dest"
|
||||||
|
|||||||
@@ -49,7 +49,12 @@ jobs:
|
|||||||
id: stage
|
id: stage
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
version="v1.0.${{ github.run_number }}"
|
# The series comes from gradle.properties, which is the same file the
|
||||||
|
# build read when it stamped the APK — so the tag and what is inside
|
||||||
|
# it cannot name different versions.
|
||||||
|
series="$(sed -n 's/^plgVersionSeries=//p' gradle.properties)"
|
||||||
|
test -n "$series"
|
||||||
|
version="v${series}.${{ github.run_number }}"
|
||||||
src="app/build/outputs/apk/debug/app-debug.apk"
|
src="app/build/outputs/apk/debug/app-debug.apk"
|
||||||
dest="ProLibertateGames-${version}.apk"
|
dest="ProLibertateGames-${version}.apk"
|
||||||
cp "$src" "$dest"
|
cp "$src" "$dest"
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ Skipping step 4 leaves a branch whose head was never built and no release.
|
|||||||
Both long-lived branches publish, so a merge is a release, not just an
|
Both long-lived branches publish, so a merge is a release, not just an
|
||||||
integration:
|
integration:
|
||||||
|
|
||||||
- **`dev`** → `ci.yml` publishes a `v1.0.N-dev` **prerelease**, offered by the
|
- **`dev`** → `ci.yml` publishes a `v<series>.N-dev` **prerelease**, offered by the
|
||||||
in-app updater to anyone on the Dev channel.
|
in-app updater to anyone on the Dev channel.
|
||||||
- **`main`** → `release.yml` publishes a **production** release, which the
|
- **`main`** → `release.yml` publishes a **production** release, which the
|
||||||
updater installs for everyone on the Production channel.
|
updater installs for everyone on the Production channel.
|
||||||
|
|||||||
@@ -165,9 +165,10 @@ production package instead.
|
|||||||
|
|
||||||
- `.github/workflows/ci.yml` — builds, tests and lints on `dev` and on pull
|
- `.github/workflows/ci.yml` — builds, tests and lints on `dev` and on pull
|
||||||
requests into `dev` or `main`. Its APK artifact is a dev build, versioned
|
requests into `dev` or `main`. Its APK artifact is a dev build, versioned
|
||||||
`1.0.0-dev`.
|
`<series>.0-dev` — the series being whatever `plgVersionSeries` says in
|
||||||
|
`gradle.properties`, currently **1.1**.
|
||||||
- `.github/workflows/release.yml` — on push to `main`, builds the APK and
|
- `.github/workflows/release.yml` — on push to `main`, builds the APK and
|
||||||
publishes it as a GitHub Release tagged `v1.0.<run-number>`. The in-app updater
|
publishes it as a GitHub Release tagged `v<series>.<run-number>`. The in-app updater
|
||||||
reads that tag, which is why the APK's `versionCode` is the same run number.
|
reads that tag, which is why the APK's `versionCode` is the same run number.
|
||||||
|
|
||||||
### Installing without the app
|
### Installing without the app
|
||||||
@@ -186,14 +187,34 @@ prereleases by design, and that is exactly what keeps a production install from
|
|||||||
being handed a dev build. Dev builds are reached through the in-app updater with
|
being handed a dev build. Dev builds are reached through the in-app updater with
|
||||||
the channel set to dev, or from the releases page.
|
the channel set to dev, or from the releases page.
|
||||||
|
|
||||||
|
### The version series
|
||||||
|
|
||||||
|
A version is **`<series>.<run number>`**. The series is set by hand, once, in
|
||||||
|
`gradle.properties`:
|
||||||
|
|
||||||
|
```properties
|
||||||
|
plgVersionSeries=1.1
|
||||||
|
```
|
||||||
|
|
||||||
|
Both workflows read that same property when they name a release tag, and the
|
||||||
|
build reads it when it stamps the APK, so the tag and what is inside it cannot
|
||||||
|
name different versions. Bumping a series is a one-line change to that file and
|
||||||
|
nothing else.
|
||||||
|
|
||||||
|
The number after it is the CI run number and keeps climbing on its own, which is
|
||||||
|
what makes a series bump safe: `versionCode` is the run number *alone*, so
|
||||||
|
going from 1.0 to 1.1 never looks like a downgrade to Android and never
|
||||||
|
interrupts an OTA update. The series is a name for people; the run number is
|
||||||
|
what the machines compare.
|
||||||
|
|
||||||
### Update channels
|
### Update channels
|
||||||
|
|
||||||
Both pipelines publish, to two separate channels:
|
Both pipelines publish, to two separate channels:
|
||||||
|
|
||||||
| Channel | Published by | Tag | Marked |
|
| Channel | Published by | Tag | Marked |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Production | `release.yml`, push to `main` | `v1.0.<n>` | release |
|
| Production | `release.yml`, push to `main` | `v<series>.<n>` | release |
|
||||||
| Dev | `ci.yml`, any build of `dev` | `v1.0.<n>-dev` | prerelease |
|
| Dev | `ci.yml`, any build of `dev` | `v<series>.<n>-dev` | prerelease |
|
||||||
|
|
||||||
Dev builds are published as **prereleases** deliberately: GitHub's "latest
|
Dev builds are published as **prereleases** deliberately: GitHub's "latest
|
||||||
release" endpoint skips prereleases, so a production-channel install can never
|
release" endpoint skips prereleases, so a production-channel install can never
|
||||||
|
|||||||
+12
-4
@@ -16,6 +16,11 @@ val buildChannel = System.getenv("PLG_CHANNEL").orEmpty()
|
|||||||
val runNumber = (System.getenv("GITHUB_RUN_NUMBER") ?: "").toIntOrNull() ?: 0
|
val runNumber = (System.getenv("GITHUB_RUN_NUMBER") ?: "").toIntOrNull() ?: 0
|
||||||
val stampVersion = buildChannel.isNotEmpty() && runNumber > 0
|
val stampVersion = buildChannel.isNotEmpty() && runNumber > 0
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
val versionSeries = (project.findProperty("plgVersionSeries") as String?) ?: "1.0"
|
||||||
|
|
||||||
// Anything that is not an explicit production build is a dev build: ci.yml
|
// Anything that is not an explicit production build is a dev build: ci.yml
|
||||||
// stamps "dev", and a local build with nothing set counts as dev too.
|
// stamps "dev", and a local build with nothing set counts as dev too.
|
||||||
//
|
//
|
||||||
@@ -43,12 +48,15 @@ android {
|
|||||||
// know its own channel, so it must survive into the shipped APK. It
|
// know its own channel, so it must survive into the shipped APK. It
|
||||||
// tracks isDevBuild rather than the stamp alone, so an unstamped local
|
// tracks isDevBuild rather than the stamp alone, so an unstamped local
|
||||||
// build cannot end up claiming a channel its applicationId contradicts.
|
// build cannot end up claiming a channel its applicationId contradicts.
|
||||||
|
// versionCode stays the run 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
|
versionCode = if (stampVersion) runNumber else 1
|
||||||
versionName = when {
|
versionName = when {
|
||||||
stampVersion && buildChannel == "production" -> "1.0.$runNumber"
|
stampVersion && buildChannel == "production" -> "$versionSeries.$runNumber"
|
||||||
stampVersion -> "1.0.$runNumber-dev"
|
stampVersion -> "$versionSeries.$runNumber-dev"
|
||||||
isDevBuild -> "1.0.0-dev"
|
isDevBuild -> "$versionSeries.0-dev"
|
||||||
else -> "1.0.0"
|
else -> "$versionSeries.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
// The launcher label. With both copies on the phone the app drawer shows
|
// The launcher label. With both copies on the phone the app drawer shows
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ private const val DEV_SUFFIX = "-dev"
|
|||||||
/**
|
/**
|
||||||
* Over-the-air updates from the repository's GitHub Releases.
|
* Over-the-air updates from the repository's GitHub Releases.
|
||||||
*
|
*
|
||||||
* Release tags are v1.0.<run-number> and the APK's versionCode is that same run
|
* Release tags are v<series>.<run-number> and the APK's versionCode is that same run
|
||||||
* number, so comparing the two is enough to tell whether a newer build exists.
|
* number, so comparing the two is enough to tell whether a newer build exists.
|
||||||
* The repository's releases must be publicly downloadable — no token is
|
* The repository's releases must be publicly downloadable — no token is
|
||||||
* embedded in the app, and GitHub blocks anonymous access to private assets.
|
* embedded in the app, and GitHub blocks anonymous access to private assets.
|
||||||
@@ -112,7 +112,9 @@ class Updater(private val activity: Activity) {
|
|||||||
|
|
||||||
private fun toRelease(json: JSONObject): Release? {
|
private fun toRelease(json: JSONObject): Release? {
|
||||||
val tag = json.optString("tag_name").ifBlank { return null }
|
val tag = json.optString("tag_name").ifBlank { return null }
|
||||||
// Tags are v1.0.<n> or v1.0.<n>-dev; the run number is the trailing part.
|
// Tags are v<series>.<n>, with -dev on a prerelease. Only the trailing
|
||||||
|
// run number is read: the series is a name for people and changing it
|
||||||
|
// must not make an older build look newer.
|
||||||
val versionCode = tag.substringAfterLast('.')
|
val versionCode = tag.substringAfterLast('.')
|
||||||
.removeSuffix(DEV_SUFFIX)
|
.removeSuffix(DEV_SUFFIX)
|
||||||
.toIntOrNull()
|
.toIntOrNull()
|
||||||
|
|||||||
@@ -11,3 +11,15 @@ kotlin.code.style=official
|
|||||||
|
|
||||||
# Only build the resources needed for the configuration being built.
|
# Only build the resources needed for the configuration being built.
|
||||||
android.nonTransitiveRClass=true
|
android.nonTransitiveRClass=true
|
||||||
|
|
||||||
|
# The version series every build and every release tag is named for: an APK is
|
||||||
|
# <series>.<run number>, a production tag is v<series>.<n> and a dev tag adds
|
||||||
|
# -dev. It lives here rather than in the build file because the workflows have
|
||||||
|
# to name the tag as well, and they read it straight out of this file — three
|
||||||
|
# copies of "1.1" would be three chances for a release to be tagged one thing
|
||||||
|
# and built as another.
|
||||||
|
#
|
||||||
|
# Only the series is set by hand. The number after it is the CI run number, so
|
||||||
|
# it keeps climbing on its own and an APK's versionCode never goes backwards
|
||||||
|
# when this changes.
|
||||||
|
plgVersionSeries=1.1
|
||||||
|
|||||||
Reference in New Issue
Block a user