I'm trying to use ProGuard to minimize my gradle plugin and it works well, producing the output file a-min.jar
However, com.gradle.plugin-publish plugin just doesn't recognize it when using task publishPlugins, it tells
Cannot determine main artifact to upload - could not find jar artifact with empty classifier
Strangely, when using publishToMavenLocal it did work well.
I've tried some tricks to replace the main jar with my processed jar, but always failed. Is there any new sight here?
afterEvaluate {
publishing {
publications {
withType<MavenPublication> {
if (name == "pluginMaven") {
setArtifacts(listOf(
artifact(minJarPath){
classifier = ""
extension = "jar"
}
))
}
}
}
}
}
I've tried to decompile com.gradle.plugin-publish:0.18.0, getting that
private File findMainArtifact() {
if (this.useAutomatedPublishing) {
for (UsageContext variant : this.javaRuntimeVariants) {
for (PublishArtifact artifact : variant.getArtifacts()) {
if (Util.isBlank(artifact.getClassifier()) && "jar".equals(artifact.getExtension()))
return artifact.getFile();
}
}
} else {
Configuration archivesConfiguration = getProject().getConfigurations().getByName("archives");
for (PublishArtifact artifact : archivesConfiguration.getAllArtifacts()) {
if (Util.isBlank(artifact.getClassifier()) && "jar".equals(artifact.getExtension()))
return artifact.getFile();
}
}
throw new IllegalArgumentException("Cannot determine main artifact to upload - could not find jar artifact with empty classifier");
}
But I don't know how to add a artifact to "AllArtifacts".
Full code: GitHub#ArcticLampyrid/gradle-git-version
Resolved by some tricks although it is not elegant.
Solution
Create a real jar task to include proguard outputs and add it to outgoing of apiElements & runtimeElements.
Delete the unprocessed jar from apiElements & runtimeElements. (for publishPlugins task)
Also, modify publications (for publishToMavenLocal task)
Example
/* Written in Kotlin DSL for Gradle */
/* build.gradle.kts */
// for `publishPlugins` task
val minJar by tasks.creating(Jar::class){
dependsOn(genMinJar)
from(zipTree(minJarPath))
}
jar {
archiveClassifier.set("unpacked")
}
configurations {
artifacts {
arrayOf(apiElements, runtimeElements).forEach {
it.get().outgoing.artifacts.removeIf { it.classifier == "unpacked" }
it.get().outgoing.artifact(minJar)
}
}
}
// for `publishToMavenLocal` task
afterEvaluate {
publishing {
publications {
withType<MavenPublication> {
if (name == "pluginMaven") {
setArtifacts(listOf(minJar))
}
}
}
}
}
Details
See https://github.com/ArcticLampyrid/gradle-git-version/commit/23ccfc8bdf16c9352024dc0b7722f534a310551f
Related
I'm trying to publish a jar to oss.sontatype.org using id 'maven-publish' (gradle 6.8.1).
Problem is that by default gradle publishes its module metadata and sonatype.org does not seem to like that. What happens is that sonatype does not list the jar artifact anymore. All I see (in the sontype ui) is:
myproject-SNAPSHOT-javadoc.jar
myproject-SNAPSHOT-source.jar
myproject-SNAPSHOT.module
The jar is missing although I can see in the gradle log that it uploads the jar.
If I disable the gradle metadata
tasks.withType(GenerateModuleMetadata) {
enabled = false
}
I see the expected files:
myproject-SNAPSHOT-javadoc.jar
myproject-SNAPSHOT-source.jar
myproject-SNAPSHOT.jar
I wonder if it is possible to publish gradle module metadata to oss.sonatype.org?
Here is my publishing configuration on github and inline:
// does not work on oss.sonatype.org
tasks.withType(GenerateModuleMetadata) {
enabled = false
}
publishing {
publications {
OpenApiProcessor (MavenPublication) {
groupId project.group
artifactId project.name
version project.version
from components.java
artifact sourcesJar
artifact javadocJar
pom {
name = project.projectTitle
description = project.projectDesc
url = project.projectUrl
licenses {
license {
name = 'The Apache Software License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
distribution = "repo"
}
}
developers {
developer {
id = 'hauner'
name = 'Martin Hauner'
}
}
scm {
url = "https://github.com/${project.projectGithubRepo}".toString ()
}
}
}
}
repositories {
maven {
def releaseRepository = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2")
def snapshotRepository = uri("https://oss.sonatype.org/content/repositories/snapshots")
url = project.isReleaseVersion ? releaseRepository : snapshotRepository
credentials {
username = publishUser
password = publishKey
}
}
}
}
tasks.withType(Sign) {
onlyIf { project.isReleaseVersion }
}
signing {
useInMemoryPgpKeys(signKey, signPwd)
signing {
sign publishing.publications.OpenApiProcessor
}
}
I would like to exclude all config files from the jar file since they will be provided at the provisioning and having a different version in the build path may create some runtime issues. I am using the following Gradle build script, but for some reason, I can still see whatever exist in the resources directory to be copied into the built Jar. Which means for some reason the provided Gradle build is not working as expected.
apply plugin: 'distribution'
distributions {
main {
baseName = "${project.name}"
contents {
into('/conf'){
from('src/main/resources')
exclude("application.yml")
}
into('/lib'){
from('build/libs')
}
into('/bin'){
from('../bin')
}
}
}
}
processResources {
# Not sure how I need to point to the resources, so I included both. However, none is working.
exclude('resources/*')
exclude('src/main/resources/*')
}
bootJar{
# Not sure how I need to point to the resources, so I included both. However, none is working.
exclude('resources/*')
exclude('src/main/resources/*')
}
distTar {
dependsOn bootJar
}
tasks.withType(Tar) {
compression = Compression.GZIP
extension = "tar.gz"
}
configurations {
customArch
}
artifacts {
customArch file(distTar.archivePath)
}
I was able to exclude resources from appearing in the Jar file by using processResources.enabled = false, so the build file is as follows.
apply plugin: 'distribution'
distributions {
main {
baseName = "${project.name}"
contents {
into('/conf'){
from('src/main/resources')
exclude("application.yml")
}
into('/lib'){
from('build/libs')
}
into('/bin'){
from('../bin')
}
}
}
}
processResources.enabled = false
distTar {
dependsOn bootJar
}
tasks.withType(Tar) {
compression = Compression.GZIP
extension = "tar.gz"
}
configurations {
customArch
}
artifacts {
customArch file(distTar.archivePath)
}
I found that this solution works for me:
processResources {
exclude('logback-spring.xml')
}
...where logback-spring.xml is located in src/main/resources
I want to fail the gradle build if the current project still has snapshot dependencies.
My code so far only looks for java dependencies, missing the .NET ones so it only works for java projects. I want to make it work for all projects.
def addSnapshotCheckingTask(Project project) {
project.tasks.withType(JavaCompile) { compileJava ->
project.tasks.create(compileJava.name + 'SnapshotChecking', {
onlyIf {
project.ext.isRelease || project.ext.commitVersion != null
}
compileJava.dependsOn it
doLast {
def snapshots = compileJava.classpath
.filter { project.ext.isRelease || !(it.path ==~ /(?i)${project.rootProject.projectDir.toString().replace('\\', '\\\\')}.*build.libs.*/) }
.filter { it.path =~ /(?i)-SNAPSHOT/ }
.collect { it.name }
.unique()
if (!snapshots.isEmpty()) {
throw new GradleException("Please get rid of snapshots for following dependencies before releasing $snapshots")
}
}
})
}
}
I need some help in generifying this snippet to be applicable to all types of dependencies(not just java)
Thanks!
L.E. Could something like this work?
https://discuss.gradle.org/t/how-can-i-check-for-snapshot-dependencies-and-throw-an-exception-if-some-where-found/4064
So I got it working by tweaking a bit the response of #lance-java, it looks something like:
Task snapshotCheckingTask = project.tasks.create('snapshotCheckingTask', {
doLast {
def snapshots = new ArrayList()
def projectConfigurations = project.configurations.findAll { true }
projectConfigurations.each {
if (it.isCanBeResolved()) {
it.resolvedConfiguration.resolvedArtifacts.each {
if (it.moduleVersion.id.version.endsWith('-SNAPSHOT')) {
snapshots.add(it)
}
}
}
}
if (!snapshots.isEmpty()) {
throw new GradleException("Please get rid of snapshots for following dependencies before releasing $snapshots")
} else {
throw new GradleException("Hah, no snapshots!")
}
}
})
project.tasks.release.dependsOn snapshotCheckingTask
cc #Eugene
P.S. However, this does not take into account .net dependencies
Something like
Collection<ResolvedArtifact> snapshotArtifacts = project.configurations*.resolvedConfiguration.resolvedArtifacts.filter { it.moduleVersion.id.version.endsWith('-SNAPSHOT') }
if (!snapshotArtifacts.empty) {
// throw exception
}
See
https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/Configuration.html#getResolvedConfiguration--
https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/ResolvedConfiguration.html#getResolvedArtifacts--
Here's what I came up with using Gradle 7.2 and the modern Kotlin DSL:
tasks.register("releaseEnforcement") {
group = "verification"
description = "Check whether there are any SNAPSHOT dependencies."
doLast {
val violations = project.configurations
.filter { it.name == "compileClasspath" || it.name == "runtimeClasspath" }
.flatMap { configuration ->
configuration.resolvedConfiguration.resolvedArtifacts
.map { it.moduleVersion.id }
.filter { it.version.endsWith("-SNAPSHOT") }
}
.toSet()
if (violations.isNotEmpty()) {
error("Snapshot dependencies found:\n\n${violations.joinToString(separator = "\n")}")
}
}
}
I'm using Gradle 4.4 (edit: issue still present in Gradle 4.8). For reasons my project has the following layout
src/main/java/com/company/common
src/main/java/com/company/mod1
src/main/java/com/company/mod2
The build can generate either mod1 or mod2, depending on the build task executed. Classes from mod1 shall never use classes from mod2 and vice versa. Therefore I want the build to fail, if either uses classes from the other. However I still want to be able to develop both sources in Eclipse, which is why I only want the build to fail on our CI server. The CI server provides a parameter CI_BUILD. The build file uses the following mechanism to allow this:
Excludes aren't applied properly here:
ext {
ext_template_mod1 = [:]
ext_template_mod1.src_excludes = "**/mod2/**"
ext_template_mod2 = [:]
ext_template_mod2.src_excludes = "**/mod1/**"
if (project.hasProperty("mod2")) {
ext_template = ext_template_mod2
} else {
ext_template = ext_template_mod1
}
}
sourceSets {
main {
java {
if (project.hasProperty("CI_BUILD")) {
exclude "${project.ext_template.src_excludes}"
}
}
}
}
For some reason this doesn't work. gradlew build -PCI_BUILD doesn't fail if a source file on mod1 references a source file from mod2.
I fail to understand why it doesn't. If I don't check for the project property, the exclude works as expected:
Working configuration:
ext {
ext_template_mod1 = [:]
ext_template_mod1.src_excludes = "**/mod2/**"
ext_template_mod2 = [:]
ext_template_mod2.src_excludes = "**/mod1/**"
if (project.hasProperty("mod2")) {
ext_template = ext_template_mod2
} else {
ext_template = ext_template_mod1
}
}
sourceSets {
main {
java {
exclude "${project.ext_template.src_excludes}"
}
}
}
Now gradlew build -PCI_BUILD fails as expected when a source file on mod1 references a source file from mod2.
But now my IDE won't recognize the sources in the mod2 folder as sources anymore.
How can I apply excludes to my source set based on the existence of a build parameter?
I've been creating a minimal example and it works just fine there:
apply plugin: 'java'
ext {
ext_template_mod1 = [:]
ext_template_mod1.src_excludes = "**/mod2/**"
ext_template_mod2 = [:]
ext_template_mod2.src_excludes = "**/mod1/**"
if (project.hasProperty("mod2")) {
ext_template = ext_template_mod2
} else {
ext_template = ext_template_mod1
}
}
sourceSets {
main {
java {
if (project.hasProperty("CI_BUILD")) {
exclude "${project.ext_template.src_excludes}"
}
}
}
}
jar {
if (project.hasProperty("CI_BUILD")) {
exclude "${project.ext_template.src_excludes}"
}
}
The issue above was an artifact of my own build. I had used dynamic task generation and forgotten to provide the parameter I was checking for as a startParameter.projectProperties.
I am trying to create gradle tasks to run only a sub set of tests based on annotations, which is detailed in the gradle dsl. I am trying to set the testInstrumentationRunnerArguments during the gradle execution phase. While I am successfully setting the arguments it doesn't appear to actually do any filtering.
We do have the tests located in a different source set path but we have added them to the default androidTest source set. The tests all run they are simply not filtered.
My questions then become: Can the test arguments be dynamically set during the execution phase of gradle or do they need to be set in the configuration phase? If they can be set during execution can any one point out why the below gradle wont work?
Here is my test.gradle which is applied after the android library configuration closure.
/*
* Copyright (c) 2018 company. All rights reserved.
*/
ext {
integrationTest = false
networkIntegrationTest = false
}
android.sourceSets {
androidTest {
java {
// add our custom test source sets so android studio gives us good tooling
srcDirs += './src/integrationNetworkTest/java'
srcDirs += './src/integrationTest/java'
}
res {
srcDirs += './src/integrationNetworkTest/res'
srcDirs += './src/integrationTest/res'
}
}
}
tasks.whenTaskAdded { task ->
def name = task.name.toLowerCase()
if(name.contains('connectedcheck') || task.name.matches("connected([a-zA-Z]?)+AndroidTest")) {
task.doFirst {
if(!integrationTest && !networkIntegrationTest) {
android.productFlavors.each {
it.testInstrumentationRunnerArguments.put('notAnnotation',
'com.company.android.infrastructure.test.IntegrationTest,com.company.android.infrastructure.test.IntegrationNetworkTest')
}
}
else {
StringBuilder sb = new StringBuilder()
if(integrationTest && networkIntegrationTest) {
sb.append('com.company.android.infrastructure.test.IntegrationTest')
sb.append(',')
sb.append('com.company.android.infrastructure.test.IntegrationNetworkTest')
}
else if (integrationTest) {
sb.append('com.company.android.infrastructure.test.IntegrationTest')
}
else if (networkIntegrationTest) {
sb.append('com.company.android.infrastructure.test.IntegrationNetworkTest')
}
if(integrationTest || networkIntegrationTest) {
android.productFlavors.each {
it.testInstrumentationRunnerArguments.put('annotation', sb.toString())
}
}
}
android.productFlavors.each {
println "${it.name} Test Annotations: ${it.testInstrumentationRunnerArguments}"
}
}
}
}
project.afterEvaluate {
android.libraryVariants.each { variant ->
tasks.create("${variant.name}IntegrationTest") {
group 'company'
description 'Run company Integration tests with only network requests mocked'
finalizedBy "connected${variant.name.capitalize()}AndroidTest"
doLast {
integrationTest = true
}
}
tasks.create("${variant.name}IntegrationNetworkTest") {
group 'company'
description 'Run company Integration tests with real network requests'
finalizedBy "connected${variant.name.capitalize()}AndroidTest"
doLast {
networkIntegrationTest = true
}
}
}
}
Gradle: 4.1
Android Plugin: 3.0.1
*Edit: * I think its a bug: Android Bug Tracker