diff --git a/.gitignore b/.gitignore index c5a9d217..c5d7d4fc 100644 --- a/.gitignore +++ b/.gitignore @@ -16,9 +16,11 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* -# Ignore Gradle +# Ignore Gradle related files we don't want to commit /.gradle/ build/ +gradle/analytics +local.properties # Ignore IntelliJ /out/ diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000..166664b2 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,58 @@ +/* + * Copyright 2015 MovingBlocks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +pipeline { + agent { + label "light-java" + } + stages { + stage('Build') { + steps { + sh './gradlew --info --console=plain jar' + } + } + stage('Analytics') { + steps { + sh './gradlew --info --console=plain javadoc check' + } + } + stage('Publish') { + when { + anyOf { + branch 'master' + branch pattern: "release/v\\d+.x", comparator: "REGEXP" + } + } + steps { + withCredentials([usernamePassword(credentialsId: 'artifactory-gooey', usernameVariable: 'artifactoryUser', passwordVariable: 'artifactoryPass')]) { + sh './gradlew --info --console=plain -Dorg.gradle.internal.publish.checksums.insecure=true publish -PmavenUser=${artifactoryUser} -PmavenPass=${artifactoryPass}' + } + } + } + stage('Record') { + steps { + junit testResults: '**/build/test-results/test/*.xml', allowEmptyResults: true + recordIssues tool: javaDoc() + //Note: Javadoc archiver only works for one directory :-( + step([$class: 'JavadocArchiver', javadocDir: 'gestalt-entity-system/build/docs/javadoc', keepAll: false]) + recordIssues tool: checkStyle(pattern: '**/build/reports/checkstyle/*.xml') + recordIssues tool: spotBugs(pattern: '**/build/reports/spotbugs/main/*.xml', useRankAsPriority: true) + recordIssues tool: pmdParser(pattern: '**/build/reports/pmd/*.xml') + recordIssues tool: taskScanner(includePattern: '**/*.java,**/*.groovy,**/*.gradle', lowTags: 'WIBNIF', normalTags: 'TODO', highTags: 'ASAP') + } + } + } +} diff --git a/build.gradle b/build.gradle index cdb60580..ad122d81 100644 --- a/build.gradle +++ b/build.gradle @@ -1,161 +1,68 @@ -/* - * This is a Gradle build file: - * - Gradle Homepage: http://gradle.org/ - * - Gradle Documentation: http://gradle.org/documentation - * - View tasks for this project: $ gradlew tasks - */ -apply plugin: 'project-report' - -allprojects { - apply plugin: 'idea' - - group = 'org.terasology' - - // Declare remote repositories we're interested in - library files will be fetched from here +buildscript { repositories { - // Main Maven repo + // External libs - jcenter is Bintray and is supposed to be a superset of Maven Central, but do both just in case + jcenter() mavenCentral() - maven { - url "http://artifactory.terasology.org/artifactory/repo" - } + gradlePluginPortal() } -} - -subprojects { - apply plugin: 'java' - apply plugin: 'eclipse' -} - -configure(subprojects.findAll { !it.name.contains("testpack") && !it.name.startsWith("module") }) { - apply plugin: 'checkstyle' - apply plugin: 'pmd' - apply plugin: 'findbugs' - apply plugin: 'maven' - apply plugin: 'java-library-distribution' - apply plugin: 'artifactory-publish' - apply plugin: 'maven-publish' - // Primary dependencies definition dependencies { - compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.21' - compile group: 'com.google.guava', name: 'guava', version: '19.0' - - // These dependencies are only needed for running tests - testCompile group: 'junit', name: 'junit', version: '4.12' - testCompile group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.7' - testCompile group: 'org.mockito', name: 'mockito-core', version: '1.10.19' - } - - // Set the expected module Java level (can use a higher Java to run, but should not use features from a higher Java) - sourceCompatibility = 1.8 - targetCompatibility = 1.8 - - jar { - manifest { - attributes("Implementation-Title": project.name, - "Implementation-Version": version) - } - from(['LICENSE', 'NOTICE']) + //Spotbugs + classpath "gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:4.0.0" } +} - task sourceJar(type: Jar) { - description = "Create a JAR with all sources" - from sourceSets.main.allSource - from sourceSets.test.allSource - classifier = 'sources' - } +// Needed for extending the "clean" task to also delete custom stuff defined here like analytics config +apply plugin: 'base' - task javadocJar(type: Jar, dependsOn: javadoc) { - description = "Create a JAR with the JavaDoc for the java sources" - from javadoc.destinationDir - classifier = 'javadoc' - } - - // A configuration for publishing artifacts - configurations { - published - } +ext { + dirAnalyticsConfig = 'gradle/analytics' +} - // Define the artifacts we want to publish (the .pom will also be included since the Maven plugin is active) - artifacts { - published jar - published sourceJar - published javadocJar - } +// Define configurations for analytics config +configurations { + codeAnalyticsConfig +} - publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact jar { - } - artifact sourceJar { - classifier "sources" - } - artifact javadocJar { - classifier "javadoc" - } - } - } - } +dependencies { + // Config for our code analytics lives in a centralized repo: https://github.com/MovingBlocks/TeraConfig + codeAnalyticsConfig group: 'org.terasology.config', name: 'codemetrics', version: '1.3.2', ext: 'zip' +} - artifactory { - publish { - defaults { - publications('mavenJava') - } +task extractAnalyticsConfig(type: Copy) { + description = "Extracts configuration files for our analytics from the zip we fetched as a dependency" + from { + configurations.codeAnalyticsConfig.collect { + zipTree(it) } } - - // Technically the plain "jar" both here and above is included automatically, but leaving it explicit for clarity - artifactoryPublish { - dependsOn jar, sourceJar, javadocJar - } - - checkstyle { - ignoreFailures = true - configFile = new File(rootDir, "config/checkstyle/checkstyle.xml") - configProperties.samedir = new File(rootDir, "config/checkstyle") - toolVersion = "6.5" - } - - pmd { - ignoreFailures = true - ruleSetFiles = files(new File(rootDir, "config/pmd/pmd.xml")) - } - - findbugs { - toolVersion = '3.0.0' - ignoreFailures = true - effort = 'max' - reportLevel = 'medium' - excludeFilter = new File(rootDir, "config/findbugs/findbugs-exclude.xml") - } + into "$rootDir/$dirAnalyticsConfig" } -// gradle wrapper version -wrapper { - gradleVersion '1.10' +// Include deletion of extracted stuff in the global clean task. Without the doLast it runs on *every* execution ... +clean.doLast { + new File(dirAnalyticsConfig).deleteDir() + println "Cleaned root - don't forget to re-extract stuff! 'gradlew extractAnalyticsConfig' will do so" } -ext { - // Read environment variables, including variables passed by jenkins continuous integration server - env = System.getenv() -} - -// Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-( -buildscript { +allprojects { + apply plugin: 'idea' + + // Declare remote repositories we're interested in - library files will be fetched from here repositories { + // Main Maven repo mavenCentral() maven { - url 'http://dl.bintray.com/jfrog/jfrog-jars' + name "Terasology Artifactory" + url "http://artifactory.terasology.org/artifactory/virtual-repo-live" + allowInsecureProtocol true // 😱 } } +} - dependencies { - // Artifactory plugin - classpath(group: 'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '2.2.3') - } +//configure(subprojects.findAll { !it.name.contains("testpack") && !it.name.startsWith("module") }) { +subprojects { + apply from: "$rootDir/gradle/common.gradle" } // Library and distribution config @@ -198,7 +105,6 @@ idea { } ext { - // Activate 'git' as VCS ideaActivateGit = { Node iprNode -> def vcsMappings = iprNode.component.find { it.'@name' == 'VcsDirectoryMappings' } @@ -250,5 +156,4 @@ ext { ''')) } } - } diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml deleted file mode 100644 index 4b124382..00000000 --- a/config/checkstyle/checkstyle.xml +++ /dev/null @@ -1,309 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml deleted file mode 100644 index 9b82f417..00000000 --- a/config/checkstyle/suppressions.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - diff --git a/config/findbugs/findbugs-exclude.xml b/config/findbugs/findbugs-exclude.xml deleted file mode 100644 index c6b33af0..00000000 --- a/config/findbugs/findbugs-exclude.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/config/pmd/pmd.xml b/config/pmd/pmd.xml deleted file mode 100644 index f0139a6f..00000000 --- a/config/pmd/pmd.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - .*/org.terasology.protobuf/.* - diff --git a/gestalt-asset-core/build.gradle b/gestalt-asset-core/build.gradle index c8906810..f897849f 100644 --- a/gestalt-asset-core/build.gradle +++ b/gestalt-asset-core/build.gradle @@ -1,9 +1,4 @@ -/* - * This is a Gradle build file: - * - Gradle Homepage: http://gradle.org/ - * - Gradle Documentation: http://gradle.org/documentation - * - View tasks for this project: $ gradlew tasks - */ +apply from: "$rootDir/gradle/publish.gradle" // Primary dependencies definition dependencies { diff --git a/gestalt-entity-system/build.gradle b/gestalt-entity-system/build.gradle index 821fcdf8..104e5efc 100644 --- a/gestalt-entity-system/build.gradle +++ b/gestalt-entity-system/build.gradle @@ -1,9 +1,4 @@ -/* - * This is a Gradle build file: - * - Gradle Homepage: http://gradle.org/ - * - Gradle Documentation: http://gradle.org/documentation - * - View tasks for this project: $ gradlew tasks - */ +apply from: "$rootDir/gradle/publish.gradle" // Primary dependencies definition dependencies { diff --git a/gestalt-module/build.gradle b/gestalt-module/build.gradle index 6c5d80df..17306d5d 100644 --- a/gestalt-module/build.gradle +++ b/gestalt-module/build.gradle @@ -1,9 +1,4 @@ -/* - * This is a Gradle build file: - * - Gradle Homepage: http://gradle.org/ - * - Gradle Documentation: http://gradle.org/documentation - * - View tasks for this project: $ gradlew tasks - */ +apply from: "$rootDir/gradle/publish.gradle" // Primary dependencies definition dependencies { @@ -30,4 +25,4 @@ gatherModules { } ideaModule.dependsOn gatherModules -test.dependsOn gatherModules \ No newline at end of file +test.dependsOn gatherModules diff --git a/gestalt-module/src/main/java/org/terasology/module/ModulePathScanner.java b/gestalt-module/src/main/java/org/terasology/module/ModulePathScanner.java index e02a2ae5..8e9c69db 100644 --- a/gestalt-module/src/main/java/org/terasology/module/ModulePathScanner.java +++ b/gestalt-module/src/main/java/org/terasology/module/ModulePathScanner.java @@ -1,18 +1,5 @@ -/* - * Copyright 2015 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.module; @@ -23,6 +10,7 @@ import org.terasology.util.io.FilesUtil; import java.io.IOException; +import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.Collection; @@ -90,8 +78,11 @@ public void scan(ModuleRegistry registry, Collection paths) { * @throws IOException If an error occurs scanning the directory - but not an individual module. */ private void scanModuleArchives(Path discoveryPath, ModuleRegistry registry) throws IOException { - for (Path modulePath : Files.newDirectoryStream(discoveryPath, new FileTypesFilter("jar", "zip"))) { - loadModule(registry, modulePath); + try (DirectoryStream discoveryDirectory = Files.newDirectoryStream(discoveryPath, + new FileTypesFilter("jar", "zip"))) { + for (Path modulePath : discoveryDirectory) { + loadModule(registry, modulePath); + } } } @@ -103,8 +94,11 @@ private void scanModuleArchives(Path discoveryPath, ModuleRegistry registry) thr * @throws IOException If an error occurs scanning the directory - but not an individual module. */ private void scanModuleDirectories(Path discoveryPath, ModuleRegistry registry) throws IOException { - for (Path modulePath : Files.newDirectoryStream(discoveryPath, FilesUtil.DIRECTORY_FILTER)) { - loadModule(registry, modulePath); + try (DirectoryStream discoveryDirectory = Files.newDirectoryStream(discoveryPath, + FilesUtil.DIRECTORY_FILTER)) { + for (Path modulePath : discoveryDirectory) { + loadModule(registry, modulePath); + } } } diff --git a/gestalt-util/build.gradle b/gestalt-util/build.gradle index 091cdc66..91a2ebd5 100644 --- a/gestalt-util/build.gradle +++ b/gestalt-util/build.gradle @@ -1,9 +1,4 @@ -/* - * This is a Gradle build file: - * - Gradle Homepage: http://gradle.org/ - * - Gradle Documentation: http://gradle.org/documentation - * - View tasks for this project: $ gradlew tasks - */ +apply from: "$rootDir/gradle/publish.gradle" // Primary dependencies definition dependencies { @@ -11,4 +6,4 @@ dependencies { } // Library and distribution config -description = 'Common utility classes' \ No newline at end of file +description = 'Common utility classes' diff --git a/gradle.properties b/gradle.properties index d88a0625..6fc5879b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=5.1.5 +version=5.1.6-SNAPSHOT diff --git a/gradle/common.gradle b/gradle/common.gradle new file mode 100644 index 00000000..60fbee87 --- /dev/null +++ b/gradle/common.gradle @@ -0,0 +1,130 @@ +// Analytics +apply plugin: 'project-report' +apply plugin: 'checkstyle' +apply plugin: 'pmd' +apply plugin: 'com.github.spotbugs' + +apply plugin: 'java' +apply plugin: 'eclipse' + +apply plugin: 'java-library-distribution' + +// Primary dependencies definition +dependencies { + compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.21' + compile group: 'com.google.guava', name: 'guava', version: '19.0' + + // These dependencies are only needed for running tests + testCompile group: 'junit', name: 'junit', version: '4.12' + testCompile group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.7' + testCompile group: 'org.mockito', name: 'mockito-core', version: '1.10.19' +} + +jar { + manifest { + attributes("Implementation-Title": project.name, + "Implementation-Version": version) + } + from(['LICENSE', 'NOTICE']) +} + +task sourceJar(type: Jar) { + description = "Create a JAR with all sources" + from sourceSets.main.allSource + from sourceSets.test.allSource + classifier = 'sources' +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + description = "Create a JAR with the JavaDoc for the java sources" + from javadoc.destinationDir + classifier = 'javadoc' +} + +java { + withSourcesJar() + withJavadocJar() + + sourceCompatibility(JavaVersion.VERSION_1_8) + targetCompatibility(JavaVersion.VERSION_1_8) +} + +// Extract analytics config files if needed (note: does not help IDE execution or cases like 'gradlew spotbugsMain') +check.dependsOn rootProject.extractAnalyticsConfig + +// We use both Maven Central and our own Artifactory instance, which contains module builds, extra libs, and so on +repositories { + // For development so you can publish binaries locally and have them grabbed from there + mavenLocal() + + // External libs - jcenter is Bintray and is supposed to be a superset of Maven Central, but do both just in case + jcenter() + mavenCentral() + + // Terasology Artifactory instance for libs not readily available elsewhere plus our own libs + maven { + def repoViaEnv = System.getenv()["RESOLUTION_REPO"] + if (rootProject.hasProperty("alternativeResolutionRepo")) { + // If the user supplies an alternative repo via gradle.properties then use that + name "from alternativeResolutionRepo property" + url alternativeResolutionRepo + } else if (repoViaEnv != null && repoViaEnv != "") { + name "from \$RESOLUTION_REPO" + url = repoViaEnv + } else { + // Our default is the main virtual repo containing everything except repos for testing Artifactory itself + name "Terasology Artifactory" + url "http://artifactory.terasology.org/artifactory/virtual-repo-live" + allowInsecureProtocol true // 😱 + } + } +} + +// Extra details provided for unit tests +test { + useJUnitPlatform() + + // ignoreFailures: Specifies whether the build should break when the verifications performed by this task fail. + ignoreFailures = true + // showStandardStreams: makes the standard streams (err and out) visible at console when running tests + testLogging.showStandardStreams = true + reports { + junitXml.enabled = true + } + // Arguments to include while running tests + jvmArgs '-Xms512m', '-Xmx1024m' +} + +// In theory all Javadoc should be good and fixed, but it might be a bit much to entirely fail a build over. For now at least ... +// Note: In IntelliJ 2020.1+ running a javadoc Gradle task may still *look* alarming in the UI, but errors should be ignored +javadoc { + failOnError = false +} + +checkstyle { + ignoreFailures = true + configFile = new File(rootDir, 'gradle/analytics/checkstyle/checkstyle.xml') + configProperties.samedir = checkstyle.configFile.parentFile +} + +pmd { + ignoreFailures = true + ruleSetFiles = files("$rootDir/gradle/analytics/pmd/pmd.xml") + // By default, gradle uses both ruleset file AND the rulesets. Override the ruleSets to use only those from the file + ruleSets = [] +} + +spotbugs { + toolVersion = '4.0.0' + ignoreFailures = true + excludeFilter = new File(rootDir, "gradle/analytics/findbugs/findbugs-exclude.xml") +} + +spotbugsMain { + reports { + xml { + enabled = true + destination = file("$buildDir/reports/spotbugs/main/spotbugs.xml") + } + } +} diff --git a/gradle/publish.gradle b/gradle/publish.gradle new file mode 100644 index 00000000..a437fbbb --- /dev/null +++ b/gradle/publish.gradle @@ -0,0 +1,53 @@ +apply plugin: 'maven-publish' + +group = 'org.terasology' + +publishing { + publications { + "$project.name"(MavenPublication) { + // Without this we get a .pom with no dependencies + from components.java + + repositories { + maven { + name = 'TerasologyOrg' + allowInsecureProtocol true // 😱 - no https on our Artifactory yet + + if (rootProject.hasProperty("publishRepo")) { + // This first option is good for local testing, you can set a full explicit target repo in gradle.properties + url = "http://artifactory.terasology.org/artifactory/$publishRepo" + + logger.info("Changing PUBLISH repoKey set via Gradle property to {}", publishRepo) + } else { + // Support override from the environment to use a different target publish org + String deducedPublishRepo = System.getenv()["PUBLISH_ORG"] + if (deducedPublishRepo == null || deducedPublishRepo == "") { + // If not then default + deducedPublishRepo = "libs" + } + + // Base final publish repo on whether we're building a snapshot or a release + if (project.version.endsWith('SNAPSHOT')) { + deducedPublishRepo += "-snapshot-local" + } else { + deducedPublishRepo += "-release-local" + } + + logger.info("The final deduced publish repo is {}", deducedPublishRepo) + url = "http://artifactory.terasology.org/artifactory/$deducedPublishRepo" + } + + if (rootProject.hasProperty("mavenUser") && rootProject.hasProperty("mavenPass")) { + credentials { + username = "$mavenUser" + password = "$mavenPass" + } + authentication { + basic(BasicAuthentication) + } + } + } + } + } + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 58385981..94336fca 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 65b57de8..3f2a33d1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Dec 23 21:49:03 CET 2013 +#Sat Jul 18 22:45:28 CDT 2020 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-bin.zip +zipStoreBase=GRADLE_USER_HOME