Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

End to End testing for the publish plugin & clean-up of previously failed changes #375

Merged
merged 14 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
DEVELOCITY_BUILD_CACHE_NODE_KEY: ${{ secrets.GRADLE_ENTERPRISE_BUILD_CACHE_NODE_KEY }}
run: ./gradlew build
publish:
if: github.event_name == 'push'
if: github.event_name == 'push' && github.repository_owner == 'grails'
needs: ['build']
runs-on: ubuntu-latest
steps:
Expand All @@ -59,7 +59,7 @@ jobs:
-Dorg.gradle.internal.publish.checksums.insecure=true
publish
docs:
if: github.event_name == 'push'
if: github.event_name == 'push' && github.repository_owner == 'grails'
needs: publish
runs-on: ubuntu-latest
permissions:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/release-notes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ on:
workflow_dispatch:
jobs:
release_notes:
if: github.event_name == 'push' && github.repository_owner == 'grails'
permissions:
contents: read
runs-on: ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ The credentials and connection url must be specified as a project property or an
NEXUS_PUBLISH_SNAPSHOT_URL
NEXUS_PUBLISH_STAGING_PROFILE_ID

By default, the release or snapshot state is determined by the project.version or projectVersion gradle property. To override this behavior, use the environment variable `GRAILS_PUBLISH_RELEASE` to decide if it's a release or snapshot.

grails-web
---------
* Adds web specific extensions
Expand Down
32 changes: 26 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,30 @@ dependencies {
// compile grails-gradle-plugin with the Groovy version provided by Gradle
// to ensure build compatibility with Gradle, currently Groovy 3.0.x
// see: https://docs.gradle.org/current/userguide/compatibility.html#groovy
compileOnly "org.codehaus.groovy:groovy:$GroovySystem.version"
compileOnly "org.codehaus.groovy:groovy:$GroovySystem.version"
compileOnly "org.grails:grails-bootstrap:$grailsVersion", {
exclude group: 'org.apache.groovy'
exclude group: 'org.spockframework'
}
compileOnly "org.grails:grails-shell:$grailsShellVersion", {
exclude group: 'org.apache.groovy'
exclude group: 'org.spockframework'
}

runtimeOnly "org.grails:grails-bootstrap:$grailsVersion"
runtimeOnly "org.grails:grails-shell:$grailsShellVersion"
runtimeOnly "org.grails:grails-bootstrap:$grailsVersion", {
exclude group: 'org.apache.groovy'
exclude group: 'org.spockframework'
}
runtimeOnly "org.grails:grails-shell:$grailsShellVersion", {
exclude group: 'org.apache.groovy'
exclude group: 'org.spockframework'
}

implementation "org.grails:grails-gradle-model:$grailsVersion", {
exclude group: 'org.apache.groovy'
exclude group: 'org.spockframework'
}

implementation "org.grails:grails-gradle-model:$grailsVersion"

implementation "io.github.gradle-nexus:publish-plugin:$gradleNexusPublishPluginVersion"
implementation "com.bmuschko:gradle-nexus-plugin:$gradleNexusPluginVersion"
implementation "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
Expand Down Expand Up @@ -238,6 +249,14 @@ publishing {
}
}

// publishAllPublicationsToTestCaseMavenRepoRepository
repositories {
maven {
name = "TestCaseMavenRepo"
url = layout.buildDirectory.dir('local-maven')
}
}

