Skip to content

Commit 6022537

Browse files
pditommasoclaude
andcommitted
Improve build metadata generation and validation
- Move plugins-info.txt generation from buildInfo to releaseInfo task - Add validation task to prevent releases with stale metadata - Use GITHUB_RUN_NUMBER for build counter in CI to preserve incrementing across builds - Validate build number and commit ID match GitHub Actions environment variables - Add outputs.upToDateWhen { false } to ensure metadata tasks always run - Update task documentation with detailed descriptions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> Signed-off-by: Paolo Di Tommaso <[email protected]>
1 parent 67a5320 commit 6022537

File tree

3 files changed

+107
-22
lines changed

3 files changed

+107
-22
lines changed

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ Follow these actions to make a new release:
124124
- Run `make releaseInfo` to update the version number and generate checksums.
125125
- Run this command to stage for commit the release files:
126126
```
127-
git add VERSION changelog.txt nextflow nextflow.md5 nextflow.sha1 nextflow.sha256
127+
git add VERSION changelog.txt nextflow nextflow.md5 nextflow.sha1 nextflow.sha256 modules/nextflow/src/main/resources/META-INF/plugins-info.txt
128128
```
129129
- Make a commit using the `[release]` tag in the comment and push it upstream to trigger the release automation with GitHub action:
130130
```

build.gradle

Lines changed: 103 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -189,16 +189,26 @@ jar.enabled = false
189189
/*
190190
* Update the build timestamp in the source source file
191191
*/
192-
task buildInfo { doLast {
192+
task buildInfo {
193+
// Always run this task - never consider it up-to-date
194+
outputs.upToDateWhen { false }
195+
196+
doLast {
193197

194198
def file0 = file('modules/nextflow/src/main/resources/META-INF/build-info.properties')
195199
def buildNum = 0
196-
def src = file0.text
197-
src.find(/build *= *([0-9]*)/) { buildNum = it[1]?.toInteger()+1 }
198-
if( !buildNum ) {
199-
println "WARN: Unable to find current build number"
200+
201+
// Use GitHub Actions run number if available, otherwise increment local counter
202+
if (System.getenv('GITHUB_RUN_NUMBER')) {
203+
buildNum = System.getenv('GITHUB_RUN_NUMBER').toInteger()
204+
println "Using GitHub Actions run number: $buildNum"
205+
} else {
206+
def src = file0.text
207+
src.find(/build *= *([0-9]*)/) { buildNum = it[1]?.toInteger()+1 }
208+
if( !buildNum ) {
209+
println "WARN: Unable to find current build number"
210+
}
200211
}
201-
file0.text = src
202212

203213
// -- update build-info file
204214
file0.text = """\
@@ -207,22 +217,24 @@ task buildInfo { doLast {
207217
timestamp=${System.currentTimeMillis()}
208218
commitId=${project.property('commitId')}
209219
""".stripIndent()
210-
211-
212-
// -- create plugins-info file
213-
def plugins = []
214-
new File(rootProject.rootDir, 'plugins')
215-
.eachDir { if(it.name.startsWith('nf-')) plugins << project(":plugins:${it.name}") }
216-
217-
def meta = plugins .collect { "$it.name@$it.version" }
218-
file('modules/nextflow/src/main/resources/META-INF/plugins-info.txt').text = meta.toSorted().join('\n')
219220
}}
220221

221222
/*
222-
* Update release information in nextflow wrapper and dockerfile
223+
* Update release information in nextflow wrapper, dockerfile, and plugin metadata.
224+
*
225+
* This task:
226+
* 1. Updates the NXF_VER version string in the nextflow launch script
227+
* 2. Updates the release version in docker/Dockerfile
228+
* 3. Generates plugins-info.txt with current plugin versions from VERSION files
229+
*
230+
* This task always runs to ensure all release artifacts are updated with current versions.
223231
*/
224-
task releaseInfo { doLast {
225-
232+
task releaseInfo {
233+
// Always run this task - never consider it up-to-date
234+
outputs.upToDateWhen { false }
235+
236+
doLast {
237+
226238
// -- update 'nextflow' wrapper
227239
def file0 = file('nextflow')
228240
def src = file0.text
@@ -234,8 +246,80 @@ task releaseInfo { doLast {
234246
src = file0.text
235247
src = src.replaceAll(/releases\/v[0-9a-zA-Z_\-\.]+\//, "releases/v$version/" as String)
236248
file0.text = src
249+
250+
// -- create plugins-info file
251+
def plugins = []
252+
new File(rootProject.rootDir, 'plugins')
253+
.eachDir { if(it.name.startsWith('nf-')) plugins << project(":plugins:${it.name}") }
254+
def meta = plugins.collect { "$it.name@$it.version" }
255+
file('modules/nextflow/src/main/resources/META-INF/plugins-info.txt').text = meta.toSorted().join('\n')
237256
}}
238257

258+
/*
259+
* Validate that plugins-info.txt matches plugin VERSION files and that build-info.properties
260+
* contains the correct build number and commit ID when running in GitHub Actions.
261+
*
262+
* This task ensures:
263+
* 1. All plugin versions in plugins-info.txt match their corresponding VERSION files
264+
* 2. The build number in build-info.properties matches GITHUB_RUN_NUMBER (in CI)
265+
* 3. The commit ID in build-info.properties matches GITHUB_SHA (in CI)
266+
*
267+
* This validation prevents releases with stale or mismatched metadata.
268+
*/
269+
task validatePluginVersions {
270+
dependsOn buildInfo
271+
inputs.file('modules/nextflow/src/main/resources/META-INF/plugins-info.txt')
272+
inputs.file('modules/nextflow/src/main/resources/META-INF/build-info.properties')
273+
inputs.files(fileTree('plugins') { include '*/VERSION' })
274+
275+
doLast {
276+
// Get expected versions from plugin projects
277+
def expected = []
278+
new File(rootProject.rootDir, 'plugins')
279+
.eachDir { if(it.name.startsWith('nf-')) expected << project(":plugins:${it.name}") }
280+
def expectedVersions = expected.collect { "$it.name@$it.version" }.toSorted()
281+
282+
// Get actual versions from plugins-info.txt
283+
def actualVersions = file('modules/nextflow/src/main/resources/META-INF/plugins-info.txt').readLines()
284+
285+
// Compare plugin versions
286+
if (expectedVersions != actualVersions) {
287+
def diffs = []
288+
expectedVersions.eachWithIndex { exp, i ->
289+
def act = actualVersions.size() > i ? actualVersions[i] : 'missing'
290+
if (exp != act) diffs << " expected: $exp, actual: $act"
291+
}
292+
throw new GradleException("Plugin version mismatch:\n${diffs.join('\n')}\nRun 'make assemble' to fix.")
293+
}
294+
295+
// Validate build-info.properties - require GitHub Actions environment variables
296+
if (!System.getenv('GITHUB_RUN_NUMBER')) {
297+
throw new GradleException("GITHUB_RUN_NUMBER environment variable is required")
298+
}
299+
if (!System.getenv('GITHUB_SHA')) {
300+
throw new GradleException("GITHUB_SHA environment variable is required")
301+
}
302+
303+
def buildInfoFile = file('modules/nextflow/src/main/resources/META-INF/build-info.properties')
304+
def props = new Properties()
305+
buildInfoFile.withInputStream { props.load(it) }
306+
307+
def actualBuild = props.getProperty('build')
308+
def expectedBuild = System.getenv('GITHUB_RUN_NUMBER')
309+
if (actualBuild != expectedBuild) {
310+
throw new GradleException("Build number mismatch: build-info.properties has '${actualBuild}' but GITHUB_RUN_NUMBER is '${expectedBuild}'. Run 'make assemble' to fix.")
311+
}
312+
313+
def actualCommit = props.getProperty('commitId')
314+
def expectedCommit = System.getenv('GITHUB_SHA').take(9) // GitHub SHA is full hash, we use short form
315+
if (actualCommit != expectedCommit) {
316+
throw new GradleException("Commit ID mismatch: build-info.properties has '${actualCommit}' but GITHUB_SHA is '${expectedCommit}'. Run 'make assemble' to fix.")
317+
}
318+
319+
println "✅ Build info validation passed: build=${actualBuild}, commitId=${actualCommit}"
320+
println "✅ Plugin version validation passed: all ${expected.size()} plugin versions match"
321+
}
322+
}
239323

240324
/*
241325
* Compile sources and copies all libs to target directory
@@ -425,6 +509,7 @@ releaseInfo.finalizedBy makeDigest
425509
task upload {
426510
dependsOn compile
427511
dependsOn coreProjects.publish
512+
dependsOn validatePluginVersions
428513
}
429514

430515

packing.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ task pack( dependsOn: [packOne, packDist]) {
126126

127127
}
128128

129-
task deploy( type: Exec, dependsOn: [clean, compile, pack]) {
129+
task deploy( type: Exec, dependsOn: [clean, compile, pack, validatePluginVersions]) {
130130

131131
def temp = File.createTempFile('upload',null)
132132
temp.deleteOnExit()
@@ -233,10 +233,10 @@ task dockerPack(type: Exec, dependsOn: ['packOne']) {
233233

234234
/*
235235
* Tag and upload the release
236-
*
236+
*
237237
* https://github.com/aktau/github-release/
238238
*/
239-
task release(type: Exec, dependsOn: [pack, dockerImage]) {
239+
task release(type: Exec, dependsOn: [pack, dockerImage, validatePluginVersions]) {
240240

241241
def launcherFile = file('nextflow').absoluteFile
242242
def launcherSha1 = file('nextflow.sha1').absoluteFile

0 commit comments

Comments
 (0)