What is it ?

Jerkar is a Java build tool ala Gradle, Ant/Ivy or Maven. It differs from the others in that it requires pure Java code instead of XML files or dynamic language scripts to describe builds.

Into the box

Also as an automation tool Jerkar provides :

Motivation

As a Java developer you may have already been frustrated of not being able to write your build scripts with your favorite language and, moreover, with the same language as the project to build.
Indeed most of mainstream and JVM languages have first class build tool where definitions are expressed using the language itself : Gradle for Groovy, Nodejs based tools for Javascript, SBT for Scala, PyBuilder for Python, Rake for Ruby, Leiningen for Clojure, Kobalt for Kotlin ...

Jerkar purposes to fill the gap by providing a full-featured build tool allowing Java developers to build their projects by just writing regular Java classes as they are so familiar with.

Benefits

As said, with Jerkar, build definitions are plain old java classes. This bare metal approach brings concrete benefits :

How does it look like ?

All related Jerkar files lies within the project to build, under 'jerkar' diectory.

myproject
   + jerkar             
      + def             <-----  Java code that build your project goes here (this should be identifed as a java source folder in your IDE)
         + Build.java   
      + output          <---- Build artifacts are generated here 
   + src                <---- Sources of the project to build according build class defined below.
   ...


The following Build.java mimics a Ant file defining various Jave build tasks. Every public no-args void methods is callable from the command line.
Moreover, public fields value can be set from command line.
For instance : jerkar clean compile test -forkTest=true will inject true value to forkTest field then invoke clean, compile and test methods.

@JkImport("commons-httpclient:commons-httpclient:3.1")  // Import HttpClient and its deps for usage in this script
class Build extends JkRun {
	
    @JkDoc("Run test in a forked process if true.")
    public boolean forkTest;
    
    private JkPathTree src = getBaseTree().goTo("src");
    private Path classDir = getOutputDir().resolve("classes");
    private Path jarFile = getOutputDir().resolve("capitalizer.jar");
    private Path testSrc = getBaseDir().resolve("test");
    private Path testClassDir = getOutputDir().resolve("test-classes");
    private Path reportDir = getOutputDir().resolve("junitRreport");
    private JkClasspath classpath;
    private JkClasspath testClasspath;
    
    Build() {  // Here, classpath is made of local jars + jars hosted in Maven Central
        JkResolveResult deps = JkDependencyResolver.of(JkRepo.ofMavenCentral()).resolve(JkDependencySet.of()
            .and("org.hibernate:hibernate-entitymanager:5.4.2.Final")
            .and("com.h2database:h2:1.4.199"));
        List<Path> localJars = getBaseTree().andMatching("libs/compile/*.jar").getFiles();
        classpath = JkClasspath.of(localJars).and(deps.getFiles());   
        testClasspath = classpath.and(getBaseTree().andMatching("libs/test/*.jar").getFiles());
    }
    
    public void runDefault() {
        clean(); compile(); test(); jar();
    }
    
    public void compile() {
        JkJavaCompiler.ofJdk().compile(
            JkJavaCompileSpec.of()
                .setClasspath(classpath)
                .addSources(src)
                .setOutputDir(classDir));
        src.andMatching(false,"**/*.java").copyTo(classDir);  /// copy resources
    }
    
    @JkDoc("Create jar file on already compiled classes.")
    public void jar() {
        JkManifest.ofEmpty().addMainClass("org.jerkar.samples.RunClass").writeToStandardLocation(classDir);
        JkPathTree.of(classDir).zipTo(jarFile);
    }
    
    private void compileTest() {
        JkJavaCompiler.ofJdk().compile(
            JkJavaCompileSpec.of()
                .setClasspath(testClasspath)
                .addSources(testSrc)
                .setOutputDir(testClassDir));
        src.andMatching(false,"**/*.java").copyTo(testClassDir);  /// copy test resources
    }
    
    public void test() {
        compileTest();
        JkUnit.of()
            .withReportDir(reportDir).withReport(JunitReportDetail.FULL)
            .withForking(forkTest)
            .run(testClasspath.and(classDir), JkPathTree.of(testClassDir));
    }
    
    @JkDoc("Performs some http client tasks")
    public void seleniumLoadTest() throws IOException {
        HttpClient client = new HttpClient();
        GetMethod getMethod = new GetMethod("http://my.url");
        client.executeMethod(getMethod);
        // ....
    }
    
    public static void main(String[] args) {
        JkInit.instanceOf(TaskBuild.class, args).runDefault();
    }

}


The example below shows how Java plugin helps to build Java project with minimal typing. This plugin simply exposes a pre-configured JkJavaProject instance that you can reshape.
Executing jerkar java#pack java#publish invokes pack and publish methods on the Java plugin. This leads in compilation, test compilation, test executions, packaging jars and publish artifacts to default Maven repositoy.

class JavaPluginBuild extends JkRun {

    final JkPluginJava javaPlugin = getPlugin(JkPluginJava.class);

    @Override
    protected void setup() {
        JkJavaProject project = javaPlugin.getProject();
        project.setVersionedModule("org.jerkar:examples-java-template", "1.0-SNAPSHOT");
        project.getCompileSpec().setSourceAndTargetVersion(JkJavaVersion.V8);
        project.addDependencies(JkDependencySet.of()
                .and("com.google.guava:guava:18.0")
                .and("junit:junit:4.12", TEST)
        );
    }

    public static void main(String[] args) {
        JkInit.instanceOf(ClassicBuild.class, args).javaPlugin.clean().pack();
    }

}


Jerkar also allows to activate plugins on the fly without explicitly instantiating it in the build class :
jerkar sonar# jacoco# java#pack processes test coverage along SonarQube analysis prior publishing artifacts.

Multi-techno projects

Beside building Java projects, Jerkar can be used for any automation purpose, for example, Jerkar is used to generate this site.

For building multi-techno projects embedding other technologies than java, we suggest the following approach :

Library

Jerkar can also be embedded in your product as a simple jar library, to leverage directly the fluent API for manipulating files, launch external tools or other. It is available on Maven Central.

Icing on the cake : Jerkar has zero dependency.