Scripting with Ruby and Maven

Filed under: Automation, Maven, — Tags: Ant, JRuby, Ruby, Scripting — Thomas Sundberg — 2014-02-28

In my assignment as a Configuration Manager, CM, I need to script a lot of things. I also need to automate the execution. Most of the stuff I build is built using Maven. Some is built using Ant. Both Maven and Ant are easy to run from TeamCity. But none of them are very flexible when it comes to scripting. Maven isn't designed for it and Ant is missing some features and get very verbose. The most important feature I am missing in Ant is repetition.

I saw a panel debate a while ago where three guys were discussing their favorite tools. The tools represented were Scala, Ruby and Groovy. One thing that I remembered from that session was that the Scala guy mentioned that he often used Ruby when scripting. My problem with using Ruby is that I don't have control over my execution environment. I can't install tools in it. I am not interested, either, because that wouldn't scale very well since the installation done on our build servers are done manually. I can, however, expect that Maven and Ant will work.

Given that I can expect Maven to work, I decided to try to execute a Ruby script from Maven. It turned out to work very well. I was able to reduce the size of an Ant script with 50% on my first attempt. In my opinion, the readability increased a lot. I was able to write the script more or less as prose.

If you are interested, this is how I did.

The file structure I use in this example looks like this:

example
|-- pom.xml
`-- src
    `-- main
        `-- ruby
            `-- script_from_maven.rb

I will execute a Ruby script from Maven. Let me start with a simple script that will demonstrate this. It is a little more than a Hello World, but not much. If you are a Ruby guy, you might have opinions about my style. Please let me know, I am just starting out on the Ruby path.

This is my script. I define a Ruby class. At the end of the file I create an instance of the class and executes one method.

src/main/ruby/script_from_maven.rb

class Script_from_maven
  def hello
    puts 'Hello!'
    puts ENV['JAVA_HOME']
  end
end

s = Script_from_maven.new
s.hello

The only thing I do is print hello to greet any user and print the value of my JAVA_HOME environment variable. But this is enough for me to know that my script was possible to execute.

I need a Maven pom that calls my script above. An example may look like this:

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>se.thinkcode.blog</groupId>
    <artifactId>example</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <executions>
                    <execution>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>org.jruby.Main</mainClass>
                    <arguments>
                        <argument>${basedir}/src/main/ruby/script_from_maven.rb</argument>
                    </arguments>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.jruby</groupId>
            <artifactId>jruby-complete</artifactId>
            <version>1.7.10</version>
        </dependency>
    </dependencies>
</project>

The two important things in this pom are the Maven exec plugin that I use to call JRuby and the dependency to JRuby.

I execute JRuby in the same Java process as Maven is executed. This has the benefit that I will not risk leaving any dangling processes behind if something fails unexpectedly. I also connect the execution to a Maven lifecycle phase to make my life easier. I have decided that this fantastic script should always be executed during the process-resources phase.

Why not write a Maven plugin that will solve the same problem? This is a valid question and the simple answer is that sometimes I don't have a need to be a part of the Maven eco system. In these cases, it definitely makes sense to script using something else. In other situations, it may be a good thing to be a part of the Maven eco system. When I have that need I will write a Maven plugin instead.

As usual, it all depends, and using the right tool at the right time is important.

Why is this so good then?

Do I need more reasons than this? No, not really. Two of them would have been enough.

Resources



(less...)

Pages

About
Events
Why

Categories

Agile
Automation
BDD
Clean code
Continuous delivery
Continuous deployment
Continuous integration
Cucumber
Culture
Design
DevOps
Executable specification
Git
Gradle
Guice
J2EE
JUnit
Java
Javascript
Kubernetes
Linux
Load testing
Maven
Mockito
New developers
Pair programming
PicoContainer
Presentation
Programming
Public speaking
Quality
React
Recruiting
Requirements
Scala
Selenium
Software craftsmanship
Software development
Spring
TDD
Teaching
Technical debt
Test automation
Tools
Web
Windows
eXtreme Programming

Authors

Thomas Sundberg
Adrian Bolboaca

Archives

Meta

rss RSS