Intégration Continue (CI) – HoNoSoFt https://blog.honosoft.com Blog & Roll Fri, 11 Jan 2019 12:52:34 +0000 en-CA hourly 1 https://wordpress.org/?v=6.8.11 https://blog.honosoft.com/wp-content/uploads/2018/06/logo.png Intégration Continue (CI) – HoNoSoFt https://blog.honosoft.com 32 32 Canvas Chart ➡️ Snapshot ➡️ Manipulate ➡️ Send it to your confluence page (or elsewhere) https://blog.honosoft.com/2019/01/11/canvas-chart-%e2%9e%a1%ef%b8%8f-snapshot-%e2%9e%a1%ef%b8%8f-manipulate-%e2%9e%a1%ef%b8%8f-send-it-to-your-confluence-page-or-elsewhere/?utm_source=rss&utm_medium=rss&utm_campaign=canvas-chart-%25e2%259e%25a1%25ef%25b8%258f-snapshot-%25e2%259e%25a1%25ef%25b8%258f-manipulate-%25e2%259e%25a1%25ef%25b8%258f-send-it-to-your-confluence-page-or-elsewhere https://blog.honosoft.com/2019/01/11/canvas-chart-%e2%9e%a1%ef%b8%8f-snapshot-%e2%9e%a1%ef%b8%8f-manipulate-%e2%9e%a1%ef%b8%8f-send-it-to-your-confluence-page-or-elsewhere/#respond Fri, 11 Jan 2019 12:39:37 +0000 https://blog.honosoft.com/?p=426 Continue Reading]]> Today, let’s create a connection between one of your app using ChartJs + Confluence and send or synchronize a chart. The flow with Confluence server used will be with the basic authentication. In the case you want to build a real plugin/extension to Confluence, please follow the proper guide about it. In this blog post, the basic authentication is simply a mean to an end for quick prototyping.

A complete example of a standalone project can be found on Github (https://github.com/Nordes/HoNoSoFt.PushChartToConfluence.Sample).

Introduction

Like I said, we will have an application serving some charts using the Canvas (HTML5) technology. We will then resize, take a snapshot and then transmit this file to our backend server. Then it will connect to confluence, look at the existing attachments and if it exists it will update using a comment or in the case where the file does not exists, we will be posting a new file. It is nice to update the file, but why not add the file (image) to the page if it is not already there. 🙂

Proposal using a chart

Note that we’re going to add the chart, but the same flow could be used to also update some comment/text. As long as you are familiar with html syntax, you should be able to do something good.

Pre-requisites before starting

  1. If you already have a confluence server or follow the official installation guide from Confluence, skip to #3 (Create a small application)
  2. For the docker users, let’s go towards the evaluation “just because”
    1. docker pull atlassian/confluence-server:latest
      1. About 700mo
    2. While it download, you can start by requesting a KEY
      1. https://my.atlassian.com/license/evaluation
      2. Select a Confluence server license and keep that page open until the docker image is ready.
    3. Start the docker image
      • Command: docker run -v $volume$:/var/atlassian/application-data/confluence --name="confluence" -d -p 8090:8090 -p 8091:8091 atlassian/confluence-server
        • $volume$: C:/demo/your/confluence/home
      • Open site: http://localhost:8090/
    4. During installation, fetch the Server ID and input it in the evaluation page.
      1. Follow the instructions
        1. Select trial
        2. Get the Server ID
        3. Go on your atlassian page already open and paste it
        4. Generate your key
        5. Copy/paste your key in the form within the confluence page
        6. Click next (wait a little) and voilà
        7. Setup a user or two and then let’s start
  3. Create a small application with ChartJs (or use the one built in the previous post )

Back-End

In the back-end, we will first be receiving the image to at least test our local upload between front-end and back-end. After, we will start integrating the Confluence connexion.

Dotnet ImagesController: Receive Images (Part 1)

Within Dotnet Core, we can receive files or forms controls using the IFormCollection. I don’t think it is common to receive such thing, but when talking about receiving files, this comes handy. The client (JavaScript) will then create a collection and send it using a multipart/form-data. In there we can find many things, however what we will only using here are the files (((IFormCollection)MyFormCollection).Files).

Let’s create a controller named ImagesController we will receive the files as stream and then copy those files to a temporary folders. If you already played around with file streaming you can probably skip this part.

[Route("api/[controller]")]
[ApiController]
public ImagesController : ControllerBase {
    // .. some constructor stuff

    /// <summary>
    /// This will save the image in your local "temp" folder.
    /// </summary>
    [HttpPost]
    [ProducesResponseType((int)HttpStatusCode.Created)]
    public async Task<IActionResult> PostAsync(IFormCollection formCollection)
    {
        var files = formCollection.Files;
        long size = files.Sum(f => f.Length);
        List<string> fileList = new List<string>();

        foreach (var formFile in files)
        {
            // full path to file in temp location
            var filePath = Path.GetTempFileName();
            if (formFile.Length > 0)
            {
                using (var stream = new FileStream(filePath, FileMode.Create))
                {
                    // Save to file... We could remove the await, have a List<Task<..>> and then do a Task.WhenAll(myList)
                    await formFile.CopyToAsync(stream);
                    fileList.Add(filePath);
                }
            }
        }

        // Example of processed uploaded files returning details of the new file + original request.
        // You shouldn't rely on (or) trust the FileName property without validation.
        return Ok(new { count = files.Count, size, fileList });
    }
}

This is named Part 1 since we will come back in that code in order to add some code to send to confluence.

Front-End

Do the snapshot

From JavaScript, we have two methods that are quite handy to take snapshot of a Canvas. The first one is “toBlob(…)” and the second is “toDataUrl(…)“. While “toBlob” is not supported everywhere, I find it more useful for the demo, otherwise feel free to use “toDataUrl” for all browsers supports except Edge and then convert that base64 into a binary data (image/png). In case you go towards the “toDataUrl” method, don’t forget that you will have to transform the data once it’s server side for something readable (binary) as an image/png.

You will see in the next sub-section how to start from a ChartJs chart which you’d like to push to your back-end having a resolution of 1200px wide. Don’t forget that if you use an adaptive screen UX, it will not be displayed as 1200px until you do a snapshot for a fraction of a second.

How does the resizing work?

As you already know, a ChartJs canvas does not resize automatically at your wishes and if you want a snapshot, you are required to hack your way. Next, we are going to have the following flow:

Interesting part in the JS, I will skip the trivial step of generating a chart since you’re I suspect that you’re already able to do so.

// Some code (I used VueJs, but other language should look alike)

snapshot: function () {
  // Resize to desired size, bigger it is, more heavy will be the blob file.
  this.$refs.chartContainer.style.width = '1200px'
  this.chart.resize()
  var ctx = this

  // Do a snapshot
  this.$refs.chart.toBlob(function (blob) {
    // Resize back to original size
    ctx.$refs.chartContainer.style.width = ""
    ctx.chart.resize()

    // Prepare the form post
    // The file name used will be the chart title, but depending on your case, you
    // might want to have something more precise based on parameter (hash, encoding, something). 
    var filename = `${ctx.chartConfig.options.title.text}.png`
    var data = new FormData()
    data.append('file', blob, filename)

    const config = {
        headers: { 'content-type': 'multipart/form-data' }
    }

    // Post the file to your backend
    ctx.$http.post('/api/images', data, config)
    // Later in the article it should become as
    // ctx.$http.post('/api/images/confluence/{desiredPageId}', data, config)
  }, "image/png", 0.95);
}

// Some code

As you can see, I resize to 1200px => snapshot (toBlob) => resize back to original => send the file as multipart/form-data to the api.

The file should normally be created within your temp folder and the exact location will come back through the API. It is also part of the current data contract. Now that you have that, you can consider yourself ready for the next step, which is to transfer that buffered binary data directly to confluence using their API’s.

Back-end Part 2 – Use confluence API’s

Now that we know we can receive file and save it, we now simply need to use the Confluence API’s from Atlassian. The related documentation for that is:

API’s that we’re going to use for this demo are:

  • [GET] api/content/{pageId}/child/attachment?filename={formFile.FileName}&expand=version
    • Search/Retrieve the existing attachment. In case it does not exists, it will sends back an empty array.
  • [POST] api/content/{pageId}/child/attachment/{attachmentData.Id}/data
    • Update in case of existing attachment
  • [POST] api/content/{pageId}/child/attachment
    • Create the attachment resource if it was not already existing
  • [GET] api/content/{pageId}?expand=version,body.storage
    • Retrieve the details on the current page, especially the body specified in readable/editable way (storage). The version is also mandatory when you want to update the page.
  • [PUT] api/content/{pageId}
    • Api used in order to update the confluence page.

Update the ImagesController to forward to Confluence

There’s maybe more code than required in the controller. The proper approach would be to use a IDataProvider injected (for UT) and then implement the provider using the IHttpClientFactory. That way, all would be testable and also it would also put the logic where it should be. However, let’s put all for now in one place and please adapt for your needs.

// some code in the controller

        /// <summary>
        /// Receive 1 or more images to be sent to Confluence server.
        /// </summary>
        /// <param name="formCollection">The form data (only files are being consumed)</param>
        /// <param name="pageId">The confluence page Id</param>
        /// <remarks>
        /// More details can be found at https://developer.atlassian.com/server/confluence/confluence-rest-api-examples/
        /// </remarks>
        [HttpPost("confluence/{pageId}")]
        [ProducesResponseType((int)HttpStatusCode.Created)]
        public async Task<IActionResult> PostToConfluence(IFormCollection formCollection, int pageId)
        {
            var files = formCollection.Files;
            long size = files.Sum(f => f.Length);
            List<string> fileList = new List<string>();
            var forwardAttachmentTasks = new List<Task<FileTransferResult>>();

            foreach (var formFile in files)
            {
                if (formFile.Length > 0)
                {
                    forwardAttachmentTasks.Add(ForwardFileToConfluence(pageId, formFile));
                }
            }

            // In case we had multiple tasks at the same time.
            await Task.WhenAll(forwardAttachmentTasks.ToArray()).ConfigureAwait(false);
            await UpdatePage(pageId, forwardAttachmentTasks).ConfigureAwait(false);

            return StatusCode((int)HttpStatusCode.InternalServerError, new { count = files.Count, size, fileList });
        }

        private async Task UpdatePage(int pageId, List<Task<FileTransferResult>> forwardTasks)
        {
            if (forwardTasks.Any())
            {
                // Update the page
                var pageContentResult = await _confluenceHttpClient.GetAsync($"content/{pageId}?expand=version,body.storage");
                var pageContentData = JsonConvert.DeserializeObject<Models.Confluence.Content.ContentStorage>(await pageContentResult.Content.ReadAsStringAsync());

                string newContent = string.Empty;
                foreach (var sentAttachmentTask in forwardTasks)
                {
                    var sentAttachment = await sentAttachmentTask;
                    if (sentAttachment != null && sentAttachment.Results.Any())
                    {
                        // Add the file if not present on the page.
                        var fileName = sentAttachment.Results.First().Title;
                        if (pageContentData.Body.Storage.Value.IndexOf($"<ri:attachment ri:filename=\"{fileName}\" />") == -1)
                        {
                            newContent += $"<h2>You've just pushed: {fileName}</h2><p><ac:image><ri:attachment ri:filename=\"{fileName}\" /></ac:image></p>";
                        }
                        // Else: Nothing to do, it's already on the page somewhere.
                    }
                }

                // Update object (camelCase mandatory, so use a proper serializer in real life scenario)
                var updateQuery = new
                {
                    id = pageContentData.Id,
                    title = pageContentData.Title,
                    status = pageContentData.Status,
                    type = pageContentData.Type,
                    version = new { number = pageContentData.Version.Number + 1 },
                    body = new
                    {
                        storage = new
                        {
                            value = pageContentData.Body.Storage.Value + newContent,
                            representation = "storage"
                        }
                    }
                };

                var result = await _confluenceHttpClient.PutAsJsonAsync($"content/{pageId}", updateQuery);
            }
        }

        private async Task<FileTransferResult> ForwardFileToConfluence(int pageId, IFormFile formFile)
        {
            // Start getting if attachment exists
            var getIfAttachmentExists = _confluenceHttpClient.GetAsync($"content/{pageId}/child/attachment?filename={formFile.FileName}&expand=version").ConfigureAwait(false);
            // While previous request goes on, let's get the file.
            byte[] data;
            using (var br = new BinaryReader(formFile.OpenReadStream()))
            {
                data = br.ReadBytes((int)formFile.OpenReadStream().Length);
            }

            ByteArrayContent bytes = new ByteArrayContent(data);
            MultipartFormDataContent multipartContent = new MultipartFormDataContent();
            multipartContent.Add(bytes, "file", formFile.FileName);

            var attachmentRequestData = await getIfAttachmentExists;
            if (attachmentRequestData.IsSuccessStatusCode && attachmentRequestData.StatusCode == HttpStatusCode.OK)
            {
                // Page exists and no errors...
                var attachmentRequestContent = await attachmentRequestData.Content.ReadAsStringAsync().ConfigureAwait(false);
                var attachmentData = JsonConvert.DeserializeObject<FileSearch>(attachmentRequestContent);

                HttpResponseMessage putAttachmentResponse;
                // Update existing data.
                if (attachmentData.Size == 1)
                {
                    multipartContent.Add(new StringContent($"Automatic update/upload from TestApplication ;)."), "comment");
                    putAttachmentResponse = await _confluenceHttpClient.PostAsync(
                        $"content/{pageId}/child/attachment/{attachmentData.Results.First().Id}/data",
                        multipartContent);

                    // Result is 1 "item"
                    var content = await putAttachmentResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
                    var result = JsonConvert.DeserializeObject<Models.Confluence.Result>(content);

                    return new FileTransferResult() { Results = new Models.Confluence.Result[] { result }, Size = 1 };
                }
                else
                {
                    // Create the attachment
                    multipartContent.Add(new StringContent($"Automatic upload from TestApplication ;)."), "comment");
                    putAttachmentResponse = await _confluenceHttpClient.PostAsync(
                        $"content/{pageId}/child/attachment",
                        multipartContent);

                    // Result is a list of item.
                    var content = await putAttachmentResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
                    return JsonConvert.DeserializeObject<FileTransferResult>(content);
                }
            }

            return default(FileTransferResult);
        }

// some code in the controller

It’s a lot of code. By reading it, it should be really easy to understand. During the file upload to Atlassian Confluence, we add a comment (updated or created) and the version gets updated. That way you could show the changes over time.

What else you could do?

  • Transform the backend in order to have a provider injected
  • Create UT
  • Create IT
  • Change the token used in order to use the official Atlassian flow for plugins
  • Automate everything back-end by creating a scheduled job (not tested, but should be feasible)
    1. Selenium
    2. Image docker + chromium
    3. Execute the javascript using chrome Webdriver
    4. Send the image using a job.
  • Send a SnapShot (not necessarily from Charts) while building your backend app in a pipeline.

Conclusion

Thank you for reading and I hope you have learned something today, or at least enjoyed this article.

]]>
https://blog.honosoft.com/2019/01/11/canvas-chart-%e2%9e%a1%ef%b8%8f-snapshot-%e2%9e%a1%ef%b8%8f-manipulate-%e2%9e%a1%ef%b8%8f-send-it-to-your-confluence-page-or-elsewhere/feed/ 0
Tutorial: Bamboo ➕ NDepend => How to integrate them together https://blog.honosoft.com/2018/11/13/tutorial-bamboo-%e2%9e%95-ndepend-how-to-integrate-them-together/?utm_source=rss&utm_medium=rss&utm_campaign=tutorial-bamboo-%25e2%259e%2595-ndepend-how-to-integrate-them-together https://blog.honosoft.com/2018/11/13/tutorial-bamboo-%e2%9e%95-ndepend-how-to-integrate-them-together/#respond Tue, 13 Nov 2018 12:44:26 +0000 https://blog.honosoft.com/?p=348 Continue Reading]]> This tutorial is intended to help you to integrate NDepend within your current builds or your new builds. In cases you missed it, NDepend is a tool in order to validate your dependencies within your project. You can look at the previous post on HoNoSoFt (French). The topic of this tutorial will be discussing about are the following:

What is Bamboo?

Quickly speaking, Bamboo is the Build server from Atlassian in it’s CI stack. It is often used with the integration of BitBucket and it also offer the possibilities to connect to any other repositories (GitHub included). Bamboo itself allow you to create build project, deployment strategy, interconnection with other Atlassian tools or even send automatically a message with the build status to your #Slack channels. If you already played with Jenkins, AppVeyor or GitLab, you should be already familiar with the daily usage of such a tool. In order to get more details on Bamboo, please follow this link, it will give a full details on Bamboo.

Pre-Requisites

  • Bamboo Server (or Agent) in Windows. In case you need to install a new instance, click here to download Bamboo.
    • It is mandatory to use or install the JDK 1.8 (Or JRE also seems to works) in a folder without any spaces. Any version greater than 8 won’t be working. This is supposed to become supported in the future.
    • If you run a test server locally in order to look how it works, it will be accessible on http://localhost:8085/
    • During the first time wizard a key will be required for activation (30 days or real license). To obtain a 30 days license, go into your Atlassian space or simply use this link in order to request the evaluation license for your account
  • NDepend Build license or Trial active on the build machine (or your current machine, if you run Bamboo locally)
  • PowerShell is not mandatory, but you will see later that it is a must in case you want to have a proper build without failure

Bamboo – Add NDepend Capability

What is a capability in Bamboo

In Bamboo, in order to be able to use any build related tools, you should normally set it for each agent in order to add a specific capabilities. In this case, we will be adding the NDepend capability to a Windows agent. That capability will be pointing to the NDepend.Console.exe coming from the NDepend package previously installed/downloaded. Don’t forget to launch it at least once in order to trigger the license. The details are available in the documentation. In my case, it is installed into [D:\Ndepend\NDepend_2018.2.1.9119]. I prefer to keep the version within the folder name. This is easy to know if my agent is using the proper version of the tool. This capability, if I change the executable folder will affect automatically all the build that was using this capability. It will not, in any cases, re-trigger an automatic build. The variable will then be re-applied starting from the next build.

