Migrate versioning to Gradle plugin and automate version bumps (#1282)
This commit is contained in:
parent
405e1d1772
commit
3a2cfd22e6
6 changed files with 180 additions and 12 deletions
61
.github/workflows/draft_new_release.yml
vendored
61
.github/workflows/draft_new_release.yml
vendored
|
@ -9,32 +9,73 @@ jobs:
|
||||||
name: "Draft a new release"
|
name: "Draft a new release"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
|
||||||
with:
|
|
||||||
ref: 'release'
|
|
||||||
- name: Extract version from milestone
|
- name: Extract version from milestone
|
||||||
run: |
|
run: |
|
||||||
VERSION="${{ github.event.milestone.title }}"
|
VERSION="${{ github.event.milestone.title }}"
|
||||||
echo "RELEASE_VERSION=${VERSION/v/}" >> $GITHUB_ENV
|
RELEASE_VERSION="${VERSION/v/}"
|
||||||
|
# Transforms 1.13.2 to 1.13 so that we can re-use the same
|
||||||
|
# branch for patch releases.
|
||||||
|
BRANCH_VERSION="${RELEASE_VERSION:$i:-2}"
|
||||||
|
if [[ "${RELEASE_VERSION: -1}" == "0" ]]; then
|
||||||
|
CHECKOUT_REF="develop"
|
||||||
|
else
|
||||||
|
CHECKOUT_REF="release-${BRANCH_VERSION}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Export variables separately so the scripting above is more legible,
|
||||||
|
# and we can actually use them within this block. Changes to $GITHUB_ENV
|
||||||
|
# only affect the next step, not the current one.
|
||||||
|
echo "RELEASE_VERSION=${RELEASE_VERSION}" >> $GITHUB_ENV
|
||||||
|
echo "CHECKOUT_REF=${CHECKOUT_REF}" >> $GITHUB_ENV
|
||||||
|
echo "BRANCH_VERSION=${BRANCH_VERSION}" >> $GITHUB_ENV
|
||||||
|
echo "PR_BASE=release-${BRANCH_VERSION}" >> $GITHUB_ENV
|
||||||
|
echo "PR_HEAD=release-prep" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||||
|
with:
|
||||||
|
ref: ${{ env.CHECKOUT_REF }}
|
||||||
|
|
||||||
- name: Update changelog
|
- name: Update changelog
|
||||||
uses: thomaseizinger/keep-a-changelog-new-release@96ebf19f2bddaf72406c84691b9c2d827da53140
|
uses: thomaseizinger/keep-a-changelog-new-release@96ebf19f2bddaf72406c84691b9c2d827da53140
|
||||||
with:
|
with:
|
||||||
version: ${{ env.RELEASE_VERSION }}
|
version: ${{ github.event.milestone.title }}
|
||||||
|
|
||||||
- name: Initialize git config and commit changes
|
- name: Initialize git config and commit changes
|
||||||
run: |
|
run: |
|
||||||
|
# Configure name and email for Actions user
|
||||||
git config user.name "GitHub Actions"
|
git config user.name "GitHub Actions"
|
||||||
git config user.email noreply@github.com
|
git config user.email noreply@github.com
|
||||||
|
|
||||||
|
# It is necessary to create the $PR_BASE branch if it doesn't
|
||||||
|
# already exist because we want to start a PR against it.
|
||||||
|
if [[ "${CHECKOUT_REF}" == "develop" ]]; then
|
||||||
|
git branch -c develop "${PR_BASE}"
|
||||||
|
git push origin "${PR_BASE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stage and commit changes to the changelog
|
||||||
|
git add CHANGELOG.md
|
||||||
|
git commit -m "CHANGELOG: bump for ${{ github.event.milestone.title }}"
|
||||||
|
|
||||||
|
# Increment the version as necessary. If we checked out develop it means
|
||||||
|
# that the version number is already correct, and we only need to drop the
|
||||||
|
# -SNAPSHOT suffix.
|
||||||
|
if [[ "${CHECKOUT_REF}" == "develop" ]]; then
|
||||||
|
./gradlew clearPreRelease
|
||||||
|
else
|
||||||
|
./gradlew bumpPatch
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Commit changes to the versioning
|
||||||
|
git add **/version.properties
|
||||||
|
git commit -m "build: bump version"
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@45c510e1f68ba052e3cd911f661a799cfb9ba3a3
|
uses: peter-evans/create-pull-request@45c510e1f68ba052e3cd911f661a799cfb9ba3a3
|
||||||
with:
|
with:
|
||||||
author: GitHub Actions <noreply@github.com>
|
author: GitHub Actions <noreply@github.com>
|
||||||
base: release
|
body: This is an automated pull request to bump the changelog for the ${{ github.event.milestone.title }} release.
|
||||||
body: This is an automated pull request to bump the changelog for the v${{ env.RELEASE_VERSION }} release.
|
base: ${{ env.PR_BASE }}
|
||||||
branch: release-${{ env.RELEASE_VERSION }}
|
branch: ${{ env.PR_HEAD }}
|
||||||
commit-message: "CHANGELOG: bump for ${{ env.RELEASE_VERSION }}"
|
|
||||||
draft: true
|
|
||||||
title: Release v${{ env.RELEASE_VERSION }}
|
title: Release v${{ env.RELEASE_VERSION }}
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import com.android.build.gradle.internal.api.BaseVariantOutputImpl
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
kotlin("android")
|
kotlin("android")
|
||||||
|
`versioning-plugin`
|
||||||
`aps-plugin`
|
`aps-plugin`
|
||||||
`crowdin-plugin`
|
`crowdin-plugin`
|
||||||
}
|
}
|
||||||
|
@ -26,8 +27,6 @@ android {
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "dev.msfjarvis.aps"
|
applicationId = "dev.msfjarvis.aps"
|
||||||
versionCode = 2_00_00
|
|
||||||
versionName = "2.0.0-SNAPSHOT"
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
6
app/version.properties
Normal file
6
app/version.properties
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#
|
||||||
|
#This file was automatically generated by 'versioning-plugin'. DO NOT EDIT MANUALLY.
|
||||||
|
#
|
||||||
|
#Sun Jan 17 12:32:03 IST 2021
|
||||||
|
versioning-plugin.versionCode=20000
|
||||||
|
versioning-plugin.versionName=2.0.0-SNAPSHOT
|
|
@ -25,6 +25,10 @@ gradlePlugin {
|
||||||
id = "crowdin-plugin"
|
id = "crowdin-plugin"
|
||||||
implementationClass = "CrowdinDownloadPlugin"
|
implementationClass = "CrowdinDownloadPlugin"
|
||||||
}
|
}
|
||||||
|
register("versioning") {
|
||||||
|
id = "versioning-plugin"
|
||||||
|
implementationClass = "VersioningPlugin"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,4 +37,5 @@ dependencies {
|
||||||
implementation(build.getValue("androidGradlePlugin"))
|
implementation(build.getValue("androidGradlePlugin"))
|
||||||
implementation(build.getValue("binaryCompatibilityValidator"))
|
implementation(build.getValue("binaryCompatibilityValidator"))
|
||||||
implementation(build.getValue("downloadTaskPlugin"))
|
implementation(build.getValue("downloadTaskPlugin"))
|
||||||
|
implementation(build.getValue("jsemver"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ rootProject.ext.versions = [
|
||||||
kotlin : '1.4.21',
|
kotlin : '1.4.21',
|
||||||
binary_compatibility_validator : '0.2.4',
|
binary_compatibility_validator : '0.2.4',
|
||||||
download_plugin : '4.1.1',
|
download_plugin : '4.1.1',
|
||||||
|
semver : '0.9.0',
|
||||||
]
|
]
|
||||||
|
|
||||||
rootProject.ext.build = [
|
rootProject.ext.build = [
|
||||||
|
@ -10,4 +11,5 @@ rootProject.ext.build = [
|
||||||
kotlinGradlePlugin : "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}",
|
kotlinGradlePlugin : "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}",
|
||||||
binaryCompatibilityValidator : "org.jetbrains.kotlinx:binary-compatibility-validator:${versions.binary_compatibility_validator}",
|
binaryCompatibilityValidator : "org.jetbrains.kotlinx:binary-compatibility-validator:${versions.binary_compatibility_validator}",
|
||||||
downloadTaskPlugin : "de.undercouch:gradle-download-task:${versions.download_plugin}",
|
downloadTaskPlugin : "de.undercouch:gradle-download-task:${versions.download_plugin}",
|
||||||
|
jsemver : "com.github.zafarkhaja:java-semver:${versions.semver}",
|
||||||
]
|
]
|
||||||
|
|
115
buildSrc/src/main/java/VersioningPlugin.kt
Normal file
115
buildSrc/src/main/java/VersioningPlugin.kt
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import com.android.build.gradle.internal.plugins.AppPlugin
|
||||||
|
import com.github.zafarkhaja.semver.Version
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.util.Properties
|
||||||
|
import org.gradle.api.Plugin
|
||||||
|
import org.gradle.api.Project
|
||||||
|
|
||||||
|
private const val VERSIONING_PROP_FILE = "version.properties"
|
||||||
|
private const val VERSIONING_PROP_VERSION_NAME = "versioning-plugin.versionName"
|
||||||
|
private const val VERSIONING_PROP_VERSION_CODE = "versioning-plugin.versionCode"
|
||||||
|
private const val VERSIONING_PROP_COMMENT = """
|
||||||
|
This file was automatically generated by 'versioning-plugin'. DO NOT EDIT MANUALLY.
|
||||||
|
"""
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Gradle [Plugin] that takes a [Project] with the [AppPlugin] applied and dynamically sets the
|
||||||
|
* versionCode and versionName properties based on values read from a [VERSIONING_PROP_FILE] file in
|
||||||
|
* the [Project.getBuildDir] directory. It also adds Gradle tasks to bump the major, minor, and patch
|
||||||
|
* versions along with one to prepare the next snapshot.
|
||||||
|
*/
|
||||||
|
@Suppress(
|
||||||
|
"UnstableApiUsage",
|
||||||
|
"NAME_SHADOWING"
|
||||||
|
)
|
||||||
|
class VersioningPlugin : Plugin<Project> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the Android 'versionCode' property
|
||||||
|
*/
|
||||||
|
private fun Version.androidCode(): Int {
|
||||||
|
return majorVersion * 1_00_00 +
|
||||||
|
minorVersion * 1_00 +
|
||||||
|
patchVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write an Android-specific variant of [this] to [stream]
|
||||||
|
*/
|
||||||
|
private fun Version.writeForAndroid(stream: OutputStream) {
|
||||||
|
val newVersionCode = androidCode()
|
||||||
|
val props = Properties()
|
||||||
|
props.setProperty(VERSIONING_PROP_VERSION_CODE, "$newVersionCode")
|
||||||
|
props.setProperty(VERSIONING_PROP_VERSION_NAME, toString())
|
||||||
|
props.store(stream, VERSIONING_PROP_COMMENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the same [Version], but with build metadata stripped.
|
||||||
|
*/
|
||||||
|
private fun Version.clearPreRelease(): Version {
|
||||||
|
return Version.forIntegers(majorVersion, minorVersion, patchVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun apply(project: Project) {
|
||||||
|
with(project) {
|
||||||
|
val appPlugin = requireNotNull(plugins.findPlugin(AppPlugin::class.java)) {
|
||||||
|
"Plugin 'com.android.application' must be applied to use this plugin"
|
||||||
|
}
|
||||||
|
val propFile = layout.projectDirectory.file(VERSIONING_PROP_FILE)
|
||||||
|
require(propFile.asFile.exists()) {
|
||||||
|
"A 'version.properties' file must exist in the project subdirectory to use this plugin"
|
||||||
|
}
|
||||||
|
val contents = providers.fileContents(propFile).asText.forUseAtConfigurationTime()
|
||||||
|
val versionProps = Properties().also { it.load(contents.get().byteInputStream()) }
|
||||||
|
val versionName = requireNotNull(versionProps.getProperty(VERSIONING_PROP_VERSION_NAME)) {
|
||||||
|
"version.properties must contain a '$VERSIONING_PROP_VERSION_NAME' property"
|
||||||
|
}
|
||||||
|
val versionCode = requireNotNull(versionProps.getProperty(VERSIONING_PROP_VERSION_CODE).toInt()) {
|
||||||
|
"version.properties must contain a '$VERSIONING_PROP_VERSION_CODE' property"
|
||||||
|
}
|
||||||
|
appPlugin.extension.defaultConfig.versionName = versionName
|
||||||
|
appPlugin.extension.defaultConfig.versionCode = versionCode
|
||||||
|
afterEvaluate {
|
||||||
|
val version = Version.valueOf(versionName)
|
||||||
|
tasks.register("clearPreRelease") {
|
||||||
|
doLast {
|
||||||
|
version.clearPreRelease()
|
||||||
|
.writeForAndroid(propFile.asFile.outputStream())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks.register("bumpMajor") {
|
||||||
|
doLast {
|
||||||
|
version.incrementMajorVersion()
|
||||||
|
.writeForAndroid(propFile.asFile.outputStream())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks.register("bumpMinor") {
|
||||||
|
doLast {
|
||||||
|
version.incrementMinorVersion()
|
||||||
|
.writeForAndroid(propFile.asFile.outputStream())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks.register("bumpPatch") {
|
||||||
|
doLast {
|
||||||
|
version.incrementPatchVersion()
|
||||||
|
.writeForAndroid(propFile.asFile.outputStream())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks.register("bumpSnapshot") {
|
||||||
|
doLast {
|
||||||
|
version.incrementMinorVersion()
|
||||||
|
.setPreReleaseVersion("SNAPSHOT")
|
||||||
|
.writeForAndroid(propFile.asFile.outputStream())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue