build: use git commit count for versionCode (#3233)

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
James Rich
2025-09-28 14:49:12 -05:00
committed by GitHub
parent ac51c1b9f6
commit c5da2c4e13
5 changed files with 67 additions and 84 deletions

View File

@@ -45,13 +45,21 @@ jobs:
id: get_version_name
run: echo "APP_VERSION_NAME=$(echo ${GITHUB_REF_NAME#v} | sed 's/-.*//')" >> $GITHUB_OUTPUT
- name: Calculate Version Code from Epoch
- name: Extract VERSION_CODE_OFFSET from config.properties
id: get_version_code_offset
run: |
OFFSET=$(grep '^VERSION_CODE_OFFSET=' config.properties | cut -d'=' -f2)
echo "VERSION_CODE_OFFSET=$OFFSET" >> $GITHUB_OUTPUT
- name: Calculate Version Code from Git Commit Count
id: calculate_version_code
# We use epoch minutes to ensure a unique, always-incrementing version code.
# This is compatible with our release strategy of tagging the same commit for different
# channels (internal, closed, open, prod), as each build needs a unique code.
# This will overflow Integer.MAX_VALUE in the year 6052, hopefully we'll have moved on by then.
run: echo "versionCode=$(( $(date +%s) / 60 ))" >> $GITHUB_OUTPUT
run: |
COMMIT_COUNT=$(git rev-list --count HEAD)
OFFSET=${{ steps.get_version_code_offset.outputs.VERSION_CODE_OFFSET }}
VERSION_CODE=$((COMMIT_COUNT + OFFSET))
echo "versionCode=$VERSION_CODE" >> $GITHUB_OUTPUT
shell: bash
# This matches the reproducible versionCode strategy: versionCode = git commit count + offset
release-google:
runs-on: ubuntu-latest

View File

@@ -15,7 +15,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import com.geeksville.mesh.buildlogic.Configs
import com.geeksville.mesh.buildlogic.GitVersionValueSource
import java.io.FileInputStream
import java.util.Properties
@@ -44,10 +43,16 @@ if (keystorePropertiesFile.exists()) {
FileInputStream(keystorePropertiesFile).use { keystoreProperties.load(it) }
}
val configPropertiesFile = rootProject.file("config.properties")
val configProperties = Properties()
if (configPropertiesFile.exists()) {
FileInputStream(configPropertiesFile).use { configProperties.load(it) }
}
android {
namespace = "com.geeksville.mesh"
// Assuming Configs object is available (e.g., from buildSrc)
compileSdk = Configs.COMPILE_SDK
namespace = configProperties.getProperty("APPLICATION_ID")
compileSdk = configProperties.getProperty("COMPILE_SDK").toInt()
signingConfigs {
create("release") {
@@ -58,25 +63,26 @@ android {
}
}
defaultConfig {
applicationId = Configs.APPLICATION_ID
minSdk = Configs.MIN_SDK
targetSdk = Configs.TARGET_SDK
applicationId = configProperties.getProperty("APPLICATION_ID")
minSdk = configProperties.getProperty("MIN_SDK").toInt()
targetSdk = configProperties.getProperty("TARGET_SDK").toInt()
// Prioritize injected props, then ENV, then fallback to git commit count
val vcOffset = configProperties.getProperty("VERSION_CODE_OFFSET")?.toInt() ?: 0
println("Version code offset: $vcOffset")
versionCode =
(
project.findProperty("android.injected.version.code")?.toString()?.toInt()
?: System.getenv("VERSION_CODE")?.toInt()
?: gitVersionProvider.get().toInt() // Restored GitVersionValueSource fallback
?: (gitVersionProvider.get().toInt() + vcOffset)
)
versionName =
(
project.findProperty("android.injected.version.name")?.toString()
?: System.getenv("VERSION_NAME")
?: Configs.VERSION_NAME_BASE // Restored Configs.VERSION_NAME_BASE fallback
?: configProperties.getProperty("VERSION_NAME_BASE")
)
buildConfigField("String", "MIN_FW_VERSION", "\"${Configs.MIN_FW_VERSION}\"") // Used Configs
buildConfigField("String", "ABS_MIN_FW_VERSION", "\"${Configs.ABS_MIN_FW_VERSION}\"") // Used Configs
buildConfigField("String", "MIN_FW_VERSION", "\"${configProperties.getProperty("MIN_FW_VERSION")}\"")
buildConfigField("String", "ABS_MIN_FW_VERSION", "\"${configProperties.getProperty("ABS_MIN_FW_VERSION")}\"")
// We have to list all translated languages here,
// because some of our libs have bogus languages that google play
// doesn't like and we need to strip them (gr)
@@ -152,12 +158,6 @@ secrets {
propertiesFileName = "secrets.properties"
}
datadog {
// if (!gradle.startParameter.taskNames.any { it.contains("fdroid", ignoreCase = true) }) {
// composeInstrumentation = InstrumentationMode.AUTO
// }
}
// workaround for https://github.com/google/ksp/issues/1590
androidComponents {
onVariants(selector().withBuildType("release")) { variant ->

View File

@@ -1,58 +0,0 @@
/*
* Copyright (c) 2025 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.buildlogic
/*
* Copyright (c) 2025 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
object Configs {
const val APPLICATION_ID = "com.geeksville.mesh"
const val MIN_SDK = 26
const val TARGET_SDK = 36
const val COMPILE_SDK = 36
/**
* This version string serves as a fallback for local development environments
* where the version cannot be automatically determined from Git tags (e.g., a fresh clone
* without fetching tags, or if Git is not accessible).
*
* On CI servers, the version is dynamically generated based on the current Git tag.
*
* Before creating a new release, this value should be updated manually
* to reflect the version number of the Git tag that will be created for that release.
* @see [RELEASE_PROCESS.md]
*/
const val VERSION_NAME_BASE = "2.7.1"
const val MIN_FW_VERSION = "2.5.14" // Minimum device firmware version supported by this app
const val ABS_MIN_FW_VERSION = "2.3.15" // Minimum device firmware version supported by this app
}

View File

@@ -53,8 +53,7 @@ abstract class GitVersionValueSource : ValueSource<String, GitVersionValueSource
}
output.toString().trim()
} catch (e: Exception) {
// Fallback to timestamp if git command fails (e.g., in a shallow clone)
(System.currentTimeMillis() / 1000).toString()
throw RuntimeException("Failed to determine git commit count for versionCode. Ensure you have a full git history (not a shallow clone) and .git is present.\nOriginal error: ${e.message}", e)
}
}
}

34
config.properties Normal file
View File

@@ -0,0 +1,34 @@
#
# Copyright (c) 2025 Meshtastic LLC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# Offset for reproducible versionCode calculation (see RELEASE_PROCESS.md)
VERSION_CODE_OFFSET=29314197
# Application and SDK versions
APPLICATION_ID=com.geeksville.mesh
MIN_SDK=26
TARGET_SDK=36
COMPILE_SDK=36
# Base version name for local development and fallback
# On CI, this is overridden by the Git tag
# Before a release, update this to the new Git tag version
VERSION_NAME_BASE=2.7.1
# Minimum firmware versions supported by this app
MIN_FW_VERSION=2.5.14
ABS_MIN_FW_VERSION=2.3.15