plugins { id 'java' id 'maven-publish' id 'java-gradle-plugin' id 'idea' id 'eclipse' id 'groovy' id 'checkstyle' id 'codenarc' alias(libs.plugins.kotlin) alias(libs.plugins.spotless) alias(libs.plugins.retry) } tasks.withType(JavaCompile).configureEach { it.options.encoding = "UTF-8" } tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { kotlinOptions { jvmTarget = "21" } } group = "dev.architectury" def baseVersion = '1.12' def ENV = System.getenv() def runNumber = ENV.GITHUB_RUN_NUMBER ?: "9999" def isSnapshot = ENV.PR_NUM != null if (!isSnapshot) { version = baseVersion + "." + runNumber } else { version = baseVersion + "-PR." + ENV.PR_NUM + "." + runNumber } logger.lifecycle(":building plugin v${version}") // We must build against the version of Kotlin Gradle ships with. def props = new Properties() Project.class.getClassLoader().getResource("gradle-kotlin-dsl-versions.properties").openStream().withCloseable { props.load(it) } def kotlinVersion = props.getProperty("kotlin") if (libs.versions.kotlin.get() != kotlinVersion) { throw new IllegalStateException("Requires Kotlin version: ${kotlinVersion}") } repositories { mavenCentral() maven { url = "https://maven.fabricmc.net/" } maven { url = "https://maven.architectury.dev/" } maven { url = "https://maven.minecraftforge.net/" content { excludeGroupByRegex "org\\.eclipse\\.?.*" } } } configurations.configureEach { resolutionStrategy { // I am sorry, for now // failOnNonReproducibleResolution() } if (canBeConsumed) { attributes { attribute(GradlePluginApiVersion.GRADLE_PLUGIN_API_VERSION_ATTRIBUTE, objects.named(GradlePluginApiVersion, GradleVersion.current().getVersion())) } } } // Arch: Prevent compiling against Guava. // The dependency is still leaked from DFU, but it shouldn't be used to keep up with upstream standards. configurations.named('compileClasspath') { exclude group: 'com.google.guava' } sourceSets { commonDecompiler { java { srcDir("src/decompilers/common") } } fernflower { java { srcDir("src/decompilers/fernflower") } } cfr { java { srcDir("src/decompilers/cfr") } } vineflower { java { srcDir("src/decompilers/vineflower") } } } dependencies { implementation gradleApi() // libraries implementation libs.gson implementation libs.bundles.asm // game handling utils implementation (libs.fabric.stitch) { exclude module: 'mercury' exclude module: 'enigma' } // tinyfile management implementation libs.fabric.tiny.remapper implementation libs.fabric.clazz.tweaker implementation libs.fabric.mapping.io implementation (libs.fabric.lorenz.tiny) { transitive = false } implementation "dev.architectury:refmap-remapper:1.0.5" implementation libs.fabric.loom.nativelib // decompilers fernflowerCompileOnly runtimeLibs.fernflower fernflowerCompileOnly libs.fabric.mapping.io cfrCompileOnly runtimeLibs.cfr cfrCompileOnly libs.fabric.mapping.io vineflowerCompileOnly runtimeLibs.vineflower vineflowerCompileOnly libs.fabric.mapping.io fernflowerApi sourceSets.commonDecompiler.output cfrApi sourceSets.commonDecompiler.output vineflowerApi sourceSets.commonDecompiler.output implementation sourceSets.commonDecompiler.output implementation sourceSets.fernflower.output implementation sourceSets.cfr.output implementation sourceSets.vineflower.output // source code remapping implementation libs.fabric.mercury implementation libs.fabric.unpick implementation libs.fabric.unpick.utils // Kotlin implementation(libs.kotlin.metadata) { transitive = false } // Kapt integration compileOnly libs.kotlin.gradle.plugin // Forge patches implementation libs.lorenz implementation libs.mcinjector implementation libs.opencsv implementation libs.forge.diffpatch implementation libs.datafixerupper implementation libs.at // Forge mods.toml parsing implementation libs.night.config.toml // quilt.mod.json5 parsing implementation libs.jankson // Testing testImplementation(gradleTestKit()) testImplementation(testLibs.spock) { exclude module: 'groovy-all' } testImplementation testLibs.junit.jupiter.engine testRuntimeOnly testLibs.junit.platform.launcher testImplementation (testLibs.javalin) { exclude group: 'org.jetbrains.kotlin' } testImplementation testLibs.mockito testImplementation testLibs.java.debug testImplementation testLibs.bcprov testImplementation testLibs.bcutil testImplementation testLibs.bcpkix testImplementation testLibs.fabric.loader compileOnly runtimeLibs.jetbrains.annotations testCompileOnly runtimeLibs.jetbrains.annotations testCompileOnly (testLibs.mixin) { transitive = false } } jar { manifest { attributes 'Implementation-Version': project.version } from sourceSets.commonDecompiler.output.classesDirs from sourceSets.cfr.output.classesDirs from sourceSets.fernflower.output.classesDirs from sourceSets.vineflower.output.classesDirs } base { archivesName = project.name } tasks.withType(JavaCompile).configureEach { it.options.release = 21 } java { withSourcesJar() sourceCompatibility = JavaVersion.VERSION_21 targetCompatibility = JavaVersion.VERSION_21 } spotless { lineEndings = com.diffplug.spotless.LineEnding.UNIX java { licenseHeaderFile(rootProject.file("HEADER")).yearSeparator("-") targetExclude("**/loom/util/DownloadUtil.java", "**/loom/util/FileSystemUtil.java") targetExclude("**/dev/architectury/**") } groovy { importOrder('java', 'javax', '', 'net.fabricmc', '\\#') licenseHeaderFile(rootProject.file("HEADER")).yearSeparator("-") greclipse() } groovyGradle { target 'src/**/*.gradle', '*.gradle' greclipse() targetExclude( // These files use a @MAPPINGS@ token which is not valid Groovy '**/projects/forge/simple/build.gradle', '**/projects/neoforge/simple/build.gradle' ) } kotlin { licenseHeaderFile(rootProject.file("HEADER")).yearSeparator("-") targetExclude("**/build.gradle.kts") targetExclude("src/test/resources/projects/*/**") ktlint() } } checkstyle { configFile = file('checkstyle.xml') toolVersion = libs.versions.checkstyle.get() } codenarc { toolVersion = libs.versions.codenarc.get() configFile = file("codenarc.groovy") } gradlePlugin { plugins { fabricLoom { id = 'dev.architectury.loom' implementationClass = 'net.fabricmc.loom.LoomGradlePlugin' } fabricLoomCompanion { id = 'dev.architectury.loom-companion' implementationClass = 'net.fabricmc.loom.LoomCompanionGradlePlugin' } } } test { maxHeapSize = "2560m" jvmArgs "-XX:+HeapDumpOnOutOfMemoryError" useJUnitPlatform() // Forward system prop onto tests. if (System.getProperty("fabric.loom.test.homeDir")) { systemProperty "fabric.loom.test.homeDir", System.getProperty("fabric.loom.test.homeDir") } if (ENV.CI) { retry { maxRetries = 3 } } testLogging { // Log everything to the console setEvents(TestLogEvent.values().toList()) } } // Workaround https://github.com/gradle/gradle/issues/25898 tasks.withType(Test).configureEach { jvmArgs = [ '--add-opens=java.base/java.lang=ALL-UNNAMED', '--add-opens=java.base/java.util=ALL-UNNAMED', '--add-opens=java.base/java.lang.invoke=ALL-UNNAMED', '--add-opens=java.base/java.net=ALL-UNNAMED' ] } import org.gradle.api.tasks.testing.logging.TestLogEvent import org.gradle.util.GradleVersion import org.w3c.dom.Document import org.w3c.dom.Element import org.w3c.dom.Node publishing { publications { if (!isSnapshot && !ENV.EXPERIMENTAL) { // Also publish a snapshot so people can use the latest version if they wish snapshot(MavenPublication) { publication -> groupId = project.group artifactId = project.base.archivesName.get() version = baseVersion + '-SNAPSHOT' from components.java } gradlePlugin.plugins.forEach { plugin -> // Manually crate the plugin marker for snapshot versions it.create(plugin.id + "SnapshotMarker", MavenPublication) { publication -> groupId = plugin.id artifactId = plugin.id + '.gradle.plugin' version = baseVersion + '-SNAPSHOT' pom.withXml({ // Based off org.gradle.plugin.devel.plugins.MavenPluginPublishPlugin Element root = asElement() Document document = root.getOwnerDocument() Node dependencies = root.appendChild(document.createElement('dependencies')) Node dependency = dependencies.appendChild(document.createElement('dependency')) Node groupId = dependency.appendChild(document.createElement('groupId')) groupId.setTextContent(project.group) Node artifactId = dependency.appendChild(document.createElement('artifactId')) artifactId.setTextContent(project.archivesBaseName) Node version = dependency.appendChild(document.createElement('version')) version.setTextContent(project.version) }) } } } } repositories { if (ENV.MAVEN_PASS != null) { maven { url = "https://deploy.shedaniel.me/" credentials { username = "shedaniel" password = ENV.MAVEN_PASS } } } } } // A task to output a json file with a list of all the test to run tasks.register('writeActionsTestMatrix') { doLast { def testMatrix = [] def extendedTests = Boolean.parseBoolean(System.getenv('EXTENDED_TESTS') ?: 'false') file('src/test/groovy/net/fabricmc/loom/test/integration').traverse { if (it.name.endsWith("Test.groovy")) { if (it.name.endsWith("ReproducibleBuildTest.groovy")) { // This test gets a special case to run across all os's return } if (it.name.endsWith("DebugLineNumbersTest.groovy") && !extendedTests) { // Known flakey test return } if (it.name.endsWith("FabricAPITest.groovy")) { // Arch: Disabled as it hangs return } def className = it.path.toString().replace(".groovy", "") className = className.substring(className.lastIndexOf("integration/") + "integration/".length()).replace('/', '.') testMatrix.add("net.fabricmc.loom.test.integration.${className}") } } // Run all the unit tests together testMatrix.add("net.fabricmc.loom.test.unit.*") def json = groovy.json.JsonOutput.toJson(testMatrix) def output = file("build/test_matrix.json") output.parentFile.mkdir() output.text = json } } tasks.named('wrapper') { distributionType = Wrapper.DistributionType.ALL } /** * Run this task to download the gradle sources next to the api jar, you may need to manually attach the sources jar */ tasks.register('downloadGradleSources') { doLast { // Awful hack to find the gradle api location def gradleApiFile = project.configurations.detachedConfiguration(dependencies.gradleApi()).files.stream() .find { it.name.startsWith("gradle-api") } def gradleApiSources = new File(gradleApiFile.absolutePath.replace(".jar", "-sources.jar")) def url = "https://services.gradle.org/distributions/gradle-${GradleVersion.current().getVersion()}-src.zip" gradleApiSources.delete() println("Downloading (${url}) to (${gradleApiSources})") gradleApiSources << new URL(url).newInputStream() } } tasks.withType(GenerateModuleMetadata) { enabled = false } tasks.register('printActionsTestName', PrintActionsTestName) { } /** * Replaces invalid characters in test names for GitHub Actions artifacts. */ abstract class PrintActionsTestName extends DefaultTask { @Input @Option(option = "name", description = "The test name") String testName @TaskAction def run() { def sanitised = testName.replace('*', '_') new File(System.getenv().GITHUB_OUTPUT) << "\ntest=$sanitised" } } apply from: rootProject.file('gradle/versions.gradle')