{"id":1837,"date":"2018-08-23T16:28:30","date_gmt":"2018-08-23T20:28:30","guid":{"rendered":"https:\/\/blogs.mathworks.com\/developer\/?p=1837"},"modified":"2018-08-23T16:28:30","modified_gmt":"2018-08-23T20:28:30","slug":"gitlab-jenkins-workflow","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/developer\/2018\/08\/23\/gitlab-jenkins-workflow\/","title":{"rendered":"Git to the Lab!"},"content":{"rendered":"<p><em>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!<\/em><\/p>\r\n      <h3>The Big Picture<\/h3>\r\n      <p>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. <\/p>\r\n      <p>We will not describe in detail what Continuous Integration is and everything it involves. For those interested, we recommend <a href=\"https:\/\/blogs.mathworks.com\/developer\/2015\/01\/20\/the-other-kind-of-continuous-integration\/\">this post<\/a> as an introduction to the topic. This post introduces the concept of interfacing MATLAB with <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a>, a well-known continuous integration server. Feel free to explore this and other CI related posts by looking at the <a href=\"https:\/\/blogs.mathworks.com\/developer\/category\/continuous-integration\/?s_tid=Blog_developer_Category\"><u>Continuous Integration category.<\/u><\/a><\/p>\r\n      <p>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 <a href=\"https:\/\/about.gitlab.com\/\">GitLab<\/a> (a well-known open source git repository manager) and therefore you will need to install the <a href=\"https:\/\/docs.gitlab.com\/ee\/integration\/jenkins.html\">GitLab plugin<\/a> in Jenkins. <\/p>\r\n      <h3>Let's go through the Workflow step by step.<\/h3>\r\n      <p>For purposes of this post, we will assume a simplified continuous integration workflow as follows:<\/p>\r\n      <ol>\r\n         <li>Changes are made to code or a model, staged, and committed to a git repository's testing branch.<\/li>\r\n         <li>Changes are pushed to a git remote's testing branch.<\/li>\r\n         <li>The remote repository notifies (via a web hook) the Jenkins CI server that there has been a new push event.<\/li>\r\n         <li>The Jenkins server pulls the changes from the git repository and runs a test suite.<\/li>\r\n         <li>If a test fails, it creates a bug issue in GitLab, if the test passes, it creates a merge request.<\/li>\r\n      <\/ol>\r\n      <p>Here is a picture illustrating this workflow:<\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/JenkinsGitlabPost_1-1.png\"><\/p>\r\n      <h3>Getting Jenkins Ready<\/h3>\r\n      <p>We have written before in this blog how to go about <a href=\"https:\/\/blogs.mathworks.com\/developer\/2015\/01\/20\/the-other-kind-of-continuous-integration\/\">setting up Jenkins<\/a> to launch MATLAB unit tests. So here we'll focus on configuring it, so every time you push to the <em>testing<\/em> branch, a Jenkins workflow is triggered. <\/p>\r\n      <p> 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 <em>testing<\/em> branch. <\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/JenkinsGitlabPost_2-1.png\"><\/p>\r\n      <p>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. <\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/JenkinsGitlabPost_3-1.png\"><\/p>\r\n      <p>Finally, configure launching MATLAB with <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlablinux.html#buknt9_-3\">no display<\/a>, changing directory to the Project's workspace, and running a script that we'll be writing in the following sections: <\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/JenkinsGitlabPost_4-1.png\"><\/p>\r\n      <p>After that, save your changes. Your freestyle project is ready. Now off to GitLab.<\/p>\r\n      <h3>Getting GitLab ready<\/h3>\r\n      <p>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: <\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/JenkinsGitlabPost_5-1.png\"><\/p>\r\n      <p>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 <em>Test<\/em> button, select Push Events. You should immediately get a blue ribbon at the top indicating that your web hook executed successfully <\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/JenkinsGitlabPost_6-1.png\"><\/p>\r\n      <p>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. <\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/JenkinsGitlabPost_7-1.png\"><\/p>\r\n      <p>After you click the green <em>Create personal access token <\/em> 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. <\/p>\r\n      <h3>Testing Script<\/h3>\r\n      <p>We will use a variation of the script published for <a href=\"https:\/\/blogs.mathworks.com\/simulink\/2017\/05\/25\/simulation-based-testing-with-simulink-test-manager\/\">this Simulink's Blog post<\/a>. <\/p>\r\n      <p><b>Convert it to a function to receive one argument:<\/b> 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. <\/p><pre class=\"language-matlab\"><span class=\"keyword\">function<\/span> runMyTests (ranInCI)\r\n\r\nimport <span class=\"string\">matlab.unittest.TestRunner<\/span>\r\nimport <span class=\"string\">matlab.unittest.plugins.TAPPlugin<\/span>\r\nimport <span class=\"string\">matlab.unittest.plugins.ToFile<\/span>\r\n\r\nworkspace = pwd;\r\n\r\n<span class=\"keyword\">if<\/span> ranInCI == 1\r\n    resultsLocation = fullfile(pwd, <span class=\"string\">'results'<\/span>);\r\n\r\n.\r\n.\r\n.\r\n<\/pre>\r\n      <p><b>Collect Data about the current commit<\/b>: 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). <\/p><pre class=\"language-matlab\"><span class=\"comment\">% Collect data from the current commit to include in the<\/span>\r\n<span class=\"comment\">% body of the issue or merge request.<\/span>\r\n[~, commit] = system(<span class=\"string\">'git rev-parse --short HEAD'<\/span>);\r\n[~, branch] = system(<span class=\"string\">'git rev-parse --abbrev-ref HEAD'<\/span>);\r\n<\/pre>\r\n      <p><b>Do a web GET or POST to GitLab's API:<\/b> 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. <\/p><pre class=\"language-matlab\"><span class=\"keyword\">if<\/span> ranInCI == 1\r\n    copyfile(tapResultsFile, fullfile(resultsLocation, <span class=\"string\">'TAPResults.tap'<\/span>));\r\n    totalFailures = sum(vertcat(results(:).Failed));\r\n    writeOptions = weboptions(<span class=\"string\">'MediaType'<\/span>,<span class=\"string\">'application\/x-www-form-urlencoded'<\/span>,<span class=\"keyword\">...<\/span>\r\n                              <span class=\"string\">'HeaderFields'<\/span>, <span class=\"keyword\">...<\/span>\r\n                              {<span class=\"string\">'PRIVATE-TOKEN'<\/span>, gitPrivateToken});\r\n    <span class=\"keyword\">if<\/span> totalFailures == 0\r\n        <span class=\"comment\">% If no failures, create a merge request<\/span>\r\n        writeMergeURL = [gitLabAPI <span class=\"string\">'projects\/'<\/span> ProjectID <span class=\"string\">'\/merge_requests?'<\/span>];\r\n        webwrite(writeMergeURL, <span class=\"keyword\">...<\/span>\r\n                 <span class=\"string\">'title'<\/span>, <span class=\"keyword\">...<\/span>\r\n                 [<span class=\"string\">'[Jenkins] Test(s) Passed for commit '<\/span> strtrim(commit)], <span class=\"keyword\">...<\/span>\r\n                 <span class=\"string\">'description'<\/span>, <span class=\"keyword\">...<\/span>\r\n                 [<span class=\"string\">'Continous Integration passed on commit '<\/span> strtrim(commit) <span class=\"keyword\">...<\/span>\r\n                     <span class=\"string\">' of branch '<\/span> strtrim(branch) <span class=\"keyword\">...<\/span>\r\n                     <span class=\"string\">'. Merge request ready for review'<\/span>], <span class=\"keyword\">...<\/span>\r\n                 <span class=\"string\">'labels'<\/span>, <span class=\"string\">'merge_request'<\/span>, <span class=\"keyword\">...<\/span>\r\n                 <span class=\"string\">'source_branch'<\/span>, strtrim(branch), <span class=\"keyword\">...<\/span>\r\n                 <span class=\"string\">'target_branch'<\/span>, <span class=\"string\">'master'<\/span>, <span class=\"keyword\">...<\/span>\r\n                 <span class=\"string\">'approvals_before_merge'<\/span>, <span class=\"string\">'3'<\/span>, <span class=\"keyword\">...<\/span>\r\n                  writeOptions);\r\n    <span class=\"keyword\">else<\/span>\r\n        <span class=\"comment\">% Tests failed, create a test failure issue in GitLab<\/span>\r\n        writeIssueURL = [gitLabAPI <span class=\"string\">'projects\/'<\/span> ProjectID <span class=\"string\">'\/issues?'<\/span>];\r\n        webwrite(writeIssueURL, <span class=\"keyword\">...<\/span>\r\n                 <span class=\"string\">'title'<\/span>, <span class=\"keyword\">...<\/span>\r\n                 [<span class=\"string\">'[Jenkins] Test(s) Failing in commit '<\/span> strtrim(commit)], <span class=\"keyword\">...<\/span>\r\n                 <span class=\"string\">'description'<\/span>, <span class=\"keyword\">...<\/span>\r\n                 [<span class=\"string\">'Continous Integration Failed when running on commit '<\/span> <span class=\"keyword\">...<\/span>\r\n                 strtrim(commit) <span class=\"string\">' of branch '<\/span> strtrim(branch) <span class=\"string\">'.'<\/span>], <span class=\"keyword\">...<\/span>\r\n                 <span class=\"string\">'labels'<\/span>, <span class=\"string\">'bug'<\/span>, <span class=\"keyword\">...<\/span>\r\n                  writeOptions);\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span><\/pre>\r\n      <h3>Putting it all Together<\/h3>\r\n      <p>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. <\/p>\r\n\r\n<div class=\"row\"><div class=\"col-xs-12 containing-block\"><div class=\"bc-outer-container add_margin_20\"><videoplayer><div class=\"video-js-container\"><video data-video-id=\"5797720327001\" data-video-category=\"blog\" data-autostart=\"false\" data-account=\"62009828001\" data-omniture-account=\"mathwgbl\" data-player=\"rJ9XCz2Sx\" data-embed=\"default\" id=\"mathworks-brightcove-player\" class=\"video-js\" controls><\/video><script src=\"\/\/players.brightcove.net\/62009828001\/rJ9XCz2Sx_default\/index.min.js\"><\/script><script>if (typeof(playerLoaded) === 'undefined') {var playerLoaded = false;}(function isVideojsDefined() {if (typeof(videojs) !== 'undefined') {videojs(\"mathworks-brightcove-player\").on('loadedmetadata', function() {playerLoaded = true;});} else {setTimeout(isVideojsDefined, 10);}})();<\/script><\/div><\/videoplayer><\/div><\/div><\/div>\r\n\r\n      <p>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! <\/p>","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/developer\/files\/JenkinsGitlabPost_1-1.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>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... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/developer\/2018\/08\/23\/gitlab-jenkins-workflow\/\">read more >><\/a><\/p>","protected":false},"author":90,"featured_media":1823,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[4],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/1837"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/users\/90"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/comments?post=1837"}],"version-history":[{"count":5,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/1837\/revisions"}],"predecessor-version":[{"id":1847,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/1837\/revisions\/1847"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/media\/1823"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/media?parent=1837"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/categories?post=1837"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/tags?post=1837"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}