Skip to content

Commit 6276f01

Browse files
committed
stage-vote-release: generate and publish checksums to SVN even if release artifact is UP-TO-DATE (regression since 1.75)
Previously, sha512 task was using task.state.run { executed && !skipped }, however in fact, "skipped" means "did not have to execute". In other words, UP-TO-DATE and FROM-CACHE return as "skipped", so the proper check should be upToDate || skipMessage == null.
1 parent 78ff381 commit 6276f01

File tree

5 files changed

+242
-27
lines changed

5 files changed

+242
-27
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ This library is distributed under terms of Apache License 2.0
8787

8888
Change log
8989
----------
90+
v1.90
91+
* stage-vote-release: generate and publish checksums to SVN even if release artifact is UP-TO-DATE (regression since 1.75)
92+
* stage-vote-release: added previewSvnDist task to preview SVN dist contents without publishing it
93+
9094
v1.89
9195
* checksum-dependency: reduce the number of idle threads
9296
* crlf: ignore inaccessible files/folders in gitignore filter
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2019 Vladimir Sitnikov <[email protected]>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
package com.github.vlsi.gradle.release
18+
19+
import org.gradle.api.DefaultTask
20+
import org.gradle.api.file.ProjectLayout
21+
import org.gradle.api.file.RegularFileProperty
22+
import org.gradle.api.tasks.InputFile
23+
import org.gradle.api.tasks.OutputFile
24+
import org.gradle.api.tasks.TaskAction
25+
import org.gradle.kotlin.dsl.withGroovyBuilder
26+
import javax.inject.Inject
27+
28+
abstract class CreateChecksumTask : DefaultTask() {
29+
@get:Inject
30+
protected abstract val layout: ProjectLayout
31+
32+
@get:InputFile
33+
abstract val archiveFile: RegularFileProperty
34+
35+
@get:OutputFile
36+
abstract val checksumFile: RegularFileProperty
37+
38+
init {
39+
checksumFile.convention(
40+
layout.buildDirectory.file(
41+
archiveFile.locationOnly.map { "checksums/$name/${it.asFile.name}.sha512" }
42+
)
43+
)
44+
}
45+
46+
@TaskAction
47+
fun createChecksum() {
48+
logger.lifecycle("Checksum ${archiveFile.get()} to ${checksumFile.get()}")
49+
ant.withGroovyBuilder {
50+
"checksum"(
51+
"file" to archiveFile.get(),
52+
"todir" to checksumFile.get().asFile.parentFile.absolutePath,
53+
"algorithm" to "SHA-512",
54+
"fileext" to ".sha512",
55+
"forceoverwrite" to "yes",
56+
// Make the files verifiable with shasum -c *.sha512
57+
"format" to "MD5SUM"
58+
)
59+
}
60+
}
61+
}

plugins/stage-vote-release-plugin/src/main/kotlin/com/github/vlsi/gradle/release/ReleaseArtifacts.kt

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package com.github.vlsi.gradle.release
1919
import com.github.vlsi.gradle.release.StageVoteReleasePlugin.Companion.PREVIEW_SITE_CONFIGURATION_NAME
2020
import com.github.vlsi.gradle.release.StageVoteReleasePlugin.Companion.RELEASE_FILES_CONFIGURATION_NAME
2121
import com.github.vlsi.gradle.release.StageVoteReleasePlugin.Companion.RELEASE_SIGNATURES_CONFIGURATION_NAME
22-
import java.io.File
2322
import javax.inject.Inject
2423
import org.gradle.api.Action
2524
import org.gradle.api.Project
@@ -31,8 +30,8 @@ import org.gradle.kotlin.dsl.configure
3130
import org.gradle.kotlin.dsl.dependencies
3231
import org.gradle.kotlin.dsl.get
3332
import org.gradle.kotlin.dsl.project
33+
import org.gradle.kotlin.dsl.register
3434
import org.gradle.kotlin.dsl.the
35-
import org.gradle.kotlin.dsl.withGroovyBuilder
3635
import org.gradle.plugins.signing.SigningExtension
3736

3837
open class ReleaseArtifacts @Inject constructor(
@@ -64,34 +63,18 @@ open class ReleaseArtifacts @Inject constructor(
6463
project.artifacts {
6564
add(RELEASE_FILES_CONFIGURATION_NAME, taskProvider)
6665
}
67-
val archiveFile = taskProvider.flatMap { it.archiveFile }
68-
val sha512File = archiveFile.map { File(it.asFile.absolutePath + ".sha512") }
69-
val archiveBuilt = taskProvider.map { it.state.run { executed && !skipped } }
70-
val shaTask = project.tasks.register(taskProvider.name + "Sha512") {
71-
onlyIf { archiveBuilt.get() }
72-
inputs.file(archiveFile)
73-
outputs.file(sha512File)
74-
doLast {
75-
ant.withGroovyBuilder {
76-
"checksum"(
77-
"file" to archiveFile.get(),
78-
"algorithm" to "SHA-512",
79-
"fileext" to ".sha512",
80-
// Make the files verifiable with shasum -c *.sha512
81-
"format" to "MD5SUM"
82-
)
83-
}
66+
val archiveBuilt = taskProvider.map {
67+
it.state.run {
68+
executed && (upToDate || skipMessage == null)
8469
}
8570
}
71+
val shaTask = project.tasks.register<CreateChecksumTask>(taskProvider.name + "Sha512") {
72+
onlyIf { archiveBuilt.get() }
73+
archiveFile.set(taskProvider.flatMap { it.archiveFile })
74+
mustRunAfter(taskProvider)
75+
}
8676
project.artifacts {
87-
add(RELEASE_SIGNATURES_CONFIGURATION_NAME, sha512File) {
88-
// https://github.com/gradle/gradle/issues/16777
89-
// The exact values do not seem to be really important, are they?
90-
name = shaTask.name
91-
classifier = ""
92-
extension = "sha512"
93-
// https://github.com/gradle/gradle/issues/10960
94-
type = "sha512"
77+
add(RELEASE_SIGNATURES_CONFIGURATION_NAME, shaTask.flatMap { it.checksumFile }) {
9578
builtBy(shaTask)
9679
}
9780
}

plugins/stage-vote-release-plugin/src/main/kotlin/com/github/vlsi/gradle/release/StageVoteReleasePlugin.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,19 @@ class StageVoteReleasePlugin @Inject constructor(private val instantiator: Insta
171171
files.from(releaseExt.checksums)
172172
}
173173

174+
tasks.register<Sync>("previewSvnDist") {
175+
description = "Creates a preview of the artifacts that will be published to SVN dist repository"
176+
group = RELEASE_GROUP
177+
onlyIf { releaseExt.svnDistEnabled.get() }
178+
into(layout.buildDirectory.dir("previewSvnDist"))
179+
dependsOn(validateBeforeBuildingReleaseArtifacts)
180+
from(releaseExt.archives)
181+
from(releaseExt.checksums)
182+
doLast {
183+
logger.info("Generated SVN dist preview to $destinationDir")
184+
}
185+
}
186+
174187
val publishSvnDist = tasks.register<PromoteSvnRelease>(PUBLISH_SVN_DIST_TASK_NAME) {
175188
description = "Publish release artifacts to SVN dist repository"
176189
group = RELEASE_GROUP
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright 2019 Vladimir Sitnikov <[email protected]>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
package release
18+
19+
import com.github.vlsi.gradle.BaseGradleTest
20+
import org.eclipse.jgit.api.Git
21+
import org.gradle.testkit.runner.TaskOutcome
22+
import org.junit.jupiter.api.Assertions.assertEquals
23+
import org.junit.jupiter.api.Assertions.assertFalse
24+
import org.junit.jupiter.api.Assertions.assertTrue
25+
import org.junit.jupiter.api.fail
26+
import org.junit.jupiter.params.ParameterizedTest
27+
import org.junit.jupiter.params.provider.Arguments
28+
import org.junit.jupiter.params.provider.MethodSource
29+
30+
class ChecksumFileTest : BaseGradleTest() {
31+
companion object {
32+
val isCI = System.getenv().containsKey("CI") || System.getProperties().containsKey("CI")
33+
34+
@JvmStatic
35+
private fun gradleVersionAndSettings(): Iterable<Arguments> {
36+
if (!isCI) {
37+
// Use only the minimum supported Gradle version to make the test faster
38+
return listOf(Arguments.arguments("8.1.1", ConfigurationCache.OFF))
39+
}
40+
return mutableListOf<Arguments>().apply {
41+
add(Arguments.arguments("6.0", ConfigurationCache.OFF))
42+
add(Arguments.arguments("6.5", ConfigurationCache.OFF))
43+
add(Arguments.arguments("7.0", ConfigurationCache.OFF))
44+
add(Arguments.arguments("7.4.2", ConfigurationCache.OFF))
45+
add(Arguments.arguments("8.1.1", ConfigurationCache.OFF))
46+
}
47+
}
48+
}
49+
50+
@ParameterizedTest
51+
@MethodSource("gradleVersionAndSettings")
52+
fun previewSvnDist(gradleVersion: String, configurationCache: ConfigurationCache) {
53+
enableConfigurationCache(gradleVersion, configurationCache)
54+
projectDir.resolve("src/main/java/acme").toFile().mkdirs()
55+
projectDir.resolve("src/main/java/acme/Main.java").write(
56+
/* language=Java */
57+
"""
58+
public class Main {
59+
public int sum(int a, int b) {
60+
return a + b;
61+
}
62+
}
63+
""".trimIndent()
64+
)
65+
Git.init().apply {
66+
setGitDir(projectDir.toFile())
67+
call()
68+
}
69+
projectDir.resolve("settings.gradle").write(
70+
/* language=gradle */
71+
"""
72+
rootProject.name = 'checksums'
73+
""".trimIndent()
74+
)
75+
projectDir.resolve("build.gradle").write(
76+
/* language=gradle */
77+
"""
78+
plugins {
79+
id 'java-library'
80+
id 'maven-publish'
81+
id 'com.github.vlsi.stage-vote-release'
82+
}
83+
84+
releaseParams {
85+
tlp = "tulip"
86+
}
87+
88+
releaseArtifacts {
89+
// Release artifacts from the root project
90+
fromProject(":")
91+
92+
// Add jar as a release artifact, so create checksum for it, and so on
93+
releaseArtifacts {
94+
artifact(tasks.named('jar'))
95+
}
96+
}
97+
98+
tasks.withType(Sign).configureEach {
99+
enabled = false
100+
}
101+
""".trimIndent()
102+
)
103+
prepare(gradleVersion, "previewSvnDist", "-i", "-Prc=1").build().let { result ->
104+
if (isCI) {
105+
println(result.output)
106+
}
107+
108+
assertChecksumFilePresent("First execution")
109+
}
110+
111+
prepare(gradleVersion, "previewSvnDist", "-i", "-Prc=1").build().let { result ->
112+
if (isCI) {
113+
println(result.output)
114+
}
115+
assertEquals(TaskOutcome.UP_TO_DATE, result.task(":jarSha512")?.outcome) {
116+
"jar is UP-TO-DATE, so jarSha512 should be UP-TO-DATE as well"
117+
}
118+
119+
assertChecksumFilePresent("Checksum file should be present in up-to-date execution")
120+
}
121+
122+
prepare(
123+
gradleVersion,
124+
"cleanJarSha512",
125+
"previewSvnDist",
126+
"-x",
127+
"jar",
128+
"-i",
129+
"-Prc=1"
130+
).build().let { result ->
131+
if (isCI) {
132+
println(result.output)
133+
}
134+
assertEquals(TaskOutcome.SKIPPED, result.task(":jarSha512")?.outcome) {
135+
"jar is SKIPPED, so jarSha512 should be SKIPPED as well"
136+
}
137+
138+
assertChecksumFileAbsent("jar task is skipped, so checksum file should not be generated")
139+
}
140+
}
141+
142+
private fun assertChecksumFilePresent(message: String) {
143+
val sha512File = projectDir.resolve("build/previewSvnDist/checksums.jar.sha512").toFile()
144+
assertTrue(sha512File.isFile) { "$message: file $sha512File should exist" }
145+
if (sha512File.length() < 140) {
146+
fail("$message: file $sha512File should have length 140 or more, got ${sha512File.length()}")
147+
}
148+
}
149+
150+
private fun assertChecksumFileAbsent(message: String) {
151+
val sha512File = projectDir.resolve("build/previewSvnDist/checksums.jar.sha512").toFile()
152+
assertFalse(sha512File.isFile) { "$message: file $sha512File should not exist" }
153+
}
154+
}

0 commit comments

Comments
 (0)