Versión de Android del proyecto de git describe automáticamente con Android Studio/Gradle
android-studio auto-versioning (8)
Aquí hay otra solución que requiere declaraciones en lugar de funciones para acceder a la línea de comandos. Advertencia: * nix solo solución
def gitSha = ''git rev-parse --short HEAD''.execute([], project.rootDir).text.trim()
// Auto-incrementing commit count based on counting commits to master (Build #543)
def commitCount = Integer.parseInt(''git rev-list master --count''.execute([], project.rootDir).text.trim())
// I want to use git tags as my version names (1.2.2)
def gitCurrentTag = ''git describe --tags --abbrev=0''.execute([], project.rootDir).text.trim()
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.some.app"
minSdkVersion 16
targetSdkVersion 22
versionCode commitCount
versionName gitCurrentTag
buildConfigField "String", "GIT_SHA", "/"${gitSha}/""
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile(''proguard-android.txt''), ''proguard-rules.pro''
}
}
}
He buscado mucho, pero probablemente debido a la novedad de Android Studio y Gradle, no he encontrado ninguna descripción de cómo hacer esto. Quiero básicamente hacer exactamente lo que se describe en esta publicación , pero con Android Studio, Gradle y Windows en lugar de Eclipse y Linux.
Coloque lo siguiente en su archivo build.gradle para el proyecto. No es necesario modificar el manifiesto directamente: Google proporcionó los enganches necesarios en su configuración.
def getVersionCode = { ->
try {
def code = new ByteArrayOutputStream()
exec {
commandLine ''git'', ''tag'', ''--list''
standardOutput = code
}
return code.toString().split("/n").size()
}
catch (ignored) {
return -1;
}
}
def getVersionName = { ->
try {
def stdout = new ByteArrayOutputStream()
exec {
commandLine ''git'', ''describe'', ''--tags'', ''--dirty''
standardOutput = stdout
}
return stdout.toString().trim()
}
catch (ignored) {
return null;
}
}
android {
defaultConfig {
versionCode getVersionCode()
versionName getVersionName()
}
}
Tenga en cuenta que si git no está instalado en la máquina, o hay algún otro error al obtener el nombre / código de la versión, de manera predeterminada aparecerá lo que está en su manifiesto de Android.
Después de ver la respuesta de moveaway00 y el comentario de Avinash R sobre esa respuesta , terminé usando esto:
apply plugin: ''android''
def getVersionCode = { ->
try {
def stdout = new ByteArrayOutputStream()
exec {
commandLine ''git'', ''rev-list'', ''--first-parent'', ''--count'', ''master''
standardOutput = stdout
}
return Integer.parseInt(stdout.toString().trim())
}
catch (ignored) {
return -1;
}
}
def getVersionName = { ->
try {
def stdout = new ByteArrayOutputStream()
exec {
commandLine ''git'', ''describe'', ''--tags'', ''--dirty''
standardOutput = stdout
}
return stdout.toString().trim()
}
catch (ignored) {
return null;
}
}
android {
defaultConfig {
versionCode getVersionCode()
versionName getVersionName()
}
}
He editado el código de moveaway00 para incluir también el comentario de Avinash R: el código de la versión ahora es el número de confirmaciones desde el master
, ya que se supone que es el código de la versión.
Tenga en cuenta que no necesité especificar el código de la versión y el nombre de la versión en el manifiesto, Gradle se encargó de ello.
En base a la respuesta de Léo Lam y mis explorations anteriores sobre la misma solución para hormiga, he ideado una solución puramente multiplataforma utilizando jgit:
( source original)
Archivo: git-version.gradle
buildscript {
dependencies {
//noinspection GradleDynamicVersion
classpath "org.eclipse.jgit:org.eclipse.jgit:4.1.1.+"
}
repositories {
jcenter()
}
}
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.revwalk.RevWalk
import org.eclipse.jgit.storage.file.FileRepositoryBuilder
import static org.eclipse.jgit.lib.Constants.MASTER
def git = Git.wrap(new FileRepositoryBuilder()
.readEnvironment()
.findGitDir()
.build())
ext.readVersionCode = {
def repo = git.getRepository()
def walk = new RevWalk(repo)
walk.withCloseable {
def head = walk.parseCommit(repo.getRef(MASTER).getObjectId())
def count = 0
while (head != null) {
count++
def parents = head.getParents()
if (parents != null && parents.length > 0) {
head = walk.parseCommit(parents[0])
} else {
head = null
}
}
walk.dispose()
println("using version name: $count")
return count
}
}
ext.readVersionName = {
def tag = git.describe().setLong(false).call()
def clean = git.status().call().isClean()
def version = tag + (clean ? '''' : ''-dirty'')
println("using version code: $version")
return version
}
El uso será:
apply from: ''git-version.gradle''
android {
...
defaultConfig {
...
versionCode readVersionCode()
versionName readVersionName()
...
}
...
}
Si puede ser de alguna ayuda, he configurado un script de Gradle de ejemplo que usa etiquetas de Git y describe a Git para lograr esto. Aquí está el código (también puedes encontrarlo here ).
1) Primero crea un archivo versioning.gradle que contenga:
import java.text.SimpleDateFormat
/**
* This Gradle script relies on Git tags to generate versions for your Android app
*
* - The Android version NAME is specified in the tag name and it''s 3 digits long (example of a valid tag name: "v1.23.45")
* If the tag name is not in a valid format, then the version name will be 0.0.0 and you should fix the tag.
*
* - The Android version CODE is calculated based on the version name (like this: (major * 1000000) + (minor * 10000) + (patch * 100))
*
* - The 4 digits version name is not "public" and the forth number represents the number of commits from the last tag (example: "1.23.45.178")
*
*/
ext {
getGitSha = {
return ''git rev-parse --short HEAD''.execute().text.trim()
}
getBuildTime = {
def df = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm''Z''")
df.setTimeZone(TimeZone.getTimeZone("UTC"))
return df.format(new Date())
}
/**
* Git describe returns the following: [GIT_TAG_NAME]-[BUILD_NUMBER]-[GIT_SHA]
*/
getAndroidGitDescribe = {
return "git -C ${rootDir} describe --tags --long".execute().text.trim()
}
/**
* Returns the current Git branch name
*/
getGitBranch = {
return "git rev-parse --abbrev-ref HEAD".execute().text.trim()
}
/**
* Returns the full version name in the format: MM.mm.pp.ccc
*
* The version name is retrieved from the tag name which must be in the format: vMM.mm.pp, example: "v1.23.45"
*/
getFullVersionName = {
def versionName = "0.0.0.0"
def (tag, buildNumber, gitSha) = getAndroidGitDescribe().tokenize(''-'')
if (tag && tag.startsWith("v")) {
def version = tag.substring(1)
if (version.tokenize(''.'').size() == 3) {
versionName = version + ''.'' + buildNumber
}
}
return versionName
}
/**
* Returns the Android version name
*
* Format "X.Y.Z", without commit number
*/
getAndroidVersionName = {
def fullVersionName = getFullVersionName()
return fullVersionName.substring(0, fullVersionName.lastIndexOf(''.''))
}
/**
* Returns the Android version code, deducted from the version name
*
* Integer value calculated from the version name
*/
getAndroidVersionCode = {
def (major, minor, patch) = getAndroidVersionName().tokenize(''.'')
(major, minor, patch) = [major, minor, patch].collect{it.toInteger()}
return (major * 1000000) + (minor * 10000) + (patch * 100)
}
/**
* Return a pretty-printable string containing a summary of the version info
*/
getVersionInfo = {
return "/nVERSION INFO:/n/tFull version name: " + getFullVersionName() +
"/n/tAndroid version name: " + getAndroidVersionName() +
"/n/tAndroid version code: " + getAndroidVersionCode() +
"/n/tAndroid Git branch: " + getGitBranch() +
"/n/tAndroid Git describe: " + getAndroidGitDescribe() +
"/n/tGit SHA: " + getGitSha() +
"/n/tBuild Time: " + getBuildTime() + "/n"
}
// Print version info at build time
println(getVersionInfo());
}
2) Luego edite su aplicación / build.gradle para usarla así:
import groovy.json.StringEscapeUtils;
apply plugin: ''com.android.application'' // << Apply the plugin
android {
configurations {
// ...
}
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
minSdkVersion 17
targetSdkVersion 22
applicationId "app.example.com"
versionCode getAndroidVersionCode() // << Use the plugin!
versionName getAndroidVersionName() // << Use the plugin!
// Build config constants
buildConfigField "String", "GIT_SHA", "/"${getGitSha()}/""
buildConfigField "String", "BUILD_TIME", "/"${getBuildTime()}/""
buildConfigField "String", "FULL_VERSION_NAME", "/"${getVersionName()}/""
buildConfigField "String", "VERSION_DESCRIPTION", "/"${StringEscapeUtils.escapeJava(getVersionInfo())}/""
}
signingConfigs {
config {
keyAlias ''MyKeyAlias''
keyPassword ''MyKeyPassword''
storeFile file(''my_key_store.keystore'')
storePassword ''MyKeyStorePassword''
}
}
buildTypes {
debug {
minifyEnabled false
debuggable true
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile(''proguard-android.txt''), ''proguard-rules.pro''
signingConfig signingConfigs.config
debuggable false
}
}
productFlavors {
// ...
}
dependencies {
// ...
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
}
/**
* Save a build.info file
*/
task saveBuildInfo {
def buildInfo = getVersionInfo()
def assetsDir = android.sourceSets.main.assets.srcDirs.toArray()[0]
assetsDir.mkdirs()
def buildInfoFile = new File(assetsDir, ''build.info'')
buildInfoFile.write(buildInfo)
}
gradle.projectsEvaluated {
assemble.dependsOn(saveBuildInfo)
}
La parte más importante es aplicar el complemento
apply plugin: ''com.android.application''
Y luego usarlo para el nombre y código de la versión de Android
versionCode getAndroidVersionCode()
versionName getAndroidVersionName()
Una manera más apropiada y delgada de lograr el resultado que ganó fuerza últimamente sería usar la integración de gradle git a través de enlaces Groovy JGit . Como usa JGit, ni siquiera requiere que git se instale para funcionar.
Aquí hay un ejemplo básico que muestra una solución similar (pero con algo de información adicional en gitVersionName):
buildscript {
dependencies {
classpath ''org.ajoberstar:grgit:1.4.+''
}
}
ext {
git = org.ajoberstar.grgit.Grgit.open()
gitVersionCode = git.tag.list().size()
gitVersionName = "${git.describe()}"
}
android {
defaultConfig {
versionCode gitVersionCode
versionName gitVersionName
}
}
[...]
Como puede ver en la documentación de la API de Grgit, la operación de descripción proporciona información adicional distinta a la etiqueta más reciente accesible en la historia:
Encuentra la etiqueta más reciente que se puede alcanzar desde HEAD. Si la etiqueta apunta a la confirmación, solo se muestra la etiqueta. De lo contrario, incluye el nombre de la etiqueta con el número de confirmaciones adicionales en la parte superior del objeto etiquetado y el nombre abreviado del objeto de la confirmación más reciente.
De todos modos, no dirá si el estado está sucio o no. Esta información se puede agregar fácilmente al observar el estado de limpieza del repositorio y agregar una cadena si no está limpio.
Otra forma más:
https://github.com/gladed/gradle-android-git-version es un nuevo plugin de gradle que calcula los nombres de versiones compatibles con android y los códigos de versión de forma automática.
Maneja muchos casos especiales que no son posibles usando la solución aceptada:
- etiquetas de versión para proyectos múltiples en el mismo repositorio
- códigos de versión ampliada como 1002003 para 1.2.3
- tareas de gradle para extraer fácilmente información de versión para herramientas de CI
- etc.
Descargo de responsabilidad: lo escribí.
Otra forma, usando Android Studio (Gradle): Echa un vistazo a esta publicación en el blog: http://blog.android-develop.com/2014/09/automatic-versioning-and-increment.html
Aquí está la implementación del blog:
android {
defaultConfig {
...
// Fetch the version according to git latest tag and "how far are we from last tag"
def longVersionName = "git -C ${rootDir} describe --tags --long".execute().text.trim()
def (fullVersionTag, versionBuild, gitSha) = longVersionName.tokenize(''-'')
def(versionMajor, versionMinor, versionPatch) = fullVersionTag.tokenize(''.'')
// Set the version name
versionName "$versionMajor.$versionMinor.$versionPatch($versionBuild)"
// Turn the version name into a version code
versionCode versionMajor.toInteger() * 100000 +
versionMinor.toInteger() * 10000 +
versionPatch.toInteger() * 1000 +
versionBuild.toInteger()
// Friendly print the version output to the Gradle console
printf("/n--------" + "VERSION DATA--------" + "/n" + "- CODE: " + versionCode + "/n" +
"- NAME: " + versionName + "/n----------------------------/n")
...
}
}