Dev #41

Merged
altavir merged 17 commits from dev into master 2022-03-15 13:06:15 +03:00
19 changed files with 474 additions and 350 deletions

View File

@ -7,47 +7,60 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
### Added ### Added
### Changed
- Separate release tasks for each target
### Deprecated
### Removed
### Fixed
### Security
## [0.11.1-kotlin-1.6.10]
### Added
- Default templates for README and ARTIFACT
### Changed
- Replaced Groovy templates by FreeMarker
### Deprecated
### Removed
### Fixed
- JS publication sources jar
### Security
## [0.10.9-kotlin-1.6.10]
### Added
- html builders for readme - html builders for readme
### Changed ### Changed
- Kotlin 1.6.0 - Kotlin 1.6.0
- Use indy lambdas by default #32 - Use indy lambdas by default #32
- Change version scheme to `<version>-kotlin-<kotlin version>`
### Deprecated
### Removed
### Fixed ### Fixed
- remove `nativeMain` dependency from `nativeTest` - remove `nativeMain` dependency from `nativeTest`
### Security
## [0.10.4] ## [0.10.4]
### Added
### Changed ### Changed
- Kotlin 1.6 - Kotlin 1.6
### Deprecated
### Removed
### Fixed ### Fixed
- Some issues with opt-ins - Some issues with opt-ins
### Security
## [0.10.2] ## [0.10.2]
### Added ### Added
- Experimental automatic JS project bundling in MPP - Experimental automatic JS project bundling in MPP
### Changed ### Changed
- Remove vcs requirement for Space publication - Remove vcs requirement for Space publication
### Fixed ### Fixed
-Release task (#19) -Release task (#19)
@ -57,12 +70,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- BOM for kotlin-wrappers on JS - BOM for kotlin-wrappers on JS
- Jupyter loader - Jupyter loader
### Changed ### Changed
- API validation disabled for dev versions - API validation disabled for dev versions
- Kotlin plugins are propagated downstream - Kotlin plugins are propagated downstream
### Removed ### Removed
- bson support - bson support
@ -71,18 +82,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Disable API validation for snapshots - Disable API validation for snapshots
- `-Xjvm-default=all` on JVM - `-Xjvm-default=all` on JVM
### Changed ### Changed
- `publication.platform` changed to `publishing.platform` - `publication.platform` changed to `publishing.platform`
- Dokka version to `1.4.30` - Dokka version to `1.4.30`
- `useDateTime` in extension - `useDateTime` in extension
- Kotlin 1.5 - Kotlin 1.5
### Removed ### Removed
- Publish plugin. Use MavenPublish instead - Publish plugin. Use MavenPublish instead
### Fixed ### Fixed
- Removed unnecessary `afterEvaluate` for compatibility with gradle 7.0 - Removed unnecessary `afterEvaluate` for compatibility with gradle 7.0
@ -90,16 +98,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Skip sonatype publishing for dev versions - Skip sonatype publishing for dev versions
### Changed ### Changed
- Publishing repositories are explicit and defined in the top level project - Publishing repositories are explicit and defined in the top level project
- Paths to publishing properties now use dot notation like `publishing.github.user` - Paths to publishing properties now use dot notation like `publishing.github.user`
### Deprecated ### Deprecated
- Publishing plugin - Publishing plugin
### Removed ### Removed
- Bintray publishing - Bintray publishing
@ -108,12 +113,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Adaptive support for host OS in native - Adaptive support for host OS in native
- CSS support for JS targets - CSS support for JS targets
### Changed ### Changed
- Kotlin 1.4.31 - Kotlin 1.4.31
- Coroutines 1.4.3 - Coroutines 1.4.3
### Fixed ### Fixed
- Plugin loading order for publishing - Plugin loading order for publishing
- Release task - Release task
@ -125,7 +128,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add sonatype publishing - Add sonatype publishing
- Per-platform release publishing - Per-platform release publishing
### Changed ### Changed
- Kotlin to 1.4.30 stable. - Kotlin to 1.4.30 stable.
- Added intermediate jsCommon main/test sourcesSet for node plugin. - Added intermediate jsCommon main/test sourcesSet for node plugin.
@ -133,11 +135,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Common plugin id changed to `common` - Common plugin id changed to `common`
- Plugins group changed to `ru.mipt.npm` with `gradle` prefix - Plugins group changed to `ru.mipt.npm` with `gradle` prefix
### Removed ### Removed
- kaml - kaml
### Fixed ### Fixed
- Fix publishing load order for sonatype - Fix publishing load order for sonatype
- Fix root project readme - Fix root project readme
@ -151,7 +151,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Moved all logic to a common plugin, leaving only proxies for platform plugins - Moved all logic to a common plugin, leaving only proxies for platform plugins
- Suppress API validation for modules with maturity below DEVELOPMENT - Suppress API validation for modules with maturity below DEVELOPMENT
### Changed ### Changed
- Remove node plugin. Node binaries should be turned on manually. - Remove node plugin. Node binaries should be turned on manually.
- Use default webpack distribution path. - Use default webpack distribution path.
@ -162,12 +161,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Moved internals to internals - Moved internals to internals
- Kotlin 1.4.30-RC - Kotlin 1.4.30-RC
### Deprecated ### Deprecated
- Support of `kaml` and `snake-yaml` in favor of `yamlKt` - Support of `kaml` and `snake-yaml` in favor of `yamlKt`
- Publish plugin - Publish plugin
### Removed ### Removed
- `useDokka` method. Documentation jar should be added manually if needed. - `useDokka` method. Documentation jar should be added manually if needed.
@ -178,7 +175,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add `application()` toggle in plugin configuration to produce binaries on JS and applicaion plugin on jvm. - Add `application()` toggle in plugin configuration to produce binaries on JS and applicaion plugin on jvm.
- Add `publish` to expose publishing configuration. - Add `publish` to expose publishing configuration.
### Changed ### Changed
-Publishing in bintray now is automatic. -Publishing in bintray now is automatic.

View File

@ -33,12 +33,13 @@ dependencies {
implementation(libs.dokka.gradle) implementation(libs.dokka.gradle)
implementation(libs.kotlin.jupyter.gradle) implementation(libs.kotlin.jupyter.gradle)
implementation(libs.kotlin.serialization) implementation(libs.kotlin.serialization)
@Suppress("UnstableApiUsage")
implementation(libs.kotlinx.html) implementation(libs.kotlinx.html)
implementation("org.tomlj:tomlj:1.0.0") implementation("org.tomlj:tomlj:1.0.0")
// // nexus publishing plugin // // nexus publishing plugin
// implementation("io.github.gradle-nexus:publish-plugin:1.1.0") // implementation("io.github.gradle-nexus:publish-plugin:1.1.0")
implementation("org.freemarker:freemarker:2.3.31")
testImplementation(kotlin("test")) testImplementation(kotlin("test"))
} }
@ -58,7 +59,7 @@ gradlePlugin {
create("project") { create("project") {
id = "ru.mipt.npm.gradle.project" id = "ru.mipt.npm.gradle.project"
description = "The root plugin for multimodule project infrastructure" description = "The root plugin for multi-module project infrastructure"
implementationClass = "ru.mipt.npm.gradle.KScienceProjectPlugin" implementationClass = "ru.mipt.npm.gradle.KScienceProjectPlugin"
} }
@ -122,7 +123,7 @@ afterEvaluate {
publications { publications {
create<MavenPublication>("catalog") { create<MavenPublication>("catalog") {
from(components["versionCatalog"]) from(components["versionCatalog"])
this.artifactId = "version-catalog" artifactId = "version-catalog"
pom { pom {
name.set("version-catalog") name.set("version-catalog")
@ -134,6 +135,7 @@ afterEvaluate {
artifact(javadocsJar) artifact(javadocsJar)
pom { pom {
name.set(project.name)
description.set(project.description) description.set(project.description)
url.set(vcs) url.set(vcs)
@ -212,6 +214,10 @@ afterEvaluate {
} }
} }
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.jvmTarget = "11"
}
tasks.processResources.configure { tasks.processResources.configure {
duplicatesStrategy = DuplicatesStrategy.INCLUDE duplicatesStrategy = DuplicatesStrategy.INCLUDE
from("gradle/libs.versions.toml") from("gradle/libs.versions.toml")

View File

@ -1,25 +1,25 @@
[versions] [versions]
tools = "0.10.7" tools = "0.11.2-kotlin-1.6.10"
kotlin = "1.6.0" kotlin = "1.6.10"
atomicfu = "0.16.3" atomicfu = "0.17.1"
binary-compatibility-validator = "0.8.0" binary-compatibility-validator = "0.8.0"
changelog = "1.3.1" changelog = "1.3.1"
dokka = "1.5.30" dokka = "1.6.10"
kotlin-jupyter = "0.10.3-36" kotlin-jupyter = "0.11.0-62"
kotlinx-benchmark = "0.3.1" kotlinx-benchmark = "0.4.2"
kotlinx-cli = "0.3.3" kotlinx-cli = "0.3.4"
kotlinx-collections-immutable = "0.3.4" kotlinx-collections-immutable = "0.3.5"
kotlinx-coroutines = "1.5.2" kotlinx-coroutines = "1.6.0"
kotlinx-datetime = "0.3.1" kotlinx-datetime = "0.3.2"
kotlinx-html = "0.7.3" kotlinx-html = "0.7.3"
kotlinx-knit = "0.2.3" kotlinx-knit = "0.3.0"
kotlinx-nodejs = "0.0.7" kotlinx-nodejs = "0.0.7"
kotlinx-serialization = "1.3.1" kotlinx-serialization = "1.3.2"
ktor = "1.6.3" ktor = "1.6.7"
xmlutil = "0.83.0" xmlutil = "0.84.0"
yamlkt = "0.10.2" yamlkt = "0.10.2"
jsBom = "0.0.1-pre.265-kotlin-1.5.31" jsBom = "0.0.1-pre.313-kotlin-1.6.10"
junit = "5.8.1" junit = "5.8.2"
[libraries] [libraries]
atomicfu-gradle = { module = "org.jetbrains.kotlinx:atomicfu-gradle-plugin", version.ref = "atomicfu" } atomicfu-gradle = { module = "org.jetbrains.kotlinx:atomicfu-gradle-plugin", version.ref = "atomicfu" }

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -1,3 +1 @@
rootProject.name = "gradle-tools" rootProject.name = "gradle-tools"
enableFeaturePreview("VERSION_CATALOGS")

View File

@ -2,169 +2,10 @@ package ru.mipt.npm.gradle
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.*
import org.jetbrains.dokka.gradle.DokkaPlugin
import org.jetbrains.kotlin.gradle.dsl.KotlinJsProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import ru.mipt.npm.gradle.internal.applyRepos
import ru.mipt.npm.gradle.internal.applySettings
import ru.mipt.npm.gradle.internal.fromJsDependencies
@Suppress("UNUSED_VARIABLE") @Suppress("UNUSED_VARIABLE")
public open class KScienceCommonPlugin : Plugin<Project> { public open class KScienceCommonPlugin : Plugin<Project> {
public companion object{ override fun apply(project: Project): Unit = project.configureKScience(
public val defaultJvmArgs: List<String> = listOf("-Xjvm-default=all","-Xlambdas=indy") KotlinVersion(1, 6, 10)
} )
override fun apply(project: Project): Unit = project.run {
//Common configuration
registerKScienceExtension()
repositories.applyRepos()
//Configuration for K-JVM plugin
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
//logger.info("Applying KScience configuration for JVM project")
configure<KotlinJvmProjectExtension> {
explicitApiWarning()
sourceSets.all {
languageSettings.applySettings()
}
sourceSets["test"].apply {
dependencies {
implementation(kotlin("test-junit5"))
implementation("org.junit.jupiter:junit-jupiter:${KScienceVersions.junit}")
}
}
}
tasks.withType<KotlinJvmCompile> {
kotlinOptions {
jvmTarget = KScienceVersions.JVM_TARGET.toString()
freeCompilerArgs = freeCompilerArgs + defaultJvmArgs
}
}
extensions.findByType<JavaPluginExtension>()?.apply {
targetCompatibility = KScienceVersions.JVM_TARGET
}
tasks.withType<Test> {
useJUnitPlatform()
}
}
pluginManager.withPlugin("org.jetbrains.kotlin.js") {
//logger.info("Applying KScience configuration for JS project")
configure<KotlinJsProjectExtension> {
explicitApiWarning()
js(IR) {
browser {
commonWebpackConfig {
cssSupport.enabled = true
}
}
}
sourceSets.all {
languageSettings.applySettings()
}
sourceSets["main"].apply {
dependencies {
api(project.dependencies.platform("org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:${KScienceVersions.jsBom}"))
}
}
sourceSets["test"].apply {
dependencies {
implementation(kotlin("test-js"))
}
}
}
(tasks.findByName("processResources") as? Copy)?.apply {
fromJsDependencies("runtimeClasspath")
}
}
pluginManager.withPlugin("org.jetbrains.kotlin.multiplatform") {
configure<KotlinMultiplatformExtension> {
explicitApiWarning()
jvm {
compilations.all {
kotlinOptions {
jvmTarget = KScienceVersions.JVM_TARGET.toString()
freeCompilerArgs = freeCompilerArgs + defaultJvmArgs
}
}
}
js(IR) {
browser {
commonWebpackConfig {
cssSupport.enabled = true
}
}
}
sourceSets {
val commonMain by getting {
dependencies {
api(project.dependencies.platform("org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:${KScienceVersions.jsBom}"))
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val jvmMain by getting
val jvmTest by getting {
dependencies {
implementation(kotlin("test-junit5"))
implementation("org.junit.jupiter:junit-jupiter:${KScienceVersions.junit}")
}
}
val jsMain by getting
val jsTest by getting {
dependencies {
implementation(kotlin("test-js"))
}
}
}
sourceSets.all {
languageSettings.applySettings()
}
(tasks.findByName("jsProcessResources") as? Copy)?.apply {
fromJsDependencies("jsRuntimeClasspath")
}
extensions.findByType<JavaPluginExtension>()?.apply {
targetCompatibility = KScienceVersions.JVM_TARGET
}
tasks.withType<Test> {
useJUnitPlatform()
}
}
}
// apply dokka for all projects
if (!plugins.hasPlugin("org.jetbrains.dokka")) {
apply<DokkaPlugin>()
}
}
} }

View File

@ -141,12 +141,13 @@ public class KScienceExtension(public val project: Project) {
} }
/** /**
* Apply jupyter plugin and add entry point for the jupyter library * Apply jupyter plugin and add entry point for the jupyter library.
* If left empty applies a plugin without declaring library producers
*/ */
public fun jupyterLibrary(pluginClass: String, vararg additionalPluginClasses: String) { public fun jupyterLibrary(vararg pluginClasses: String) {
project.plugins.apply("org.jetbrains.kotlin.jupyter.api") project.plugins.apply("org.jetbrains.kotlin.jupyter.api")
project.tasks.named("processJupyterApiResources", JupyterApiResourcesTask::class.java) { project.tasks.named("processJupyterApiResources", JupyterApiResourcesTask::class.java) {
libraryProducers = listOf(pluginClass, *additionalPluginClasses) libraryProducers = pluginClasses.toList()
} }
} }

View File

@ -23,6 +23,8 @@ public class KScienceNativePlugin : Plugin<Project> {
linuxX64(), linuxX64(),
mingwX64(), mingwX64(),
macosX64(), macosX64(),
iosX64(),
iosArm64()
) )
sourceSets { sourceSets {

View File

@ -2,7 +2,10 @@ package ru.mipt.npm.gradle
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.kotlin.dsl.* import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.findPlugin
import org.gradle.kotlin.dsl.invoke
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
/** /**

View File

@ -1,11 +1,10 @@
package ru.mipt.npm.gradle package ru.mipt.npm.gradle
import groovy.text.SimpleTemplateEngine
import kotlinx.validation.ApiValidationExtension import kotlinx.validation.ApiValidationExtension
import kotlinx.validation.BinaryCompatibilityValidatorPlugin import kotlinx.validation.BinaryCompatibilityValidatorPlugin
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task import org.gradle.api.publish.maven.tasks.PublishToMavenRepository
import org.gradle.kotlin.dsl.* import org.gradle.kotlin.dsl.*
import org.jetbrains.changelog.ChangelogPlugin import org.jetbrains.changelog.ChangelogPlugin
import org.jetbrains.changelog.ChangelogPluginExtension import org.jetbrains.changelog.ChangelogPluginExtension
@ -13,11 +12,12 @@ import org.jetbrains.dokka.gradle.AbstractDokkaTask
import org.jetbrains.dokka.gradle.DokkaPlugin import org.jetbrains.dokka.gradle.DokkaPlugin
import ru.mipt.npm.gradle.internal.* import ru.mipt.npm.gradle.internal.*
private fun Project.allTasks(): Set<Task> = allprojects.flatMapTo(HashSet()) { it.tasks } /**
* Simplifies adding repositories for Maven publishing, responds for releasing tasks for projects.
@Suppress("unused") */
public class KSciencePublishingExtension(public val project: Project) { public class KSciencePublishingExtension(public val project: Project) {
private var isVcsInitialized = false private var isVcsInitialized = false
internal val repositoryNames = mutableSetOf<String>()
@Deprecated("Use git function and report an issue if other VCS is used.") @Deprecated("Use git function and report an issue if other VCS is used.")
public fun vcs(vcsUrl: String) { public fun vcs(vcsUrl: String) {
@ -54,61 +54,60 @@ public class KSciencePublishingExtension(public val project: Project) {
} }
} }
private fun linkPublicationsToReleaseTask(name: String) = project.afterEvaluate {
allTasks()
.filter { it.name == "publish${publicationTarget}To${name.capitalize()}Repository" }
.forEach { releaseTask?.dependsOn(it) }
}
/** /**
* Adds GitHub as VCS and adds GitHub Packages Maven repository to publishing. * Adds GitHub as VCS and adds GitHub Packages Maven repository to publishing.
* *
* @param githubProject the GitHub project. * @param githubProject the GitHub project.
* @param githubOrg the GitHub user or organization. * @param githubOrg the GitHub user or organization.
* @param release whether publish packages in the `release` task to the GitHub repository. * @param addToRelease publish packages in the `release` task to the GitHub repository.
*/ */
public fun github(githubProject: String, githubOrg: String = "mipt-npm", release: Boolean = false, publish: Boolean = true) { public fun github(
githubProject: String,
githubOrg: String = "mipt-npm",
addToRelease: Boolean = project.requestPropertyOrNull("publishing.github") == "true",
) {
// Automatically initialize VCS using GitHub // Automatically initialize VCS using GitHub
if (!isVcsInitialized) { if (!isVcsInitialized) {
git("https://github.com/$githubOrg/${githubProject}", "https://github.com/$githubOrg/${githubProject}.git") git("https://github.com/$githubOrg/${githubProject}", "https://github.com/$githubOrg/${githubProject}.git")
} }
if (publish) project.addGithubPublishing(githubOrg, githubProject) if (addToRelease) {
if (release) linkPublicationsToReleaseTask("github") try {
project.addGithubPublishing(githubOrg, githubProject)
repositoryNames += "github"
} catch (t: Throwable) {
project.logger.error("Failed to set up github publication", t)
}
} }
private val releaseTask by lazy {
project.tasks.findByName("release")
} }
/** /**
* Adds Space Packages Maven repository to publishing. * Adds Space Packages Maven repository to publishing.
* *
* @param spaceRepo the repository URL. * @param spaceRepo the repository URL.
* @param release whether publish packages in the `release` task to the Space repository. * @param addToRelease publish packages in the `release` task to the Space repository.
*/ */
public fun space(spaceRepo: String = "https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven", release: Boolean = true) { public fun space(
spaceRepo: String = "https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven",
addToRelease: Boolean = project.requestPropertyOrNull("publishing.space") != "false",
) {
project.addSpacePublishing(spaceRepo) project.addSpacePublishing(spaceRepo)
if (release) linkPublicationsToReleaseTask("space") if (addToRelease) repositoryNames += "space"
} }
// // Bintray publishing
// var bintrayOrg: String? by project.extra
// var bintrayUser: String? by project.extra
// var bintrayApiKey: String? by project.extra
// var bintrayRepo: String? by project.extra
/** /**
* Adds Sonatype Maven repository to publishing. * Adds Sonatype Maven repository to publishing.
* *
* @param release whether publish packages in the `release` task to the Sonatype repository. * @param addToRelease publish packages in the `release` task to the Sonatype repository.
*/ */
public fun sonatype(release: Boolean = true) { public fun sonatype(
addToRelease: Boolean = (project.requestPropertyOrNull("publishing.sonatype") != "false"),
) {
require(isVcsInitialized) { "The project vcs is not set up use 'git' method to do so" } require(isVcsInitialized) { "The project vcs is not set up use 'git' method to do so" }
project.addSonatypePublishing() project.addSonatypePublishing()
if (release) linkPublicationsToReleaseTask("sonatype") if (addToRelease) repositoryNames += "sonatype"
} }
} }
@ -119,7 +118,6 @@ public class KSciencePublishingExtension(public val project: Project) {
public open class KScienceProjectPlugin : Plugin<Project> { public open class KScienceProjectPlugin : Plugin<Project> {
override fun apply(target: Project): Unit = target.run { override fun apply(target: Project): Unit = target.run {
apply<ChangelogPlugin>() apply<ChangelogPlugin>()
apply<DokkaPlugin>() apply<DokkaPlugin>()
apply<BinaryCompatibilityValidatorPlugin>() apply<BinaryCompatibilityValidatorPlugin>()
@ -136,7 +134,8 @@ public open class KScienceProjectPlugin : Plugin<Project> {
} }
val rootReadmeExtension = KScienceReadmeExtension(this) val rootReadmeExtension = KScienceReadmeExtension(this)
extensions.add("ksciencePublish", KSciencePublishingExtension(this)) val ksciencePublish = KSciencePublishingExtension(this)
extensions.add("ksciencePublish", ksciencePublish)
extensions.add("readme", rootReadmeExtension) extensions.add("readme", rootReadmeExtension)
//Add readme generators to individual subprojects //Add readme generators to individual subprojects
@ -150,7 +149,7 @@ public open class KScienceProjectPlugin : Plugin<Project> {
if (readmeExtension.readmeTemplate.exists()) { if (readmeExtension.readmeTemplate.exists()) {
inputs.file(readmeExtension.readmeTemplate) inputs.file(readmeExtension.readmeTemplate)
} }
readmeExtension.additionalFiles.forEach { readmeExtension.inputFiles.forEach {
if (it.exists()) { if (it.exists()) {
inputs.file(it) inputs.file(it)
} }
@ -172,6 +171,36 @@ public open class KScienceProjectPlugin : Plugin<Project> {
} }
} }
val releaseAll by tasks.creating {
group = RELEASE_GROUP
description = "Publish development or production release based on version suffix"
}
allprojects {
afterEvaluate {
ksciencePublish.repositoryNames.forEach { repositoryName ->
val repositoryNameCapitalized = repositoryName.capitalize()
tasks.withType<PublishToMavenRepository>()
.filter { it.name.startsWith("publish") && it.name.endsWith("To${repositoryNameCapitalized}Repository") }
.forEach {
val theName = "release${
it.name.removePrefix("publish").removeSuffix("To${repositoryNameCapitalized}Repository")
}"
val targetReleaseTask = tasks.findByName(theName) ?: tasks.create(theName) {
group = RELEASE_GROUP
description = "Publish platform release artifact"
}
releaseAll.dependsOn(targetReleaseTask)
targetReleaseTask.dependsOn(it)
}
}
}
}
val generateReadme by tasks.creating { val generateReadme by tasks.creating {
group = "documentation" group = "documentation"
description = "Generate a README file and a feature matrix if stub is present" description = "Generate a README file and a feature matrix if stub is present"
@ -185,7 +214,8 @@ public open class KScienceProjectPlugin : Plugin<Project> {
if (rootReadmeExtension.readmeTemplate.exists()) { if (rootReadmeExtension.readmeTemplate.exists()) {
inputs.file(rootReadmeExtension.readmeTemplate) inputs.file(rootReadmeExtension.readmeTemplate)
} }
rootReadmeExtension.additionalFiles.forEach {
rootReadmeExtension.inputFiles.forEach {
if (it.exists()) { if (it.exists()) {
inputs.file(it) inputs.file(it)
} }
@ -207,8 +237,7 @@ public open class KScienceProjectPlugin : Plugin<Project> {
val name = subproject.name val name = subproject.name
val path = subproject.path.replaceFirst(":", "").replace(":", "/") val path = subproject.path.replaceFirst(":", "").replace(":", "/")
val ext = subproject.extensions.findByType<KScienceReadmeExtension>() val ext = subproject.extensions.findByType<KScienceReadmeExtension>()
appendLine("<hr/>") appendLine("\n### [$name]($path)")
appendLine("\n* ### [$name]($path)")
if (ext != null) { if (ext != null) {
appendLine("> ${ext.description}") appendLine("> ${ext.description}")
appendLine(">\n> **Maturity**: ${ext.maturity}") appendLine(">\n> **Maturity**: ${ext.maturity}")
@ -219,16 +248,13 @@ public open class KScienceProjectPlugin : Plugin<Project> {
} }
} }
} }
appendLine("<hr/>")
} }
val rootReadmeProperties: Map<String, Any?> = rootReadmeExtension.property("modules", modulesString)
rootReadmeExtension.actualizedProperties + ("modules" to modulesString)
readmeFile.writeText( rootReadmeExtension.readmeString()?.let {
SimpleTemplateEngine().createTemplate(rootReadmeExtension.readmeTemplate) readmeFile.writeText(it)
.make(rootReadmeProperties).toString() }
)
} }
} }
@ -238,14 +264,6 @@ public open class KScienceProjectPlugin : Plugin<Project> {
dependsOn(generateReadme) dependsOn(generateReadme)
} }
//val patchChangelog by tasks.getting
@Suppress("UNUSED_VARIABLE") val release by tasks.creating {
group = RELEASE_GROUP
description = "Publish development or production release based on version suffix"
dependsOn(generateReadme)
}
// Disable API validation for snapshots // Disable API validation for snapshots
if (isSnapshot()) { if (isSnapshot()) {
extensions.findByType<ApiValidationExtension>()?.apply { extensions.findByType<ApiValidationExtension>()?.apply {

View File

@ -1,6 +1,9 @@
package ru.mipt.npm.gradle package ru.mipt.npm.gradle
import groovy.text.SimpleTemplateEngine import freemarker.cache.StringTemplateLoader
import freemarker.template.Configuration
import freemarker.template.Template
import freemarker.template.TemplateNotFoundException
import kotlinx.html.TagConsumer import kotlinx.html.TagConsumer
import kotlinx.html.div import kotlinx.html.div
import kotlinx.html.stream.createHTML import kotlinx.html.stream.createHTML
@ -8,6 +11,7 @@ import kotlinx.validation.ApiValidationExtension
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.kotlin.dsl.findByType import org.gradle.kotlin.dsl.findByType
import java.io.File import java.io.File
import java.io.StringWriter
import kotlin.collections.component1 import kotlin.collections.component1
import kotlin.collections.component2 import kotlin.collections.component2
import kotlin.collections.set import kotlin.collections.set
@ -20,6 +24,12 @@ public enum class Maturity {
DEPRECATED DEPRECATED
} }
private fun Template.processToString(args: Map<String, Any?>): String {
val writer = StringWriter()
process(args, writer)
return writer.toString()
}
public class KScienceReadmeExtension(public val project: Project) { public class KScienceReadmeExtension(public val project: Project) {
public var description: String = project.description ?: "" public var description: String = project.description ?: ""
@ -40,7 +50,41 @@ public class KScienceReadmeExtension(public val project: Project) {
} }
} }
/**
* If true, use default templates provided by plugin if override is not defined
*/
public var useDefaultReadmeTemplate: Boolean = true
/**
* Use this template file if it is provided, otherwise use default template
*/
public var readmeTemplate: File = project.file("docs/README-TEMPLATE.md") public var readmeTemplate: File = project.file("docs/README-TEMPLATE.md")
set(value) {
field = value
if (value.exists()) {
fmLoader.putTemplate("readme", value.readText())
}
}
private val fmLoader = StringTemplateLoader().apply {
putTemplate(
"artifact",
this@KScienceReadmeExtension.javaClass.getResource("/templates/ARTIFACT-TEMPLATE.md")!!.readText()
)
if (readmeTemplate.exists()) {
putTemplate("readme", readmeTemplate.readText())
} else if (useDefaultReadmeTemplate) {
putTemplate(
"readme",
this@KScienceReadmeExtension.javaClass.getResource("/templates/README-TEMPLATE.md")!!.readText()
)
}
}
private val fmCfg = Configuration(Configuration.VERSION_2_3_31).apply {
defaultEncoding = "UTF-8"
templateLoader = fmLoader
}
public data class Feature(val id: String, val description: String, val ref: String?, val name: String = id) public data class Feature(val id: String, val description: String, val ref: String?, val name: String = id)
@ -73,11 +117,20 @@ public class KScienceReadmeExtension(public val project: Project) {
"name" to { project.name }, "name" to { project.name },
"group" to { project.group }, "group" to { project.group },
"version" to { project.version }, "version" to { project.version },
"features" to { featuresString() } "description" to { project.description ?: "" },
"features" to { featuresString() },
"published" to { project.plugins.findPlugin("maven-publish") != null },
"artifact" to {
val projectProperties = mapOf(
"name" to project.name,
"group" to project.group,
"version" to project.version
)
fmCfg.getTemplate("artifact").processToString(projectProperties)
}
) )
public val actualizedProperties: Map<String, Any?> public fun getPropertyValues(): Map<String, Any?> = properties.mapValues { (_, value) -> value() }
get() = properties.mapValues { (_, value) -> value() }
public fun property(key: String, value: Any?) { public fun property(key: String, value: Any?) {
properties[key] = { value } properties[key] = { value }
@ -87,17 +140,28 @@ public class KScienceReadmeExtension(public val project: Project) {
properties[key] = value properties[key] = value
} }
public fun propertyByTemplate(key: String, template: String) { public fun propertyByTemplate(key: String, templateString: String) {
val actual = actualizedProperties //need to freeze it, otherwise values could change
properties[key] = { SimpleTemplateEngine().createTemplate(template).make(actual).toString() } val actual = getPropertyValues()
fmLoader.putTemplate(key, templateString)
val template = fmCfg.getTemplate(key)
properties[key] = { template.processToString(actual) }
} }
internal val additionalFiles = ArrayList<File>() /**
* Files that are use in readme generation
*/
internal val inputFiles = ArrayList<File>()
public fun propertyByTemplate(key: String, template: File) { public fun propertyByTemplate(key: String, templateFile: File) {
val actual = actualizedProperties //need to freeze it, otherwise values could change
properties[key] = { SimpleTemplateEngine().createTemplate(template).make(actual).toString() } val actual = getPropertyValues()
additionalFiles += template fmLoader.putTemplate(key, templateFile.readText())
val template: Template = fmCfg.getTemplate(key)
properties[key] = { template.processToString(actual) }
inputFiles += templateFile
} }
/** /**
@ -110,12 +174,12 @@ public class KScienceReadmeExtension(public val project: Project) {
} }
/** /**
* Generate a readme string from the stub * Generate a readme string from the template
*/ */
public fun readmeString(): String? = if (readmeTemplate.exists()) { public fun readmeString(): String? = try {
val actual = actualizedProperties fmCfg.getTemplate("readme").processToString(getPropertyValues())
SimpleTemplateEngine().createTemplate(readmeTemplate).make(actual).toString() } catch (ex: TemplateNotFoundException) {
} else { project.logger.warn("Template with name ${ex.templateName} not found in ${project.name}")
null null
} }
} }

View File

@ -0,0 +1,166 @@
package ru.mipt.npm.gradle
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.*
import org.jetbrains.dokka.gradle.DokkaPlugin
import org.jetbrains.kotlin.gradle.dsl.KotlinJsProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import ru.mipt.npm.gradle.internal.applyRepos
import ru.mipt.npm.gradle.internal.applySettings
import ru.mipt.npm.gradle.internal.fromJsDependencies
private val defaultJvmArgs: List<String> = listOf("-Xjvm-default=all", "-Xlambdas=indy")
public fun Project.configureKScience(
kotlinVersion: KotlinVersion
){
//Common configuration
registerKScienceExtension()
repositories.applyRepos()
//Configuration for K-JVM plugin
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
//logger.info("Applying KScience configuration for JVM project")
configure<KotlinJvmProjectExtension> {
explicitApiWarning()
sourceSets.all {
languageSettings.applySettings(kotlinVersion)
}
sourceSets["test"].apply {
dependencies {
implementation(kotlin("test-junit5"))
implementation("org.junit.jupiter:junit-jupiter:${KScienceVersions.junit}")
}
}
}
tasks.withType<KotlinJvmCompile> {
kotlinOptions {
jvmTarget = KScienceVersions.JVM_TARGET.toString()
freeCompilerArgs = freeCompilerArgs + defaultJvmArgs
}
}
extensions.findByType<JavaPluginExtension>()?.apply {
targetCompatibility = KScienceVersions.JVM_TARGET
}
tasks.withType<Test> {
useJUnitPlatform()
}
}
pluginManager.withPlugin("org.jetbrains.kotlin.js") {
//logger.info("Applying KScience configuration for JS project")
configure<KotlinJsProjectExtension> {
explicitApiWarning()
js(IR) {
browser {
commonWebpackConfig {
cssSupport.enabled = true
}
}
}
sourceSets.all {
languageSettings.applySettings(kotlinVersion)
}
sourceSets["main"].apply {
dependencies {
api(project.dependencies.platform("org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:${KScienceVersions.jsBom}"))
}
}
sourceSets["test"].apply {
dependencies {
implementation(kotlin("test-js"))
}
}
}
(tasks.findByName("processResources") as? Copy)?.apply {
fromJsDependencies("runtimeClasspath")
}
}
pluginManager.withPlugin("org.jetbrains.kotlin.multiplatform") {
configure<KotlinMultiplatformExtension> {
explicitApiWarning()
jvm {
compilations.all {
kotlinOptions {
jvmTarget = KScienceVersions.JVM_TARGET.toString()
freeCompilerArgs = freeCompilerArgs + defaultJvmArgs
}
}
}
js(IR) {
browser {
commonWebpackConfig {
cssSupport.enabled = true
}
}
}
sourceSets {
val commonMain by getting {
dependencies {
api(project.dependencies.platform("org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:${KScienceVersions.jsBom}"))
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val jvmMain by getting
val jvmTest by getting {
dependencies {
implementation(kotlin("test-junit5"))
implementation("org.junit.jupiter:junit-jupiter:${KScienceVersions.junit}")
}
}
val jsMain by getting
val jsTest by getting {
dependencies {
implementation(kotlin("test-js"))
}
}
}
sourceSets.all {
languageSettings.applySettings(kotlinVersion)
}
(tasks.findByName("jsProcessResources") as? Copy)?.apply {
fromJsDependencies("jsRuntimeClasspath")
}
extensions.findByType<JavaPluginExtension>()?.apply {
targetCompatibility = KScienceVersions.JVM_TARGET
}
tasks.withType<Test> {
useJUnitPlatform()
}
}
}
// apply dokka for all projects
if (!plugins.hasPlugin("org.jetbrains.dokka")) {
apply<DokkaPlugin>()
}
}

View File

@ -11,9 +11,12 @@ import org.gradle.language.jvm.tasks.ProcessResources
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
internal fun LanguageSettingsBuilder.applySettings() { internal fun LanguageSettingsBuilder.applySettings(
languageVersion = "1.6" kotlinVersion: KotlinVersion
apiVersion = "1.6" ) {
val versionString = "${kotlinVersion.major}.${kotlinVersion.minor}"
languageVersion = versionString
apiVersion = versionString
progressiveMode = true progressiveMode = true
optIn("kotlin.RequiresOptIn") optIn("kotlin.RequiresOptIn")

View File

@ -2,7 +2,6 @@ package ru.mipt.npm.gradle.internal
import org.apache.tools.ant.taskdefs.condition.Os import org.apache.tools.ant.taskdefs.condition.Os
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.findByType import org.gradle.kotlin.dsl.findByType
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension

View File

@ -11,10 +11,10 @@ import org.gradle.plugins.signing.SigningPlugin
import org.jetbrains.kotlin.gradle.dsl.KotlinJsProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinJsProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
private fun Project.requestPropertyOrNull(propertyName: String): String? = findProperty(propertyName) as? String internal fun Project.requestPropertyOrNull(propertyName: String): String? = findProperty(propertyName) as? String
?: System.getenv(propertyName) ?: System.getenv(propertyName)
private fun Project.requestProperty(propertyName: String): String = requestPropertyOrNull(propertyName) internal fun Project.requestProperty(propertyName: String): String = requestPropertyOrNull(propertyName)
?: error("Property $propertyName not defined") ?: error("Property $propertyName not defined")
@ -27,12 +27,10 @@ internal fun Project.setupPublication(mavenPomConfiguration: MavenPom.() -> Unit
val sourcesJar by tasks.creating(Jar::class) { val sourcesJar by tasks.creating(Jar::class) {
archiveClassifier.set("sources") archiveClassifier.set("sources")
kotlin.sourceSets.forEach {
kotlin.sourceSets.all { from(it.kotlin)
from(kotlin)
} }
} }
afterEvaluate {
publications.create<MavenPublication>("js") { publications.create<MavenPublication>("js") {
kotlin.js().components.forEach { kotlin.js().components.forEach {
from(it) from(it)
@ -40,7 +38,7 @@ internal fun Project.setupPublication(mavenPomConfiguration: MavenPom.() -> Unit
artifact(sourcesJar) artifact(sourcesJar)
} }
}
} }
plugins.withId("org.jetbrains.kotlin.jvm") { plugins.withId("org.jetbrains.kotlin.jvm") {
@ -69,7 +67,6 @@ internal fun Project.setupPublication(mavenPomConfiguration: MavenPom.() -> Unit
} }
// Process each publication we have in this project // Process each publication we have in this project
afterEvaluate {
publications.withType<MavenPublication> { publications.withType<MavenPublication> {
artifact(dokkaJar) artifact(dokkaJar)
@ -104,20 +101,9 @@ internal fun Project.setupPublication(mavenPomConfiguration: MavenPom.() -> Unit
} }
} }
} }
}
internal fun Project.isSnapshot() = "dev" in version.toString() || version.toString().endsWith("SNAPSHOT") internal fun Project.isSnapshot() = "dev" in version.toString() || version.toString().endsWith("SNAPSHOT")
internal val Project.publicationTarget: String
get() {
val publicationPlatform = project.findProperty("publishing.platform") as? String
return if (publicationPlatform == null) {
"AllPublications"
} else {
publicationPlatform.capitalize() + "Publication"
}
}
internal fun Project.addGithubPublishing( internal fun Project.addGithubPublishing(
githubOrg: String, githubOrg: String,
githubProject: String, githubProject: String,
@ -126,8 +112,8 @@ internal fun Project.addGithubPublishing(
logger.info("Skipping github publishing because publishing is disabled") logger.info("Skipping github publishing because publishing is disabled")
return return
} }
if (requestPropertyOrNull("publishing.github") == "false") { if (requestPropertyOrNull("publishing.github") != "false") {
logger.info("Skipping github publishing because `publishing.github == false`") logger.info("Skipping github publishing because `publishing.github != true`")
return return
} }

View File

@ -0,0 +1,26 @@
## Artifact:
The Maven coordinates of this project are `${group}:${name}:${version}`.
**Gradle Groovy:**
```groovy
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation '${group}:${name}:${version}'
}
```
**Gradle Kotlin DSL:**
```kotlin
repositories {
maven("https://repo.kotlin.link")
mavenCentral()
}
dependencies {
implementation("${group}:${name}:${version}")
}
```

View File

@ -0,0 +1,15 @@
# Module ${name}
${description}
<#if features?has_content>
## Features
${features}
</#if>
<#if published>
## Usage
${artifact}
</#if>