web-dev-qa-db-ja.com

Androidの自動バージョン管理は、Gradleでgit describeを使用してビルドします

私は広範囲にわたって検索しましたが、Android StudioとGradleの新しさのためと考えられます。これを行う方法の説明は見つかりませんでした。基本的には、 この投稿 、ただしAndroid Eclipse、LinuxではなくStudio、Gradle、Windowsを使用。

39
Mike Yount

最近牽引力を獲得した結果を達成するためのより適切で無駄のない方法は、 Groovy JGitバインディング を介して gradle git integration を使用することです。 JGitを使用しているため、動作するためにgitをインストールする必要さえありません。

同様の(ただし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
  }
}
[...]

Grgit APIドキュメント で確認できるように、 describe operation は、履歴で到達可能な最新のタグ以外の追加情報を提供します。

HEADから到達可能な最新のタグを見つけます。タグがコミットを指す場合、タグのみが表示されます。それ以外の場合は、タグ付けされたオブジェクトの上に追加のコミットの数を付けたタグ名と、最新のコミットの省略されたオブジェクト名の接尾辞を付けます。

とにかく、状態が汚れているかどうかはわかりません。この情報は、リポジトリの クリーンステータス を確認し、クリーンでない場合は文字列を追加することで簡単に追加できます。

25
Diego

プロジェクトのbuild.gradleファイルに以下を追加します。マニフェストを直接変更する必要はありません。Googleは構成に必要なフックを提供しました。

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

Gitがマシンにインストールされていない場合、またはバージョン名/コードの取得中に他のエラーが発生した場合は、デフォルトでAndroidマニフェストにあるものになります。

43
moveaway00

moveaway00の回答その回答に関するAvinash Rのコメント を確認した後、私はこれを使用してしまいました。

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

Moveaway00のコードを編集して、Avinash Rのコメントも含めました。バージョンコードは、バージョンコードが想定されているものであるため、master以降のコミット数になりました。

マニフェストでバージョンコードとバージョン名を指定する必要がないことに注意してください。Gradleが処理しました。

27
Léo Lam

さらに別の方法:

https://github.com/gladed/gradle-Android-git-version は、Android対応のバージョン名とバージョンコードを自動的に計算する新しいGradleプラグインです。

承認済みのソリューションでは不可能な多くの特殊なケースを処理します。

  • 同じリポジトリ内の複数のプロジェクトのバージョンタグ
  • 1.2.3の1002003のような拡張バージョンコード
  • cIツールのバージョン情報を簡単に抽出するためのGradleタスク
  • 等.

免責事項:私はそれを書きました。

11
gladed

コマンドラインにアクセスするには、関数ではなくステートメントを必要とする別のソリューションを次に示します。 警告:* nixのみのソリューション

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'
        }

    }
}
5
jpotts18

Android Studio(Gradle):を使用した別の方法:このブログ投稿を確認してください: http:/ /blog.Android-develop.com/2014/09/automatic-versioning-and-increment.html

これがブログの実装です:

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

}

3
Sean

それが何らかの助けになれば、GitタグとGit説明を使用してこれを実現するGradleスクリプトの例を設定しました。ここにコードがあります(それを見つけることもできます here )。

1)最初にversioning.gradleファイルを作成します:

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)次に、app/build.gradleを編集して、次のように使用します。

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

最も重要な部分はプラグインを適用することです

apply plugin: 'com.Android.application'

そして、それをAndroidバージョン名とコードに使用します

versionCode getAndroidVersionCode()
versionName getAndroidVersionName()
3
Soloist

LéoLam's answer と以前の explorations に基づいて、antの同じ解決策に基づいて、純粋なクロスプラットフォームjgitを使用したソリューション:

(オリジナル ソース

ファイル: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
}

使用法は次のとおりです。

apply from: 'git-version.gradle'

Android {
  ...
  defaultConfig {
    ...
    versionCode readVersionCode()
    versionName readVersionName()
    ...
  }
  ...
}
1
Avinash R

これは Diego's answer のわずかに変更されたバージョンであり、バージョン名を次のスタイルにしたいという私の願望を満たしています。

{最新のタグ}-{現在のコミットの短いハッシュ}-{現在のコミットの時間}

    import Java.text.SimpleDateFormat

    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            classpath 'org.ajoberstar.grgit:grgit-core:3.1.1'
        }
    }

    /**
     * Version name will be in following format:
     *
     * "{latest release tag}-{short commit hash of current commit}-{time of current commit}"
     *
     * Example: 1.6.0-5ae9b86-2019-07-04-13:20
     */
    ext {
        git = org.ajoberstar.grgit.Grgit.open(currentDir: projectDir)

        listOfTags = git.tag.list()
        noTags = listOfTags.isEmpty()
        head = git.head()

        if (noTags) {
            gitVersionCode = 0
            gitVersionName = "no-tag-${head.abbreviatedId}-${head.time}"
        } else {
            tagNames = listOfTags.collect { git.describe(commit: it.commit, tags: true) }
            mostRecentVersion = mostRecentVersion(tagNames)

            def date = new SimpleDateFormat('yyyy-MM-dd-HH:mm').format(new Date(head.time * 1000))
            gitVersionCode = listOfTags.size()
            gitVersionName = "$mostRecentVersion-${head.abbreviatedId}-${date}"
        }
    }

    /**
     * Shamelessly stolen from <a href="https://stackoverflow.com/a/7723766/">StackOverflow</a>.
     */
    static String mostRecentVersion(List versions) {
        def sorted = versions.sort(false) { a, b ->
            List verA = a.tokenize('.')
            List verB = b.tokenize('.')

            def commonIndices = Math.min(verA.size(), verB.size())

            for (int i = 0; i < commonIndices; ++i) {
                def numA = verA[i].toInteger()
                def numB = verB[i].toInteger()

                if (numA != numB) {
                    return numA <=> numB
                }
            }
            // If we got this far then all the common indices are identical, so whichever version is longer must be more recent
            verA.size() <=> verB.size()
        }

        // println "Sorted versions: $sorted"
        sorted[-1]
    }

    task printVersion() {
        println("Version Code: $gitVersionCode")
        println("Version Name: $gitVersionName")
    }

versionNameSuffixモジュールのbuild.gradleappも次のように指定したと仮定します。

    Android {
        ...
        productFlavors {
            debug {
                versionCode gitVersionCode
                versionName gitVersionName
                versionNameSuffix '-DEBUG'
                ...
            }
            // ... other flavors here
        }
    }

次に、これはバージョン名になります。

Version name as can be seen by user in settings

0
azizbekian

Gradleファイルで単純な関数を定義します。

def getVersion(){
    def out = new ByteArrayOutputStream();
    exec {
        executable = 'git'
        args = ['describe', '--tags']
        standardOutput = out
    }
    return out.toString().replace('\n','')
}

これを使って:

project.version = getVersion()
0
S.D.