Publish java library with custom primary artifact - java

I m trying to create a java library with custom primary artifact..
I followed this documentation, but the problem is when i run the "publish" task, i get this error.
Could not determine the dependencies of task ':publishMavenPublicationToMyRepoRepository'.
> Task with path 'rpm' not found in root project 'commons'.
This is my gradle file :
import com.netflix.gradle.plugins.rpm.Rpm
plugins {
`java-library`
`maven-publish`
id("nebula.ospackage") version "7.4.1"
kotlin("jvm") version "1.3.50"
}
group = "com.test"
version = "1.0.0"
java.sourceCompatibility = JavaVersion.VERSION_1_8
repositories {
mavenCentral()
}
dependencies {
implementation("javax.xml.bind:jaxb-api:2.3.1")
implementation("io.jsonwebtoken:jjwt:0.9.1")
implementation("com.googlecode.libphonenumber:libphonenumber:8.10.14")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.9")
}
tasks.withType<Rpm> {
version = "1.0.0"
release = "1"
packageName = "com.test.commons"
into("$buildDir/rpms/com.test.commons.rpm")
}
val rpmFile = file("$buildDir/rpms/com.test.commons.rpm")
val rpmArtifact = artifacts.add("archives", rpmFile) {
type = "rpm"
builtBy("rpm")
}
publishing {
publications {
create<MavenPublication>("maven") {
artifact(rpmArtifact)
}
}
repositories {
maven {
name = "myRepo"
url = uri("file://${buildDir}/repo")
}
}
}
I think the problem is in the rpm task, how can i solve that?

The rpm task type is available with the nebula.rpm plugin as explained in the wiki here
plugins {
id("nebula.ospackage") version "7.4.1"
id("nebula.rpm") version "7.4.1"
}
Not familiar with this plugin, but it doesn't look like applying nebula.ospackage is enough.

The nebula.ospackage plugin will create a task named buildRpm of type com.netflix.gradle.plugins.rpm.Rpm.
In your script you reference a task by the name rpm, which does not exists : this explains the error you got (> Task with path 'rpm' not found in root project 'commons'.)
Just update your script to use correct task name :
val rpmArtifact = artifacts.add("archives", rpmFile) {
type = "rpm"
builtBy("buildRpm") // <=== instead of "rpm"
}
Note : you don't have to apply plugin nebula.rpm, nebula.ospackage is enough.

Related

LWJGL natives os + JPMS + GRADLE

ERROR: UnsatisfiedLinkError
[LWJGL] Failed to load a library. Possible solutions:
a) Add the directory that contains the shared library to -Djava.library.path or -Dorg.lwjgl.librarypath.
b) Add the JAR that contains the shared library to the classpath.
[LWJGL] Enable debug mode with -Dorg.lwjgl.util.Debug=true for better diagnostics.
[LWJGL] Enable the SharedLibraryLoader debug mode with -Dorg.lwjgl.util.DebugLoader=true for better diagnostics.
Exception in thread "main" java.lang.UnsatisfiedLinkError: Failed to locate library: lwjgl.dll
at org.lwjgl/org.lwjgl.system.Library.loadSystem(Library.java:162)
at org.lwjgl/org.lwjgl.system.Library.loadSystem(Library.java:62)
at org.lwjgl/org.lwjgl.system.Library.<clinit>(Library.java:50)
at org.lwjgl.glfw/org.lwjgl.glfw.GLFW.<clinit>(GLFW.java:674)
FAILURE: Build failed with an exception.
I tried to had/implement the java platform module system to one of my
projects and this linking error had me. The following lines are build script and the module-info src code.
lib module: buld.gradle.kts
import org.gradle.kotlin.dsl.support.unzipTo
plugins {
`java-library`
}
group = "com.moc"
version = "0.0"
java {
modularity.inferModulePath.set(true)
}
repositories {
mavenCentral()
}
val nativesClasses: Configuration by configurations.creating {
isTransitive = false
extendsFrom(configurations.runtimeOnly.get())
}
tasks.register("unzips") {
nativesClasses.asFileTree.forEach {
unzipTo(File("${buildDir}/libs/natives"), it)
}
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.1")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
implementation(fileTree("hard-typed/path/for/the/lwjgl-3.2.3/lwjgl.jar") )
implementation(fileTree("hard-typed/path/for/the/lwjgl-3.2.3/lwjgl-glfw.jar") )
implementation(fileTree("hard-typed/path/for/the/lwjgl-3.2.3/lwjgl-assimp.jar") )
implementation(fileTree("hard-typed/path/for/the/lwjgl-3.2.3/lwjgl-opengl.jar") )
runtimeOnly( fileTree("hard-typed/path/for/the/lwjgl-3.2.3/lwjgl-natives-windows.jar" ) )
runtimeOnly( fileTree("hard-typed/path/for/the/lwjgl-3.2.3/wjgl-glfw-natives-windows.jar" ) )
runtimeOnly( fileTree("hard-typed/path/for/the/lwjgl-3.2.3/lwjgl-assimp-natives-windows.jar" ) )
runtimeOnly( fileTree("hard-typed/path/for/the/lwjgl-3.2.3/lwjgl-opengl-natives-windows.jar" ) )
}
tasks.test {
useJUnitPlatform()
}
app module: build.gradle.kts
plugins {
application
}
group = "com.moc"
version = "0.0"
java {
modularity.inferModulePath.set(true)
}
application {
mainModule.set("moc.app")
mainClass.set("com.moc.main.App")
}
tasks.withType<JavaExec> {
System.setProperty("org.lwjgl.librarypath",
"hard-typed/path/of/natives-os/lwjgl;" +
"hard-typed/path/of/natives-os/opengl;" +
"hard-typed/path/of/natives-os/glfw;" +
"hard-typed/path/of/natives-os/assimp" )
}
repositories {
mavenCentral()
}
dependencies {
implementation(project(":lib"))
}
lib & app module: module-info.java
module moc.lib {
requires org.lwjgl.glfw;
requires org.lwjgl.opengl;
requires org.lwjgl.assimp;
exports com.moc;
}
module moc.app {
requires moc.lib;
}
> How do we link this natives os to our project by using a gradle build script and without any external plugins?
I tried this one and it's working but somehow I feel this is not the right way?
tasks.withType<JavaExec> {
val lwjgl = System.setProperty("org.lwjgl.librarypath", "../libs/natives"
systemProperty("org.lwjgl.librarypath", System.getProperty("org.lwjgl.librarypath") )
}
repositories {
mavenCentral()
}
And try this one for the application extension
val lwjgNativesProp : String? = System.setProperty("org.lwjgl.librarypathz", "../libs/natives")
application {
applicationDefaultJvmArgs = arrayListOf("-Dorg.lwjgl.librarypath=${System.getProperty("org.lwjgl.librarypathz")}")
}
tasks.withType<JavaExec> {
lwjglNativesProp?.let { systemProperty("org.lwjgl.librarypath", it) }
}

is it possible to publish gradle module metadata to oss.sontatype.org?

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
}
}

Create multiple shadowJars for each flavor of application

I'm experimenting with gradle and trying to setup a system that builds different flavors (brands) of an application, which differ by configuration mainly. What I have so far are two versions of the build scripts - both not working.
Version 1
First flavor specific resource folder flavor-res is added to sourcesets, which achieves overwriting some default resources. A task rule defines tasks for each flavor, which should (ideally) trigger build of the whole jar.
This works fine and generates the required jar, for one flavor at a time, like
gradle clean flavorOne
but the shadowJar task runs only once, if I do
gradle clean flavorOne flavorTwo
Stripped down Script:
sourceSets {
main {
...
resources {
srcDirs = ['src/main/resources', "${project.buildDir}/flavor-res/"]
}
}
}
shadowJar { classifier = 'SNAPSHOT' }
tasks.addRule("Pattern: flavor<Name>") { String taskName ->
if (taskName.startsWith("flavor")) {
String flavorName = (taskName - "flavor")
String flavorOutDir = "${project.buildDir}/${flavorName}"
// Set output folder and jar name
task("${taskName}Configure") {
outputs.dir(flavorOutDir)
doFirst {
archivesBaseName = flavorName
project.buildDir = flavorOutDir
}
}
// Copy res to folder used in sourcesets
task("${taskName}CopyResources") {
mustRunAfter = ["${taskName}Configure"]
outputs.dir("${project.buildDir}/flavor-res")
doFirst {
copy {
from "flavors/${flavorName}/"
into "${project.buildDir}/flavor-res/"
}
}
}
shadowJar.mustRunAfter = ["${taskName}Configure", "${taskName}CopyResources"]
// Define task that depends on shadowJar
task(taskName, dependsOn: ["${taskName}Configure", "${taskName}CopyResources",
shadowJar]) {
println "Configuring ${taskName}"
}
}
Sensing that it probably doesnt work because the change detection somehow doesnt work, I tried an alternative approach. Here is a simplified version of script
Version 2
Modified the rule to define a shadowJar dynamic task for each flavor.
/* Removed sourceSets in this version */
shadowJar { classifier = 'SNAPSHOT' }
tasks.addRule("Pattern: flavor<Name>") { String taskName ->
if (taskName.startsWith("flavor")) {
String flavorName = (taskName - "flavor")
String flavorOutDir = "${project.buildDir}/${flavorName}"
// Set resources for main sourceset
task("${taskName}Configure") {
outputs.dir(flavorOutDir)
doFirst {
archivesBaseName = flavorName
sourceSets.main.resources.srcDirs = ['src/main/resources', "${flavorOutDir}/flavor-res"]
project.buildDir = flavorOutDir
}
}
task("${taskName}CopyResources") {
outputs.dir("${flavorOutDir}/flavor-res")
dependsOn "${taskName}Configure"
doFirst {
copy {
from "flavors/${flavorName}/"
into "${project.buildDir}/flavor-res/"
}
}
}
// This should shadowJar for each flavor - but generate jars dont have the required artifacts.
task ("${taskName}Build", type: ShadowJar) {
from sourceSets.main.output
configurations = [ configurations.runtime ]
classifier = 'SNAPSHOT'
dependsOn "${taskName}CopyResources"
}
task(taskName, dependsOn: ["${taskName}Build"]) {
}
}
}
However, now, the generated jars are malformed. The first flavor gets just the artifacts for main, but no showed jars. The second jar has just the manifest and nothing else.
What would be the correct way of achieving that.
PS: No, its not an android application (flavor is just a synonym for a brand).
I decided to recreate a flavor build script, because it can be simplified to what you have now. The ShadowJar task can handle copying all the classes and resources by itself, there is no need to define separate ones. I also took some default configuration that would have been applied to the shadowJar task and applied this to the custom ShadowJar tasks to get the same behavior.
I first build a quick test project structure which can be found here:
Test Structure
Then I came up with the following script:
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins {
id 'java'
id "com.github.johnrengelman.shadow" version "2.0.4"
}
group 'your-group'
version 'dev-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
// Example dependency
compile group: 'com.google.guava', name: 'guava', version: '19.0'
}
tasks.addRule("Pattern: flavor<Name>") { def taskName ->
if (!taskName.startsWith("flavor")) {
return
}
def flavorName = taskName - "flavor"
// Define the shadow task
def shadowTask = task ("${flavorName}ShadowJar", type: ShadowJar) {
classifier = flavorName
// Add our flavor resources, first to prioritize these resources
from file("src/main/flavors/${flavorName}")
// Include our project classes
from project.sourceSets.main.output
// Don't include duplicate resources, only the first ones added, in
// this case the flavored resources will override the default ones
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
// Some defaults taken from the default shadowJar task
// https://github.com/johnrengelman/shadow/blob/master/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy#L48
configurations = [ project.configurations.runtime ]
manifest.inheritFrom project.tasks.jar.manifest
exclude('META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA')
}
// Define the flavor task
task ("${taskName}", dependsOn: shadowTask) {}
}

How to conditionally apply source set excludes to build based on parameter provided

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.

How to add static files to jar using Gradle build in Spring Boot + Angular 2 project

I have a Spring Boot + Angular 2 project. I want to deploy it to Heroku.
I'm able to run the npm build then copy the generated files over to the public folder (src/resources/public) manually, then run the backend build.
What I want to do is to set up a gradle build that will do all of that at once.
What I have so far is a gradle build that will build the front end, build the backend, however it does not copy the static files before generating the jar. Since the jar does not contain said static files, it won't work on Heroku.
Here's the project folder structure:
root
backend
src/main/java
src/main/resources
frontend
--> angular files go here
build/libs -> where the JAR file goes
The gradle build file:
buildscript {
repositories {
mavenCentral()
}
dependencies {
// spring
classpath('org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE')
classpath('org.springframework:springloaded:1.2.6.RELEASE')
}
}
plugins {
id "com.moowork.node" version "1.2.0"
}
// gradle wrapper
task wrapper(type: Wrapper) {
gradleVersion = '3.4'
}
// configure gradle-node-plugin
node {
version = '8.1.4'
npmVersion = '5.0.3'
download = true
workDir = file("${project.projectDir}/node")
nodeModulesDir = file("${project.projectDir}/")
}
// clean node/node_modules/dist
task npmClean(type: Delete) {
final def webDir = "${rootDir}/frontend"
delete "${webDir}/node"
delete "${webDir}/node_modules"
delete "${webDir}/dist"
delete "${webDir}/coverage"
delete "${rootDir}/backend/src/main/resources/public"
}
// clean task for npm
task copyFiles {
doLast {
copy {
from "${rootDir}/frontend/dist"
into "${rootDir}/backend/src/main/resources/public"
}
}
}
// build task for npm
task frontendBuild {}
frontendBuild.dependsOn(npm_install)
frontendBuild.dependsOn(npm_run_build)
npm_install {
args = ['--prefix', './frontend']
}
npm_run_build {
args = ['--prefix', './frontend']
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
sourceSets {
main {
java {
srcDirs = ['backend/src/main/java']
}
resources {
srcDirs = ['backend/src/main/resources']
}
}
}
copyFiles.dependsOn(frontendBuild);
compileJava.dependsOn(frontendBuild);
task backendBuild {}
backendBuild.dependsOn(compileJava)
backendBuild.dependsOn(jar)
jar.dependsOn(copyFiles)
repositories {
mavenCentral()
}
eclipse {
classpath {
containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
containers('org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8')
}
}
idea {
module {
inheritOutputDirs = false
outputDir = file("${buildDir}/classes/main/")
}
}
jar {
baseName = 'expense-splitter'
version = '0.0.1'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
configurations {
dev
}
dependencies {
// spring
compile('org.springframework.boot:spring-boot-starter-web:1.5.2.RELEASE')
compile('org.springframework.boot:spring-boot-starter-data-jpa:1.5.2.RELEASE')
compile('org.springframework.boot:spring-boot-starter-security:1.5.2.RELEASE')
compile('org.apache.commons:commons-lang3:3.3.2')
// to make hibernate handle java 8 date and time types correctly
// it's marked as deprecated but we need to keep it until
// spring boot jpa starts using hibernate 5.2
compile('org.hibernate:hibernate-java8:5.1.0.Final')
// json web tokens
compile ('io.jsonwebtoken:jjwt:0.7.0')
compile 'mysql:mysql-connector-java'
// google gson
compile('com.google.code.gson:gson:2.8.0')
// jackson - parsing of java 8 date and time types
compile('com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.7')
// spring dev tools
dev('org.springframework.boot:spring-boot-devtools:1.5.2.RELEASE')
// testing
testCompile('org.springframework.boot:spring-boot-starter-test:1.5.2.RELEASE')
}
// run spring boot app
bootRun {
//addResources = true
classpath = sourceSets.main.runtimeClasspath + configurations.dev
jvmArgs = ["-Xdebug -agentlib:jdwp=transport=dt_socket,address=8080,server=y,suspend=n"]
}
// run all task
task runAll {}
runAll.dependsOn(bootRun)
Thanks in advance,
Try a different approach. Instead of manually copying the resources, tell Gradle that when it processes resources for the JAR, also take into consideration what is in frontend/dist/:
processResources {
from ('frontend/dist/') {
into 'public'
}
}
This should result in a JAR containing a public/ directory, with the contents of frontend/dist/ inside of it.
Gradle configuration for Spring Boot 1.5\2.x + Angular 2-6
Angular in sub-folder frontend
Frontend module
Crate build.gradle:
plugins {
id "com.moowork.node" version "1.2.0"
}
node {
version = '8.11.3'
npmVersion = '5.6.0'
download = true
workDir = file("${project.buildDir}/node")
nodeModulesDir = file("${project.projectDir}")
}
task build(type: NpmTask) {
args = ['run', 'build']
}
build.dependsOn(npm_install)
Note for Angular 6
Update outputPath value in angular.json to 'dist'
Backend module
Edit build.gradle for backend module:
Spring Boot 2.X:
bootJar {
archiveName = "yourapp.jar"
mainClassName = 'com.company.app.Application'
from('frontend/dist') {
into 'static'
}
}
Spring Boot 1.5.X:
jar {
archiveName = "yourapp.jar"
manifest {
attributes 'Main-Class': 'com.company.app.Application'
}
from('frontend/dist') {
into 'static'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Finally execute bootRepackage or bootJar task and check results in builds/libs
Assume that front end is located at the following folder: src/main/webapp/fe-ui/, the following solution for the Spring Boot version 2.1.1.RELEASE could be considered:
bootJar {
baseName = 'jar-name'
version = '0.1.0'
from('src/main/webapp/fe-ui/build') {
into 'public'
}
}
task installFeDependencies(type: NpmTask) {
args = ['install']
}
task buildFe(type: NpmTask) {
args = ['run', 'build']
dependsOn installFeDependencies
}
compileJava {
dependsOn buildFe
}
Running gradlew build will install, build front end as well as will invoke bootJar. The latter will package built front end bundle.

Categories