Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Gradle: Fix file-modifications example, add hint about non-reproducible withXml() behavior

...

Gradle builds may require setting some options in the build to ensure reproducible artifacts. Using the file-system permissions can be fine, but consider that different users (and OS's) may have different umask settings/defaults.

import java.nio.file.Files
import java.nio.file.attribute.PosixFilePermission

// This is applied to all Jar, Zip and Tar tasks.
tasks.withType<AbstractArchiveTask>().configureEach {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
// consistent directory permissions, ignoring system's umask
  dirPermissions { unix("755") }
// consistent file permissions, ignoring system's umask, retaining the executable permission (either 644 or 755)
eachFile {
  filePermissionspermissions {
  val isExec = Files.getPosixFilePermissions(file.toPath()).contains(PosixFilePermission.OWNER_EXECUTE)
    user.read = true
    user.write = true
    group.read = true
    group.write = false
    other.read = true
    other.write = false
  }  unix(if (isExec) "755" else "644")
}
  }
}

Java / Gradle / Modifying the pom.xml content

To modify the generated pom.xml, Gradle offers a mechanism on the MavenPublication type via the withXml function.

Using Node.appendNode() can lead to non-reproducible builds, depending on whether your code can run before or after Gradle added the <dependencies> node.

Example code (Kotlin Script) to place a <parent> element at a deterministic position:

withXml {
  val projectNode = asNode()

  val parentNode = projectNode.appendNode("parent")
  val parent = project.parent!!
  // Add GAV to <parent> element
  parentNode.appendNode("groupId", parent.group)
  parentNode.appendNode("artifactId", parent.name)
  parentNode.appendNode("version", parent.version)

  // Guarantee that the <parent> element is at a deterministic location.
  val groupIdElementIndex = projectNode.children().withIndex()
      .filter { it.value is Node && ((it.value as Node).name() as QName).localPart == "groupId" }
      .map { it.index }
    .single()
  projectNode.remove(parentNode)
  projectNode.children().add(groupIdElementIndex, parentNode)
}

Java / .properties files

...