Skip to content

Instantly share code, notes, and snippets.

@borsini
Last active April 21, 2022 20:50
Show Gist options
  • Save borsini/a501f5927d8a2fb90b11213c50b8d5dd to your computer and use it in GitHub Desktop.
Save borsini/a501f5927d8a2fb90b11213c50b8d5dd to your computer and use it in GitHub Desktop.
Gradle dependencies lock
/**
* Compares the current project dependencies with the ones stored in the dependencies.lock file
* Fails if the dependencies do no match and outputs the difference
*/
task compareDependencies {
dependsOn "generateCurrentDependencies"
def lockFile = new File(rootProject.rootDir, "dependencies.lock")
doFirst {
if (!lockFile.exists()) throw new IllegalStateException("${lockFile.path} file is missing. You may want to execute the 'generateDependenciesLockFile' task")
}
doLast {
println "Comparing current project dependencies with the one locked in the ${lockFile.path} file..."
def tmpLockFile = generateCurrentDependencies.outputs.getFiles().getSingleFile()
if (lockFile.text != tmpLockFile.text) {
println "diff ${lockFile.path} ${tmpLockFile.path}".execute().text
throw new IllegalStateException("""Project dependencies and lock dependencies are different. You may want to :
|- check why there is a difference
|- or execute the 'generateDependenciesLockFile' task to overwrite the current file""".stripMargin())
}
println "Dependencies match, all good !"
}
}
dependencies {
implementation "com.google.firebase:firebase-core:20.0.0" // Fixed
implementation "com.google.firebase:firebase-core:[20.0.0, 20.99.99]" // Ranged
implementation "com.google.firebase:firebase-core:20.+" // Prefixed
implementation "com.google.firebase:firebase-core" // Not constrained ...
}
dependencies {
implementation "com.squareup.okhttp3:okhttp:4.9.2"
implementation "com.datadoghq:dd-sdk-android:1.10.0"
// ...
}
dependencies {
implementation "com.onesignal:OneSignal:4.3.0"
// ...
}
/**
* Generates a temporary file in the [buildDirectory] folder containing the tree structure of the app:dependencies command
* @returns tmpLockFile a RegularFileProperty
*/
abstract class GenerateCurrentDependencies extends DefaultTask {
@OutputFile
final abstract RegularFileProperty tmpLockFile = project.objects.fileProperty().convention(project.layout.buildDirectory.file('dependencies.lock.tmp'))
GenerateCurrentDependencies() {
outputs.upToDateWhen { false }
}
@TaskAction
void join() {
println "Fetching project dependencies"
def output = "./gradlew app:dependencies --configuration releaseRuntimeClasspath".execute().text
def startIndex = output.indexOf("releaseRuntimeClasspath")
def endIndex = output.indexOf("BUILD SUCCESSFUL")
def tmpFile = tmpLockFile.get().asFile
tmpFile.delete()
tmpFile << output.substring(startIndex, endIndex).replace("\\---", "+---")
}
}
tasks.register('generateCurrentDependencies', GenerateCurrentDependencies)
/**
* Generates a dependencies.lock file containing the tree structure of the app:dependencies command
*/
task generateDependenciesLockFile {
dependsOn "generateCurrentDependencies"
def lockFile = new File(rootProject.rootDir, "dependencies.lock")
doLast {
println "Locking project dependencies..."
def tmpLockFile = generateCurrentDependencies.outputs.getFiles().getSingleFile()
lockFile.delete()
lockFile << tmpLockFile.text
println "Dependencies written down to ${lockFile.path}"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment