How can I publish either my obfuscated jar or unobfuscated jar depending on if the obfuscation step runs?

I tried the code below, but things aren’t evaluated in the right order for it to work. (‘obfuscate’ is a ProGuardTask):

publishing {

publications {

main(MavenPublication) {

artifact { obfuscate.getState().getExecuted() ? file("$projectDir/build/proguard/${jar.archiveName}") : jar.archivePath }

}

}

}

For more background… I want to publish unobfuscated code to MavenLocal for easier development/debugging. I want to publish obfuscated code to the main repo.

(Note that the mavenLocal issues with not finding dependencies are becoming extremely painful.)

I got it to work doing the following, is it sane?

publishing {

publications {

main(MavenPublication) {

artifact jar

}

}

}

publishing {

obfuscate << {

publications.main.artifacts.clear()

publications.main.artifact { file("$projectDir/build/proguard/${jar.archiveName}") }

}

}

I now need to do this with the ‘maven’ plugin instead of ‘maven-publish’ because ‘maven-publish’ doesn’t work with the release plugin.

Obfuscation is common, is there a best-practice for how this should be done somewhere?

There is no best practice; the solution depends on the specifics of how the tasks/plugins (e.g. proguard) work. Looking at your solution above, I’d try to configure the correct archive from the start, rather than fixing it up later. To run conditional code depending on whether a certain task will get executed, you can use ‘gradle.taskGraph.whenReady { graph -> if (graph.hasTask(“foo”)) { … } }’.

With the ‘maven’ plugin, you might have no choice but to fix up the artifacts similar to what you did above. Something like ‘configurations.archives.artifacts.clear(); artifacts { archives … }’.

Thanks for the response. I thought that the whenReady mechanism would make sense, but I didn’t have a clear idea of what I am allowed to do at that point. I guess anything that doesn’t change the taskGraph?

So something like this?

gradle.taskGraph.whenReady { graph -> if (graph.hasTask(“obfuscate”)) {

artifacts { archives obfuscatedJar }

} else {

artifacts { archives jar }

}

}

The part that I am unsure of is how the uploadArchives or publish task has a dependency on the archive tasks… that would alter the task graph.

Something like this should work, but you might additionally have to undo the fact that the Java plugin already does ‘artifacts { archives jar }’ (see my previous post). Configurations (and also ‘Configuration.artifacts’) are ‘Buildable’ and therefore task dependencies are inferred automatically if some task takes them as input.

Okay… so I do the whenReady stuff to replace the Jar with the obfuscated version, and that seems to work. But in my multi-project build I have a project that does some integration tests with JNI methods that depends on the output of my java project and a native project. It seems now that it doesn’t run the obfuscate step on the java project before trying to run those tests. That in turn leads to the main output artifact of that project not being present when it tries to compile the test code and so it fails.

It seems that when the task graph is ready it is too late to replace the artifact because the ‘test’ task in my IntegrationTest project thinks that the output of the ‘jar’ task is the artifact and that it doesn’t need to run the obfuscate step on my java library. By the time it runs though the artifact has been replaced with the obfucated jar… but that hasn’t been built yet because the task graph was already determined!

I have temporarily worked around this by making my integration tests explicitly declare the need to run the obfuscation step in the other project, like this:

compileTestJava.dependsOn tasks.getByPath(’:MyLibrary:obfuscate’)

The down side is that I’m not able to test without obfuscating.

Am I missing something or is there a way to get around this?