How to use Gradle's dynamic versions and avoid betas?

You could use ComponentMeta to set the status:

dependencies {
   components {
     eachComponent { ComponentMetadataDetails details ->
         def version = details.id.version
         if (version.contains("beta") || version.contains("alpha")) {
             details.status = "milestone" // default in Gradle
         }
     }
   }
 }

Then use the status range syntax for your dependency:

testCompile(group: 'junit', name: 'junit', version: 'latest.release')

Now Gradle won't consider your beta a "release", and hence it won't match 4.12-beta-1. This won't let you only pick 4.x releases though, i.e. a 5.2 release would also apply.