From 1087e265aa17d8caf663ed8b189b32ca88bfb7a4 Mon Sep 17 00:00:00 2001 From: Marc Hermans Date: Wed, 30 Nov 2022 23:11:14 +0100 Subject: [PATCH] Enable additional build types to handle pull request validation. (#9160) --- .teamcity/settings.kts | 74 ++++++++++++++++- build.gradle | 79 +++++++++---------- buildSrc/build.gradle | 1 + ...DownloadBaseCompatibilityBinPatches.groovy | 39 --------- .../forge/tasks/MergeJars.groovy | 44 +++++++++++ .../tasks/SetupCheckJarCompatibility.groovy | 64 +++++++++++++++ .../minecraftforge/forge/tasks/Util.groovy | 27 ++++--- gradle/wrapper/gradle-wrapper.properties | 2 +- 8 files changed, 236 insertions(+), 94 deletions(-) delete mode 100644 buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/DownloadBaseCompatibilityBinPatches.groovy create mode 100644 buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/MergeJars.groovy create mode 100644 buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/SetupCheckJarCompatibility.groovy diff --git a/.teamcity/settings.kts b/.teamcity/settings.kts index 8b65073f36..0bb215e441 100644 --- a/.teamcity/settings.kts +++ b/.teamcity/settings.kts @@ -1,5 +1,7 @@ import jetbrains.buildServer.configs.kotlin.v2019_2.* import jetbrains.buildServer.configs.kotlin.v2019_2.projectFeatures.githubIssues +import jetbrains.buildServer.configs.kotlin.* +import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle /* The settings script is an entry point for defining a TeamCity @@ -30,11 +32,13 @@ project { buildType(Build) buildType(BuildSecondaryBranches) buildType(PullRequests) + buildType(PullRequestChecks) + buildType(PullRequestCompatibility) params { text("docker_jdk_version", "17", label = "Gradle version", description = "The version of the JDK to use during execution of tasks in a JDK.", display = ParameterDisplay.HIDDEN, allowEmpty = false) text("docker_gradle_version", "7.4", label = "Gradle version", description = "The version of Gradle to use during execution of Gradle tasks.", display = ParameterDisplay.HIDDEN, allowEmpty = false) - text("git_main_branch", "1.18.x", label = "Git Main Branch", description = "The git main or default branch to use in VCS operations.", display = ParameterDisplay.HIDDEN, allowEmpty = false) + text("git_main_branch", "1.19.x", label = "Git Main Branch", description = "The git main or default branch to use in VCS operations.", display = ParameterDisplay.HIDDEN, allowEmpty = false) text("git_branch_spec", """ +:refs/heads/(main*) +:refs/heads/(master*) @@ -134,3 +138,71 @@ object PullRequests : BuildType({ """.trimIndent() } }) + +object PullRequestChecks : BuildType({ + templates(AbsoluteId("MinecraftForge_BuildPullRequests"), AbsoluteId("MinecraftForge_SetupGradleUtilsCiEnvironmen"), AbsoluteId("MinecraftForge_BuildWithDiscordNotifications"), AbsoluteId("MinecraftForge_SetupProjectUsingGradle")) + id("MinecraftForge_MinecraftForge__PullRequestChecks") + name = "Pull Requests (Checks)" + description = "Checks pull requests for the project" + + steps { + gradle { + name = "Check" + id = "RUNNER_10_Check" + + tasks = "checkAll" + gradleParams = "--continue %gradle_custom_args%" + enableStacktrace = true + dockerImage = "%docker_gradle_image%" + dockerRunParameters = """ + -v "/opt/cache/agent/gradle:/home/gradle/.gradle" + -v "/opt/cache/shared/gradle:/home/gradle/rocache:ro" + --network=host + -u 1000:1000 + %docker_additional_args% + """.trimIndent() + } + } + + vcs { + branchFilter = """ + +:* + -:1.* + -: + """.trimIndent() + } +}) + +object PullRequestCompatibility : BuildType({ + templates(AbsoluteId("MinecraftForge_BuildPullRequests"), AbsoluteId("MinecraftForge_SetupGradleUtilsCiEnvironmen"), AbsoluteId("MinecraftForge_BuildWithDiscordNotifications"), AbsoluteId("MinecraftForge_SetupProjectUsingGradle")) + id("MinecraftForge_MinecraftForge__PullRequestCompatibility") + name = "Pull Requests (Compatibility)" + description = "Validates binary compatibility for pull requests made to the project" + + steps { + gradle { + name = "Validate" + id = "RUNNER_10_Compatibility" + + tasks = "checkJarCompatibility" + gradleParams = "--continue %gradle_custom_args%" + enableStacktrace = true + dockerImage = "%docker_gradle_image%" + dockerRunParameters = """ + -v "/opt/cache/agent/gradle:/home/gradle/.gradle" + -v "/opt/cache/shared/gradle:/home/gradle/rocache:ro" + --network=host + -u 1000:1000 + %docker_additional_args% + """.trimIndent() + } + } + + vcs { + branchFilter = """ + +:* + -:1.* + -: + """.trimIndent() + } +}) diff --git a/build.gradle b/build.gradle index 699dac6b02..e04c1890a7 100644 --- a/build.gradle +++ b/build.gradle @@ -30,7 +30,7 @@ plugins { id 'com.github.ben-manes.versions' version '0.36.0' id 'net.minecraftforge.gradleutils' version '2.+' id 'eclipse' - id 'de.undercouch.download' version '4.1.2' + id 'de.undercouch.download' version '5.1.3' } Util.init() //Init all our extension methods! @@ -1166,8 +1166,6 @@ project(':forge') { excs.from patcher.excs } - task checkAll(dependsOn: [checkATs, checkSAS, checkExcs, findFieldInstanceChecks]){} - task checkPatchesAndFix(type: CheckPatches, dependsOn: genPatches) { patchDir = file("$rootDir/patches") autoFix = true @@ -1184,54 +1182,51 @@ project(':forge') { lineEnding = '\n' } - def baseForgeVersion = LAST_RB == null ? null : "${MC_VERSION}-${LAST_RB}" - - task downloadBaseCompatibilityBinPatches(type: DownloadBaseCompatibilityBinPatches) { - inputVersion = baseForgeVersion + def baseForgeVersionProperty = project.objects.property(String) + baseForgeVersionProperty.set(project.provider { getLatestForgeVersion(MC_VERSION) }.map { MC_VERSION + '-' + it }) + baseForgeVersionProperty.finalizeValueOnRead() + def jarCompatibilityTaskSetup = { task -> + task.group = 'jar compatibility' + task.onlyIf { + baseForgeVersionProperty.getOrNull() != null + } } - task applyBaseCompatibilityJarBinPatches(type: ApplyBinPatches) { - group = 'jar compatibility' - onlyIf { - baseForgeVersion != null - } - inputs.property 'baseForgeVersion', baseForgeVersion + tasks.register('setupCheckJarCompatibility', SetupCheckJarCompatibility) { + inputVersion = baseForgeVersionProperty + } - clean = createJoinedSRG.output - patch = downloadBaseCompatibilityBinPatches.output + tasks.register('applyBaseCompatibilityJarBinPatches', ApplyBinPatches) { + jarCompatibilityTaskSetup(it) + + clean = project.tasks.createJoinedSRG.output + patch = project.tasks.named('setupCheckJarCompatibility').flatMap { it.baseBinPatchesOutput } output = project.layout.buildDirectory.dir(name).map { it.file('output.jar') } } - task checkJarCompatibility(type: CheckJarCompatibility) { - group = 'jar compatibility' - onlyIf { - baseForgeVersion != null - } - inputs.property 'baseForgeVersion', baseForgeVersion + tasks.register('mergeBaseForgeJar', MergeJars) { + jarCompatibilityTaskSetup(it) - if (baseForgeVersion != null) { - def baseForgeUniversal = project.configurations.detachedConfiguration(project.dependencies.create("net.minecraftforge:forge:${baseForgeVersion}:universal")) - def fmlLibs = project.configurations.detachedConfiguration(PACKED_DEPS.collect { - def artifactId = it.split(':')[1] - return project.dependencies.create("net.minecraftforge:${artifactId}:${baseForgeVersion}") - }.toArray(Dependency[]::new)) - - baseJar = project.tasks.applyBaseCompatibilityJarBinPatches.output - baseLibraries.from(project.file(project.provider { - baseForgeUniversal.resolve().iterator().next() - })) - baseLibraries.from(project.tasks.createJoinedSRG.output) - baseLibraries.from(fmlLibs) - - inputJar = project.tasks.reobfJar.output - concreteLibraries.from(PACKED_DEPS.collect { rootProject.tasks.getByPath(it).archiveFile }) - - commonLibraries.from(project.configurations.minecraftImplementation) - commonLibraries.from(project.configurations.installer) - commonLibraries.from(project.configurations.moduleonly) - } + inputJars.from(project.tasks.named('applyBaseCompatibilityJarBinPatches').flatMap { it.output }) + inputJars.from(baseForgeVersionProperty.map { inputVersion -> + def output = project.layout.buildDirectory.dir(name).map { it.file("forge-${inputVersion}-universal.jar") }.get().asFile + project.rootProject.extensions.download.run { + src "https://maven.minecraftforge.net/net/minecraftforge/forge/${inputVersion}/forge-${inputVersion}-universal.jar" + dest output + } + return output + }) } + tasks.register('checkJarCompatibility', CheckJarCompatibility) { + jarCompatibilityTaskSetup(it) + dependsOn 'setupCheckJarCompatibility' + + baseJar = project.tasks.named('mergeBaseForgeJar').flatMap { it.output } + } + + task checkAll(dependsOn: [checkATs, checkSAS, checkExcs, findFieldInstanceChecks, checkPatches, checkLicenses]){} + task launcherJson(type: LauncherJson) { packedDependencies = [':fmlloader:jar'] doFirst { diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index f2d3e1fe1a..9c47aa540d 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -6,4 +6,5 @@ dependencies { implementation 'org.ow2.asm:asm:9.1' implementation 'org.ow2.asm:asm-tree:9.1' implementation 'net.minecraftforge:srgutils:0.4.+' + implementation 'commons-io:commons-io:2.8.0' } \ No newline at end of file diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/DownloadBaseCompatibilityBinPatches.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/DownloadBaseCompatibilityBinPatches.groovy deleted file mode 100644 index 9f1f1326c4..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/DownloadBaseCompatibilityBinPatches.groovy +++ /dev/null @@ -1,39 +0,0 @@ -package net.minecraftforge.forge.tasks - -import org.gradle.api.DefaultTask -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.Optional -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction - -import java.nio.file.Files - -abstract class DownloadBaseCompatibilityBinPatches extends DefaultTask { - DownloadBaseCompatibilityBinPatches() { - group = 'jar compatibility' - onlyIf { - inputVersion.getOrNull() != null - } - - output.convention(project.layout.buildDirectory.dir(name).map { it.file('joined.lzma') }) - } - - @TaskAction - void run() { - def dep = project.dependencies.create("net.minecraftforge:forge:${inputVersion.get()}:userdev") - def baseForgeUserdev = project.configurations.detachedConfiguration(dep).resolve().iterator().next() - - def joinedLzma = project.zipTree(baseForgeUserdev).matching { it.include('joined.lzma') }.singleFile - - Files.copy(joinedLzma.toPath(), output.get().asFile.toPath()) - } - - @Input - @Optional - abstract Property getInputVersion() - - @OutputFile - abstract RegularFileProperty getOutput() -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/MergeJars.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/MergeJars.groovy new file mode 100644 index 0000000000..73b5e69ac5 --- /dev/null +++ b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/MergeJars.groovy @@ -0,0 +1,44 @@ +package net.minecraftforge.forge.tasks + +import org.apache.commons.io.IOUtils +import org.gradle.api.DefaultTask +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction + +import java.util.zip.ZipEntry +import java.util.zip.ZipInputStream +import java.util.zip.ZipOutputStream + +abstract class MergeJars extends DefaultTask { + MergeJars() { + output.convention(project.layout.buildDirectory.dir(name).map { it.file('output.jar') }) + } + + @TaskAction + void run() { + def jars = inputJars.files + + try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(output.get().asFile))) { + for (def jar : jars) { + try (ZipInputStream zin = new ZipInputStream(new FileInputStream(jar))) { + def entry + while ((entry = zin.getNextEntry()) != null) { + ZipEntry _new = new ZipEntry(entry.getName()) + _new.setTime(0) //SHOULD be the same time as the main entry, but NOOOO _new.setTime(entry.getTime()) throws DateTimeException, so you get 0, screw you! + zout.putNextEntry(_new) + IOUtils.copy(zin, zout) + } + } + } + } + } + + @InputFiles + abstract ConfigurableFileCollection getInputJars() + + @OutputFile + abstract RegularFileProperty getOutput() +} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/SetupCheckJarCompatibility.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/SetupCheckJarCompatibility.groovy new file mode 100644 index 0000000000..045a70405f --- /dev/null +++ b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/SetupCheckJarCompatibility.groovy @@ -0,0 +1,64 @@ +package net.minecraftforge.forge.tasks + +import org.gradle.api.DefaultTask +import org.gradle.api.artifacts.Dependency +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction + +import java.nio.file.Files +import java.nio.file.StandardCopyOption + +abstract class SetupCheckJarCompatibility extends DefaultTask { + SetupCheckJarCompatibility() { + group = 'jar compatibility' + onlyIf { + inputVersion.getOrNull() != null + } + + baseBinPatchesOutput.convention(project.layout.buildDirectory.dir(name).map { it.file('joined.lzma') }) + } + + @TaskAction + void run() { + def inputVersion = inputVersion.get() + def fmlLibs = project.configurations.detachedConfiguration(project.PACKED_DEPS.collect { + def artifactId = it.split(':')[1] + return project.dependencies.create("net.minecraftforge:${artifactId}:${inputVersion}") + }.toArray(Dependency[]::new)) + + project.tasks.named('checkJarCompatibility') { + baseLibraries.from(project.tasks.createJoinedSRG.output) + baseLibraries.from(project.provider { + fmlLibs.resolvedConfiguration.lenientConfiguration.files + }) + + inputJar = project.tasks.reobfJar.output + concreteLibraries.from(project.PACKED_DEPS.collect { project.rootProject.tasks.getByPath(it).archiveFile }) + + commonLibraries.from(project.configurations.minecraftImplementation) + commonLibraries.from(project.configurations.installer) + commonLibraries.from(project.configurations.moduleonly) + } + + def baseForgeUserdev = project.layout.buildDirectory.dir(name).map { it.file("forge-${inputVersion}-userdev.jar") }.get().asFile + project.rootProject.extensions.download.run { + src "https://maven.minecraftforge.net/net/minecraftforge/forge/${inputVersion}/forge-${inputVersion}-userdev.jar" + dest baseForgeUserdev + } + + def joinedLzma = project.zipTree(baseForgeUserdev).matching { it.include('joined.lzma') }.singleFile + + Files.copy(joinedLzma.toPath(), baseBinPatchesOutput.get().asFile.toPath(), StandardCopyOption.REPLACE_EXISTING) + } + + @Input + @Optional + abstract Property getInputVersion() + + @OutputFile + abstract RegularFileProperty getBaseBinPatchesOutput() +} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/Util.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/Util.groovy index 5b6903e09f..76b171b7d1 100644 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/Util.groovy +++ b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/Util.groovy @@ -18,17 +18,17 @@ public class Util { return md.digest().collect {String.format "%02x", it}.join() } File.metaClass.getSha1 = { !delegate.exists() ? null : delegate.sha1() } - + File.metaClass.json = { -> new JsonSlurper().parseText(delegate.text) } File.metaClass.getJson = { return delegate.exists() ? new JsonSlurper().parse(delegate) : [:] } File.metaClass.setJson = { json -> delegate.text = new JsonBuilder(json).toPrettyString() } - + Date.metaClass.iso8601 = { -> def format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") def result = format.format(delegate) return result[0..21] + ':' + result[22..-1] } - + String.metaClass.rsplit = { String del, int limit = -1 -> def lst = new ArrayList() def x = 0, idx @@ -41,7 +41,7 @@ public class Util { return lst } } - + public static String[] getClasspath(project, libs, artifact) { def ret = [] artifactTree(project, artifact).each { key, lib -> @@ -51,7 +51,7 @@ public class Util { } return ret } - + public static def getArtifacts(project, config, classifiers) { def ret = [:] config.resolvedConfiguration.resolvedArtifacts.each { @@ -75,7 +75,7 @@ public class Util { url = "https://maven.minecraftforge.net/${path}" } //TODO remove when Mojang launcher is updated - if (!classifiers && art.classifier != null) { + if (!classifiers && art.classifier != null) { //Mojang launcher doesn't currently support classifiers, so... move it to part of the version, and force the extension to 'jar' // However, keep the path normal so that our mirror system works. art.version = "${art.version}-${art.classifier}" @@ -96,14 +96,14 @@ public class Util { } return ret } - - public static def getMavenPath(task) { + + public static def getMavenPath(task) { def classifier = task.archiveClassifier.get() def dep = "${task.project.group}:${task.project.name}:${task.project.version}" + (classifier == '' ? '' : ':' + classifier) return "${task.project.group.replace('.', '/')}/${task.project.name}/${task.project.version}/${task.project.name}-${task.project.version}".toString() + (classifier == '' ? '' : '-' + classifier) + '.jar' } - - public static def getMavenDep(task) { + + public static def getMavenDep(task) { def classifier = task.archiveClassifier.get() return "${task.project.group}:${task.project.name}:${task.project.version}" + (classifier == '' ? '' : ':' + classifier) } @@ -127,7 +127,7 @@ public class Util { def files = cfg.resolve() return getArtifacts(project, cfg, true) } - + private static boolean checkExists(url) { try { def code = new URL(url).openConnection().with { @@ -142,4 +142,9 @@ public class Util { throw e } } + + public static String getLatestForgeVersion(mcVersion) { + def json = new JsonSlurper().parseText(new URL("https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json").getText("UTF-8")) + return json.promos["$mcVersion-latest"] + } } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 41dfb87909..ae04661ee7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists