Developer Zone

Advanced Software Development with MATLAB

Git to the Lab!

Hello everyone, for this post, I'd like to introduce Mariano Lizarraga Fernandez as a guest blogger. He has a great story to share where he demonstrates a nicely tuned workflow between a Jenkins server and and a GitLab repository. Take it away Mariano!

The Big Picture

In this post we will present a workflow to show how we can run a MATLAB or Simulink Test suite on a Continuous Integration server every time we push to a git repository branch.

We will not describe in detail what Continuous Integration is and everything it involves. For those interested, we recommend this post as an introduction to the topic. This post introduces the concept of interfacing MATLAB with Jenkins, a well-known continuous integration server. Feel free to explore this and other CI related posts by looking at the Continuous Integration category.

In the following we assume that you have some basic familiarity with git and have a Jenkins server running (even locally) that has access to the git repository under test. We will be showing interactions between Jenkins and GitLab (a well-known open source git repository manager) and therefore you will need to install the GitLab plugin in Jenkins.

Let's go through the Workflow step by step.

For purposes of this post, we will assume a simplified continuous integration workflow as follows:

  1. Changes are made to code or a model, staged, and committed to a git repository's testing branch.
  2. Changes are pushed to a git remote's testing branch.
  3. The remote repository notifies (via a web hook) the Jenkins CI server that there has been a new push event.
  4. The Jenkins server pulls the changes from the git repository and runs a test suite.
  5. If a test fails, it creates a bug issue in GitLab, if the test passes, it creates a merge request.

Here is a picture illustrating this workflow:

Getting Jenkins Ready

We have written before in this blog how to go about setting up Jenkins to launch MATLAB unit tests. So here we'll focus on configuring it, so every time you push to the testing branch, a Jenkins workflow is triggered.

Start by creating a Freestyle project in Jenkins and configure your Source Code management tab to use git. Type the full address of your remote git repository, configure your credentials and make sure you set it to build from your testing branch.

Next, configure your project to build when a change is pushed to GitLab. Take note of the GitLab CI Service URL, as you will need it later to configure GitLab.

Finally, configure launching MATLAB with no display, changing directory to the Project's workspace, and running a script that we'll be writing in the following sections:

After that, save your changes. Your freestyle project is ready. Now off to GitLab.

Getting GitLab ready

In GitLab the first thing to do is to configure the Web Hook that will notify Jenkins when a push occurs. To do that, navigate to your settings and in the Integrations subsection, add the URL you wrote from the previous section, check the push events checkbox and click the Add Webhook button:

At this point you can test that your web hook triggers a build in Jenkins. To do that, in the same Integrations subsection in GitLab, select your webhook from the list, and using the Test button, select Push Events. You should immediately get a blue ribbon at the top indicating that your web hook executed successfully

Finally, since we will be using GitLab's RESTful API to create issues and merge requests, you'll need to get a Personal Access Token. To do that, go to your personal settings, (in the rightmost corner on a standard GitLab instance) and from there go to your Access Tokens subsection. This will take you to the Access Token creation page. Select a Name, choose an expiration date (you can also leave it blank) and for the scope check the API checkbox.

After you click the green Create personal access token button, you will be taken to a page that shows you the token. Make sure you record that token somewhere as you will not be able to see it again. We will use that token when we write our MATLAB script to run the tests in Jenkins.

Testing Script

We will use a variation of the script published for this Simulink's Blog post.

Convert it to a function to receive one argument: The argument will determine if it ran in continuous Integration or locally. This will allow us to test things locally then push it to server to run there.

function runMyTests (ranInCI)

import matlab.unittest.TestRunner
import matlab.unittest.plugins.TAPPlugin
import matlab.unittest.plugins.ToFile

workspace = pwd;

if ranInCI == 1
    resultsLocation = fullfile(pwd, 'results');

.
.
.

Collect Data about the current commit: So we can put comments on the issues or merge request about which commit passed and needs to be merged (or failed and needs to be fixed).

% Collect data from the current commit to include in the
% body of the issue or merge request.
[~, commit] = system('git rev-parse --short HEAD');
[~, branch] = system('git rev-parse --abbrev-ref HEAD');

Do a web GET or POST to GitLab's API: We will use webwrite and webread to create the issues and merge requests as necessary. Note that in you will need the private token created in GitLab.

if ranInCI == 1
    copyfile(tapResultsFile, fullfile(resultsLocation, 'TAPResults.tap'));
    totalFailures = sum(vertcat(results(:).Failed));
    writeOptions = weboptions('MediaType','application/x-www-form-urlencoded',...
                              'HeaderFields', ...
                              {'PRIVATE-TOKEN', gitPrivateToken});
    if totalFailures == 0
        % If no failures, create a merge request
        writeMergeURL = [gitLabAPI 'projects/' ProjectID '/merge_requests?'];
        webwrite(writeMergeURL, ...
                 'title', ...
                 ['[Jenkins] Test(s) Passed for commit ' strtrim(commit)], ...
                 'description', ...
                 ['Continous Integration passed on commit ' strtrim(commit) ...
                     ' of branch ' strtrim(branch) ...
                     '. Merge request ready for review'], ...
                 'labels', 'merge_request', ...
                 'source_branch', strtrim(branch), ...
                 'target_branch', 'master', ...
                 'approvals_before_merge', '3', ...
                  writeOptions);
    else
        % Tests failed, create a test failure issue in GitLab
        writeIssueURL = [gitLabAPI 'projects/' ProjectID '/issues?'];
        webwrite(writeIssueURL, ...
                 'title', ...
                 ['[Jenkins] Test(s) Failing in commit ' strtrim(commit)], ...
                 'description', ...
                 ['Continous Integration Failed when running on commit ' ...
                 strtrim(commit) ' of branch ' strtrim(branch) '.'], ...
                 'labels', 'bug', ...
                  writeOptions);
    end
end

Putting it all Together

Now you are ready to test the complete workflow. You can take a look at the video below showing the complete process. Note, the video is a silent film, no need to crank up your audio.

If you are working on MATLAB and using git for source control, consider making use of a continuous integration server to automate your testing and making sure that your tests are run. Give it a try and let us know what you think!

|
  • print

Comments

To leave a comment, please click here to sign in to your MathWorks Account or create a new one.