/* * DO NOT CHANGE THIS FILE! * Also, you may replace this file at any time if there is an update available. * Please check https://github.com/GregTechCEu/Buildscripts/blob/master/build.gradle for updates. * You can also run ./gradlew updateBuildScript to update your buildscript. */ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import com.gtnewhorizons.retrofuturagradle.mcp.ReobfuscatedJar import com.modrinth.minotaur.dependencies.ModDependency import com.modrinth.minotaur.dependencies.VersionDependency import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent import org.gradle.internal.logging.text.StyledTextOutputFactory import org.jetbrains.gradle.ext.Gradle import static org.gradle.internal.logging.text.StyledTextOutput.Style plugins { id 'java' id 'java-library' id 'eclipse' id 'maven-publish' id 'org.jetbrains.gradle.plugin.idea-ext' version '1.1.7' id 'com.gtnewhorizons.retrofuturagradle' version '1.3.19' id 'net.darkhax.curseforgegradle' version '1.0.14' apply false id 'com.modrinth.minotaur' version '2.8.0' apply false id 'com.diffplug.spotless' version '6.13.0' apply false id 'com.palantir.git-version' version '3.0.0' apply false id 'com.github.johnrengelman.shadow' version '8.1.1' apply false } if (verifySettingsGradle()) { throw new GradleException("Settings has been updated, please re-run task.") } def out = services.get(StyledTextOutputFactory).create('an-output') // Project properties // Required properties: we don't know how to handle these being missing gracefully checkPropertyExists("modName") checkPropertyExists("modId") checkPropertyExists("modGroup") checkPropertyExists("minecraftVersion") // hard-coding this makes it harder to immediately tell what version a mod is in (even though this only really supports 1.12.2) checkPropertyExists("apiPackage") checkPropertyExists("accessTransformersFile") checkPropertyExists("usesMixins") checkPropertyExists("mixinsPackage") checkPropertyExists("coreModClass") checkPropertyExists("containsMixinsAndOrCoreModOnly") propertyDefaultIfUnset("customMavenPublishUrl", "") // Project property assertions final String javaSourceDir = 'src/main/java/' final String scalaSourceDir = 'src/main/scala/' // If Kotlin is supported, add the path here final String modGroupPath = modGroup.toString().replace('.' as char, '/' as char) final String apiPackagePath = apiPackage.toString().replace('.' as char, '/' as char) String targetPackageJava = javaSourceDir + modGroupPath String targetPackageScala = scalaSourceDir + modGroupPath // If Kotlin is supported, add the path here if (!getFile(targetPackageJava).exists() && !getFile(targetPackageScala).exists()) { throw new GradleException("Could not resolve \"modGroup\"! Could not find ${targetPackageJava} or ${targetPackageScala}") } if (apiPackage) { targetPackageJava = 'src/api/java/' + modGroupPath + '/api' targetPackageScala = 'src/api/java/' + modGroupPath + '/api' if (!getFile(targetPackageJava).exists() && !getFile(targetPackageScala).exists()) { throw new GradleException("Could not resolve \"apiPackage\"! Could not find ${targetPackageJava} or ${targetPackageScala}") } } if (accessTransformersFile) { for (atFile in accessTransformersFile.split(",")) { String targetFile = 'src/main/resources/' + atFile.trim() if (!getFile(targetFile).exists()) { throw new GradleException("Could not resolve \"accessTransformersFile\"! Could not find " + targetFile) } tasks.deobfuscateMergedJarToSrg.accessTransformerFiles.from(targetFile) tasks.srgifyBinpatchedJar.accessTransformerFiles.from(targetFile) } } if (usesMixins.toBoolean()) { if (mixinsPackage.isEmpty()) { throw new GradleException("\"usesMixins\" requires \"mixinsPackage\" to be set!") } final String mixinPackagePath = mixinsPackage.toString().replaceAll('\\.', '/') targetPackageJava = javaSourceDir + modGroupPath + '/' + mixinPackagePath targetPackageScala = scalaSourceDir + modGroupPath + '/' + mixinPackagePath if (!getFile(targetPackageJava).exists()) { throw new GradleException("Could not resolve \"mixinsPackage\"! Could not find ${targetPackageJava} or ${targetPackageScala}") } } if (coreModClass) { final String coreModPath = coreModClass.toString().replaceAll('\\.', '/') String targetFileJava = javaSourceDir + modGroupPath + '/' + coreModPath + '.java' String targetFileScala = scalaSourceDir + modGroupPath + '/' + coreModPath + '.scala' String targetFileScalaJava = scalaSourceDir + modGroupPath + '/' + coreModPath + '.java' if (!getFile(targetFileJava).exists() && !getFile(targetFileScala).exists() && !getFile(targetFileScalaJava).exists()) { throw new GradleException("Could not resolve \"coreModClass\"! Could not find " + targetFileJava) } } // Plugin application // Git version checking, also checking for if this is a submodule if (project.file('.git/HEAD').isFile() || project.file('.git').isFile()) { apply plugin: 'com.palantir.git-version' } // Shadowing if (usesShadowedDependencies.toBoolean()) { apply plugin: 'com.github.johnrengelman.shadow' } java { toolchain { if (enableModernJavaSyntax.toBoolean()) { languageVersion.set(JavaLanguageVersion.of(17)) } else { languageVersion.set(JavaLanguageVersion.of(8)) } // Azul covers the most platforms for Java 8+ toolchains, crucially including MacOS arm64 vendor.set(JvmVendorSpec.AZUL) } if (!noPublishedSources.toBoolean()) { withSourcesJar() } } tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' if (enableModernJavaSyntax.toBoolean()) { if (it.name in ['compileMcLauncherJava', 'compilePatchedMcJava']) { return } sourceCompatibility = 17 options.release.set(8) javaCompiler.set(javaToolchains.compilerFor { languageVersion.set(JavaLanguageVersion.of(17)) vendor.set(JvmVendorSpec.AZUL) }) } } tasks.withType(ScalaCompile).configureEach { options.encoding = 'UTF-8' } // Allow others using this buildscript to have custom gradle code run if (getFile('addon.gradle').exists()) { apply from: 'addon.gradle' } // Configure Minecraft // Try to gather mod version from git tags if version is not manually specified if (!modVersion) { try { modVersion = gitVersion() } catch (Exception ignored) { out.style(Style.Failure).text( "Mod version could not be determined! Property 'modVersion' is not set, and either git is not installed or no git tags exist.\n" + "Either specify a mod version in 'gradle.properties', or create at least one tag in git for this project." ) modVersion = 'NO-GIT-TAG-SET' } } if (includeMCVersionJar.toBoolean()) { version = "${minecraftVersion}-${modVersion}" } else { version = modVersion } group = modGroup archivesBaseName = modArchivesBaseName minecraft { mcVersion = minecraftVersion username = developmentEnvironmentUserName.toString() useDependencyAccessTransformers = true setMcpMappingChannel("snapshot") setMcpMappingVersion("20171003") // Automatic token injection with RetroFuturaGradle if (gradleTokenModId) { injectedTags.put gradleTokenModId, modId } if (gradleTokenModName) { injectedTags.put gradleTokenModName, modName } if (gradleTokenVersion) { injectedTags.put gradleTokenVersion, modVersion } injectedTags.put("VERSION", project.version) injectedTags.put("AEVERSION", aeversion) injectedTags.put("AECHANNEL", aechannel) injectedTags.put("AEBUILD", aebuild) // JVM arguments extraRunJvmArguments.add("-ea:${modGroup}") if (usesMixins.toBoolean()) { extraRunJvmArguments.addAll([ '-Dmixin.hotSwap=true', '-Dmixin.checks.interfaces=true', '-Dmixin.debug.export=true' ]) } if (coreModClass) { extraRunJvmArguments.add("-Dfml.coreMods.load=${modGroup}.${coreModClass}") } } if (generateGradleTokenClass) { tasks.injectTags.outputClassName.set(generateGradleTokenClass) } tasks.named('processIdeaSettings').configure { dependsOn('injectTags') } tasks.register("generateMcModInfo") { } tasks.register("generatePackMcMeta") { } tasks.named('processIdeaSettings').configure { dependsOn('injectTags') } // Repositories // Allow unsafe repos but warn repositories.configureEach { repo -> if (repo instanceof UrlArtifactRepository) { if (repo.getUrl() != null && repo.getUrl().getScheme() == "http" && !repo.allowInsecureProtocol) { logger.warn("Deprecated: Allowing insecure connections for repo '${repo.name}' - add 'allowInsecureProtocol = true'") repo.allowInsecureProtocol = true } } } // Allow adding custom repositories to the buildscript if (getFile('repositories.gradle').exists()) { apply from: 'repositories.gradle' } repositories { exclusiveContent { forRepository { //noinspection ForeignDelegate maven { name = 'Curse Maven' url = 'https://www.cursemaven.com' } } filter { includeGroup 'curse.maven' } } exclusiveContent { forRepository { //noinspection ForeignDelegate maven { name = 'Modrinth' url = 'https://api.modrinth.com/maven' } } filter { includeGroup 'maven.modrinth' } } maven { name 'Cleanroom Maven' url 'https://maven.cleanroommc.com' } maven { name 'BlameJared Maven' url 'https://maven.blamejared.com' } gradlePluginPortal() mavenCentral() mavenLocal() } // Dependencies // Configure dependency configurations configurations { embed implementation.extendsFrom(embed) if (usesShadowedDependencies.toBoolean()) { for (config in [compileClasspath, runtimeClasspath, testCompileClasspath, testRuntimeClasspath]) { config.extendsFrom(shadowImplementation) config.extendsFrom(shadowCompile) } } } dependencies { if (usesMixins.toBoolean() || forceEnableMixins.toBoolean()) { implementation 'zone.rong:mixinbooter:7.0' String mixin = 'org.spongepowered:mixin:0.8.3' if (usesMixins.toBoolean()) { mixin = modUtils.enableMixins(mixin, "mixins.${modId}.refmap.json") } api(mixin) { transitive = false } annotationProcessor(mixin) { transitive = false } annotationProcessor 'org.ow2.asm:asm-debug-all:5.2' // should use 24.1.1 but 30.0+ has a vulnerability fix annotationProcessor 'com.google.guava:guava:30.0-jre' // should use 2.8.6 but 2.8.9+ has a vulnerability fix annotationProcessor 'com.google.code.gson:gson:2.8.9' } if (enableJUnit.toBoolean()) { testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1' testImplementation 'org.hamcrest:hamcrest:2.2' } if (enableModernJavaSyntax.toBoolean()) { annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:1.0.0' compileOnly('com.github.bsideup.jabel:jabel-javac-plugin:1.0.0') { transitive = false } // workaround for https://github.com/bsideup/jabel/issues/174 annotationProcessor 'net.java.dev.jna:jna-platform:5.13.0' // Allow jdk.unsupported classes like sun.misc.Unsafe, workaround for JDK-8206937 and fixes Forge crashes in tests. patchedMinecraft 'me.eigenraven.java8unsupported:java-8-unsupported-shim:1.0.0' // allow Jabel to work in tests testAnnotationProcessor "com.github.bsideup.jabel:jabel-javac-plugin:1.0.0" testCompileOnly("com.github.bsideup.jabel:jabel-javac-plugin:1.0.0") { transitive = false // We only care about the 1 annotation class } testCompileOnly "me.eigenraven.java8unsupported:java-8-unsupported-shim:1.0.0" } compileOnlyApi 'org.jetbrains:annotations:23.0.0' annotationProcessor 'org.jetbrains:annotations:23.0.0' if (includeCommonDevEnvMods.toBoolean()) { implementation 'mezz.jei:jei_1.12.2:4.16.1.302' //noinspection DependencyNotationArgument implementation rfg.deobf('curse.maven:top-245211:2667280') // TOP 1.4.28 } } if (getFile('gradle/scripts/dependencies.gradle').exists()) { apply from: 'gradle/scripts/dependencies.gradle' } apply from: 'gradle/scripts/optional.gradle' // Test configuration // Ensure tests have access to minecraft classes sourceSets { test { java { compileClasspath += patchedMc.output + mcLauncher.output runtimeClasspath += patchedMc.output + mcLauncher.output } } } test { // ensure tests are run with java8 javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(8) }.get() testLogging { events TestLogEvent.STARTED, TestLogEvent.PASSED, TestLogEvent.FAILED exceptionFormat TestExceptionFormat.FULL showExceptions true showStackTraces true showCauses true showStandardStreams true } if (enableJUnit.toBoolean()) { useJUnitPlatform() } } // Resource processing and jar building processResources { // this will ensure that this task is redone when the versions change. inputs.property 'version', modVersion inputs.property 'mcversion', minecraftVersion // Blowdryer puts these files into the resource directory, so // exclude them from builds (doesn't hurt to exclude even if not present) exclude('spotless.importorder') exclude('spotless.eclipseformat.xml') // replace stuff in mcmod.info, nothing else filesMatching('mcmod.info') { fcd -> fcd.expand( 'version': modVersion, 'mcversion': minecraftVersion, 'modid': modId, 'modname': modName ) } if (accessTransformersFile) { String[] ats = accessTransformersFile.split(',') ats.each { at -> rename "(${at})", 'META-INF/$1' } } } // Automatically generate a mixin json file if it does not already exist tasks.register('generateAssets') { group = 'GT Buildscript' description = 'Generates a pack.mcmeta, mcmod.info, or mixins.{modid}.json if needed' doLast { // pack.mcmeta def packMcmetaFile = getFile('src/main/resources/pack.mcmeta') if (!packMcmetaFile.exists()) { packMcmetaFile.text = """{ "pack": { "pack_format": 3, "description": "${modName} Resource Pack" } } """ } // mcmod.info def mcmodInfoFile = getFile('src/main/resources/mcmod.info') if (!mcmodInfoFile.exists()) { mcmodInfoFile.text = """[{ "modid": "\${modid}", "name": "\${modname}", "description": "A Mod about Matter, Energy and using them to conquer the world..", "version": "\${version}", "mcversion": "\${mcversion}", "logoFile": "assets/appliedenergistics2/meta/logo.png", "url": "https://github.com/PrototypeTrousers/Applied-Energistics-2", "authorList": ["AlgorithmX2"], "credits": "AlgorithmX2", "dependencies": [] }] """ } // mixins.{modid}.json if (usesMixins.toBoolean()) { def mixinConfigFile = getFile("src/main/resources/mixins.${modId}.json") if (!mixinConfigFile.exists()) { def mixinConfigRefmap = "mixins.${modId}.refmap.json" mixinConfigFile.text = """{ "package": "${modGroup}.${mixinsPackage}", "refmap": "${mixinConfigRefmap}", "target": "@env(DEFAULT)", "minVersion": "0.8", "compatibilityLevel": "JAVA_8", "mixins": [], "client": [], "server": [] } """ } } } } tasks.named('processResources').configure { dependsOn('generateAssets') } jar { manifest { attributes(getManifestAttributes()) } // Add all embedded dependencies into the jar from provider { configurations.embed.collect { it.isDirectory() ? it : zipTree(it) } } from sourceSets.api.output dependsOn apiClasses // specify which files are really included, can control which APIs should be in include "appeng/**" include "assets/**" include "mcmod.info" include "pack.mcmeta" include "META-INF/appliedenergistics2_at.cfg" } // Create API library jar tasks.register('apiJar', Jar) { archiveClassifier.set 'api' from(sourceSets.api.java) { include "${modGroupPath}/${apiPackagePath}/**" } from(sourceSets.api.output) { include "${modGroupPath}/${apiPackagePath}/**" } } // Configure shadow jar task if (usesShadowedDependencies.toBoolean()) { tasks.named('shadowJar', ShadowJar).configure { manifest { attributes(getManifestAttributes()) } // Only shadow classes that are actually used, if enabled if (minimizeShadowedDependencies.toBoolean()) { minimize() } configurations = [ project.configurations.shadowImplementation, project.configurations.shadowCompile ] archiveClassifier.set('dev') if (relocateShadowedDependencies.toBoolean()) { relocationPrefix = modGroup + '.shadow' enableRelocation = true } } configurations.runtimeElements.outgoing.artifacts.clear() configurations.apiElements.outgoing.artifacts.clear() configurations.runtimeElements.outgoing.artifact(tasks.named('shadowJar', ShadowJar)) configurations.apiElements.outgoing.artifact(tasks.named('shadowJar', ShadowJar)) tasks.named('jar', Jar) { enabled = false finalizedBy(tasks.shadowJar) } tasks.named('reobfJar', ReobfuscatedJar) { inputJar.set(tasks.named('shadowJar', ShadowJar).flatMap({ it.archiveFile })) } AdhocComponentWithVariants javaComponent = (AdhocComponentWithVariants) project.components.findByName('java') javaComponent.withVariantsFromConfiguration(configurations.shadowRuntimeElements) { skip() } for (runTask in ['runClient', 'runServer']) { tasks.named(runTask).configure { dependsOn('shadowJar') } } } def getManifestAttributes() { def attributes = [:] if (coreModClass) { attributes['FMLCorePlugin'] = "${modGroup}.${coreModClass}" } if (!containsMixinsAndOrCoreModOnly.toBoolean() && (usesMixins.toBoolean() || coreModClass)) { attributes['FMLCorePluginContainsFMLMod'] = true } if (accessTransformersFile) { attributes['FMLAT'] = accessTransformersFile.toString() } if (usesMixins.toBoolean()) { attributes['ForceLoadAsMod'] = !containsMixinsAndOrCoreModOnly.toBoolean() } return attributes } // IDE Configuration eclipse { classpath { downloadSources = true downloadJavadoc = true } } idea { module { inheritOutputDirs true downloadJavadoc true downloadSources true } project { settings { runConfigurations { '1. Setup Workspace'(Gradle) { taskNames = ['setupDecompWorkspace'] } '2. Run Client'(Gradle) { taskNames = ['runClient'] } '3. Run Server'(Gradle) { taskNames = ['runServer'] } '4. Run Obfuscated Client'(Gradle) { taskNames = ['runObfClient'] } '5. Run Obfuscated Server'(Gradle) { taskNames = ['runObfServer'] } if (enableSpotless.toBoolean()) { '6. Apply Spotless'(Gradle) { taskNames = ["spotlessApply"] } '7. Build Jars'(Gradle) { taskNames = ['build'] } } else { '6. Build Jars'(Gradle) { taskNames = ['build'] } } 'Update Buildscript'(Gradle) { taskNames = ['updateBuildScript'] } 'FAQ'(Gradle) { taskNames = ['faq'] } } compiler.javac { afterEvaluate { javacAdditionalOptions = '-encoding utf8' moduleJavacAdditionalOptions = [ (project.name + '.main'): tasks.compileJava.options.compilerArgs.collect { '"' + it + '"' }.join(' ') ] } } } } } // Deployment def final modrinthApiKey = providers.environmentVariable('MODRINTH_API_KEY') def final cfApiKey = providers.environmentVariable('CURSEFORGE_API_KEY') final boolean isCIEnv = providers.environmentVariable('CI').getOrElse('false').toBoolean() if (isCIEnv || deploymentDebug.toBoolean()) { artifacts { if (!noPublishedSources.toBoolean()) { archives sourcesJar } if (apiPackage) { archives apiJar } } } // Changelog generation tasks.register('generateChangelog') { group = 'GT Buildscript' description = 'Generate a default changelog of all commits since the last tagged git commit' onlyIf { generateDefaultChangelog.toBoolean() } doLast { def lastTag = getLastTag() def changelog = runShell(([ "git", "log", "--date=format:%d %b %Y", "--pretty=%s - **%an** (%ad)", "${lastTag}..HEAD" ] + (sourceSets.main.java.srcDirs + sourceSets.main.resources.srcDirs) .collect { ['--', it] }).flatten()) if (changelog) { changelog = "Changes since ${lastTag}:\n${{ ("\n" + changelog).replaceAll("\n", "\n* ") }}" } def f = getFile('build/changelog.md') changelog = changelog ?: 'There have been no changes.' f.write(changelog, 'UTF-8') // Set changelog for Modrinth if (modrinthApiKey.isPresent() || deploymentDebug.toBoolean()) { modrinth.changelog.set(changelog) } } } if (cfApiKey.isPresent() || deploymentDebug.toBoolean()) { apply plugin: 'net.darkhax.curseforgegradle' //noinspection UnnecessaryQualifiedReference tasks.register('curseforge', net.darkhax.curseforgegradle.TaskPublishCurseForge) { disableVersionDetection() debugMode = deploymentDebug.toBoolean() apiToken = cfApiKey.getOrElse('debug_token') doFirst { def mainFile = upload(curseForgeProjectId, reobfJar) def changelogFile = getChangelog() def changelogRaw = changelogFile.exists() ? changelogFile.getText('UTF-8') : "" mainFile.displayName = "${modName}: ${modVersion}" mainFile.releaseType = getReleaseType() mainFile.changelog = changelogRaw mainFile.changelogType = 'markdown' mainFile.addModLoader 'Forge' mainFile.addJavaVersion "Java 8" mainFile.addGameVersion minecraftVersion if (curseForgeRelations.size() != 0) { String[] deps = curseForgeRelations.split(';') deps.each { dep -> if (dep.size() == 0) { return } String[] parts = dep.split(':') String type = parts[0], slug = parts[1] if (!(type in ['requiredDependency', 'embeddedLibrary', 'optionalDependency', 'tool', 'incompatible'])) { throw new Exception('Invalid Curseforge dependency type: ' + type) } mainFile.addRelation(slug, type) } } for (artifact in getSecondaryArtifacts()) { def additionalFile = mainFile.withAdditionalFile(artifact) additionalFile.changelog = changelogRaw } } } tasks.curseforge.dependsOn(build) tasks.curseforge.dependsOn('generateChangelog') } if (modrinthApiKey.isPresent() || deploymentDebug.toBoolean()) { apply plugin: 'com.modrinth.minotaur' def final changelogFile = getChangelog() modrinth { token = modrinthApiKey.getOrElse('debug_token') projectId = modrinthProjectId changelog = changelogFile.exists() ? changelogFile.getText('UTF-8') : "" versionType = getReleaseType() versionNumber = modVersion gameVersions = [minecraftVersion] loaders = ["forge"] debugMode = deploymentDebug.toBoolean() uploadFile = reobfJar additionalFiles = getSecondaryArtifacts() } if (modrinthRelations.size() != 0) { String[] deps = modrinthRelations.split(';') deps.each { dep -> if (dep.size() == 0) { return } String[] parts = dep.split(':') String[] qual = parts[0].split('-') addModrinthDep(qual[0], qual[1], parts[1]) } } tasks.modrinth.dependsOn(build) tasks.modrinth.dependsOn('generateChangelog') } def addModrinthDep(String scope, String type, String name) { com.modrinth.minotaur.dependencies.Dependency dep if (!(scope in ['required', 'optional', 'incompatible', 'embedded'])) { throw new Exception('Invalid modrinth dependency scope: ' + scope) } switch (type) { case 'project': dep = new ModDependency(name, scope) break case 'version': dep = new VersionDependency(name, scope) break default: throw new Exception('Invalid modrinth dependency type: ' + type) } project.modrinth.dependencies.add(dep) } if (customMavenPublishUrl) { String publishedVersion = modVersion publishing { publications { create('maven', MavenPublication) { //noinspection GroovyAssignabilityCheck from components.java if (apiPackage) { artifact apiJar } // providers is not available here, use System for getting env vars groupId = System.getenv('ARTIFACT_GROUP_ID') ?: project.group artifactId = System.getenv('ARTIFACT_ID') ?: project.name version = System.getenv('RELEASE_VERSION') ?: publishedVersion } } repositories { maven { url = customMavenPublishUrl allowInsecureProtocol = !customMavenPublishUrl.startsWith('https') credentials { username = providers.environmentVariable('MAVEN_USER').getOrElse('NONE') password = providers.environmentVariable('MAVEN_PASSWORD').getOrElse('NONE') } } } } } def getSecondaryArtifacts() { def secondaryArtifacts = [usesShadowedDependencies.toBoolean() ? tasks.shadowJar : tasks.jar] if (!noPublishedSources.toBoolean()) secondaryArtifacts += [sourcesJar] if (apiPackage) secondaryArtifacts += [apiJar] return secondaryArtifacts } def getReleaseType() { String type = project.releaseType if (!(type in ['release', 'beta', 'alpha'])) { throw new Exception("Release type invalid! Found \"" + type + "\", allowed: \"release\", \"beta\", \"alpha\"") } return type } /* * If CHANGELOG_LOCATION env var is set, that takes highest precedence. * Next, if 'generateDefaultChangelog' option is enabled, use that. * Otherwise, try to use a CHANGELOG.md file at root directory. */ def getChangelog() { def final changelogEnv = providers.environmentVariable('CHANGELOG_LOCATION') if (changelogEnv.isPresent()) { return new File(changelogEnv.get()) } if (generateDefaultChangelog.toBoolean()) { return getFile('build/changelog.md') } return getFile('CHANGELOG.md') } // Buildscript updating def buildscriptGradleVersion = '8.1.1' tasks.named('wrapper', Wrapper).configure { gradleVersion = buildscriptGradleVersion } tasks.register('updateBuildScript') { group = 'GT Buildscript' description = 'Updates the build script to the latest version' if (gradle.gradleVersion != buildscriptGradleVersion && !Boolean.getBoolean('DISABLE_BUILDSCRIPT_GRADLE_UPDATE')) { dependsOn('wrapper') } doLast { if (performBuildScriptUpdate()) return print('Build script already up to date!') } } if (!project.getGradle().startParameter.isOffline() && !Boolean.getBoolean('DISABLE_BUILDSCRIPT_UPDATE_CHECK') && isNewBuildScriptVersionAvailable()) { if (autoUpdateBuildScript.toBoolean()) { performBuildScriptUpdate() } else { out.style(Style.SuccessHeader).println("Build script update available! Run 'gradle updateBuildScript'") if (gradle.gradleVersion != buildscriptGradleVersion) { out.style(Style.SuccessHeader).println("updateBuildScript can update gradle from ${gradle.gradleVersion} to ${buildscriptGradleVersion}\n") } } } static URL availableBuildScriptUrl() { new URL("https://raw.githubusercontent.com/GregTechCEu/Buildscripts/master/build.gradle") } static URL exampleSettingsGradleUrl() { new URL("https://raw.githubusercontent.com/GregTechCEu/Buildscripts/master/settings.gradle") } boolean verifySettingsGradle() { def settingsFile = getFile("settings.gradle") if (!settingsFile.exists()) { println("Downloading default settings.gradle") exampleSettingsGradleUrl().withInputStream { i -> settingsFile.withOutputStream { it << i } } return true } return false } boolean performBuildScriptUpdate() { if (isNewBuildScriptVersionAvailable()) { def buildscriptFile = getFile("build.gradle") availableBuildScriptUrl().withInputStream { i -> buildscriptFile.withOutputStream { it << i } } def out = services.get(StyledTextOutputFactory).create('buildscript-update-output') out.style(Style.Success).print("Build script updated. Please REIMPORT the project or RESTART your IDE!") if (verifySettingsGradle()) { throw new GradleException("Settings has been updated, please re-run task.") } return true } return false } boolean isNewBuildScriptVersionAvailable() { Map parameters = ["connectTimeout": 10000, "readTimeout": 10000] String currentBuildScript = getFile("build.gradle").getText() String currentBuildScriptHash = getVersionHash(currentBuildScript) String availableBuildScript = availableBuildScriptUrl().newInputStream(parameters).getText() String availableBuildScriptHash = getVersionHash(availableBuildScript) boolean isUpToDate = currentBuildScriptHash.empty || availableBuildScriptHash.empty || currentBuildScriptHash == availableBuildScriptHash return !isUpToDate } static String getVersionHash(String buildScriptContent) { String versionLine = buildScriptContent.find("^//version: [a-z0-9]*") if (versionLine != null) { return versionLine.split(": ").last() } return "" } // Faq tasks.register('faq') { group = 'GT Buildscript' description = 'Prints frequently asked questions about building a project' doLast { print("\nTo update this buildscript to the latest version, run 'gradlew updateBuildScript' or run the generated run configuration if you are using IDEA.\n" + "To set up the project, run the 'setupDecompWorkspace' task, which you can run as './gradlew setupDecompWorkspace' in a terminal, or find in the 'modded minecraft' gradle category.\n\n" + "To add new dependencies to your project, place them in 'dependencies.gradle', NOT in 'build.gradle' as they would be replaced when the script updates.\n" + "To add new repositories to your project, place them in 'repositories.gradle'.\n" + "If you need additional gradle code to run, you can place it in a file named 'addon.gradle' (or either of the above, up to you for organization).\n\n" + "If your build fails to recognize the syntax of newer Java versions, enable Jabel in your 'gradle.properties' under the option name 'enableModernJavaSyntax'.\n" + "To see information on how to configure your IDE properly for Java 17, see https://github.com/GregTechCEu/Buildscripts/blob/master/docs/jabel.md\n\n" + "Report any issues or feature requests you have for this build script to https://github.com/GregTechCEu/Buildscripts/issues\n") } } // Helpers def getFile(String relativePath) { return new File(projectDir, relativePath) } def checkPropertyExists(String propertyName) { if (!project.hasProperty(propertyName)) { throw new GradleException("This project requires a property \"" + propertyName + "\"! Please add it your \"gradle.properties\". You can find all properties and their description here: https://github.com/GregTechCEu/Buildscripts/blob/main/gradle.properties") } } def propertyDefaultIfUnset(String propertyName, defaultValue) { if (!project.hasProperty(propertyName) || project.property(propertyName) == "") { project.ext.setProperty(propertyName, defaultValue) } } def propertyDefaultIfUnsetWithEnvVar(String propertyName, defaultValue, String envVarName) { def envVar = providers.environmentVariable(envVarName) if (envVar.isPresent()) { project.ext.setProperty(propertyName, envVar.get()) } else { propertyDefaultIfUnset(propertyName, defaultValue) } } static runShell(command) { def process = command.execute() def outputStream = new StringBuffer() def errorStream = new StringBuffer() process.waitForProcessOutput(outputStream, errorStream) errorStream.toString().with { if (it) { throw new GradleException("Error executing ${command}:\n> ${it}") } } return outputStream.toString().trim() } def getLastTag() { def githubTag = providers.environmentVariable('GITHUB_TAG') return runShell('git describe --abbrev=0 --tags ' + (githubTag.isPresent() ? runShell('git rev-list --tags --skip=1 --max-count=1') : '')) }