Jeka is a general-purpose build tool designed as a library. In other words, users describe programmatically the actions needed to achieve automation tasks, as they would do for regular code.
The library is designed to make complex common tasks as compiling, testing or resolving dependencies as concise as possible, so building projects may require less typing compare to other tools you may know, with simplicity and transparency as a bonus.
Jeka automation code can be run indifferently from IDE (via classic main
method) or command line, thanks
to a bundled lean and fast execution engine. This engine comes with a small set of concepts promoting simplicity,
flexibility and re-usability.
By convention, every project automated or built by Jeka contains a jeka directory at its root ([Project Root]/jeka). This directory contains everything Jeka needs to automate or build the project.
In this directory, you may find :
Depending on your needs, feel free to store any build related elements in this directory (keys, document templates,...).
Besides, project root may also contains jekaw and jekaw.bat shell scripts to invoke Jeka wrapper conveniently.
For the following, when we refer to the command jeka
, you can use ./jekaw
indifferently.
All command lines are supposed to be launched from the root of the project (and not from [Project Root]/jeka).
Jeka wrapper consists in shell scripts, a thin booting jar and a configuration file in order Jeka can be executed on a specified version without being installed on the host machine. This is the recommended way of using Jeka as it makes builds portable from one machine to another.
Jeka automatically creates a directory [User Home]/.jeka when running for the first time. This directory may contain
In the contrary of Maven, Jeka does not publish locally on the same repository where are downloaded dependency artifacts.
Note : Jeka organization provides a plugin to make the following tasks smoother or transparent. Here, we'll focus only on how to do it using command line.
Prerequisite : You need a JDK 8 or higher installed on your machine. By default, Jeka will use the Java executable found in your PATH environment variable. See later sections for changing this default.
There is two ways of using jeka : by installing Jeka itself of by using a template project containing the Jeka wrapper.
jeka
command from everywhere.jekaw
command from your local directory.jeka
instead of jekaw
, add an IDE path variable JEKA_HOME pointing on [JEKA HOME].In first instance, we'll focus on how execution engine works. For simplicity's sake, we'll use trivial examples. Concrete real-life cases, as building projects, will be documented in specific sections.
jeka scaffold#run scaffold#wrap
(or just jekaw scaffold#run
if using the template wrapper project).jeka intellij#iml
or jeka eclipse#files
in order to generate IDE configuration file.Execute jeka -h
(or simply jeka
) to display a contextual help on the console.
KBean is the central concept of execution engine. It consists in classes sharing characteristics :
JkBean
public void
methods taking no arguments. All these methods are invokable from command line.public
fields (aka KBean properties). These field values can be injected from command line.init
method to perform specific initialisation tasks.postInit
method to perform tasks once all KBeans has been initialized.KBeans can be declared in def directory as source file or just be present as classes in classpath (see later).
jeka [kbeanName]#methoName [kbeanName]#[propertyName]=xxx
or
from the IDE using a basic main
method (see later).In a given project, there can only be one KBean instance per KBean class, but if you work with a multi-project build there can be several in classpath (one per project).
Generally KBeans interact with each other inside their init
method. They access each other using getRuntime().getRegistry().get(MyBean.class)
.
When a KBean depends on another one, it's good to declare it as an instance property of the first bean as this dependency will be mentioned in the quto-generated documentation.
JKBean
in def source dir.public int yourFieldName = 3;
).public void
method taking no arguments. Implement it in a way it depends on the declared field.jeka yourMethodName yourFiedName=5
on console at root of you project. It runs !Extras
@JkDoc
to provide help support.jeka help
to see KBean description in help console.@JkInjectProperty("my.prop.name")
to inject the value of a property in.dev.jeka.core.tool.FieldInjector#parse
method.dev.jeka.core.tool.builtins.project.ProjectJkBean#pack
field.Jeka embeds a bunch of utilities to perform build related tasks (file/zip manipulation, git, launching processes, compilation, testing, dependency management, crypto, ...) nevertheless, you may want rightfully to use some 3rd-party dependencies.
jeka intellij#iml
or jeka eclipse#files
.@JkInjectClasspath
mentioning either a module coordinate (e.g. org.seleniumhq.selenium:selenium-remote-driver:4.0.0) or a path on the local file system.
jeka intellij#iml
or jeka eclipse#files
.@JkInjectClasspath
annotation is imported for all build classes and not only for annotated class.@my.org:a-jeka-plugin:1.0.0
.In multi-project build, it's quite common that a KBean accesses to a KBean instance coming from another project. You can achieve it in a statically typed way.
JkBean
(e.g. ´JkBean importedBuild;`). It doesn't have to be public.@JkInjectProject
mentioning the relative path of the imported project (e.g. `@JkInjectProject("../anotherModule")).jeka intellij#iml
or jeka eclipse#files
.JkBean
to the concrete type of imported KBeanJkClass#getBaseDir
in order it can be safely executed from any working directory.There's 2 ways of launching or debugging Jeka builds from IDE. We don't mention here, usage of Intellij plugin.
main
Method inside your def ClassesCreate one or many main methods as :
public static void main(String[] args) {
JkInit.instanceOf(CoreBuild.class, args).cleanPack();
}
public static class Release {
public static void main(String[] args) {
JkInit.instanceOf(MasterBuild.class, args, "-runIT").release();
}
}
Build classes (inheriting JkClass
) must be instantiated using JkInit#instanceOf
in order it be setup in proper state.
The arguments passed in main
method are interpreted as command line arguments.
Launching or debugging this way is performant as all build classes and their dependencies are already on classpath. Therefore, no compilation or dependency resolution is needed.
Be careful to launch the main method using module dir as working dir. On IntelliJ, this is not the default (it uses project dir).
To change intelliJ defaults, follow : Edit Configurations | Edit configuration templates... | Application | Working Directory : $MODULE_DIR$.
Sometimes, you may need to mimic closer the command line behavior, for debugging purpose or to pass '@' arguments.
dev.jeka.tool.Main
as Java main class.When executing, Jeka will first determine the default KBean to instantiate it. The default KBean is determined as follows :
-kb=
option.The KBean instantiation consists in :
init
method.The init
method of the default KBean can, in turn, inkove oth
Properties are pairs of String key-value that are used across Jeka system. It typically carries urls, local paths,
tool versions or credentials. They can be globally accessed using JkProperties#get*
static method.
Properties can be defined at different level, in order of precedence :
-DpropertyName=value
. System properties can
be injected from Jeka command line.jeka.kotlin.version=1.5.21
).Standard properties :
jeka.jdk.X=
location of the JDK version X (e.g. jeka.jdk.11=/my/java/jdk11). It is used to compile projects when
project JVM target version differs from Jeka running version.jeka.repos.download.url
: Base url of the repository used to download dependencies (see later)jeka.kotlin.version
: Version of Kotlin used for compiling both def and project Koltlin sources.Jeka comes with predefined methods coming either from JkClass
or built-in plugins.
jeka
: Displays on console methods and options invokable from command line, along plugins available in the classpath.jeka [pugin-name]#help
: Displays on consoles all methods and option invokable for the specified plugin (e.g. jeka scaffold#help
).jeka intellij#iml
: Generates iml file for Intellij. It is generated according the dependencies declared for this project.jeka intellij#iml -JKC=
: If the above fails cause your def classes do not compile, using -JKC=
avoids def compilation phase.jeka eclipse#files
: Same purpose as above to generate metadata files for Eclipse.jeka scaffold#run
: Generates files for creating a basic Jeka project from scratch.jeka scaffold#wrap
: Generates wrapper files (jekaw/jekaw.bat and bootstrap jar)jeka scaffold#run java#
: Generate files for creating a Jeka project for building a JVM language projectYou can add these options to you command line.
-kb=[KBeanName]
: By default, Jeka instantiates the first KBean found under def directory to execute methods on.
You can force to instantiate a specific class by passing its long or short name.
If the class is already in classpath, then no def compilation occurs.
Using simply -JKC=
is equivalent to -JKC=JkClass
which is the base class bundled in Jeka.-lri
: Displays runtime info. This will display on console meaningfull information about current Jeka version, Java version, base directory, download repository, classpath, ...-lsu
: Shows logs about jeka setup (compilation of def classes, plugin loading, ...).These informations are not logged by default.-ls=BRACE
: Alters console output by delimiting tasks with braces and mentioning the processing time for each.-ls=DEBUG
: Alters console output by showing the class name and line number from where the log has been emitted.-lv
: Alters console output by displaying trace logs (emitted by JkLog#trace
)-dcf
: Force compilation of def classes, even if they are marked as up-to-date.To determine the JDK to run upon, jeka looks in priority order at :
If none of these variables are present, jeka will run upon the java executable accessible from your PATH environment.
By default, jeka fetch dependencies from maven central (https://repo.maven.apache.org/maven2).
You can select another default repository by setting the jeka.repos.download.url
options.
We recommend storing this value in your [USER DIR]/.jeka/options.properties file to be reused across projects.
For more details, see JkRepoFromOptions
javadoc.
Jeka contains a library for all regular things you need to build/test/publish projects.. The library does not depend on the execution engine and has zero dependency.
Jeka tries to stick with a consistent API design style.
Jk
. The reason is for easing distinction, in IDE, between classes supposed be used
in production or test and the ones used for building. It also helps to explore Jeka API.of
.get
.with
when a property is to be replaced by another.and
when a collection property is to be replaced by the same one plus an extra element.minus
when a collection property is to be replaced by the same one minus a specified element.set
to replace a single property value by another.add
to add a value to a collection property.
Those methods return the object itself for chaining.The previous example demonstrates how the Java/project API can be used to build and publish Java projects. This API relies on other lower level ones provided by Jeka. In a glance these are the domains covered by the Jeka APIs :
File manipulation is a central part for building software. Jeka embraces JDK7 java.nio.file API by adding some concepts around, to provide a powerful fluent style API performing recurrent tasks with minimal effort.
The following classes lie in dev.jeka.core.api.file
package:
JkPathFile
A simple wrapper for files (not folders). It provides copying, interpolation, checksum, deletion and creation methods.
JkPathSequence
An Immutable sequence of java.nio.file.Path
providing methods for filtering or appending.
JkPathMatcher
An immutable java.nio.file.PathMatcher
based on java.nio.file
glob pattern or regerxp.
Used by JkPathTree
to filter in/out files according name patterns.
JkPathTree
An Immutable root folder (or a zip file) along a PathMatcher
providing operations to copy, navigate, zip or iterate.
This is a central class in Jeka API.
JkPathTreeSet
An Immutable set of JkPathTree
. Helpful to define set of sources/resources and create jar/zip files.
JkResourceProcessor
A mutable processor for copying a set of files, preserving the structure and
replacing some text by other text. Typically, used for replacing token as ${server.ip}
by an actual value.
Examples
// creates a file and writes the content of the specified url.
JkPathFile.of("config/my-config.xml").createIfNotExist().replaceContentBy("http://myserver/conf/central.xml");
// copies all non java source files to another directory preserving structure
JkPathTree.of("src").andMatching(false, "**/*.java").copyTo("build/classes");
// One liner to zip an entire directory
JkPathTree.of("build/classes").zipTo(Paths.get("mylib.jar"));
The dev.jeka.core.api.system
package provides system level functions :
JkInfo
Provides meta information as the running version of Jeka.
JkLocator
Provides information about where is located repository cache or Jeka user home.
JkLog
Provides API to log Jeka event. It supports hierarchical logs through #startTask
and #endtask
methods.
JkProcess
Launcher for external process.
JkPrompt
One-liner to ask user input.
Dependency management API let define, fetch and publish dependencies. Api classes belong to dev.jeka.core.api.depmanagement
package
For Jeka, a dependency is something that can be resolved to a set of files by a JkDependencyResolver
.
Generally a dependency resolves to 1 file (or folder) but it can be 0 or many.
A dependency is always an instance of JkDependency
.
Jeka distinguishes mainly 3 types of dependency :
JkFileSystemDependency
class). These files are assumed to be present on the file system when the build is running.JkComputedDependency
class). These files may be present on file system or not. If they are not present, the computation is run in order to produce the missing files. Generally the computation stands for the build of an external project.JkModuleDependency
) hosted in a binary repository (Ivy or Maven for instance) : Jeka can consume and resolve transitively any artifact located in a repository as you would do with Maven, Ivy or Gradle.For the last, Jeka is using Ivy 2.5.0 under the hood. Jeka jar embeds Ivy and executes it in a dedicated classloader to be hidden for client code.
This is for declaring a dependency on module hosted in Maven or Ivy repository. Basically you instantiate a JkModuleDepency
from it's group, name and version.
JkDependencySet.of()
.and(JkPopularModule.GUAVA, "18.0")
.and("com.orientechnologies:orientdb-client:[2.0.8, 2.1.0[")
.and("mygroup:mymodule:myclassifier:0.2-SNAPSHOT");
There is many way to indicate a module dependency, see Javadoc for browsing possibilities.
Note that :
-SNAPSHOT
has a special meaning : Jeka will consider it "changing". This means that it won't cache it locally and will download the latest version from repository.Just mention the path of one or several files. If one of the files does not exist at resolution time (when the dependency is actually retrieved), build fails.
JkDependencySet.of().andFiles("libs/my.jar", "libs/my.testingtool.jar");
It is typically used for multi-modules or multi-techno projects.
The principle is that if the specified files are not present, the computation is run in order to generate the missing files. If some files still missing after the computation has run, the build fails.
This mechanism is quite simple yet powerful as it addresses following use cases :
JkArtifactProducer
). A JkProject
is an artifact producer.The generic way is to construct this kind of dependency using a java.lang.Runnable
.
The following snippet constructs a set of dependencies on two external projects : one is built with Maven, the other with Jeka.
Path mavenProject = Paths.get("../a-maven-project");
JkProcess mavenBuild = JkProcess.of("mvn", "clean", "install").withWorkingDir(mavenProject);
Path mavenProjectJar = mavenProject.resolve("target/maven-project.jar");
JkJavaProject externalProject = JkJavaProject.ofSimple(Paths.get("../a-jeka-project"));
JkDependencySet deps = JkDependencySet.of()
.and(JkComputedDependency.of(mavenBuild, mavenProjectJar))
.and(externalProject);
A dependencySet (JkDependencySet
) is an ordered bunch of dependencies used for a given purpose (compilation,
war packaging, testing, ...). It can contain any kind of JkDependency
. See here
dependencySet also defines :
It is designed as an immutable object where we can apply set theory operations for adding, removing or merging with other dependencies and dependencySet.
JkDependencySet deps = JkDependencySet.of()
.and("com.google.guava")
.and("org.slf4j:slf4j-simple")
.and("com.orientechnologies:orientdb-client:2.0.8")
.andFile("../libs.myjar")
.withVersionProvider(myVersionProvider);
Note that :
JkVersionProvider
.JkDependencySet
can be combined together in order to construct large dependencySet from smaller ones.JkDependencySet#ofTextDescription
provides a mean to instantiate a dependency set from a simple text.- COMPILE+RUNTIME
org.springframework.boot:spring-boot-starter-thymeleaf
org.springframework.boot:spring-boot-starter-data-jpa
- RUNTIME
com.h2database:h2
org.liquibase:liquibase-core
com.oracle:ojdbc6:12.1.0
- TEST
org.springframework.boot:spring-boot-starter-test
org.seleniumhq.selenium:selenium-chrome-driver:3.4.0
org.fluentlenium:fluentlenium-assertj:3.2.0
org.fluentlenium:fluentlenium-junit:3.2.0
- COMPILE
org.projectlombok:lombok:1.16.16
Mainstream build tools use a single concept ('scope' or 'configuration') to determine both :
This confusion leads in dependency management systems that are bloated, difficult to reason about and not quite flexible. Gradle comes with a proliferation of 'configurations' to cover most use case combinations, while Maven narrows 'scopes' to a fewer but with limitations and not-so-clear transitivity/publish rules.
In the opposite, Jeka distinguishes clearly the three purposes :
Jeka defines by default, 3 levels of transitivity :
Reminder : on Maven repositories, published poms can declare only two scopes for transitive dependencies : 'compile' and 'runtime'.
For Ivy repositories, it is possible to declare a specific transitivity that maps to a slave 'configuration'.
The below example shows a JkJavaProject declaration using explicit transitivity.
JkJavaProject.of().simpleFacade()
.setCompileDependencies(deps -> deps
.and("com.google.guava:guava:23.0", JkTransitivity.NONE)
.and("javax.servlet:javax.servlet-api:4.0.1"))
.setRuntimeDependencies(deps -> deps
.and("org.postgresql:postgresql:42.2.19")
.withTransitivity("com.google.guava:guava", JkTransitivity.RUNTIME)
.minus("javax.servlet:javax.servlet-api"))
.setTestDependencies(deps -> deps
.and(Hint.first(), "org.mockito:mockito-core:2.10.0")
)
It results in :
Declared Compile Dependencies : 2 elements.
com.google.guava:guava:23.0 transitivity:NONE
javax.servlet:javax.servlet-api:4.0.1
Declared Runtime Dependencies : 2 elements.
com.google.guava:guava:23.0 transitivity:RUNTIME
org.postgresql:postgresql:42.2.19
Declared Test Dependencies : 4 elements.
org.mockito:mockito-core:2.10.0
com.google.guava:guava:23.0 transitivity:RUNTIME
org.postgresql:postgresql:42.2.19
javax.servlet:javax.servlet-api:4.0.1
Dependencies without any transitivity specified on, will take default transitivity for their purpose, namely COMPILE for compile dependencies, and RUNTIME for runtime and test dependencies.
The API allows to redefine the transitivity declared in a upper dependency set.
Note that transitivity can only apply to JkModuleDependency
(like com.google.guava:guava:23.0)
and JkLocalProjectDependency
.
The JkDependencyResolver
class is responsible JkDependencyResolver.of(JkRepo.ofMavenCentral());to resolve dependencies by returning JkResolveResult
from a
JkdependencySet
.
JkDependencySet deps = JkDependencySet
.of("org.apache.httpcomponents:httpclient:4.5.3")
.andFile("libs/my.jar");
// Here, module dependencies are fetched from Maven central repo
JkDependencyResolver resolver = JkDependencyResolver.of(JkRepo.ofMavenCentral());
JkResolveResult result = resolver().resolve(deps);
From the result you can :
JkDependencyNode slfjApiNodeDep = result.getDependencyTree().getFirst(JkModuleId.of("org.slf4j:slf4j-api"));
System.out.println(slfjApiNode.getModuleInfo().getResolvedVersion());
JkPathSequence sequence = result.getFiles();
sequence.forEach(System.out::println); // print each files part of the dependency resolution
Jeka is able to publish on both Maven and Ivy repository. This includes repositories as Sonatype Nexus.
Maven and Ivy have different publication model, so Jeka proposes specific APIs according you want to publish on a Maven or Ivy repository.
Jeka proposes a complete API to pubish on Maven repository. POM files will be generated by Jeka according provided elements.
The following snippet demonstrate a pretty sophisticated publishing on Maven :
JkVersionedModule versionedModule = JkVersionedModule.of("org.myorg:mylib:1.2.6");
JkDependencySet deps = JkDependencySet.of()
.and("org.slf4j:slf4j-simple", COMPILE_AND_RUNTIME)
.and("junit:junit:4.11", TEST);
JkMavenPublication mavenPublication = JkMavenPublication.of(Paths.get("org.myorg.mylib.jar"))
// the following are optional but required to publish on public repositories.
.and(Paths.get("org.myorg.mylib-sources.jar"), "sources")
.and(Paths.get("org.myorg.mylib-javadoc.jar"), "javadoc")
.withChecksums("sha-2", "md5")
.withSigner(JkPgp.of(Paths.get("myPubring"), Paths.get("mySecretRing"), "mypassword"))
.with(JkMavenPublicationInfo.of("My sample project",
"A project to demonstrate publishing on Jeka",
"http://project.jeka.org")
.andApache2License()
.andDeveloper("djeang", "myemail@gmail.com", "jeka.org", "http://project.jeka.org/"));
// A complex case for repo (credential + signature + filtering)
JkRepo repo = JkRepo.of("http://myserver/myrepo")
.withOptionalCredentials("myUserName", "myPassword")
.with(JkRepo.JkPublishConfig.of()
.withUniqueSnapshot(false)
.withNeedSignature(true)
.withFilter(mod -> // only accept SNAPSHOT and MILESTONE
mod.getVersion().isSnapshot() || mod.getVersion().getValue().endsWith("MILESTONE")
));
// Actually publish the artifacts
JkPublisher publisher = JkPublisher.of(repo);
publisher.publishMaven(versionedModule, mavenPublication, deps);
Notice that Jeka allows to :
JkRepoSet
instead of a JkRepo
.To sign with PGP, no need to have PGP installed on Jeka machine. Jeka uses Bouncy Castle internally to sign artifacts.
Publishing on Ivy repo is pretty similar than on Maven though there is specific options to Ivy.
JkVersionedModule versionedModule = JkVersionedModule.of("org.myorg:mylib:1.2.6-SNAPSHOT");
JkDependencySet deps = JkDependencySet.of()
.and("org.slf4j:slf4j-simple", COMPILE_AND_RUNTIME)
.and("junit:junit:4.11", TEST);
JkIvyPublication publication = JkIvyPublication.of(Paths.get("org.myorg.mylib.jar"), "master")
.and(Paths.get("org.myorg.mylib-sources.jar"));
JkRepo repo = JkRepo.ofIvy(Paths.get("ivyrepo"));
JkPublisher publisher = JkPublisher.of(repo);
publisher.publishIvy(versionedModule, publication, deps, JkJavaDepScopes.DEFAULT_SCOPE_MAPPING,
Instant.now(), JkVersionProvider.of());
Jeka features high-level and low-level classes to deal with Java builds and JVM concepts.
Base classes are used as foundation for implementing Jeka high-level build API but they can be used directly in a low level build description.
These classes belong to dev.jeka.core.api.java
package.
JkClassLoader
and JkUrlClassloader
Wrap a java.lang.ClassLoader
adding convenient methods and classpath scanning capability.
JkJarPacker
A simple utility tyo create Jar or fat Jar file from compiled classes.
JkJavaCompiler
Wraps either a Java Compiler tool, nor a javac process.
JkJavadocProcessor
A Java source processor producing standard Javadoc
JkJavaProcess
A utility to launch Java process (from class dirs or jars)
JkManifest
Stands for the manifest file to include in jar files.
Jeka features a simple yet powerful API to launch tests. It relies entirely on JUnit5. This means that any test framework supported by Junit5 platform.
Jeka testing API mostly hides Junit Platform. For most of the cases, you won't need to code against Junit-Platform API to launch tests with Jeka. Nevertheless, Jeka allows users to code against Junit-Platform for fine-tuning.
The API classes all belongs to dev.jeka.core.api.java.testing
package.
JkTestProcessor
This is the entry point to launch tests. Tests are executed using the
current classloader classpath + extra class path mentioned in #launch
method arguments.JkTestResult
The result of a test launch : count for found, failure, skip, success ...JkTestSelection
A mean to determine which test to launch. It can be set using file or tag filter. It is
also possible to code against JUnit PlatformThis is the Jeka high-level API to build Java/JVM projects. API classes belong to dev.jeka.core.api.project
package.
It introduces the concept of JkProject
from where is performed compilation, testing, resources processing, packaging, publication and more.
JkProject
is the root of a deep structure embracing the parent-chaining pattern for readability.
The API contains a lot of extension points to add specific behaviors.
project
+- baseDir
+- outputDir
+- artifactProducer (define artifacts to be produce by the build as map of artifactName -> Consumer<Path> producing the artifact)
+- duplicateDependencyConflictStrategy
+- construction (Produce packaged binaries from sources. This includes test checking)
| +- jvmTargetVersion
| +- sourceEncoding
| +- javaCompiler
| +- dependencyResolver
| +- runtimeDependencies
| +- manifest
| +- fatJar (customize produced fat/uber jar if any)
| +- compilation (produce individual binary files from production sources. This includes resource processing, code generation, transpiling, post binary processing, ...)
| | +- layout (where are located source and resource files)
| | +- dependencies (stands for compile dependencies)
| | +- preCompileActions (including resources processing)
| | +- compileActions (including java sources compilation. Compilation for other languages can be added here)
| | +- postCompileActions
| | +- methods : resolveDependencies(), run()
| +- testing
| | +- compilation (same as above 'compilation' but for test sources/resources)
| | | +- layout
| | | +- dependencies (stands for test dependencies)
| | | + ...
| | +- breakOnFailure (true/false)
| | +- skipped (true/false)
| | +- testProcessor
| | | +- forkedProcess (configured the forked process who will run tests)
| | | +- preActions
| | | +- postActions
| | | +- engineBehavior
| | | | +- progressDisplayer
| | | | +- launcherConfiguration (based on junit5 platform API)
| | | +- testSelection
| | | | +- includePatterns
| | | | +- includeTags
| | +- method : run()
| +- methods : createBinJar(), createFatJar(), resolveRuntimeDependencies(), getDependenciesAsXml()
| + includeLocalDependencies(), includeTextDependencies()
+- documentation (mainly procude javadoc and source jar)
| +- javadocConfiguration
| +- methods : createJavadocJar(), createSourceJar(), run()
+- publication (define information about module and artifacts to be published)
| +- moduleId (group:name)
| +- version
| +- maven (maven specific information to be published in a Maven Repositoty)
| | +- dependencyCustomizer (customize the dependencies to be published)
| | +- mavenSpecificInfo
| | +- methods : publish
| +- ivy (Ivy specific information to be published in a Ivy Repositoty)
| | +- dependencyCustomizer (customize the dependencies to be published)
| | +- ivySpecifictInfo
| | +- method : publish()
| +- methods : publish(), getVersion(), getModuleId()
+ methods : getArtifacctPath(artifactName), toDependency(transitivity), getIdeSupport(), pack()
For simplicity’s sake, JkProject
provides a facade in order to setup common settings friendly,
without navigating deep into the structure. From facade, you can
setup dependencies, java version, project layout, test behavior, test selection and publication.
JkProject.of().simpleFacade()
.configureCompileDeps(deps -> deps
.and("com.google.guava:guava:21.0")
.and("com.sun.jersey:jersey-server:1.19.4")
.and("org.junit.jupiter:junit-jupiter-engine:5.6.0"))
.configureRuntimeDeps(deps -> deps
.minus("org.junit.jupiter:junit-jupiter-engine")
.and("com.github.djeang:vincer-dom:1.2.0"))
.configureTestDeps(deps -> deps
.and("org.junit.vintage:junit-vintage-engine:5.6.0"))
.addTestExcludeFilterSuffixedBy("IT", false)
.setJavaVersion(JkJavaVersion.V8)
.setPublishedModuleId("dev.jeka:sample-javaplugin")
.setPublishedVersion("1.0-SNAPSHOT");
If facade is not sufficient for setting up project build, it's still possible to complete through the main API.
JkProject
instances are highly configurable.
Here is a pretty complete example inspired from the Jeka Build Class .
The dev.jeka.core.api.tooling
package provides integration with tools developers generally deal with.
JkEclipseClasspathGenerator
and JkEclipseProjectGenerator
provides method to generate a proper .classpath and .project file respectively.
JkEclipseClasspathApplier
reads information from a .classpath file.
JkIntellijImlGenerator
generates proper .iml files.
JkGitWrapper
wraps common Git commands in a lean API.
JkMvn
wraps Maven command line in a lean API
JkPom
reads POM/BOM to extract information like : declared dependencies, dependency management, repos,
properties, version and artifactId.