diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a9e900773..cfd012067 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -138,3 +138,15 @@ jobs: run: ./gradlew runMavenTest -PtestJavaVersion=${{ matrix.test_java_version }} "-Porg.gradle.java.installations.paths=${{ env.test_jdk_path }}" env: JAVA_HOME: ${{ env.build_jdk_path }} + - name: Upload Maven integration test verification results + id: upload-results + uses: actions/upload-artifact@v7 + if: always() + with: + name: maven-test-results-${{ matrix.os }}-java${{ matrix.test_java_version }} + path: archunit-maven-test/verification-results/ + if-no-files-found: ignore + - name: Report artifact location + if: always() && steps.upload-results.outputs.artifact-url + run: | + echo "::notice title=Maven test results (logs & surefire XML)::${{ steps.upload-results.outputs.artifact-url }}" diff --git a/archunit-maven-test/.gitignore b/archunit-maven-test/.gitignore new file mode 100644 index 000000000..1d43c8300 --- /dev/null +++ b/archunit-maven-test/.gitignore @@ -0,0 +1,2 @@ +/src +/pom.xml diff --git a/archunit-maven-test/build.gradle b/archunit-maven-test/build.gradle index d16710170..e5ae89a1d 100644 --- a/archunit-maven-test/build.gradle +++ b/archunit-maven-test/build.gradle @@ -85,7 +85,7 @@ clean { } } -task initializeMavenTest { +def initializeMavenTest = tasks.register('initializeMavenTest') { doLast { verificationResultArchivePath.with { deleteDir() @@ -102,16 +102,12 @@ def mavenCommand = { String... params -> } def addMavenTest = { IntegrationTestConfig config -> - String prepareMavenTest = "prepareMavenTest${config.suffix}" - String executeRules = "executeRules${config.suffix}" - String verifyRules = "verifyRules${config.suffix}" - String cleanUpMavenTest = "cleanUpMavenTest${config.suffix}" - String runMavenTest = "runMavenTest${config.suffix}" def mavenSurefirePlugin = libs.mavenSurefirePlugin.get() def mavenCompilerPlugin = libs.mavenCompilerPlugin.get() return { - tasks.create(name: prepareMavenTest, dependsOn: initializeMavenTest) { + def prepareMavenTest = tasks.register("prepareMavenTest${config.suffix}") { + dependsOn initializeMavenTest doLast { mavenPom.delete() Files.copy(mavenPomTemplate.toPath(), mavenPom.toPath()) @@ -156,28 +152,51 @@ def addMavenTest = { IntegrationTestConfig config -> } } - def mavenExec = { closure -> - return { - workingDir projectDir - environment JAVA_HOME: jdkHome - delegate.with(closure) + def executeRules = tasks.register("executeRules${config.suffix}", Exec) { + dependsOn prepareMavenTest + + def logStream + doFirst { + def logPath = new File(verificationResultArchivePath, config.identifier) + assert logPath.mkdir() || logPath.directory : "Couldn't create directory $logPath" + def logFile = new File(logPath, "${name}.log") + logStream = new FileOutputStream(logFile) + standardOutput = logStream + errorOutput = logStream + println "\$ ${commandLine.join(" ")} > ${project.relativePath(logFile)}" } - } - tasks.create(name: executeRules, type: Exec, dependsOn: prepareMavenTest).configure mavenExec { + workingDir projectDir + environment JAVA_HOME: jdkHome commandLine mavenCommand('clean', 'test', '-P', 'execute-rules') + + doLast { + if (logStream) { + logStream.close() + } + } } - tasks.create(name: verifyRules, type: Exec, dependsOn: executeRules).configure mavenExec { + def verifyRules = tasks.register("verifyRules${config.suffix}", Exec) { + dependsOn executeRules + + doFirst { + println "\$ ${commandLine.join(" ")}" + } + + workingDir projectDir + environment JAVA_HOME: jdkHome commandLine mavenCommand('surefire:test', '-P', 'verify-rules') } - tasks.create(name: cleanUpMavenTest) { + def cleanUpMavenTest = tasks.register("cleanUpMavenTest${config.suffix}") { doFirst { + def archivePath = new File(verificationResultArchivePath, config.identifier) + println "Copying test results to ${project.relativePath(archivePath)}" copy { from verificationResultOriginPath include '**/*.xml' - into new File(verificationResultArchivePath, "${config.identifier}") + into archivePath } } doLast { @@ -187,23 +206,27 @@ def addMavenTest = { IntegrationTestConfig config -> } } - // Run cleanUp even if task fails - [tasks[prepareMavenTest], tasks[verifyRules], tasks[executeRules]]*.finalizedBy tasks[cleanUpMavenTest] + [prepareMavenTest, verifyRules, executeRules].each { taskProvider -> + taskProvider.configure { finalizedBy cleanUpMavenTest } + } - tasks.create(name: runMavenTest, dependsOn: [prepareMavenTest, executeRules, verifyRules, cleanUpMavenTest]) + def runMavenTest = tasks.register("runMavenTest${config.suffix}") { + dependsOn prepareMavenTest, executeRules, verifyRules, cleanUpMavenTest + } - [prepareMavenTest, executeRules, verifyRules, cleanUpMavenTest, runMavenTest].each { taskName -> - tasks[taskName].onlyIf("requires Java ${config.minimumJavaVersion} or higher") { - config.supports(integrationTestJavaVersion) + [prepareMavenTest, executeRules, verifyRules, cleanUpMavenTest, runMavenTest].each { taskProvider -> + taskProvider.configure { + onlyIf("requires Java ${config.minimumJavaVersion} or higher") { + config.supports(integrationTestJavaVersion) + } } } - def executeRulesTask = tasks[executeRules] gradle.projectsEvaluated { - def publishTasks = allprojects + def publishTasks = rootProject.allprojects .findAll { it.findProperty('isReleaseProject') } .collectMany { [it.publish, it.publishToMavenLocal] } - executeRulesTask.mustRunAfter(*publishTasks) + executeRules.configure { mustRunAfter(*publishTasks) } } } } @@ -265,14 +288,20 @@ integrationTestConfigs.each { config -> project.with(addMavenTest(config)) } def suffixes = integrationTestConfigs*.suffix.sort() [suffixes, suffixes.tail()].transpose().each { twoConsecutiveSuffixes -> - tasks["prepareMavenTest${twoConsecutiveSuffixes[1]}"].mustRunAfter(tasks["cleanUpMavenTest${twoConsecutiveSuffixes[0]}"]) + tasks.named("prepareMavenTest${twoConsecutiveSuffixes[1]}").configure { + mustRunAfter tasks.named("cleanUpMavenTest${twoConsecutiveSuffixes[0]}") + } +} + +tasks.register('runMavenTest') { + dependsOn integrationTestConfigs.collect { tasks.named("runMavenTest${it.suffix}") } } -task runMavenTest -tasks.findAll { it.name ==~ /^runMavenTest.+/ }.each { runMavenTest.dependsOn it } -tasks.findAll { it.name ==~ /.*MavenTest.+/ }.each { - it.doFirst { - println "Running Maven Integration Test with JDK ${integrationTestJavaVersion} located at ${jdkHome}" +tasks.configureEach { + if (name ==~ /.*MavenTest.+/) { + doFirst { + println "Running Maven Integration Test with JDK ${integrationTestJavaVersion} located at ${jdkHome}" + } } } diff --git a/archunit-maven-test/verification/TestResultTest.java b/archunit-maven-test/verification/TestResultTest.java index 5654fced7..1f89fabab 100644 --- a/archunit-maven-test/verification/TestResultTest.java +++ b/archunit-maven-test/verification/TestResultTest.java @@ -149,20 +149,7 @@ private void validateAllArchitectureFailures(Match testCaseTags) { } void assertMatchWith(GivenTestClasses givenTestClasses) { - Set onlyGiven = difference(givenTestClasses.tests, failedArchitectureTests); - assertThat(onlyGiven).as("Tests that were expected to fail, but didn't").isEmpty(); - Set onlyFailed = difference(failedArchitectureTests, givenTestClasses.tests); - assertThat(onlyFailed).as("Tests that unexpectedly failed").isEmpty(); - } - - private Set difference(Set set, Set toSubtract) { - Set result = new HashSet<>(); - for (T elem : set) { - if (!toSubtract.contains(elem)) { - result.add(elem); - } - } - return result; + assertThat(failedArchitectureTests).as("actual failures").hasSameElementsAs(givenTestClasses.tests); } void markProcessed(List testReports) {