Skip to content

Commit

Permalink
build: report with details plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
Gribbirg committed Jul 9, 2024
1 parent 6f8c7bc commit e0f73c2
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 75 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pr-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
echo $ENCODED_KEYSTORE > keystore_base64.txt
base64 -d keystore_base64.txt > $DECODED_KEYSTORE_PATH
- name: Build with Gradle
run: ./gradlew :app:reportTelegramApkForReleaseSigned $gradleFlags
run: ./gradlew :app:reportWithApkDetailsForReleaseSigned $gradleFlags
- name: Get apk file name
run: |
APK_FILE=$(find ${{ github.workspace }}/app/build/outputs/apk/release-signed/baselineProfiles/ -type f -name "*.apk" | head -n 1)
Expand Down
3 changes: 2 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ tgReporter {

token = properties.getProperty("TELEGRAM_BOT_API")
chatId = properties.getProperty("TELEGRAM_CHAT_ID")
maxFileSizeKb = 8000
maxFileSizeKb = 12000
enableDetails = true
}

android {
Expand Down
5 changes: 5 additions & 0 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,13 @@ gradlePlugin {
dependencies {
implementation(libs.agp)
implementation(libs.kotlin.gradle.plugin)

implementation(libs.kotlin.coroutines.core)

implementation(libs.ktor.client)
implementation(libs.ktor.client.okhttp)

implementation(libs.zip.file)

implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
}
2 changes: 1 addition & 1 deletion build-logic/src/main/kotlin/AndroidConst.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import org.gradle.api.JavaVersion

object AndroidConst {
const val NAMESPACE = "ru.gribbirg.todoapp"
const val COMPILE_SKD = 35
const val COMPILE_SKD = 34
const val MIN_SKD = 26
val COMPILE_JDK_VERSION = JavaVersion.VERSION_1_8
const val KOTLIN_JVM_TARGET = "1.8"
Expand Down
18 changes: 13 additions & 5 deletions build-logic/src/main/kotlin/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,27 @@ fun BaseExtension.baseAndroidConfig() {
buildTypes {
getByName("release") {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
create("release-signed") {
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
signingConfig = signingConfigs.getByName("release-signed")
}
}

applicationVariants.all {
buildOutputs.all {
val variantOutputImpl = this as com.android.build.gradle.internal.api.BaseVariantOutputImpl
variantOutputImpl.outputFileName = "todoapp-${buildType.name}-${defaultConfig.versionCode}.apk"
outputs.all {
val variantOutputImpl =
this as com.android.build.gradle.internal.api.BaseVariantOutputImpl
variantOutputImpl.outputFileName =
"todoapp-${buildType.name}-${defaultConfig.versionName}.apk"
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package ru.gribbirg.todoapp.plugins

import com.android.build.api.artifact.SingleArtifact
import com.android.build.api.variant.AndroidComponentsExtension
import com.android.build.api.variant.Variant
import com.android.build.gradle.internal.tasks.factory.dependsOn
import io.ktor.client.HttpClient
import io.ktor.client.engine.okhttp.OkHttp
import org.gradle.api.GradleException
Expand All @@ -10,11 +12,14 @@ import org.gradle.api.Project
import org.gradle.api.provider.Property
import org.gradle.kotlin.dsl.create
import ru.gribbirg.todoapp.api.TelegramApi
import ru.gribbirg.todoapp.tasks.ApkFileDetailsTask
import ru.gribbirg.todoapp.tasks.SizeCheckTask
import ru.gribbirg.todoapp.tasks.TelegramReporterTask
import java.io.File
import java.util.Locale

private const val FILES_DIR = "plugins\\tmp"

class TelegramReporterPlugin : Plugin<Project> {

override fun apply(project: Project) {
Expand All @@ -31,53 +36,70 @@ class TelegramReporterPlugin : Plugin<Project> {
val artifacts = variant.artifacts.get(SingleArtifact.APK)

val checkSizeTask = project.tasks.register(
"validateApkSizeFor${variant.name.getVariantName()}",
"validateApkSizeFor${variant.getNameForTask()}",
SizeCheckTask::class.java,
telegramApi
)
checkSizeTask.configure {
apkDir.set(artifacts)
token.set(extension.token)
chatId.set(extension.chatId)
maxSizeKb.set(extension.maxFileSizeKb.getOrElse(Int.MAX_VALUE))
outputFile.set(
File(
"${project.layout.buildDirectory.get().asFile.absolutePath}/apk-size.txt"
).apply {
configure {
apkDir.set(artifacts)
token.set(extension.token)
chatId.set(extension.chatId)
maxSizeKb.set(extension.maxFileSizeKb.getOrElse(Int.MAX_VALUE))
outputFile.set(
File(
project.layout.buildDirectory.get().asFile.absolutePath +
"\\$FILES_DIR\\apk-size-of-${variant.name}.txt"
)
)
)
}
}

project.tasks.register(
"reportTelegramApkFor${
variant
.name
.getVariantName()
}",
val reportApkTask = project.tasks.register(
"reportTelegramApkFor${variant.getNameForTask()}",
TelegramReporterTask::class.java,
telegramApi
).configure {
apkDir.set(artifacts)
token.set(extension.token)
chatId.set(extension.chatId)
apkSizeFile.set(checkSizeTask.get().outputFile)
).apply {
configure {
apkDir.set(artifacts)
token.set(extension.token)
chatId.set(extension.chatId)
apkSizeFile.set(checkSizeTask.get().outputFile)
}
}
}
}

private fun String.getVariantName() =
split("-")
.joinToString("") { word ->
word.replaceFirstChar { char ->
if (char.isLowerCase())
char.titlecase(Locale.getDefault())
else word
val apkDetailsTask = project.tasks.register(
"reportWithApkDetailsFor${variant.getNameForTask()}",
ApkFileDetailsTask::class.java,
telegramApi
).apply {
configure {
apkDir.set(artifacts)
token.set(extension.token)
chatId.set(extension.chatId)
enabledTask.set(extension.enableDetails.getOrElse(true))
}
}

reportApkTask.dependsOn(checkSizeTask)
apkDetailsTask.dependsOn(reportApkTask)
}
}
}

interface TelegramExtension {
val chatId: Property<String>
val token: Property<String>
val maxFileSizeKb: Property<Int>
val enableDetails: Property<Boolean>
}

private fun Variant.getNameForTask() =
name.split("-")
.joinToString("") { word ->
word.replaceFirstChar { char ->
if (char.isLowerCase())
char.titlecase(Locale.getDefault())
else word
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package ru.gribbirg.todoapp.tasks

import kotlinx.coroutines.runBlocking
import net.lingala.zip4j.ZipFile
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.TaskAction
import ru.gribbirg.todoapp.api.TelegramApi
import ru.gribbirg.todoapp.utils.findApk
import ru.gribbirg.todoapp.utils.roundTo
import javax.inject.Inject

abstract class ApkFileDetailsTask @Inject constructor(
private val telegramApi: TelegramApi
) : DefaultTask() {
@get:InputDirectory
abstract val apkDir: DirectoryProperty

@get:Input
abstract val token: Property<String>

@get:Input
abstract val chatId: Property<String>

@get:Input
abstract val enabledTask: Property<Boolean>

@TaskAction
fun sendDetails() {
if (!enabledTask.get()) return

val file = apkDir.get().findApk()

val text = ZipFile(file)
.fileHeaders
.groupBy { it.fileName.split("/").first() }
.map { it.key to it.value.sumOf { header -> header.uncompressedSize } / 1024.0 }
.joinToString("\n") {
"${it.first} - ${it.second.roundTo(2)} KB"
}

runBlocking {
telegramApi.sendMessage(
"Apk details:\n\n$text",
token.get(),
chatId.get()
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package ru.gribbirg.todoapp.tasks

import io.ktor.client.statement.bodyAsText
import kotlinx.coroutines.runBlocking
import okio.FileNotFoundException
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
Expand All @@ -11,6 +11,7 @@ import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import ru.gribbirg.todoapp.api.TelegramApi
import ru.gribbirg.todoapp.utils.findApk
import javax.inject.Inject

abstract class SizeCheckTask @Inject constructor(
Expand All @@ -26,37 +27,31 @@ abstract class SizeCheckTask @Inject constructor(
abstract val chatId: Property<String>

@get:Input
abstract val maxSizeKb: Property<Int?>
abstract val maxSizeKb: Property<Int>

@get:OutputFile
abstract val outputFile: RegularFileProperty

@TaskAction
fun check() {
val maxSizeKb = maxSizeKb.get() ?: return
val maxSizeKb = maxSizeKb.get()
val token = token.get()
val chatId = chatId.get()

val file = apkDir
.get()
.asFile
.listFiles()
?.firstOrNull { it.name.endsWith(".apk") }

if (file == null) {
throw FileNotFoundException("Apk not found")
}
val file = apkDir.get().findApk()

val size = file.length() / 1024
if (size > maxSizeKb) {
val text =
"Apk is too large!\nName: ${file.name}\nSize: ${size}kb\nMax size: ${maxSizeKb}kb"
"Apk is too large!\nName: ${file.name}\nSize: $size KB\nMax size: $maxSizeKb KB"
runBlocking {
telegramApi.sendMessage(
text,
token,
chatId,
)
).apply {
println(bodyAsText())
}
}
throw Exception(text)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ package ru.gribbirg.todoapp.tasks

import io.ktor.client.statement.bodyAsText
import kotlinx.coroutines.runBlocking
import okio.FileNotFoundException
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import ru.gribbirg.todoapp.api.TelegramApi
import ru.gribbirg.todoapp.utils.findApk
import javax.inject.Inject

abstract class TelegramReporterTask @Inject constructor(
Expand All @@ -21,7 +21,7 @@ abstract class TelegramReporterTask @Inject constructor(
@get:InputDirectory
abstract val apkDir: DirectoryProperty

@get:InputFile
@get:OutputFile
abstract val apkSizeFile: RegularFileProperty

@get:Input
Expand All @@ -34,23 +34,21 @@ abstract class TelegramReporterTask @Inject constructor(
fun report() {
val token = token.get()
val chatId = chatId.get()
apkDir.get().asFile.listFiles()
?.firstOrNull { it.name.endsWith(".apk") }
?.let {
runBlocking {
telegramApi.sendMessage(
"Build finished!\nApk size: ${apkSizeFile.get().asFile.readText()}kb",
token,
chatId
).apply {
println(bodyAsText())
}
}
runBlocking {
telegramApi.upload(it, token, chatId).apply {
println(bodyAsText())
}
}
} ?: throw FileNotFoundException("Apk not found")
val file = apkDir.get().findApk()

runBlocking {
telegramApi.sendMessage(
"Build finished!\nApk size: ${apkSizeFile.get().asFile.readText()} KB",
token,
chatId
).apply {
println(bodyAsText())
}
}
runBlocking {
telegramApi.upload(file, token, chatId).apply {
println(bodyAsText())
}
}
}
}
10 changes: 10 additions & 0 deletions build-logic/src/main/kotlin/ru/gribbirg/todoapp/utils/ApkFinder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package ru.gribbirg.todoapp.utils

import okio.FileNotFoundException
import org.gradle.api.file.Directory

internal fun Directory.findApk() =
asFile
.listFiles()
?.firstOrNull { it.name.endsWith(".apk") }
?: throw FileNotFoundException("Apk file not found in ${asFile.absolutePath}")
Loading

0 comments on commit e0f73c2

Please sign in to comment.