publications {
pluginMaven(MavenPublication) {
pom {
Expand Down Expand Up @@ -280,7 +299,7 @@ publishing {
}

project.afterEvaluate {
project.publishing.publications.each { MavenPublication publication->
project.publishing.publications.each { MavenPublication publication ->
if (publication.name != "pluginMaven") {
publication.pom.withXml {
def xml = asNode()
Expand All @@ -294,3 +313,4 @@ tasks.named("build").configure {
finalizedBy("groovydoc")
}

apply from: rootProject.layout.projectDirectory.file('gradle/e2eTest.gradle')
2 changes: 2 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ grailsVersion=7.0.0-SNAPSHOT
grailsShellVersion=7.0.0-SNAPSHOT
springBootVersion=3.4.0
springGradleDependencyManagementVersion=1.1.6
# Since we're pulling in spring's dependency management, we need to override this to support the groovy version of gradle
spock.version=2.3-groovy-3.0
org.gradle.caching=true
org.gradle.daemon=true
org.gradle.jvmargs=-Dfile.encoding=UTF-8 -Xmx1536M -XX:MaxMetaspaceSize=512M
35 changes: 35 additions & 0 deletions gradle/e2eTest.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
def e2eTest = sourceSets.create('e2eTest')
def e2eTestTask = tasks.register('e2eTest', Test) {
group = 'verification'
testClassesDirs = sourceSets.e2eTest.output.classesDirs
classpath = sourceSets.e2eTest.runtimeClasspath
useJUnitPlatform()
systemProperty("localMavenPath", rootProject.layout.buildDirectory.dir('local-maven').get().asFile.absolutePath)
systemProperty("grailsGradlePluginVersion", rootProject.version)

testLogging {
exceptionFormat = 'full'
events 'passed', 'skipped', 'failed', 'standardOut', 'standardError'
}
beforeTest { descriptor -> logger.quiet " -- $descriptor" }

dependsOn "publishAllPublicationsToTestCaseMavenRepoRepository"
}

tasks.named("check") {
dependsOn e2eTestTask
}

gradlePlugin {
testSourceSets e2eTest
}

dependencies {
// Note: must use a groovy 3 compatible version of Spock
e2eTestImplementation "org.spockframework:spock-core:${project['spock.version']}", {
exclude group: 'org.apache.groovy'
}
e2eTestImplementation 'commons-io:commons-io:2.18.0'
e2eTestImplementation gradleTestKit()
e2eTestRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
130 changes: 130 additions & 0 deletions src/e2eTest/groovy/org/grails/gradle/test/GradleSpecification.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package org.grails.gradle.test

import org.apache.commons.io.FileUtils
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.BuildTask
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome
import spock.lang.Specification

import java.nio.file.Files
import java.nio.file.Path

abstract class GradleSpecification extends Specification {
private static Path basePath

private static GradleRunner gradleRunner

void setupSpec() {
basePath = Files.createTempDirectory("gradle-projects")
Path testKitDirectory = Files.createDirectories(basePath.resolve('.gradle'))
gradleRunner = GradleRunner.create()
.withPluginClasspath()
.withTestKitDir(testKitDirectory.toFile())

gradleRunner = addEnvironmentVariable(
"LOCAL_MAVEN_PATH",
System.getProperty("localMavenPath"),
gradleRunner
)

gradleRunner = setGradleProperty(
"grailsGradlePluginVersion",
System.getProperty("grailsGradlePluginVersion"),
gradleRunner
)
}

GradleRunner addEnvironmentVariable(String key, String value, GradleRunner runner) {
Map environment = runner.environment
if (environment) {
environment.put(key, value)

return runner
} else {
return runner.withEnvironment([(key): value])
}
}

GradleRunner setGradleProperty(String key, String value, GradleRunner runner) {
addEnvironmentVariable("ORG_GRADLE_PROJECT_${key}", value, runner)
}

void cleanup() {
basePath.toFile().listFiles().each {
// Reuse the gradle cache from previous tests
if (it.name == ".gradle") {
return
}

FileUtils.deleteQuietly(it)
}
}

void cleanupSpec() {
FileUtils.deleteQuietly(basePath.toFile())
}

protected GradleRunner setupTestResourceProject(String type, String projectName, String nestedProject = null) {
Objects.requireNonNull(projectName, "projectName must not be null")

Path destinationDir = basePath.resolve(type)
Files.createDirectories(destinationDir)

Path sourceProjectDir = Path.of("src/e2eTest/resources/publish-projects/$type/$projectName")
FileUtils.copyDirectoryToDirectory(sourceProjectDir.toFile(), destinationDir.toFile())

setupProject(destinationDir.resolve(projectName).resolve(nestedProject ?: '.'))
}

protected GradleRunner setupProject(Path projectDirectory) {
gradleRunner.withProjectDir(projectDirectory.toFile())
}

protected Path createProjectDir(String projectName) {
Objects.requireNonNull(projectName, "projectName must not be null")

Path destinationDir = basePath.resolve(projectName)
Files.createDirectories(destinationDir)

destinationDir
}

protected BuildResult executeTask(String taskName, List<String> otherArguments = [], GradleRunner gradleRunner) {
List arguments = [taskName, "--stacktrace"]
arguments.addAll(otherArguments)

gradleRunner.withArguments(arguments).forwardOutput().build()
}

protected void assertTaskSuccess(String taskName, BuildResult result) {
def tasks = result.tasks.find { it.path.endsWith(":${taskName}") }
if (!tasks) {
throw new IllegalStateException("No tasks were found for `${taskName}`")
}

tasks.each { BuildTask task ->
if (task.outcome != TaskOutcome.SUCCESS) {
throw new IllegalStateException("Task $taskName failed with outcome $task.outcome")
}
}
}

protected void assertBuildSuccess(BuildResult result, List<String> ignoreTaskNames = []) {
def results = result.tasks.groupBy { it.outcome }

for (String ignoredTaskName : ignoreTaskNames) {
for (BuildTask ignoredTask : result.tasks.findAll { it.path.endsWith("${ignoredTaskName}") }) {
def taskOutComeTasks = results.get(ignoredTask.outcome)
taskOutComeTasks.remove(ignoredTask)
if (!taskOutComeTasks) {
results.remove(ignoredTask.outcome)
}
}
}

if (results.keySet().size() != 1) {
throw new IllegalStateException("Unexpected Task failures: ${results.findAll { it.key != TaskOutcome.SUCCESS }}")
}
}
}
Loading
Loading