It is common to keep those capabilities or executable in that screen. It regroup all your agent(s) features. More details on this feature can be found on the Atlassian website.

⚠Be aware: The capabilities displays dependencies with existing builds. That being said, if a capability variable is used within a script, you won’t see anywhere that as an active dependency. For that reason, you are required, in case of multiple agents, to specify manually what Agent should be used for your build stage.

Go to your agent configuration

  1. Click on the cog (options wheel);
  2. Select Agents;
  3. This will make you jump in the administration panel directly on the Agents build resources;
  4. Select your any of your Windows build Agent by simply clicking it.

Agent summary

  1. Validate that your agent name is valid;
  2. Go within the Capabilities tab;
  3. Click on the Add capability link button.

Adding the capability

  1. Capability type: Executable
  2. Type: Command
  3. Executable label: NDepend
  4. Path: [D:\Ndepend\NDepend_2018.2.1.9119\NDepend.Console.exe]

See the Agent specific capabilities

As you can see, after doing the previous steps, you will have your Agent specific capability added. Now, we can use that capability during our build.

Bamboo Build configuration – Capabilities (Easy)

Let’s consider you have your build already existing and that you want to add the NDepend console command. In the current tutorial bellow I will be taking a simple Dotnet Core 2.1 solution. The build will be named IdentityServer4.LdapExtension (GitHub project), where you would have your Git repository, NDepend project and your basic build already configured (checkout and build).

Add a new task to your build stage

  1. Ensure you are in the configuration of your project;
  2. Go to your build job where you usually run your tests and everything else;
  3. Within the tasks, you will find all the detail of your current job;
  4. Add a new task.

Once the popup show,

  1. Search for Command in the search box;
  2. Select Command by clicking it.

Let’s configure the command

  1. The new command task should be already displayed;
  2. The description of the task, in this case: NDepend;
  3. Select the executable you created for your agent capability: NDepend;
  4. Enter the argument to the full path of your NDPROJ  and override the indirs/outdirs parameters, see the Jenkins article for more details. Those path can be relative if you configured your project accordingly, otherwise it will be the full path. In case you don’t set those path properly, NDepend is not able to find your PDB’s files and consequently, do a proper analysis.
    • Example: ${bamboo.build.working.directory}/IdentityServer.LdapExtension.ndproj . You can add a “/silent” is if you don’t want to see all the output logs from NDepend, but I strongly not advise to do this within a build simply because you might need to debug using the logs one day. The indirs/outdirs are omitted considering you have pre-configured your project with relative path instead of the default full path.
  5. Save your configuration

Build your new configuration

I recommend to always build after doing modification. That way it’s easy to see if you caused the build to fail for a real reason (configuration) or if it’s due to code change (triggered builds).

In the case of NDepend, it’s execution returns an exit code. Be aware, the exit code will make your build fails if there’s any quality gate errors. You can read the following when executing the console application:

Notice that NDepend.Console.exe returns a non-zero exit code when at least one Quality Gate fails. This exit code can be used to eventually stop your build process in such situation.

Ref.: https://www.ndepend.com/docs/ndepend-console

The report, even on failure, will exists, however the build will be red and your artifact will probably not be even available. Since there’s no “/ErrorLevel” custom configuration for the exit code, then you will have to do differently in order to ignore those errors.

  • Option 1: Ignore the errors by adding the special tags from NDepend within your code.
    • In that case, simply add the NDepend ignore attributes where required and re-launch a build after your commit.
  • Option 2: Use a script instead of a command in order to control your flow completely and to continue even if there’s a quality gate issue
    • This is the topic of the next section

Bamboo Build configuration – PowerShell Script (Complex)

As stated previously, this is more for those who already have a project having no big issue which cause a quality gate to fail, or if you want to have the Quality Gate failed but still want to generate the reports.

Don’t get me wrong, the Capability created was not for nothing, however, the only drawback in this case is that the Capability will not be detecting our build dependency to NDepend.

In this case, instead of creating a command, we will be creating a script (or add to current Dotnet Core build script)

  1. Go in your Build configuration, default stage (or specific one) and click on Add task;
  2. Select the Script type;
  3. Enter the description and select Windows PowerShell as the Interpreter;
  4. In this case, we will be using the Inline type instead of a PS1 shell script. This option will create automatically a shell script behind the scene. After, simply re-write the code-snippet bellow the image.

The PowerShell is using the existing NDproj (XML file) and then replace the InDirs by the current build path in the command line. This is for your NDproj file that you wouldn’t have any relative path. Once this is completed, it will create the final command and execute it (Invoke-Expression). Here’s the PowerShell script used in the above picture.

# NDProj should normally be a variable in the build, the same goes for other parts. That way
# you can use a build script instead of inline, and that build script can be part of your build
# repository.
$ndproj = "IdentityServer.LdapExtension.ndproj"

# Load the NDepend XML project file.
$ndependXml = [xml](Get-Content .\${ndproj})

# If you have any spaces withn your project, you might encounter issue
# be aware of that. Here the string is a "vanilla" path.
$inDirs = (( `
    $ndependXml.SelectNodes("//Dir") |
    where {$_."#Text" -like "*IdentityServer4.LdapExtension*"} | 
    select -ExpandProperty "#Text" )`
    -replace '^.*(\\IdentityServer4\.LdapExtension\\)',"${bamboo.build.working.directory}\")`
    -join " "

## Launch NDepend command
$expr = "${bamboo.capability.system.builder.command.NDepend} " +`
   "${bamboo.build.working.directory}\${ndproj} " +`
   "/InDirs ${inDirs} " +`
   "/OutDir ${bamboo.build.working.directory}\NDependOut"

Invoke-Expression $expr

# Simple output for the execution result.
write-host "The exit code was: ${LASTEXITCODE}"

Generate the NDepend Artifact

Now, you should be able to build and have the NDepend output folder. In this demo, we have NDependOut as the folder. Todo so, we will have to add the artifact configuration. Please, go back in the Build configuration and your default stage where you have the NDepend script. Once this is complete, select the Artifacts tab and click on Create artifact button.

The fields to input are:

  • Name: NDepend
  • Location: NDependOut
  • Copy pattern: **/*

Once this is completed, you should be able to re-build your project and see if your build artifact is there. Note that if you want to have comparisons between your builds, you could re-use the shared artifact. This is a bit more complex, but it’s possible and it won’t be explored in this tutorial. Let’s say that you could simply avoid cleaning up the build folder every new build. I don’t suggest to do that, but it’s something that could work out.

For example, we have the following successful build:

  1. Green build = success
  2. Go in your artifacts of your build
  3. Click on the artifact name that interest you (NDepend in this case)

Once the artifact will open, it will show the content of the ZIP file. Simply click on the file NDependReport.html. This will then open a link that looks like: http://localhost:8085/artifact/I4E-ID/shared/build-19/NDepend/NDependReport.html#Main

Your page should look similar to this (It depends actually on your project):

Conclusion

Thank you for reading, and I hope it helped you configure your build! If you wish to also integrate with SonarQube, you also can. You simply have to do what is proposed in SonarQube integration with NDepend article and in your Bamboo script, where you build your Dotnet project, you add the NDepend Sonar Runner. The result can then be seen after your build directly within SonarQube. Don’t forget that you might want to install some Marketplace plugin in Bamboo for Sonar in order to send the data. In case you don’t want to use a plugin, don’t worry, it is also possible.

]]>
https://blog.honosoft.com/2018/11/13/tutorial-bamboo-%e2%9e%95-ndepend-how-to-integrate-them-together/feed/ 0
NDepend, SonarQube ou pourquoi pas les intégrer ensemble 😉 https://blog.honosoft.com/2018/11/05/ndepend-sonarqube-ou-pourquoi-pas-les-integrer-ensemble-%f0%9f%98%89/?utm_source=rss&utm_medium=rss&utm_campaign=ndepend-sonarqube-ou-pourquoi-pas-les-integrer-ensemble-%25f0%259f%2598%2589 https://blog.honosoft.com/2018/11/05/ndepend-sonarqube-ou-pourquoi-pas-les-integrer-ensemble-%f0%9f%98%89/#comments Mon, 05 Nov 2018 15:29:14 +0000 https://blog.honosoft.com/?p=298 Continue Reading]]> Préface

J’utilises depuis plusieurs années SonarQube (Ou sinon sur le ☁ nuage que sont les SaaS de ce monde, SonarCloud☁) afin d’avoir une idée générale de la qualité ou de la mise en application des lignes directives des développeurs (guidelines). Comme vous vous en doutez, d’autres produits peuvent soit le remplacer ou même y ajouter une “plus value” (R# par exemple). Dans cet article, nous allons traiter de NDepend et de son intégration avec d’autres produits.

Notez que j’ai eu à utiliser ce produit par le passé et j’avais vraiment eu une bonne expérience. Mais qu’en est-il aujourd’hui, plusieurs années on passés et de l’eau à coulé sous les ponts. Depuis quelques années, il est rare que j’aie un besoin essentiel de pousser ce type de produit dans l’entreprise dans laquelle je travaille ou lorsque je faisais de la consultation.

Si votre entreprise est en manque de qualité, où que vous manquez de visibilité sur ce qui se passe du côté des développeurs, ce produit s’adresse vraiment à vous. Cependant, il y a quelques limitations que nous verrons plus loin.

D’ailleurs, ici j’essaierai de rester impartial tout en donnant mon opinion personnelle. C’est article est en partie possible grâce à NDepend, qui m’offre les licences afin de tester la nouvelle version du produit.

Qu’est-ce que NDepend?

Ce que vous permet de faire NDepend est indiqué sur la page https://www.ndepend.com/features/. Voici tout de même un court résumé:

  • Permet de connaître l’état de santé de votre application
  • Permet d’avoir une idée de la qualité de votre code entre les builds
  • L’estimation de dette technique en temps réel (même lorsque vous codez sans faire vos commit/push)
  • Visibilité de la complexité de votre programme à l’aide de graphique interactif et permet ainsi d’éviter de la confusion entre développeur et architecte.
  • Effectuer des requêtes sur votre code, un peu à la manière SQL (CQLinq)
  • Meilleur visibilité des dépendances

Quelles sont les technologies accessibles à NDepend?

Malgré que vous n’avez pas posé la question, il est important de le savoir de facto avant de continuer à lire l’article. C’est d’ailleurs une question légitime que tout décideurs d’entreprise doivent se poser.

De nos jour, il est de plus en plus rare de rencontrer des équipes de développement qui travaillent avec une seule technologie. Où je travaille en ce moment, nous avons listé aujourd’hui les technologies utilisées par une équipe SCRUM afin de créer une grille de compétences. Un autre architecte et moi même avons listés environs 30 connaissances de bases nécessaires si nous voulons des développeurs versatiles sur toutes les parties de l’application couverte par l’équipe. Dans ce cas précis, ce n’est pas vraiment une application, mais environ 8 applications à maintenir et à développer et pas tous en même temps.

Si on va vers quelque chose de plus concret, dans mon cas, je suis spécialiste des technologies Microsoft. Cependant, je travaille avec énormément d’autres langages, et ce, quotidiennement. Ces autres connaissances sont soient pour faire de la validation de code, faire des preuves de concepts (PoC), du développement, du soutient ou encore effectuer des analyses pour les équipes de développement. (Oui je fais un peu de tout, je suis tombé là dedans quand j’étais petit 😉 ) D’ailleurs, en ce moment, je dois travailler sur l’acquisition d’une certification TOGAF en tant qu’architecte d’entreprise. Si on nomme les langages dont je dois valider ou du moins comprendre quotidiennement sont par exemple: C#, Java, Python, JavaScript (NodeJs), TypeScript (Node), etc. Malgré le fait que je ne suis pas expert dans tous ces langages, je n’ai aucune difficulté à lire ou à comprendre le code des autres. Il y a quelques années j’avais vu un plugin fait en Ruby et je trouvais qu’il n’en faisait pas assez, du coup j’avais fait un refactor complet et les gens de la communauté avait apprécié le changement, malgré que la stabilité n’était pas à 100% (ça y était presque, seulement des problèmes de concurrence lors de grandes charges sur les serveurs).

Tout ceci est pour en venir au fait suivant: Les erreurs rencontrées dans un langage sont souvent les mêmes que dans les autres.

Pour en revenir au titre de la section, répondons à la question plus simplement:

  • C# (Quasi toutes les versions, dont, dotnet core 1.0, 1.1, 2.1 et 2.2 preview!)
  • VbNet
Notez que ça peut s’intégrer au produit de JetBrains – TeamCity dont je n’ai jamais eu la chance de tester.

Personnellement, j’adore travailler avec C# (TCP, UDP, etc.) et encore plus depuis l’arrivée de Dotnet Core 2+. Lorsque vous avez à travailler sous TCP/UDP (incluant le web), vous devez avoir les bons outils afin d’éviter d’introduire quoi que ce soit en dettes technique. Plus on attend pour les fixer, plus on le regrette du fait que ça devient quasi impossible à corriger. Du coup, un produit comme NDepend peut venir à la rescousse. Sa version développeur s’intègre comme étant un plugin dans Visual Studio et sa license serveur peut s’intégrer sur votre serveur de build (voir plus bas).

NDepend – Les builds automatisés

Lorsque mes builds automatisés sont sur des projets public, j’utilises presque toujours AppVeyor en mode gratuit avec une connexion à mes repos GitHub ou BitBucket. Cet outil vous offre une intégration de premier plan en autant que vous sachiez ce que vous faites. Les images utilisées sont compatible Windows, donc vous pouvez compiler vos projets sans problème. En ce moment, où je travaille, j’utilise soit Bamboo ou GitLab (intégration simple et continue). Par le passé, en mode privé, j’utilisais Jenkins, TFS, ainsi que d’autres outils. Dernièrement, j’ai installé un serveur privé GitLab afin de faire des projets R&D dans mon département. Ça permet de partager simplement notre code en interne et permet aux autres de pouvoir faire comme sur github et participer dans vos projets. Je dirais qu’aujourd’hui, ça correspond à la plupart des besoins professionnels pour petites ou grandes entreprises. Je préfère l’intégration avec AD ainsi que le tout inclus dans une seule application (Wiki, Build, Source, …). C’est d’ailleurs très simple d’utilisation avec les images dockers lors de builds en parallèles. Tout ça pour dire qu’à un certain point, tout ces outils ne sont qu’une question de goût. En ce qui concerne le Cloud, vous pouvez utiliser AppVeyor ou d’autres services Azure qui s’apparente au service TFS, GitLab online, Travis, etc..

En ce qui concerne la version NDepend, il peut s’utiliser officiellement avec TeamCity (JetBrains), Jenkins (ou anciennement Hudson), AppVeyor, Team Foundation Server (TFS), Azure DevOps (ex VSTS) ainsi que quelques autres. Aucune mention sur Bamboo est disponible sur le site, mais étant donné que l’agent Bamboo peut s’exécuter sous Windows, je ne vois aucuns soucis à l’horizon. Important: N’oubliez pas que vous devrez avoir une licence serveur pour exécuter des Builds sur cette machine (Actuellement la license est détaillée au prix de 799€).

Étant donné qu’AppVeyor est déjà traité dans un autre article de ce site, j’irai vers cette solution. Sinon, Jenkins ou encore Bamboo seront de tout aussi excellents choix. Pour tester le produit en local, je vous dirais de tout simplement prendre une image Docker pour SonarQube et de même que pour le serveur principal Jenkins. Ensuite, vous pouvez configurer votre agent Windows sur votre machine même et de le configurer sous Jenkins. Concernant Bamboo, je n’ai jamais eu la chance de créer un agent, mais si c’est aussi simple que Jenkins, ça ne doit pas être très loin d’un clic. L’idée derrière la virtualisation sous docker, c’est que vous pouvez éviter de polluer trop votre environnement afin de tout tester.

De nos jours, je dirais qu’il est de plus en plus courant de rencontrer des environnements professionnels avec la stack Atlassian (Confluence, Bamboo, Jira, BitBucket/Stash). Tel qu’indiqué plus tôt, le site NDepend ne traite aucunement de plugin pour Bamboo. Je vous dirais dans ce cas de configurer comme si c’était pour votre PC, sauf que vous ajoutez une capacité à votre agent de build qui pointe sur le fichier EXE de NDepend. D’ailleurs, ceci pourrait être sans doute le sujet d’un autre billet/blog (soit ici ou bien pourquoi pas sur le site de NDepend).

Dans la prochaine section, nous allons traiter l’intégration sous AppVeyor. Note à part, si ce n’est pas déjà dit plus tôt, il est impératif d’avoir un agent Windows afin d’exécuter l’analyse et ainsi générer un “Site web” ou le build pour SonarQube. Le site web peut ensuite être mis à la disposition de votre équipe par le billet d’une automatisation (artifact + déploiement sur votre serveur IIS, Apache ou autre car c’est un site en HTML pure).

Prise en main des outils [a-Z] ou du moins le minimum

Achat, ou essaie

Avant d’acheter ce type de produit, il est toujours conseillé de tester et dans le cas de soucis ou incompréhension, communiquer directement avec le support. Ceci vous permettra de mieux comprendre le produit et ses possibilités dans votre entreprise. Afin de tester, vous n’aurez qu’à remplir un formulaire (14 jours d’essaie gratuit). Dans la plupart des cas, pour simplement tester, n’utilisez pas une licence officiel serveur pour faire que 2 Builds ;).

Téléchargement

Une fois la licence acheté ou le formulaire de 14 jours d’essaie rempli, vous devrez recevoir par e-mail un lien pour télécharger le produit (https://www.ndepend.com/download).

NDepend

Contenu du téléchargement

Vous venez de télécharger NDepend (~16 MO) et vous vous rendrez compte que l’archive est plutôt simple. Car, oui, ce sera une archive et non un exécutable “self-executable”/”extractable” qui feras l’installation dans un répertoire pour vous. Vous aurez besoin de Unzip l’archive avec soit 7Zip ou l’outil qui vient avec Windows.

Voici le contenu de l’archive:

NDepend – Contenu du Zip

Si vous avez besoin de plus d’information, c’est disponible sur le site officiel ainsi que partiellement dans le fichier README.txt. Si vous n’avez pas trop de temps, voici ici ceux qui vous intéresseront le plus. Dans le cas où la lecture ne vous intéresse pas vraiment, allez visionner la vidéo.

  • NDepend.VisualStudioExtension.Installer.exe
    • L’extension Visual Studio (pour les développeurs 🎉)
  • NDepend.Console.exe (Plus de détails ici en anglais)
    • Ce qui vous servira lors des builds.
  • VisualNDepend.exe
    • Permet de visualiser le tout sans s’intégrer dans Visual Studio. Dans ce cas, vous devrez avoir la clé de la licence sous la main, car ce sera demandé dès l’ouverture du produit.
    • Exemple une fois ouvert
  • Integration/…
    • Contiens les extensions pour SonarQube, TFS, TeamCity, XLT -> * (transformation) ainsi qu’un peu de documentation.

Les autres fichiers, oui ils vous intéresseront et ce sera du cas par cas. Ensuite, pour explorer tout le produit, je vous conseille d’ailleurs de prendre la version démo 14 jours. Si vous aimez, vous achetez, sinon, vous arrêtez.

Le projet NDepend.PowerTool.SourceCode (détails ici en anglais) vous montrera comment interagir avec l’API NDepend directement à partir de votre code. Je recommande d’y jeter un coup d’œil, mais plus afin de voir comment ça peut s’intégrer avec vos produits existant. Vous pourrez ensuite prendre ce qui vous intéresse de l’API et l’appliquer.

Votre quotidien vous appartient, n’oubliez pas!

Rapport de Build avec un de mes projets GitHub (VisualNDepend)

Je vais prendre ici un projet sur lequel j’ai créé et touché dernièrement (badgeIt), mais que je doute que beaucoup de gens l’utiliseront. Le projet a été créé dans le cas spécifique où tout est bloqué par soit des proxy ou encore des comptes d’identification à Sonar et où on ne peut pas récupérer les badges de Sonar sans que les utilisateurs soient connectés. Pour plus de détails sur ce projet, veuillez suivre ce lien vers mon autre article (SonarCloud + AppVeyor + etc.).

Donc ici, nous allons utiliser NDepend SANS l’intégration de l’extension Visual Studio 2017. Nous utiliserons que l’outil en ligne de commande (Console windows) ainsi que l’application VisualNDepend afin de nous “kick starter” ça.

  1. Clone du projet Github: > git clone https://github.com/Nordes/HoNoSoFt.BadgeIt.SonarQube.git
  2. S’assurer que tout build/s’exécute normalement: > dotnet run
    • Note: Le projet est en .NetCore 2.1 et NDepend peut analyser jusqu’à 2.2 (preview en ce moment).
  3. Alternativement au point #2, vous pouvez ouvrir la solution sous Visual Studio 2017 et exécuter avec F5.
  4. Ça affichera une jolie page de test, c’est top. Maintenant, c’est le temps d’arrêter l’application et de préparer le tout pour exécuter NDepend.

Prise en main de VisualNDepend

Commençons tout d’abord par l’application VisualNDepend où un aperçu de l’écran de démarrage est visible dans la section précédente. Cet outil s’adresse à un public plutôt expert ou aux architectes de ce monde qui veulent faire des statistiques et un peu plus. C’est parfait pour faire un rapport qui serait visible en live lors d’une présentation à une équipe agile. C’est aussi très utile afin de repérer les points critique d’une application et ainsi savoir où l’on devrait améliorer soit les dépendances ou bien la quantité de tests. Vous pouvez d’ailleurs, dans un premier temps, créer une “baseline” qui vous servira par la suite de référence dans le temps.

Au cas où vous auriez à suivre l’évolution d’un projet et montrer à vos équipes si tout va dans la bonne direction, c’est parfait. Dans mon cas, je l’utilise à la fin de chaque sprint lors de la rétrospective afin de montrer ce que l’on à fait de bien (ou de moins bien). Ce n’est en aucun cas afin de pointer quelqu’un du doigt. Ça permet d’aussi expliquer aux gens où l’ont doit s’assurer d’une certaine qualité et comment la maintenir.

Voir la quantité de code couvert par vos tests (comme à la SonarQube)

Oui, c’est possible. Cependant vos tests devront générer un fichier de résultat. (Je n’ai pas été en profondeur afin de vérifier avec XUnit ce qu’était mon résultat.) Sachez que c’est possible sans trop d’efforts. Il suffit de suivre les guides; soit sur le site de XUnit ou bien sur le site/blog de NDepend.

Si vous avez ces fichiers de résultats, vous pouvez les intégrer dans l’outil VisualNDepend.

Prise en main de NDepend.Console

Sans doute l’outil qui vous sera le plus utile pour des builds automatisés. Vous avez deux choix afin de vous guider. Soit utiliser l’outil de console afin de vous donner de l’aide, ou bien ouvrir votre navigateur web et aller tout simplement sur https://www.ndepend.com/docs/ndepend-console. Lors de l’exécution de l’application, vous noterez que si vous l’utiliser dans vos builds et que s’il y a une “Quality gate” qui ne passe pas, votre build sera marqué en route.

Afin de pouvoir l’utiliser, vous devrez impérativement vous créer un projet NDepend (votre_projet.ndproj ou votre_projet.xml) afin de gérer toutes les options et configurer sans avoir à lire tout le fichier. Je vous conseille d’utiliser tout simplement VisualNDepend. L’écran de la configuration ressemblera alors à:

Sauvegardez votre projet et ses options, ça vous sera utile pour la suite.

  1. Ouvrir votre console (CMD prompt)
    • WIN + R et taper cmd + la touche entrer
  2. Allez dans votre répertoire ou vous avez votre projet “mon_projet.ndproj”, mais ce n’est pas nécessaire, vous comprendrez à la prochaine étape
  3. Entrer la commande suivante ou bien évidemment vous mettrez les répertoires que vous allez avoir utilisés
    • > D:\Ndepend\NDepend_2018.2.1.9119\NDepend.Console.exe d:\Ndepend\Project\CognitiveServices.ndproj
    • Vous noterez les parties en caractère gras qui sont obligatoire. Oui, vous devrez absolument indiquer le chemin complet de votre fichier ndproj (c’est écrit dans la doc, sinon ça ne fonctionnera pas). Par défaut le rapport sera en HTML, veuillez consulter l’aide afin d’obtenir un rapport sous différents formats.
  4. Pour un projet .Net Core 2.1 ça vous donnera quelque chose qui ressemblera plus ou moins à ce qui suit:
    • Sortie d’écran console

  5. Et voilà c’est terminé.

La sortie produira un site web, si l’on veut, qui vous indiquera les informations, ou plutôt, vous permettra de partager les résultats avec vos équipes de travail.

Site HTML NDepend

Je n’ai pas obtenu la note de A, mais ce n’est pas bien grave.

Visualisation du rapport autre format que HTML

Oui, c’est une possibilité, mais malheureusement je ne traiterai pas du sujet ici. Vous pouvez utiliser la technologie XSLT (XSL Transform). Ça fait un bon moment que je n’ai pas eu à utiliser cette techno, mais ça vous permet de générer un rapport comme bon vous semblera. Vous pourriez, par exemple, créer un rapport qu’avec ce qui vous plait sous un format CSV par exemple.

Intégration dans un projet sur GitHub

Pour intégrer dans un projet GitHub, vous aurez besoin d’y ajouter un fichier .ndproj, car ça vous permet d’avoir les règles prédéfinies. Ensuite, l’ajout du scanner “NDepend.Console” peut soit être ajouté dans votre repository. Mais, vous pourriez tout aussi bien mettre le fichier EXE disponible au téléchargement dans l’un de vos dossiers google drive (archive zip par exemple) ou vous auriez un lien pour télécharger uniquement. Puisque que vous n’allez pas exécuter votre build “si souvent”, surtout sur github, je crois que c’est une solution viable.

Dans mon cas, afin de tester, je ne mettrai pas le fichier dans mon répertoire Github. Je vais plutôt le télécharger au moment du build. Le fichier ne fait que 60kb.

Pour ce qui concerne le fichier de licence, ce sera couvert dans la prochaine section.

Intégration dans AppVeyor (Build)

Et voilà nous y sommes. C’est le temps de faire un merveilleux build automatisé. AppVeyor, si vous ne connaissez pas, vous permet de faire des builds pour les applications .Net ou .Net Core ;). Étant donné, que dans la section précédente vous ne vouliez pas mettre votre licence disponible au grand public. Qu’est-ce que vous avez comme autre option?

  1. Faire comme pour le fichier de console et avoir un lien spécial sur Google Doc, OneDrive, Azure storage, etc.
  2. Le fichier console… est-ce assez? je ne crois pas 🙁 … d’après l’article https://www.ndepend.com/docs/appveyor-integration-ndepend on a besoin de plus de truc)

Intégration de SonarQube et AppVeyor (Build/Publication)

C’est quelque chose de tout à fait possible. Ensuite, tout dépend si votre SonarQube est accessible par le web ou seulement en intranet. Dans le cas où vous auriez votre SonarQube sur Azure ou autre, vous pourrez bien évidemment tout configurer afin de laisser AppVeyor envoyer les données vers votre serveur. N’oubliez pas de créer une clée API afin de pouvoir soumettre les rapports.

Petit rappel: La version gratuite de SonarQube ne permet pas de gérer les branches. Ce n’est pas un problème dans notre cas ici, mais dans le cas où vous voudriez avoir un semblant de branche, veuillez seulement faire vos builds avec le nom de branche qui suit le nom de votre projet (projet:nombranche). Ça permet au moins de ne pas avoir trop de pollution. La seule chose, si vous effacez la branche, vous devrez effacer manuellement votre “branche” SonarQube. Dans le cas où vous êtes futé, vous opterez pour un script qui synchronise vos branches existantes avec celles visibles sur SonarQube.

NDepend et SonarQube, ça pourrait vous sembler faire le même boulot, mais au final, non. Ces deux outils sont complémentaires. Pour plus de détails sur les règles NDepend, veuillez suivre ce lien.

Configuration AppVeyor

Pour la configuration AppVeyor, vous pouvez suivre le lien qui suit: https://www.ndepend.com/docs/appveyor-integration-ndepend

Configuration SonarQube

Pour la configuration SonarQube, vous pouvez suivre ce lien: https://www.ndepend.com/docs/sonarqube-integration-ndepend

Configuration des deux outils ensemble si vous n’avez rien sur le cloud ou déployé

Parlons maintenant de la configuration du pauvre ;). Vous voulez tout de même tester AppVeyor avec SonarQube, mais vous n’avez pas d’instance SonarQube où que ce soit. Ce n’est pas le plus facile, mais c’est possible. Pour ce faire vous aurez 2 choix que je considère “simple” en utilisant une image Docker:

Choix #1: Utiliser l’image SonarQube avec votre compte Heroku 😉

Choix #2: Utiliser l’image SonarQube en locale

Attardons-nous sur le choix #2. Il est possible en utilisant simplement NGrok (~5 mo) ou alternativement Localhost.run. Une fois configuré, vous pourrez ensuite tester rapidement sans utiliser AppVeyor afin de voir si votre configuration fonctionne. Ensuite, simplement configurer votre build avec AppVeyor.

Concernant SonarQube, n’oubliez pas qu’il vous faudra ajouter le plugin NDepend, sinon vous n’aurez pas accès à la “plus value” de NDepend. Du coup, ça ressemblera à un semblant de ce qui suit si vous n’êtes pas derrière un proxy qui bloque tout.

Prenons par exemple l’image Alpine 7.1 de SonarQube Docker

> docker pull sonarqube:7.1-alpine
> docker run -d --name sonarqube -p 9000:9000 -p 9092:9092 sonarqube:7.1-alpine

Du coup, vous aurez le port 9000 et 9092 exposé en local. Testez avant de continuer, car le serveur prend un peu de temps a démarrer gracieuseté de Maven ou Java, votre choix. Dans mon cas, ça a pris environs 5 minutes. Le port qui vous intéresse le plus sera le 9000. C’est d’ailleurs celui qui sera exposé avec NGrok. Et concernant ce dernier, n’oubliez pas de récupérer votre Token sur https://dashboard.ngrok.com/auth ;).

  • Une fois SonarQube accessible, veuillez vous connecter en utilisant le compte admin créé par défaut (admin/admin).
  • Créez un token (donnez un nom, du genre AppVeyor) et continuez
  • Choisissez le langage C#/Vb.Net (évidemment)
  • Inscrivez comme clef de projet: MyProject
  • Vous aurez ensuite une commande généré qui ressemblera à:
    • Avant le build: SonarQube.Scanner.MSBuild.exe begin /k:"MyProject" /d:sonar.host.url="http://localhost:9000" /d:sonar.login="686d032bda5d6d5fa204ba5ca21d691179c3e502"
    • Le build en soit: MsBuild.exe /t:Rebuild
    • Une fois le build terminé: SonarQube.Scanner.MSBuild.exe end /d:sonar.login="686d032bda5d6d5fa204ba5ca21d691179c3e502"
  • Vous pouvez exercer la commande en local, pour simple test, mais ce n’est pas nécessaire.
  • Normalement ici, je vous aurais simplement dit d’aller dans l’Administration, la Marketplace et pour terminer chercher le plugin NDepend, mais ce ne sera pas le cas. Le plugin ne fait pas partie de la Marketplace.
    • Du coup, si vous avez ouvert le tutoriel SonarQube sur NDepend, vous aurez vu qu’il faudra installer le plugin manuellement. Le plugin sera disponible à partir du dossier “Integration\SonarQube” de l’archive téléchargée. (sonar-ndepend-plugin-1.1.jar)
      • Note que vous avez accès au bash en effectuant > docker exec -it 70e3d40ba8ea /bin/bash où 70… signifie votre id de conteneur.
    • Copier le fichier plugin NDepend (dans mon cas, windows > Docker) > docker cp d:\Ndepend\NDepend_2018.2.1.9119\Integration\SonarQube\sonar-ndepend-plugin-1.1.jar sonarqube:/opt/sonarqube/extensions/plugins
      • Changez les permissions (sonarqube/sonarqube) du fichier et redémarrer le serveur
    • Vous devriez désormais avoir la section NDepend dans votre SonarQube 
    • On va aller en mode “par défaut”, mais sinon vous pourriez configurer le tout tel qu’indiqué sur le tutoriel. À priori, ce n’est pas nécessaire si vous effectuez votre build proprement avec votre propre fichier ndproj (projet NDepend). N’oubliez simplement pas d’activer les règles (Rules=>C# Language=>NDepend repository => Sélectionnez et configurez)

Maintenant que ça roule, il est désormais le temps de passer aux choses sérieuses. Le configuration NGrok avant le test ultime de Build + Ngrok + SonarQube

> ngrok authtoken 4wUZ8A.................
> ngrok http 9000

ngrok http 9000

C’est bon, votre NGrok est utilisable! L’identité de la redirection n’est pas permanente, donc, ça ne me dérange pas trop de vous montrer les données finales.

Exemple Ngrok + SonarQube

En espérant que vous n’êtes pas trop perdu. Maintenant vous pourrez ajouter à votre build AppVeyor les indications du tutoriel AppVeyor. Excepté que lors de l’exécution du build, vous n’allez pas exécuter la commande NDepend.Console.exe, mais celle du fichier exécutable NDepend.SonarQube.RuleRunner.exe qui se retrouvait là ou vous aviez votre plugin SonarQube. Notez qu’ici vous pouvez aussi garder NDepend.Console.Exe et générer un Artifact, mais cette partie est déjà couverte sous le tuto ;).

Comme SonarQube vous le disait à l’ouverture, vous devrez configurer le pré-build, le build ainsi que le post-build. À partir de ce moment là, vous n’avez qu’à intégrer vos commandes tels qu’indiqués dans le tutoriel SonarQube.

Ajout de l’extension Visual Studio et appréciation

Ce sera l’option la plus simple, et sans doute la plus utilisé par un développeur. Cette option n’est pas toujours possible pour tous les développeurs à cause du coût. Mais ceci-dit,  voici les parties intéressantes de l’extension (Information du site web ou sur le site Microsoft):

  • Dire au développeur avant même de faire ses commit la quantité de dette technique ajoutée
  • Affichage facile des dépendances en utilisant des graph
  • Possibilité de faire des requêtes en live sur le code (CQLinq) pour les passionné de Linq tout particulièrement sur de gros projets
  • Intégration avec VSTS (Team Service)
  • Affichage des trends LoC et bugs en autres
  • Différent affichage lors de différence entre versions (History diff) ou des dettes, etc.

Les promesses:

  • Réduire la dette technique ainsi qu’augmenter les compétences des dévs
  • Rendre le code plus simple à maintenir
  • Analyse des impacts plus simple pour les architectes
  • Plus facile de connaître les coûts lors des demandes de changement (Car les dépendances sont bien visible et clair dans les graphs)

Information importante: Le site de Microsoft n’a pas la dernière mise à jour, mais vous aurez l’extension dans votre archive.

En tant qu’architecte, est-ce que je considère cela utile?

Oui, tout à fait. J’ai souvent à faire du “Reverse Engineering” et cet outil m’aurait sauvé bien des heures à essayer de comprendre comment l’application interagit. Dans un premier temps vous pouvez vous demander pourquoi j’ai eu à faire ça. Je dirais que les applications bien documentés ça va et elle sont rare, cependant, lorsqu’elles ne le sont pas ou du moins personne ne sait vraiment dû à taux de roulement élevé ou lors de développements externes, vous verrez rapidement les bénéfices d’un tel outil. Souvent, on est emmené à sauter dans le code et analyser rapidement ce qui se passe afin de faire un choix stratégique d’architecture et ce n’est pas toujours évident. Si un peu de temps peut être gagné, ça fait déjà ça de gagné afin d’avoir une meilleure analyse.

Un autre cas où ça peut vous être utile sera le suivant. Si vous êtes consultant en .Net (C#), ça peut vous sauver des heures et vous aider à accomplir votre mandat à vitesse grand V. Vous comprendrez rapidement comment l’application s’interconnecte en plus de la qualité générale de l’application. Donc même si le produit n’est pas gratuit, il se repaiera très rapidement. D’ailleurs, en tant que consultant des fois on doit écrire du code rapidement, et il n’y a rien de plus frustrant pour le client si votre code ajoute de la dettes technique. Pensez-y ;).

Performances

Vous avez un PC qui date un peu, est-ce que ça fonctionnera dans Visual Studio sans détruire votre vie, où l’attente est interminable? D’ailleurs c’est un des soucis que j’ai avec Resharper (JetBrains) à l’ouverture de gros projets. Le temps d’analyse est long, et même sur une bonne machine, je réussi à obtenir un message de désactiver des plugins ou de changer les options R#.

À priori, l’extension ne peut pas être pire que celle de JetBrains (R#) en terme de consommation ou lenteur. R# s’est vraiment amélioré avec le temps, mais c’est encore un soucis sur mon vieux laptop. Je dirais ici que NDepend s’intègre plus simplement (moins d’options cachée) et est moins gourmand (Facteur 10x).

La question qui tue, est-ce que ça vaut la peine?

À l’époque j’avais adoré, et je crois que ça vaut toujours la peine d’avoir au moins une licence serveur si ce n’est que de connecter à SonarQube. Malgré la version développeur intéressante, je ne crois pas que ça s’applique à tous. Je vois plus soit les seniors qui doivent faire des études d’impacts, soit les juniors qui doivent s’améliorer à l’aide d’un tel outil. Ensuite, pour ceux qui sont dans le “médian”, ce n’est pas nécessairement intéressant, car ils n’utiliseront pas l’outil, ou du moins pas assez pour que ce soit intéressant par rapport au prix.

Les choses qui rendrait ça encore plus intéressant et qui sait, existeront peut-être bientôt

Ici, je vais tout simplement faire une liste de ce que j’aimerais.

  • Création d’un plugin listé dans SonarQube Marketplace qui permettrait des mises à jours ou une installation plus simple
  • Pouvoir exécuter NDepend à l’intérieur d’un environnement Linux ou pas trop loin (Mac OS à désormais aussi Visual Studio professionnel et ça serait un +). Avec l’arrivée de dotnet core, je vois bien un sonar-runner sous linux pour du code c#.
  • Intégration avec SonarCloud (si c’est possible dans le futur, mais étant donné qu’il faut installer un plugin, ce ne sera pas possible. Par contre, j’ai vu dernièrement qu’il y avait moyen de pousser des erreurs dans SonarQube qui ne viennent pas des QualityGate officielles)
  • Possibilité de corriger les erreurs banales à partir de “VisualNDepend” (Un peu comme si l’on effectuait eslint –fix qui corrige automatiquement les espacements erronées, les accolades manquantes, les lignes trop longues découpées sur plusieurs lignes, etc.)
  • Possibilité d’inclure facilement dans un build GibLab (de plus en plus populaire) ou Bamboo (très utilisé dans l’industrie de nos jours)
  • À partir de VisualNDepend, avoir une capacité de s’intégrer à Git et à reculer dans le temps (machine à voyager dans le temps). Par exemple, de dire je veux une baseline à partir du mois de Janvier 2015 et j’aimerais avoir les statistiques par mois jusqu’à aujourd’hui. Ça prendrait du temps, cependant, ça permettrait de voir dans quel direction les développements s’en vont et à quel moment certains points critiques (plusieurs dépendances) se sont développées. Ce serait vraiment une superbe fonctionnalité à avoir. Le plugin Visual Studio permet d’avoir une idée générale, mais ça, ça pousserait l’idée plus loin.

Article Sponsorisé

Merci à l’équipe NDepend de m’avoir approché afin d’écrire un article sur leur produit. Je n’avais pas eu l’opportunité d’utiliser leur produit depuis un moment et je suis bien heureux de voir les progrès fait par ce logiciel.

]]>
https://blog.honosoft.com/2018/11/05/ndepend-sonarqube-ou-pourquoi-pas-les-integrer-ensemble-%f0%9f%98%89/feed/ 1
Intégration Continue (CI) > GitHub + AppVeyor + SonarQube (cloud) + BadgeIt https://blog.honosoft.com/2018/09/24/integration-continue-ci-github-appveyor-sonarqube-cloud-badgeit/?utm_source=rss&utm_medium=rss&utm_campaign=integration-continue-ci-github-appveyor-sonarqube-cloud-badgeit https://blog.honosoft.com/2018/09/24/integration-continue-ci-github-appveyor-sonarqube-cloud-badgeit/#respond Mon, 24 Sep 2018 13:59:16 +0000 https://blog.honosoft.com/?p=247 Continue Reading]]> Voici un premier article sur de l’intégration continue. Pour ceci, nous allons utiliser tous les outils “gratuit” disponible sur le web. Dans le futur, nous allons sans doute aussi traiter de GitLab. GitLab comprend déjà 2 des points mentionné dans le titre. C’est-à-dire la gestion du code source, le “build” ainsi que le déploiement.

Pour le moment, concentrons nous sur le scénario suivant:

  • GitHub : Gestion de code source
  • AppVeyor : Build automatisé tout particulièrement pour les application .Net, sinon comme alternative, vous pouvez utiliser Travis. Travis est plutôt bien, mais j’ai eu quelques problème par le passé concernant les applications .Net. Peut-être que c’est revenu à la normal depuis le temps.
  • SonarQube (Cloud) : Ici on prend la version cloud, cependant, vous pouvez l’installer sur un serveur local tout dépendant de votre usage.
  • BadgeIt : Projet créé par HoNoSoFt qui à pour but d’utiliser l’API de SonarQube ainsi que Shields.io afin de générer vos badges.
  • #Slack (Optionel) : Envoie des notifications avec Webhook lors de fin de build et d’analyse.

GitHub – Création de votre repo.

Si vous n’avez pas déjà un compte Github, shame on you :). Enfin, je dis ça, mais c’est plutôt pour vous aider à faire les étapes suivantes où vous n’aurez qu’un login ;). Du coup créez votre compte et continuez les étapes.

  1. Une fois connecté, allez sur votre image en haut et cliquez sur “Your repositories”
  2. De là simplement cliquer sur “New” après avoir bien entendu remplis le champ contenant le nom de votre projet.
    • Alternativement, dans le cas où vous êtes très paresseux, simplement dupliquer un projet existant que vous voulez faire le build et ajouter peut-être quelques fonctionnalités, pourquoi pas.
  3. Si vous avez créer votre nouveau repository, veuillez suivres les étapes afin d’ajouter votre code déjà existant. Ce sera d’ailleurs indiqué par défaut sur la page de tout votre nouveau projet.

Une fois complété, ça ressemblera à ce qui suit:

#Slack – Configuration de notification

Dans cet article, nous utiliserons Slack. Cependant, dans la vrai vie, n’importe quel system comportant un Webhook peut être utilisé. Étant donné que Slack est déjà prêt à être utilisé par toutes les applications de cet article, utilisons le. Si vous désirez, vous pouvez choisir un autre outil.

  1. Aller sur le site de #Slack
  2. Créer votre espace, ou bien utiliser un déjà existant
  3. Connectez vous à votre espace (web ou par l’application windows)
  4. Créez vous un channel qui s’appelle par exemple #ContinuousIntegration et invitez vos amis ;). Très utile si vous travaillez à plusieurs sur un projet.
  5. Sur le menu à gauche, vous trouverez une options appelé “Apps”. Appuyez sur ce bouton
  6. Dans la recherche, veuillez indiquer “Webhook” et sélectionnez “Incoming Webhook“
  7. Ajoutez le Webhook et changez la configuration à bon vous semble, cependant veuillez prendre en note le “Webhook URL“. Cet URL est utilisé afin de poussez vos notifications sur votre channel #Slack.

AppVeyor – Création de votre premier build, ou peut-être pas

Peut-être que vous avez déjà quelques build sur cette plateforme. Si c’est le cas, veuillez sauter dans la prochaine section, ou tout simplement lire en diagonale.

Ici on prendra pour acquis que vous allez builder une application .Net Core 2.1. Si vous avez un autre type d’application à bâtir, veuillez changer les choix afin de mieux vous accommoder.

  1. Accéder le site d’AppVeyor
  2. Vous connecter en utilisant votre compte GitHub
  3. Ajouter un projet existant (le bouton est plutôt évident et si vous n’avez pas trouvé, contactez moi je modifierai l’article).
  4. Avant de lancer votre build, vous devez impérativement configurer ce dernier.
    • Si vous n’êtes pas déjà sur votre projet, veuillez y accéder
    • Choisir le menu “Settings” > Onglet “General” sur la gauche (défaut)
      • Validez que le nom de votre projet est bien le bon ainsi que les options suivantes
    • Choisir le menu “Settings” > “Build”
      • Modifiez la configuration à “Release” si votre build est pour les mises en productions
      • Modifiez le “Before build script” et choisissez “CMD”
        • Insérrer “dotnet restore” (Sinon, votre restauration Nuget ne fonctionnera pas).
      • Appuyez sur “Save“
    • Choisir le menu “Settings” > “Environment”
      • Choisir Visual Studio 2017 au lieu du choix par défaut Visual Studio 2015
      • Appuyez sur “Save”
    • Choisir le menu “Settings” > “Notifications”
      • Choisir comme nouvelle notification “Slack“.
        • Insérez votre “Webhook URL” récupéré dans l’étape précédente (#Slack).
        • Choisir les événements désiré (Succès, …)
      • Appuyez sur “Save“
  5. Revenir sur le menu “Latest build”
    1. Lancer le “Build” en appuyant sur “New Build“
    2. Si le résultat est bon ou mauvais, vous devriez recevoir votre notification sur #Slack

Résultat une fois le build complété avec succès (notez le vert sur la gauche)

Résultat sur #Slack

SonarQube (Cloud) – Intégration pour valider votre qualité de code

Pour cette partie, je vais intégrer une partie de l’article AppVeyor+SonarQube disponible sur le site officiel de AppVeyor. Notez que SonarQube Cloud est gratuit pour les projet qui sont “publique” sur “GitHub”.

Important: Avec SonarCloud sous la version gratuite, les résultats seront publique et tout le monde pourra y accéder. Dans la plupart des scénario d’entreprise, ce ne sera pas le cas et vous aurez des soucis pour afficher les badges. Par soucis de sécurité, la prochaine section sera pour vous. Les badges pouvant être généré par votre propre système ou du moins sur votre réseau privé (subnet privé sur azure par exemple). Vous comprenez sans doutes où je veux en venir ;).

  1. Accéder au site de SonarQube Cloud
  2. Connectez-vous avec votre compte Github (pour la simplicité de la chose)
  3. Une fois connecté, veuillez aller sur votre profil (icône en haut à droite) et choisir “My account“
  4. Choisissez le menu “Security” afin de créer un nouveau Token qui sera ensuite utilisé par l’application BadgeIt.
    • Donnez un nom à votre token, e.g. “BadgeIt“
    • Appuyez sur “Generate“
    • Copiez et collez votre Token dans un fichier local sécuritaire ou un endroit afin de ne pas perdre cette information. Elle ne sera accessible qu’une fois, sinon vous devrez régénérer un nouveau Token.
  5. Créer un nouveau projet
  6. À ce moment, vous avez 2 choix, utiliser une nouvelle clé pour pouvoir pousser les résultats ou bien utiliser une clé existante. Je vous conseille ici de créer une clé seulement pour AppVeyor. Du coup, votre clé sera seulement pour cette application et la clé précédemment créé sera utilisé par la section qui suivre (BadgeIt).
    • Notez le nouveau Token
  7. Retour vers AppVeyor pour terminer la configuration du build.

Re-AppVeyor

Retour vers AppVeyor, allons re-configurer les événements de build ainsi que d’ajouter des variables d’environnement.

  1. Retour sur votre Project -> Settings -> Environment
  2. Ajoutez les 3 variables suivantes. Elles seront utilisé pour un script powershell. Ça évitera d’afficher publiquement certaines informations privées.
    • sonar_project_key: Déterminé lors de la création du projet dans SonarCloud. Cette clé doit normalement être unique.
    • solution: Nom de votre solution (peut contenir un “path” et non seulement le nom de la solution. Dans mon cas, c’est à la racine de mon repo. git)
    • sonar_api_key: Créé lors de l’étape précédente. Seulement coller votre valeur ici. N’oubliez pas de sauvegarder une fois que c’est fait ;).

Vous avez enfin les variables d’environnements, maintenant retournons sur la page de configuration du build.

  1. Retour sur votre Project -> Settings -> Build
  2. Allez au bas de la page de configuration et ensuite entrer ce qui suit dans “After build script“. Choisissez PS Core (ou powershell).
    • choco install "msbuild-sonarqube-runner" -y
      
      # Votre-organization vient aussi de SonarCloud. Du coup, veuillez renseigner le champ. Dans un SonarQube normal, vous n'aurez pas besoin de cette configuration.
      # Vous pouvez aussi ajouter cette variable d'environnement en tant que variable globale d'environnement sur AppVeyor
      $cmd = "MSBuild.SonarQube.Runner.exe begin /k:""${env:sonar_project_key}"" /d:sonar.organization=""VOTRE-ORGANISATION"" /d:""sonar.host.url=https://sonarcloud.io"" /d:""sonar.login=${env:sonar_api_key}"""
      Invoke-Expression $cmd
      
      msbuild $env:solution
      $cmd = "MSBuild.SonarQube.Runner.exe end /d:""sonar.login=${env:sonar_api_key}"""
      Invoke-Expression $cmd
    • Notez que le script peut aussi être modifié afin d’ajouter le numéro de version automatiquement et du coup synchronisez vos versions entre Sonar et AppVeyor.
  3. Sauvegarder

Relancer votre build et voilà, au rafraîchissement de la page Sonar vous devriez voir apparaître quelque chose comme ce qui suit:

Mon projet n’est pas parfait, mais ce n’est pas bien grave. Là plupart des “erreurs” sont dû à du HTML/JavaScript ou du code mort créé lors de refactoring récent. Je corrigerai, mais pour le moment ça montre que les chiffres ne sont pas tous à 0 et que ça a bien marché! 😀

BadgeIt – Configuration

Ici vous avez plusieurs choix. Je vous recommande votre environnement locale, mais SI vous ne pouvez pas, tournez vous vers votre hébergement favoris (Google, AWS, Azure, Heroku ou autre). Je vais donner quelques détails pour Azure, cependant ici nous allons nous attarder à la façon Heroku histoire de montrer comment déployer .Net Core 2.1 sous un container.

Azure (WebApp)

Pour ceux qui désire prendre le choix Azure, ce sera trivial:

  • Déploiement dans sur une WebApp ou similaire
  • Affecter les variables d’environnements
    • SonarQubeApi.ApiKey: Votre clée d’API créé lors de l’étape SonarQube (Cloud) et qui porte le nom de BadgeIt.
    • SonarQubeApi.BaseUri: Dans le cas ici présent: “https://sonarcloud.io/api/” ou sinon ce sera votre SonarQube privé.
    • BadgeApi.BaseUri: Par défaut, je vous recommande “https://img.shields.io/badge/”, mais si vous voulez un peu plus d’intimité et de performance, veuillez tout simplement installer le serveur Shields.IO localement. Veuillez vous référer au site Github de Shields.IO afin d’obtenir plus de détails.
  • Démarrer votre WebApp et voilà, vous pourrez suivre un peu plus loin comment utiliser l’API, sinon tout simplement charger la page principale de la WebApp, vous aurez un exemple et vous pourrez tester.

Azure (Docker container)

Veuillez suivre l’article MSDN afin de déployer votre application.

Heroku

Si vous n’avez pas déjà un compte Heroku, créez en un. Vous devrez aussi installer Heroku-Cli, car ce sera à partir de cette application que votre déploiement se fera. Sinon en générale, ce sera plutôt trivial. (Article Heroku à ce sujet)

  • Cloner le repo. HoNoSoFt.BadgeIt.SonarQube
  • Validez que vous avez bien le fichier “Dockerfile” dans le répertoire de l’application web (Dans notre cas: HoNoSoFt.BadgeIt.SonarQube.Web).
  • Connectez-vous au serveur de conteneurs Heroku
    • > heroku container:login
      • OU
    • > docker login –username=_ –password=$(heroku auth:token) registry.heroku.com
  • Poussez votre image
    • heroku container:push <process-type>
      • OU, si votre image existe déjà (tag plus push)
      • Exemple: > heroku container:push web –recursive -a badgeit
        • Important: La commande d’exécution doit absolument passer par CMD et non ENTRYPOINT.
    • docker tag <imageregistry.heroku.com/<app>/<process-type>
  • Vous pouvez ensuite faire une release de votre image
    • Exemple > heroku container:release web -a badgeit
  • N’oubliez pas d’aller configurer votre application heroku, car vous devrez mettre à jour les variables d’environnements.
    • Exemple:

Résultat:

Et voilà! Vous avez le tout de fonctionnel. Ce n’est pas bien de ne pas tout avoir dans le vert, mais ce n’est qu’une première version.

Possibilité de faire mieux (Oui, évidemment ;))

Petit exercice au cas où vous voulez vous amuser:

  1. Créer un docker-compose
    • Ajouter l’image de conteneur de Badgeit
    • Ajouter l’image de conteneur de Shields.io
    • Configurez le tout
    • Et testez
  2. Changer le message après le build afin d’envoyer un message personalisé à Slack en utilisant une image de votre badge service (badgeIt) ou autre.

À la prochaine!

]]>
https://blog.honosoft.com/2018/09/24/integration-continue-ci-github-appveyor-sonarqube-cloud-badgeit/feed/ 0