Versión de Android del proyecto de git describe automáticamente con Android Studio / Gradle

He buscado mucho, pero probablemente debido a la novedad de Android Studio y Gradle, no he encontrado ninguna descripción de cómo hacerlo. 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.

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 documentation de API de Grgit, la operación de descripción proporciona información adicional distinta a la label más reciente accesible en la historia:

Encuentra la label más reciente que se puede alcanzar desde HEAD. Si la label apunta a la confirmación, solo se muestra la label. De lo contrario, incluye el nombre de la label con el número de confirmaciones adicionales en la parte superior del object labeldo y el nombre abreviado del object 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 repository y agregar una cadena si no está limpio.

Coloque lo siguiente en su file build.gradle para el proyecto. No es necesario modificar el manifiesto directamente: Google proporcionó los enganches necesarios en su configuration.

 def getVersionCode = { -> try { def code = new ByteArrayOutputStream() exec { commandLine 'git', 'tag', '--list' standardOutput = code } return code.toString().split("\n").size() } catch (ignonetworking) { return -1; } } def getVersionName = { -> try { def stdout = new ByteArrayOutputStream() exec { commandLine 'git', 'describe', '--tags', '--dirty' standardOutput = stdout } return stdout.toString().trim() } catch (ignonetworking) { return null; } } android { defaultConfig { versionCode getVersionCode() versionName getVersionName() } } 

Tenga en count que si git no está instalado en la máquina, o hay algún otro error al get el nombre / código de la versión, de forma pnetworkingeterminada 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 (ignonetworking) { return -1; } } def getVersionName = { -> try { def stdout = new ByteArrayOutputStream() exec { commandLine 'git', 'describe', '--tags', '--dirty' standardOutput = stdout } return stdout.toString().trim() } catch (ignonetworking) { return null; } } android { defaultConfig { versionCode getVersionCode() versionName getVersionName() } } 

He editado el código de moveaway00 para include también el comentario de Avinash R. El código de 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 count 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.

Otra forma más:

https://github.com/gladed/gradle-android-git-version es un nuevo plugin de gradle que calcula los nombres de las 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:

  • tags de versión para proyectos múltiples en el mismo repository
  • 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í.

Aquí hay otra solución que requiere declaraciones en lugar de funciones para acceder a la command-line. 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' } } } 

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") ... } 

}

Si puede ser de alguna ayuda, he configurado un script de Gradle de ejemplo que usa tags de Git y describe a Git para lograr esto. Aquí está el código (también puedes encontrarlo aquí ).

1) Primero crea un file 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 "XYZ", 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() 

En base a la respuesta de Léo Lam y mis exploraciones anteriores sobre la misma solución para ant, he ideado una solución puramente multiplataforma utilizando jgit:

( fuente 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() ... } ... }