Repository: JetBrains/compose-multiplatform
File: tools/changelog.main.kts (Kotlin)

Code before:
            }
    }
)

/**
 * Transforms v1.6.0-beta01 to 1.6.0-beta01
 */
fun commitToVersion(commit: String) =
    if (commit.startsWith("v") && commit.contains(".")) {
        commit.removePrefix("v")
    } else {
        commit
    }

fun ChangelogEntry.format() = if (link != null) "$message ([link]($link))" else message

/**
 * Extract by format https://github.com/JetBrains/compose-multiplatform/blob/b32350459acceb9cca6b9e4422b7aaa051d9ae7d/.github/PULL_REQUEST_TEMPLATE.md?plain=1
 */
fun GitHubPullEntry.extractReleaseNotes(link: String): List<ChangelogEntry> {
    // extract body inside "## Release Notes"
    val relNoteBody = run {
        val after = body?.substringAfter("## Release Notes", "")?.ifBlank { null } ?:
            body?.substringAfter("## Release notes", "")?.ifBlank { null } ?:
            body?.substringAfter("## RelNote", "")?.ifBlank { null }

        val before = after?.substringBefore("\n## ", "")?.ifBlank { null } ?:
            after?.substringBefore("\n# ", "")?.ifBlank { null } ?:
            after

        before?.trim()
    }

    val list = mutableListOf<ChangelogEntry>()
    var section: String? = null
    var subsection: String? = null

    for (line in relNoteBody.orEmpty().split("\n")) {
        // parse "### Section - Subsection"
        if (line.startsWith("### ")) {
            val s = line.removePrefix("### ")
            section = s.substringBefore("-", "").trim().ifEmpty { null }
            subsection = s.substringAfter("-", "").trim().ifEmpty { null }
        } else if (section != null && line.isNotBlank()) {
            val isTopLevel = line.startsWith("-")
            val trimmedLine = line.removeSuffix(".")
            list.add(
                ChangelogEntry(
                    trimmedLine,
                    section,
                    subsection,

Review comment (suggestion):
[`MD022` - Headings should be surrounded by blank lines](https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md022.md)

Code after:
val newChangelog = getChangelog("v$previousVersion", versionCommit)

changelogFile.writeText(
    newChangelog + previousChangelog
)

println()
println("CHANGELOG.md changed")


fun getChangelog(firstCommit: String, lastCommit: String): String {
    val entries = entriesForRepo("JetBrains/compose-multiplatform-core", firstCommit, lastCommit) +
            entriesForRepo("JetBrains/compose-multiplatform", firstCommit, lastCommit)

    return buildString {
        appendLine("# ${commitToVersion(lastCommit)} (${currentChangelogDate()})")

        appendLine()
        appendLine("_Changes since ${commitToVersion(firstCommit)}_")
        appendLine()

        entries
            .sortedBy { it.sectionOrder() }
            .groupBy { it.sectionName() }
            .forEach { (section, sectionEntries) ->
                appendLine("## $section")
                appendLine()

                sectionEntries
                    .sortedBy { it.subsectionOrder() }
                    .groupBy { it.subsectionName() }
                    .forEach { (subsection, subsectionEntries) ->
                        appendLine("### $subsection")
                        appendLine()
                        subsectionEntries.forEach {
                            appendLine(it.format())
                        }
                        appendLine()
                    }
            }

        append(
            """
                ## Dependencies
        
                - Gradle Plugin `org.jetbrains.compose`, version `${commitToVersion(lastCommit)}`. Based on Jetpack Compose libraries:
                  - [Runtime REDIRECT_PLACEHOLDER](https://developer.android.com/jetpack/androidx/releases/compose-runtime#REDIRECT_PLACEHOLDER)
                  - [UI REDIRECT_PLACEHOLDER](https://developer.android.com/jetpack/androidx/releases/compose-ui#REDIRECT_PLACEHOLDER)
                  - [Foundation REDIRECT_PLACEHOLDER](https://developer.android.com/jetpack/androidx/releases/compose-foundation#REDIRECT_PLACEHOLDER)
                  - [Material REDIRECT_PLACEHOLDER](https://developer.android.com/jetpack/androidx/releases/compose-material#REDIRECT_PLACEHOLDER)
                  - [Material3 REDIRECT_PLACEHOLDER](https://developer.android.com/jetpack/androidx/releases/compose-material3#REDIRECT_PLACEHOLDER)