2
votes

My company only uses Ant to build projects. However, Jenkins only suggests Maven as a build tool for plugin development.

How could I package my Jenkins plugin to a .hpi file using Ant and avoiding Maven at all costs?

2
some good advice below... Are you using ivy now? It would be much cleaner to use ant/ivy to handle the dependencies rather than coping all the jars around. - thekbb

2 Answers

1
votes

Here is a way to build a Jenkins plugin using Ant. Let's make a script that builds a plugin skeleton which name is "awesome".

Default plugin arborescence

awesome-plugin/
-- awesome/
   -- src/
   -- pom.xml

Instructions

  1. Add a lib/ folder which contains the following jars:
    • to be found in your Jenkins home directory Jenkins\war\WEB-INF\lib (note: you have to use the exact same versions that your current Jenkins use):
      • access-modifier-annotation-1.4.jar
      • bridge-method-annotation-1.4.jar
      • commons-io-1.4.jar
      • guava-11.0.1.jar
      • jenkins-core-1.513.jar
      • json-lib-2.4-jenkins-1.jar
      • remoting-2.23.jar
      • sezpoz-1.9.jar
      • stapler-1.207.jar
    • to be found on the web (you can choose the last version released):
  2. Replace the existing pom.xml with the following build.xml.
  3. In the Ant script, you should adapt:
    • the project name, awesome here,
    • the plugin version,
    • the Jenkins version this plugin is made for,
    • the project group.id (main package), org.jenkinsci.plugins.awesome here.

New plugin arborescence

awesome-plugin/
-- awesome/
   -- src/
   -- lib/
      -- you should have 10 jars here
   -- build.xml

build.xml

<!-- Project dependent properties -->
<property name="project_name" value="awesome"/>
<property name="project_version" value="1.0"/>
<property name="jenkins_version" value="1.513"/> <!-- which version of Jenkins is this plugin built against? -->
<property name="project_groupid" value="org.jenkinsci.plugins.awesome"/>

<!-- Build properties -->
<property name="lib_dir" value="./lib"/>
<property name="bin_dir" value="./bin" />
<property name="target_dir" value="./target"/>
<property name="target_bin_dir" value="${target_dir}/${project_name}"/>
<property name="plugin_targetMetaInf_dir" value="${target_bin_dir}/META-INF"/>
<property name="plugin_targetWebInf_dir" value="${target_bin_dir}/WEB-INF"/>
<property name="plugin_targetWebInfBin_dir" value="${plugin_targetWebInf_dir}/classes"/>

<!-- Project paths -->
<path id="project.source.path">
    <pathelement path="src/main/java" />
</path>
<path id="project.class.path">
    <fileset dir="${lib_dir}" includes="*.jar"/>    
</path>

<!-- Build flow -->
<target name="build">
    <antcall target="clean" />
    <antcall target="compile" />
    <antcall target="createTreeDirectory" />
    <antcall target="copyBin"/>
    <condition property="has_file">
        <and>
            <available file="${target_dir}/${project_name}.hpi" type="file"/>
        </and>
    </condition>
    <antcall target="createHpi"/>
    <condition property="has_dir">
        <and>
            <available file="${target_bin_dir}" type="dir"/>
        </and>
    </condition>
    <antcall target="cleanTargetDirectory" />
</target>

<!-- Cleans existing binaries -->
<target name="clean">
    <delete includeEmptyDirs="true" quiet="true">
        <fileset dir="${bin_dir}" />
    </delete>
    <mkdir dir="${bin_dir}"/>
</target>

<!-- Compiles JAVA code -->
<target name="compile">
    <javac includeantruntime="false" destdir="${bin_dir}" debug="false" optimize="${optimize}" deprecation="${deprecation}" classpathref="project.class.path">
        <src refid="project.source.path" />
    </javac>
</target>

<!-- Creates necessary target folders -->
<target name="createTreeDirectory" >
    <mkdir dir="${target_bin_dir}"/>
    <mkdir dir="${plugin_targetMetaInf_dir}"/>
    <mkdir dir="${plugin_targetWebInf_dir}"/>
    <mkdir dir="${plugin_targetWebInfBin_dir}"/>
</target>

<!-- Moves new binaries to the plugin target -->
<target name="copyBin">
    <copy todir="${plugin_targetWebInfBin_dir}" >
        <fileset dir="${bin_dir}"/>
        <fileset dir="src/main/resources"/>
    </copy>
</target>

<!-- Cleans the target directory -->
<target name="cleanTargetDirectory" if="has_dir">
    <delete dir="${target_bin_dir}"/>
</target>

<!-- Backup previous plugin -->
<target name="saveOldHpiFile" if="has_file">
    <move file="${target_dir}/${project_name}.hpi" tofile="${target_dir}/${project_name}.save.hpi"/>
</target>

<!-- Archives the plugin -->
<target name="createHpi">
    <antcall target="saveOldHpiFile"/>
    <jar destfile="${target_dir}/${project_name}.hpi" basedir="${target_bin_dir}">
        <manifest>
            <attribute name="Manifest-Version" value="{project_version}"/>
            <attribute name="Built-By" value="${user.name}"/>
            <attribute name="Created-By" value="${user.name}"/>
            <attribute name="Build-Jdk" value="${ant.java.version}"/>
            <attribute name="Extension-Name" value="${project_name}"/>
            <attribute name="Implementation-Title" value="${project_name}"/>
            <attribute name="Implementation-Version" value="${version}"/>
            <attribute name="Group-Id" value="${project_groupid}"/>
            <attribute name="Short-Name" value="${project_name}"/>
            <attribute name="Long-Name" value="${project_name}"/>
            <attribute name="Plugin-Version" value="${project_version}"/>
            <attribute name="Jenkins-Version" value="${jenkins_version}"/>
            <attribute name="Hudson-Version" value="${jenkins_version}"/>
        </manifest>
    </jar>
</target>

To launch the build, cd towards the build.xml and type ant.

0
votes

I know you stated "at all costs", but a compromise might be less effort, and still give super fast builds. A big reason for me to try to avoid maven is that the compile time is sloooowwwwww. That said, maven is quite good at creating the hpl file, and handling dependencies. The following targets are quite useful for helping to set up a super-fast non-maven build:

  • use 'mvn hpi:hpl' to generate the hpl file
  • use 'mvn dependency:copy-dependencies' to download all your dependencies, and put them into target/dependency, where it's easy to reference them from your ant script (you can add a symbolic link if necessary, from lib to target/dependency)