All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gabrielittner.github.diff.services.MarkdownCommentBuilder.kt Maven / Gradle / Ivy

There is a newer version: 0.8.0
Show newest version
package com.gabrielittner.github.diff.services

import com.gabrielittner.github.diff.CommentBuilder
import com.jakewharton.byteunits.BinaryByteUnit
import kotlin.math.abs

class MarkdownCommentBuilder(apkName: String) : CommentBuilder {

    private val builder = StringBuilder("### $apkName")
    private val initialLength = builder.length

    private val columns = mutableListOf().also {
        it.addColumn("", "Commit", "Apk size", "Methods", "Fields")
    }

    override fun appendPermissionAddedNote(baseLabel: String, added: Int) {
        builder.appendImportantDiff("permissions", "added", added)
    }

    override fun appendPermissionRemovedNote(baseLabel: String, removed: Int) {
        builder.appendImportantDiff("permissions", "removed", removed)
    }

    override fun appendRequiredFeaturesAddedNote(baseLabel: String, added: Int) {
        builder.appendImportantDiff("required features", "added", added)
    }

    override fun appendRequiredFeaturesRemovedNote(baseLabel: String, removed: Int) {
        builder.appendImportantDiff("required features", "removed", removed)
    }

    override fun appendApkSizeIncreasedNote(baseLabel: String, change: Int, percentage: Double) {
        builder.appendHighlight(baseLabel, "apk size", change, percentage, ::binaryFormat)
    }

    override fun appendApkSizeDecreasedNote(baseLabel: String, change: Int, percentage: Double) {
        builder.appendHighlight(baseLabel, "apk size", change, percentage, ::binaryFormat)
    }

    override fun appendMethodCountIncreasedNote(baseLabel: String, change: Int, percentage: Double) {
        builder.appendHighlight(baseLabel, "method count", change, percentage, ::simpleFormat)
    }

    override fun appendMethodCountDecreasedNote(baseLabel: String, change: Int, percentage: Double) {
        builder.appendHighlight(baseLabel, "method count", change, percentage, ::simpleFormat)
    }

    override fun appendManifestDiffUrl(baseLabel: String, url: String) {
        builder.append("\n\n")
        builder.append("$baseLabel manifest diff".linkify(url))
    }

    override fun appendCurrentStats(url: String, commit: String, size: Int, methods: Int, fields: Int) {
        columns.addColumn("current".linkify(url), commit, size, methods, fields)
    }

    override fun appendOldStats(
        label: String,
        labelUrl: String,
        commit: String,
        size: Int,
        methods: Int,
        fields: Int
    ) {
        columns.addColumn(label.linkify(labelUrl), commit, size, methods, fields)
    }

    override fun appendOldStatsDiff(
        sizeChange: Int,
        sizePercentage: Double,
        sizeDiffUrl: String?,
        methodsChange: Int,
        methodsPercentage: Double,
        methodsDiffUrl: String?,
        fieldsChange: Int,
        fieldsPercentage: Double,
        fieldDiffUrl: String?
    ) {
        columns.addColumn(
            "",
            "",
            relativeFormat(sizeChange, sizePercentage, ::binaryFormat).linkify(sizeDiffUrl),
            relativeFormat(methodsChange, methodsPercentage, ::simpleFormat).linkify(methodsDiffUrl),
            relativeFormat(fieldsChange, fieldsPercentage, ::simpleFormat).linkify(fieldDiffUrl)
        )
    }

    override fun build(): String {
        val finalBuilder = StringBuilder(builder.toString())
        if (finalBuilder.length == initialLength) {
            finalBuilder.append("\nNo changes of note")
        }
        finalBuilder.append("\n\n")
        for (row in 0..5) {
            finalBuilder.append("\n|")
            columns.forEach {
                finalBuilder.append(" ")
                finalBuilder.append(it.getRow(row))
                finalBuilder.append(" |")
            }
        }
        return finalBuilder.toString()
    }

    private fun StringBuilder.appendImportantDiff(label: String, direction: String, change: Int) {
        append("\n:bangbang: $direction $change $label")
    }

    private fun StringBuilder.appendHighlight(type: String, label: String, sizeDiff: Int, percentage: Double, diffFormat: (Int) -> String) {
        append("\n")
        if (sizeDiff > 0) {
            append(":warning:️ Compared to $type the $label increased by ")
        } else {
            append(":white_check_mark: Compared to $type the $label decreased by ")
        }
        append(diffFormat(sizeDiff))
        append(percentageFormat(percentage))
    }

    private fun MutableList.addColumn(label: String, commit: String?, size: Int, methods: Int, fields: Int) {
        addColumn(label, commit ?: "n/a", binaryFormat(size), simpleFormat(methods), simpleFormat(fields))
    }

    private fun MutableList.addColumn(label: String, commit: String, size: String, methods: String, fields: String) {
        add(Column(label, commit, size, methods, fields))
    }

    private fun simpleFormat(count: Int) = String.format("%,d", abs(count))

    private fun binaryFormat(size: Int) = BinaryByteUnit.format(abs(size).toLong(), "#.##")!!

    private fun relativeFormat(diff: Int, percentage: Double, diffFormat: (Int) -> String): String {
        val prefix = when {
            diff < 0 -> "-"
            diff > 0 -> "+"
            else -> ""
        }
        val formatted = "$prefix${diffFormat(diff)}${percentageFormat(percentage)}"
        if (abs(percentage) >= 5.0) {
            return "**$formatted**"
        }
        return formatted
    }

    private fun percentageFormat(percentage: Double): String {
        return if (abs(percentage) < 0.1) {
            ""
        } else {
            String.format(" (%+.1f%%)", percentage)
        }
    }

    private fun String.linkify(url: String?): String {
        return if (url != null) {
            "[$this]($url)"
        } else {
            this
        }
    }

    private data class Column(
            val title: String,
            val commit: String,
            val apkSize: String,
            val methods: String,
            val fields: String
    ) {
        fun getRow(row: Int): String {
            return when (row) {
                0 -> title
                1 -> "---"
                2 -> commit
                3 -> apkSize
                4 -> methods
                5 -> fields
                else -> throw IllegalArgumentException("Unsupported row $row")
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy