Reproducible builds: creating a '.buildinfo' file when publishing

Hi everyone,
I’m looking at modifying some Gradle based projects to produce reproducible builds (see This works great -Working With Files

My remaining problem is the META-INF/MANIFEST.MF. Our build adds useful properties like a build timestamp to this. This will have to go if I want the reproducible jar to come out exactly the same on all builds (based on same git commit).

sbt automatically produces a separate .buildinfo file and this ends up published to Maven repos. There is an example in Index of /groups/snapshots/org/apache/pekko/pekko-actor_3/0.0.0+26705-97cf472a-SNAPSHOT

Does anyone know of any Gradle plugins that might do something similar? I found some when searching for ‘buildinfo’ but the ones I found created BuildInfo classes or modified the META-INF/MANIFEST.MF which is not what I want.

Any pointers would be appreciated.

I dont’t know of any plugin, but it shouldn’t be more than having a task that generates the file, for example of type WriteProperties, and then adding that task to the Java component. That should be all you need I think.

1 Like

I added produce buildinfo file as part of Maven publish · apache/xmlbeans@8befe6f · GitHub to get such a file published.

I had to do a few workarounds because the publishing is dependent on a custom task - and the build fails if that dependency is not called out explicitly.

Why should the jar and publish* tasks depend on that task directly?

Besides that you should definitely not use afterEvaluate and with your findAll completely break task-configuration avoidance which both are quite bad on their own.

You should als not add the artifact to the archives configuration, it is old and deprecated and shouldn’t be used for anything.

Your main problem why you have all the things I just complained about is probably because you create a separate publication for that file which you shouldn’t do. You could just add the task as artifact to the existing publication which would more be what you want. But even that would not be correct. As I said, you should add the artifact to the Java component instead, then it should be built and published along automatically just like I wrote in my answer above. :wink:

The thing is I can’t find any comprehensible documentation or examples on how to add files to - while the RPM example in Customizing publishing is quite easy to follow. That is where I got the ‘archives’ configuration from. With a little bit of trial and error, I have something that works.

The archives configuration in that example is just an example that shows how to add an artifact to an arbitrary configuration. That the archives configuration is used by now is just unfortunate.

Iirc, to model it properly you should create a consumable configuration with the artifact outgoing and then add that configuration to the component.

Like this:

diff --git a/build.gradle b/build.gradle
index 4abf6fca..502fbd44 100644
--- a/build.gradle
+++ b/build.gradle
@@ -424,7 +424,7 @@ tasks.withType(AbstractArchiveTask).configureEach {

 def buildInfoFile = layout.buildDirectory.file("buildinfo/xmlbeans-${XMLBeansVersion}.buildinfo")

-task writeBuildInfo(type: WriteProperties) {
+def writeBuildInfo = tasks.register("writeBuildInfo", WriteProperties) {
     outputFile buildInfoFile
     property 'Built-By',['']
     property 'Build-Timestamp', new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(new Date())
@@ -433,15 +433,17 @@ task writeBuildInfo(type: WriteProperties) {
     property 'Build-OS', "${['']} ${['os.arch']} ${['os.version']}"

-jar.dependsOn 'writeBuildInfo'
-project.afterEvaluate {
-    tasks.findAll {'publish') }*.dependsOn('writeBuildInfo')
+configurations {
+    buildInfo {
+        visible = false
+        canBeResolved = false
+        canBeConsumed = true
+        outgoing.artifact(writeBuildInfo)
-def buildInfoArtifact = artifacts.add('archives', buildInfoFile.get().asFile) {
-    type 'buildinfo'
 } { }
 rat {
     dependsOn 'cacheJava9'

@@ -560,10 +562,6 @@ distributions {

 publishing {
     publications {
-        maven(MavenPublication) {
-            artifact buildInfoArtifact
-            version XMLBeansVersion
-        }
         POI(MavenPublication) {
             groupId 'org.apache.xmlbeans'
             artifactId project.archivesBaseName