smlunit hello world – with a python dependency

Three years is long enough to forget a lot so I managed to forget that I got this working with python shortly after writing this blog post. Writing this down so I don’t forget again.

  1. Download the smlunit github project. (at a minimum you need the smlunit file and the lib directory)
  2. Download the asserts file and put it in your directory (or elsewhere and refer to it from there)
  3. Write a simple function in a file named helloWorld.sml:
    fun hello(name : string) = "Hello " ^ name
  4. Write a simple test in a file named helloWorldTest.sml:
    use "asserts.sml";
    use "helloWorld.sml";
    
    assertEqual "hello" (hello("Jeanne")) "did it work?";
  5. Run it:
    Jjeanne$ ./smlunit helloWorldTest.sml 
    did it work?..........................................................FAIL
        Expected: "Hello Jeanne"
        Actual: "hello"
    
    ---------------------------------------
    Ran 1 test in 0.204 seconds (1 failure)
    
  6. It didn’t work! Fix the expected string in the test (should be assertEqual “Hello Jeanne”…
  7. Run the test again
    jeanne$ ./smlunit helloWorldTest.sml 
    did it work?............................................................OK
    
    ---------------------------
    Ran 1 test in 0.207 seconds
    
  8. Success!

where did the workspace go in jenkins pipelines

I was encountering an odd problem and needed to see what files were in a Jenkins workspace. For a freestyle job, this is easy; you just click on “workspace.”

workspace-freestyle

Where did it go?

When using a pipeline, you can have multiple nodes in your pipeline so it isn’t that simple. As described in JENKINS-33839, this means you need to click around to get to it. While I did find it, this isn’t something I do often enough to remember so writing it up for my future self and anyone else who happens to read this. (Right after I wrote this, I saw JENKINS-34321 which does explain the steps well. Mine has pictures so might as well leave it.)

  1. First, go to the build run you are interested in and click “pipeline steps”.
    pipeline-1
  2. The click “allocate node: start”. If you have multiple nodes, you’ll need to do this more than once.
    pipeline-2
  3. Then you click the workspace link.
    pipeline-3

 

Implication #1 – wipe out workspace is gone

Since the workspace is no longer tied to the job, there’s also no “wipe out workspace” option. If you need to delete the workspace, you need to delete the entire run of the job. (Maybe someone had something in the build that they shouldn’t and you want it gone.) Ok. No big deal. You have to delete a bit more than before, but it isn’t as if it is something you need for posterity.

Implication #2 – multiple “workspaces”

Since you get to the workspace from within the build, I thought this meant there were multiple. And I was afraid for the disk space. Luckily, that is not the case. Within the same node, each build does re-use the same workspace. So if you go to an old build and look at the “workspace”, it is the workspace from the latest run. Which isn’t intuitive, but I’m glad it works that way.

upgrading from jenkins 1 to jenkins 2

The first Jenkins LTS (long term support) release fro Jenkins 2.0 came out this week.  It is Jenkins 2.7.1 and is available for download here. CodeRanch is running 1.640 and we decided to upgrade shortly after the LTS release came out. There have been numerous weekly releases for 2.0. We wanted the LTS release so it is a little more stable.

Backup

Another moderator at CodeRanch installed Jenkins and Sonar originally. Unfortunately, they are mixed together in the data directory. Anyway, I started by taking a backup in case I want to go back to 1.X at any point or mess it up/ I’m not terribly worried because our Jenkins install has 5 jobs on it. Worse case, I can do a fresh install and re-create them. I want to try upgrading first though since it is easier (at least in theory.)

tar -cvf jenkins1-20060709-bkp.tar *

The tar file was 1.2 GB. This is because it includes the job workspaces and Sonar.

Install

Conveniently our Jenkins install is just the war. So I backed up the old war and uploaded the new one:

mv jenkins.war jenkins1-bkp

Starting up with Jenkins 2

Loading Jenkins showed a nice banner with a big button to click

jenkins2-splash

So I clicked the “upgrade now” button. That led to a prompt to ask if I wanted to install some pipeline related plugins.

I said yes so they installed.

Then I got another button that Jenkins was ready. Still looks the same and my jobs are still there.

jenkins-ready

When I went to look at the plugins that were installed, I saw “Warning: This Jenkins instance requires a restart. Changing the state of plugins at this time is strongly discouraged. Restart Jenkins before proceeding.”. Which makes sense. Odd the upgrade process didn’t prompt me to restart. I did it myself at this point.

Existing Jobs

The five existing jobs ran the same way as they did before upgrade.  That odd phrasing was because what really happened was:

  • Three jobs were successful
  • One job hasn’t been run in ages and was clearly an old experiment. I deleted it.
  • One job has been failing for a few days and nobody noticed. It doesn’t have email notification and is triggered by the main job. (It was failing because it was relying on an Ant 1.9 feature and Jenkins was using Ant 1.8.) I upgraded Ant and then it was good. I also added email notification so that doesn’t happen again.

Jenkins 2 claims to be fully backwards compatible. As near as I can tell, this is true. I didn’t run into any issues related to migration. I even felt comfortable deleting the giant backup file at this point.

What did change

What I noticed very quickly

  1. The job configuration screen now tab navigation which takes you right to a section on the page.
  2. The configuration of external tools is now under Maven Jenkins > Global Tool Configuration instead of Manage System.

Actually using pipelines

Granted Pipelines were available in Jenkins 1. Looking at the jobs we had, we have three distinct steps (the main build runs CI and Sonar and then a JavaDoc build runs.) It would be good to have the Sonar one as a top level citizen and equal to the JavaDoc one. I decided to try to re-write the whole thing in Groovy (rather than calling the existing jobs) to see how hard it would be. I also split the Sonar step out into its own stage. This would have been more difficult to do as a separate job because I’d have had to pass the Sonar revision number and hack at it to use the same workspace. (I know how to do both those things – after all the original JavaDoc job uses an absolute path to the Ant script to run in the original workspace – but still.)

As an aside, I had trouble finding the workspace.

Figuring out email notification was a pain. In particular, getting it to email on every failure and first success just like the default used to be. But the rest worked pretty easily and end to end it only took me a couple hours (and 37 test builds) – it’s a pretty simple set of jobs. And now the email list is one place for all the JForum stages so we won’t have the JavaDoc build failing and nobody knowing again. The script wound up being:

def emailRecipients = 'xxx@gmail.com'

node {
 // hack to get workspace variable - https://issues.jenkins-ci.org/browse/JENKINS-33511
 env.WORKSPACE = pwd()
 
 try {
 stage 'Build'
 // poll SVN and check out updates if changes
 checkout poll: true, scm: [$class: 'SubversionSCM', additionalCredentials: [], excludedCommitMessages: '', excludedRegions: '', excludedRevprop: '', excludedUsers: '', filterChangelog: false, ignoreDirPropChanges: false, includedRegions: '', locations: [[credentialsId: 'e10831de-302f-4c1d-9518-fa7fb81bab9e', depthOption: 'infinity', ignoreExternalsOption: true, local: '.', remote: 'https://xxxx/svn/xxx']], workspaceUpdater: [$class: 'UpdateUpdater']]
 // call Ant
 def antHome = tool 'apache-ant-1.9.7'
 sh "${antHome}/bin/ant clean compile jacoco dist-work"
 step([$class: 'JUnitResultArchiver', testResults: 'qa/reports/*.xml'])
 
 stage 'Sonar'
 sh "${antHome}/bin/ant sonar -DprojectVersion=${env.SVN_REVISION}"
 
 stage 'JavaDoc'
 sh "${antHome}/bin/ant javadocs"
 // archive only if run successfully
 step([$class: 'JavadocArchiver', javadocDir: "${env.WORKSPACE}/docs/api", keepAll: false])
 
 // without this, you don't get emails
 currentBuild.result = 'SUCCESS' 
 
 } catch (err) { 
 // without this, you don't get emails
 currentBuild.result = 'FAILURE' 
 throw err
 } finally {
 echo "currentBuild.result: ${currentBuild.result}"
 // send email whether job failed or not
 step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: emailRecipients, sendToIndividuals: false])
 }
}