<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="3.5.2">Jekyll</generator><link href="https://www.appveyor.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.appveyor.com/" rel="alternate" type="text/html" hreflang="en" /><updated>2017-10-02T17:14:40+00:00</updated><id>https://www.appveyor.com/</id><title type="html">AppVeyor</title><subtitle>#1 Continuous Delivery service for Windows</subtitle><entry><title type="html">Sharing configuration between branches in appveyor.yml</title><link href="https://www.appveyor.com/blog/2017/08/01/sharing-configuration-between-branches-in-appveyor-yml/" rel="alternate" type="text/html" title="Sharing configuration between branches in appveyor.yml" /><published>2017-08-01T00:00:00+00:00</published><updated>2017-08-01T00:00:00+00:00</updated><id>https://www.appveyor.com/blog/2017/08/01/sharing-configuration-between-branches-in-appveyor-yml</id><content type="html" xml:base="https://www.appveyor.com/blog/2017/08/01/sharing-configuration-between-branches-in-appveyor-yml/">&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;/h2&gt;

&lt;p&gt;There are two options to have branch-specific configuration with &lt;code class=&quot;highlighter-rouge&quot;&gt;appveyor.yml&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Commit &lt;code class=&quot;highlighter-rouge&quot;&gt;appveyor.yml&lt;/code&gt; into each branch with branch-specific settings.&lt;/li&gt;
  &lt;li&gt;Use &lt;a href=&quot;/docs/branches/#conditional-build-configuration&quot;&gt;Conditional build configuration&lt;/a&gt; where &lt;code class=&quot;highlighter-rouge&quot;&gt;appveyor.yml&lt;/code&gt; has &lt;em&gt;a list&lt;/em&gt; of configurations for different branches.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The problem with 1st approach is merging as you are overriding &lt;code class=&quot;highlighter-rouge&quot;&gt;appveyor.yml&lt;/code&gt; in the base branch with one from the branch being merged.&lt;/p&gt;

&lt;p&gt;2nd approach requires &lt;code class=&quot;highlighter-rouge&quot;&gt;appveyor.yml&lt;/code&gt; of the following format:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# configuration for &quot;master&quot; branch&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# build in Release mode and deploy to Azure&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;only&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;master&lt;/span&gt;

  &lt;span class=&quot;s&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Release&lt;/span&gt;

  &lt;span class=&quot;s&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;AzureCS&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# configuration for all branches starting from &quot;dev-&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# build in Debug mode and deploy locally for testing&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;only&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/dev-.*/&lt;/span&gt;

  &lt;span class=&quot;s&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Debug&lt;/span&gt;

  &lt;span class=&quot;s&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Local&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;fall back&quot; configuration for all other branches&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# no &quot;branches&quot; section defined&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# do not deploy at all&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Debug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;While this approach works great in the most cases there is one incovenience though - with large configuration and many branches &lt;code class=&quot;highlighter-rouge&quot;&gt;appveyor.yml&lt;/code&gt; becomes really unmanageable and error-prone as you have to repeat (copy-paste) entire configuration for every branch.&lt;/p&gt;

&lt;h2 id=&quot;the-solution&quot;&gt;The solution&lt;/h2&gt;

&lt;p&gt;We just deployed an update to AppVeyor that allows sharing common configuration between branches in a single &lt;code class=&quot;highlighter-rouge&quot;&gt;appveyor.yml&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;There is new &lt;code class=&quot;highlighter-rouge&quot;&gt;for&lt;/code&gt; node with a list of branch-specific configurations &lt;strong&gt;overriding&lt;/strong&gt; common configuration defined on the top most level, for example:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c1&quot;&gt;# common configuration for ALL branches&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;MY_VAR1&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;value-A&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;do_something_on_init.cmd&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;install&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;do_something_on_install.cmd&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Debug&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# here we are going to override common configuration&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# override settings for `master` branch&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;only&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;master&lt;/span&gt;

  &lt;span class=&quot;s&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Release&lt;/span&gt;

  &lt;span class=&quot;s&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;FTP&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# override settings for `dev-*` branches&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;only&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/dev-.*/&lt;/span&gt;

  &lt;span class=&quot;s&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;MY_VAR2&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;value-B&lt;/span&gt;

  &lt;span class=&quot;s&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Local&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;In the example above we define &lt;code class=&quot;highlighter-rouge&quot;&gt;environment&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;init&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;install&lt;/code&gt; sections for all branches as well as stating that default &lt;code class=&quot;highlighter-rouge&quot;&gt;configuration&lt;/code&gt; is &lt;code class=&quot;highlighter-rouge&quot;&gt;Debug&lt;/code&gt;.
Then, for &lt;code class=&quot;highlighter-rouge&quot;&gt;master&lt;/code&gt; branch we override default settings by changing &lt;code class=&quot;highlighter-rouge&quot;&gt;configuration&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;Release&lt;/code&gt; and adding deployment with &lt;code class=&quot;highlighter-rouge&quot;&gt;FTP&lt;/code&gt; provider.
For &lt;code class=&quot;highlighter-rouge&quot;&gt;dev-*&lt;/code&gt; branches we define a second environment variable &lt;code class=&quot;highlighter-rouge&quot;&gt;MY_VAR2&lt;/code&gt; and enable deployment to &lt;code class=&quot;highlighter-rouge&quot;&gt;Local&lt;/code&gt; environment.&lt;/p&gt;

&lt;p&gt;Configuration merging rules:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Scalar values such as &lt;code class=&quot;highlighter-rouge&quot;&gt;image&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;version&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;configuration&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;platform&lt;/code&gt;, etc. defined on branch level override default ones;&lt;/li&gt;
  &lt;li&gt;Script sections such &lt;code class=&quot;highlighter-rouge&quot;&gt;init&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;install&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;before_build&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;test_script&lt;/code&gt;, etc. defined on branch level override default ones;&lt;/li&gt;
  &lt;li&gt;Environment variables defined in &lt;code class=&quot;highlighter-rouge&quot;&gt;environment&lt;/code&gt; sections are merged (new) and overridden (existing);&lt;/li&gt;
  &lt;li&gt;Build matrix defined on branch level merges with default one;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;deploy&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;artifacts&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;notifications&lt;/code&gt; section can be either overridden or extended.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, consider the following configuration:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;artifacts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bin&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Local&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;notifications&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Email&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;only&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;master&lt;/span&gt;

  &lt;span class=&quot;s&quot;&gt;artifacts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;docs&lt;/span&gt;

  &lt;span class=&quot;s&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;off&lt;/span&gt;

  &lt;span class=&quot;s&quot;&gt;notifications&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Slack&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;In the example above we do the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For &lt;code class=&quot;highlighter-rouge&quot;&gt;master&lt;/code&gt; branch we &lt;em&gt;adding&lt;/em&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;docs&lt;/code&gt; folder to artifacts definition, so both &lt;code class=&quot;highlighter-rouge&quot;&gt;bin&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;docs&lt;/code&gt; folders collected. Both default and branch-specific collections were merged.&lt;/li&gt;
  &lt;li&gt;For &lt;code class=&quot;highlighter-rouge&quot;&gt;master&lt;/code&gt; branch we &lt;em&gt;disable&lt;/em&gt; any deployment. &lt;code class=&quot;highlighter-rouge&quot;&gt;off&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;none&lt;/code&gt; on branch-level clears default collection.&lt;/li&gt;
  &lt;li&gt;For &lt;code class=&quot;highlighter-rouge&quot;&gt;master&lt;/code&gt; branch we &lt;em&gt;replace&lt;/em&gt; all notifications on default level with a single &lt;code class=&quot;highlighter-rouge&quot;&gt;Slack&lt;/code&gt; notification.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best regards,&lt;br /&gt;
AppVeyor team&lt;/p&gt;

&lt;p&gt;Follow us on Twitter: &lt;a href=&quot;https://twitter.com/appveyor&quot;&gt;@appveyor&lt;/a&gt;&lt;/p&gt;</content><author><name>Feodor Fitsner</name></author><summary type="html">The problem</summary></entry><entry><title type="html">CodeCov Test Coverage Integration</title><link href="https://www.appveyor.com/blog/2017/03/17/codecov/" rel="alternate" type="text/html" title="CodeCov Test Coverage Integration" /><published>2017-03-17T00:00:00+00:00</published><updated>2017-03-17T00:00:00+00:00</updated><id>https://www.appveyor.com/blog/2017/03/17/codecov</id><content type="html" xml:base="https://www.appveyor.com/blog/2017/03/17/codecov/">&lt;p&gt;This is a guest post by &lt;a href=&quot;https://github.com/ceddlyburge&quot;&gt;Cedd Burge&lt;/a&gt;, Software Developer Lead at &lt;a href=&quot;http://resgroup.github.io/&quot;&gt;RES&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;CodeCov visualises code coverage and can enforce standards via GitHub and AppVeyor. More information is available on &lt;a href=&quot;https://codecov.io/&quot;&gt;CodeCov.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This post is written from the point of view of someone (me) who is already proficient in C# and unit testing, but was new to AppVeyor and integrating CodeCov with GitHub.&lt;/p&gt;

&lt;p&gt;It contains from scratch steps to run CodeCov test coverage on a sample C# project using GitHub, AppVeyor, &lt;a href=&quot;https://github.com/OpenCover/opencover&quot;&gt;OpenCover&lt;/a&gt; and &lt;a href=&quot;https://xunit.github.io/&quot;&gt;XUnit&lt;/a&gt;. You can &lt;a href=&quot;https://github.com/ceddlyburge/codecov-on-appveyor&quot;&gt;look at the repo I created to test this post&lt;/a&gt; if you get stuck.&lt;/p&gt;

&lt;h2 id=&quot;create-a-new-github-repo&quot;&gt;Create a new GitHub Repo&lt;/h2&gt;

&lt;p&gt;If you are new to GitHub, see &lt;a href=&quot;https://guides.github.com/activities/hello-world/&quot;&gt;this getting started guide&lt;/a&gt;, otherwise simply create a new repo (&lt;strong&gt;YourRepositoryName&lt;/strong&gt; from now on) and git clone it somewhere convenient.&lt;/p&gt;

&lt;h2 id=&quot;create-a-new-system-under-test-sut-project-and-a-new-test-project&quot;&gt;Create a new System Under Test (SUT) project and a new Test project&lt;/h2&gt;

&lt;p&gt;In my version of Visual Studio (Community 2015), you can do this by clicking on &lt;em&gt;“File - New - Project”&lt;/em&gt; on the main menu, then &lt;em&gt;“Class Library”&lt;/em&gt; from &lt;em&gt;“Templates - Visual C#”&lt;/em&gt;. Give it a interesting name, which I will assume to be &lt;strong&gt;YourSUTProjectName&lt;/strong&gt; for the rest of this post.&lt;/p&gt;

&lt;p&gt;Repeat this for the test project, which I will assume to be &lt;strong&gt;YourTestProjectName&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Add the &lt;code class=&quot;highlighter-rouge&quot;&gt;xunit&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;xunit.runner.visualstudio&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;xunit.runner.console&lt;/code&gt; nuget packages to your test project.&lt;/p&gt;

&lt;p&gt;Add an  XUnit test to &lt;strong&gt;YourTestProjectName&lt;/strong&gt; and the corresponding thing under test to &lt;strong&gt;YourSUTProjectName&lt;/strong&gt;, or &lt;a href=&quot;https://github.com/ceddlyburge/codecov-on-appveyor/blob/master/Tests/Tests.cs&quot;&gt;copy and paste mine&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Run this test to make sure it passes.&lt;/p&gt;

&lt;h2 id=&quot;setup-appveyor-integration&quot;&gt;Setup AppVeyor Integration&lt;/h2&gt;

&lt;p&gt;You will need to link an AppVeyor account to your GitHub one, so let’s do that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Navigate to your repo in GitHub&lt;/li&gt;
  &lt;li&gt;Click “Settings” on the repo&lt;/li&gt;
  &lt;li&gt;Click “Integrations and services”&lt;/li&gt;
  &lt;li&gt;Click “Browse Directory”&lt;/li&gt;
  &lt;li&gt;Click “AppVeyor”&lt;/li&gt;
  &lt;li&gt;Click “Configure”&lt;/li&gt;
  &lt;li&gt;Click “Grant Access”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now Log in to &lt;a href=&quot;https://ci.appveyor.com&quot;&gt;AppVeyor.com&lt;/a&gt;, probably using your GitHub account&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Click “Projects”&lt;/li&gt;
  &lt;li&gt;Click “New Project”&lt;/li&gt;
  &lt;li&gt;Choose &lt;strong&gt;YourRepositoryName&lt;/strong&gt; and click “Add”&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;sign-up-with-codecov&quot;&gt;Sign up with CodeCov&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Go to &lt;a href=&quot;https://codecov.io/&quot;&gt;https://codecov.io/&lt;/a&gt; and click “Sign up with GitHub”&lt;/li&gt;
  &lt;li&gt;Click “Add new repository” and choose &lt;strong&gt;YourRepositoryName&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Make a note of the Upload token (&lt;strong&gt;YourUploadToken&lt;/strong&gt; from now on)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;run-coverage-analysis-locally&quot;&gt;Run Coverage Analysis Locally&lt;/h2&gt;

&lt;p&gt;When working with AppVeyor, it always makes sense to test on your own computer first. The feedback is immediate and you iterate very quickly. It takes a lot longer to modify the appveyor.yml file, push it and wait for a build to go through. Also, if it works locally but doesn’t work on AppVeyor, you know the problem is a configuration difference between your computer and the AppVeyor environment (eg a different version of msbuild).&lt;/p&gt;

&lt;p&gt;However, this step is not required, so skip to “Run Coverage Analysis on AppVeyor” if you wish.&lt;/p&gt;

&lt;p&gt;CodeCov.io is a tool for visualising and integrating coverage data, which we need to create. We will use &lt;a href=&quot;https://github.com/OpenCover/opencover&quot;&gt;OpenCover&lt;/a&gt; to do this.&lt;/p&gt;

&lt;h3 id=&quot;analyse&quot;&gt;Analyse&lt;/h3&gt;

&lt;p&gt;Add the &lt;code class=&quot;highlighter-rouge&quot;&gt;OpenCover&lt;/code&gt; nuget package to the solution (which will install OpenCover.Console.exe, probably in packages\OpenCover.4.6.519\tools) and then run the following in a command window.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;YourTestDLL&lt;/strong&gt; is the relative path to the dll for your test project, eg. &lt;em&gt;Tests\bin\Debug\tests.dll&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;-register[:user]&lt;/strong&gt; asks OpenCover to register the code coverage profiler under HKEY_CURRENT_USER, which doesn’t require the user to have administrative permissions.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;-target:&lt;/strong&gt; asks OpenCover to run XUnit&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;-targetargs:&lt;/strong&gt; are arguments that OpenCover passes to XUnit&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;-output:&lt;/strong&gt; is the file to contain the coverage results&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;YourSUTNamepace&lt;/strong&gt;, &lt;strong&gt;YourTestNamespace&lt;/strong&gt; are the namespaces for your Test and SystemUnderTest projects. If these filters aren’t specified OpenCover will try and analyse everything, including the XUnit dlls.&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&quot;language-batch&quot;&gt;packages\OpenCover.4.6.519\tools\OpenCover.Console.exe -register:user -target:&quot;packages\xunit.runner.console.2.2.0\tools\xunit.console.x86.exe&quot; -targetargs:&quot;YourTestDLL -noshadow&quot; -output:&quot;.\coverage.xml&quot; -filter:&quot;+[YourSUTNamepace*]* -[YourTestNamespace*]*&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;upload&quot;&gt;Upload&lt;/h3&gt;

&lt;p&gt;Download and install &lt;a href=&quot;https://www.python.org/downloads/&quot;&gt;Python 3.x&lt;/a&gt;, make sure to tick the box to add Python to your path (or do so manually).&lt;/p&gt;

&lt;p&gt;Run the following on the command line. You may need to close and reopen the console to pick up changes to the path. &lt;strong&gt;YourUploadToken&lt;/strong&gt; is the CodeCov token that you took a note of earlier, or available on the project settings page on CodeCov (eg &lt;code class=&quot;highlighter-rouge&quot;&gt;https://codecov.io/gh/YourGitHubUserName/YourRepositoryName/settings&lt;/code&gt;)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-batch&quot;&gt;pip install codecov
codecov -f &quot;coverage.xml&quot; -t YourUploadToken
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The output will show a url with the results (eg &lt;code class=&quot;highlighter-rouge&quot;&gt;https://codecov.io/gh/YourGitHubUserName/YourRepositoryName&lt;/code&gt;)&lt;/p&gt;

&lt;h2 id=&quot;run-coverage-analysis-on-appveyor&quot;&gt;Run Coverage Analysis on AppVeyor&lt;/h2&gt;

&lt;p&gt;Now that the coverage upload is working locally, we can run it on AppVeyor.&lt;/p&gt;

&lt;p&gt;Add and commit an &lt;code class=&quot;highlighter-rouge&quot;&gt;appveyor.yml&lt;/code&gt; file to the root of the repository as below.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;YourSolution&lt;/strong&gt; is the relative path of the .sln file to build (eg &lt;em&gt;codecov-on-appveyor.sln&lt;/em&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;YourUploadToken&lt;/strong&gt; is not required if you are uploading from a public repo with AppVeyor, but is included in case you are using a private repo.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;%xunit20%&lt;/strong&gt;. XUnit is installed on the AppVeyor build environment by default, and AppVeyor provide the &lt;strong&gt;%xunit20%&lt;/strong&gt; environment variable for the installation path.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;before_build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nuget restore&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;build_script&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;msbuild /verbosity:quiet &quot;YourSolution&quot;&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;test_script&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;.\packages\OpenCover.4.6.519\tools\OpenCover.Console.exe -register:user -target:&quot;%xunit20%\xunit.console.x86.exe&quot; -targetargs:&quot;YourTestDll -noshadow&quot; -output:&quot;coverage.xml&quot; -filter:&quot;+[YourSUTNamepace*]* -[YourTestNamespace*]*&quot;&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;after_test&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;SET&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;PATH=C:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Python34;C:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Python34&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Scripts;%PATH%&quot;&lt;/span&gt;
 &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;pip install codecov&lt;/span&gt;
 &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;codecov -f &quot;coverage.xml&quot; -t YourUploadToken&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;add-coverage-graphics-to-the-repository&quot;&gt;Add Coverage Graphics to the Repository&lt;/h2&gt;

&lt;p&gt;There are various badges and graphs available. Click on your project in CodeCov, then “Settings” and “Badge” (eg &lt;code class=&quot;highlighter-rouge&quot;&gt;https://codecov.io/gh/YourGitHubUserName/YourRepositoryName/settings/badge&lt;/code&gt;) to see what’s available.&lt;/p&gt;

&lt;p&gt;Copy and paste a code snippet from this in to your README.md, such as this one &lt;img src=&quot;/assets/img/posts/codecov-test-coverage-integration/code-coverage-badge.svg&quot; alt=&quot;Code Coverage Badge&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;You can &lt;a href=&quot;https://github.com/ceddlyburge/codecov-on-appveyor/blob/master/README.md&quot;&gt;look at my readme for example badges&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;integrate-codecov-with-pull-requests&quot;&gt;Integrate CodeCov with Pull Requests&lt;/h2&gt;

&lt;p&gt;CodeCov automatically integrates with GitHub pull requests (as long as you signed up to CodeCov via your GitHub account) which you can see on &lt;a href=&quot;https://github.com/ceddlyburge/codecov-on-appveyor/pull/1&quot;&gt;this pull request&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It will show some statistics, such as the increase or decrease in coverage, and by default will fail the build if coverage decreases. You can &lt;a href=&quot;https://docs.codecov.io/docs/commit-status&quot;&gt;configure this with a ‘codecov.yml’ file&lt;/a&gt; in the root of your repository.&lt;/p&gt;

&lt;h2 id=&quot;install-the-browser-plugin&quot;&gt;Install the browser plugin&lt;/h2&gt;

&lt;p&gt;There is a &lt;a href=&quot;https://docs.codecov.io/docs/browser-extension&quot;&gt;CodeCov browser plugin&lt;/a&gt;, for all reputable browsers, that adds coverage when browsing GitHub.com. Code is highlighted in red / green, and a coverage percentage is shown.&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;It can be difficult keeping control of test coverage for a project, especially with distributed and transient team structures. The combination of GitHub, AppVeyor OpenCover and CodeCov make it very easy to visualise the coverage, and allow you to enforce standards to ensure that it improves over time.&lt;/p&gt;

&lt;p&gt;Best regards,&lt;br /&gt;
Cedd Burge&lt;/p&gt;

&lt;p&gt;Follow Cedd on Twitter: &lt;a href=&quot;https://twitter.com/cuddlyburger&quot;&gt;@cuddlyburger&lt;/a&gt;&lt;br /&gt;
Follow AppVeyor on Twitter: &lt;a href=&quot;https://twitter.com/appveyor&quot;&gt;@appveyor&lt;/a&gt;&lt;/p&gt;</content><author><name>Feodor Fitsner</name></author><summary type="html">This is a guest post by Cedd Burge, Software Developer Lead at RES.</summary></entry><entry><title type="html">SonarQube Analysis</title><link href="https://www.appveyor.com/blog/2016/12/23/sonarqube/" rel="alternate" type="text/html" title="SonarQube Analysis" /><published>2016-12-23T00:00:00+00:00</published><updated>2016-12-23T00:00:00+00:00</updated><id>https://www.appveyor.com/blog/2016/12/23/sonarqube</id><content type="html" xml:base="https://www.appveyor.com/blog/2016/12/23/sonarqube/">&lt;p&gt;This is a guest post by &lt;a href=&quot;https://github.com/ceddlyburge&quot;&gt;Cedd Burge&lt;/a&gt;, Software Developer Lead at &lt;a href=&quot;http://resgroup.github.io/&quot;&gt;RES&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;SonarQube / SonarSource analyzes code, highlights quality issues and calculates metrics such as technical debt. More information is available on &lt;a href=&quot;https://www.sonarsource.com/&quot;&gt;SonarSource.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This post is written from the point of view of someone (me) who is already proficient in C#, and had even used SonarQube, but was new to AppVeyor and integrating SonarQube with GitHub.&lt;/p&gt;

&lt;p&gt;It contains from scratch steps to run the SonarQube analysis on a sample project and to publish the results to the publicly available Nemo instance of SonarQube. You can &lt;a href=&quot;https://github.com/ceddlyburge/sonarqube-nemo-on-appveyor&quot;&gt;look at the repo I created to test this post&lt;/a&gt; if you get stuck.&lt;/p&gt;

&lt;h2 id=&quot;create-a-new-github-repository&quot;&gt;Create a new GitHub repository&lt;/h2&gt;

&lt;p&gt;If you are new to GitHub, see &lt;a href=&quot;https://guides.github.com/activities/hello-world/&quot;&gt;this getting started guide&lt;/a&gt;, otherwise simply create a new repo and git clone it somewhere convenient.&lt;/p&gt;

&lt;h2 id=&quot;create-a-new-project&quot;&gt;Create a new project&lt;/h2&gt;

&lt;p&gt;In my version of Visual Studio (Community 2015), you can do this by clicking on &lt;em&gt;“File - New - Project”&lt;/em&gt; on the main menu, then &lt;em&gt;“Class Library”&lt;/em&gt; from &lt;em&gt;“Templates - Visual C#”&lt;/em&gt;. Give it a interesting name, which I will assume to be &lt;strong&gt;YourProjectName&lt;/strong&gt; for the rest of this post.&lt;/p&gt;

&lt;p&gt;Add some code that has some quality issues (e.g. a variable that is declared but never used). You can use the &lt;a href=&quot;http://dist.sonarsource.com/reports/coverage/rules/csharpsquid_rules_coverage.html&quot;&gt;the full list of SonarQube C# issues&lt;/a&gt; for inspiration. Alternatively you can copy and paste &lt;a href=&quot;https://github.com/ceddlyburge/sonarqube-nemo-on-appveyor/blob/master/ExampleSonarQubeIssues.cs&quot;&gt;some of mine&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Install the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=SonarSource.SonarLintforVisualStudio&quot;&gt;SonarLint Visual Studio Plugin&lt;/a&gt;. This highlights quality issues in your code as you type and gives you a chance to fix them before committing.&lt;/p&gt;

&lt;h2 id=&quot;integrate-with-appveyor&quot;&gt;Integrate with AppVeyor&lt;/h2&gt;

&lt;p&gt;You will need to link an AppVeyor account to your GitHub one, so let’s do that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Navigate to your repo in GitHub&lt;/li&gt;
  &lt;li&gt;Click “Settings” on the repo&lt;/li&gt;
  &lt;li&gt;Click “Integrations and services”&lt;/li&gt;
  &lt;li&gt;Click “Browse Directory”&lt;/li&gt;
  &lt;li&gt;Click “AppVeyor”&lt;/li&gt;
  &lt;li&gt;Click “Configure”&lt;/li&gt;
  &lt;li&gt;Click “Grant Access”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now Log in to &lt;a href=&quot;https://ci.appveyor.com&quot;&gt;AppVeyor.com&lt;/a&gt;, probably using your GitHub account&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Click “Projects”&lt;/li&gt;
  &lt;li&gt;Click “New Project”&lt;/li&gt;
  &lt;li&gt;Choose your GitHub repository and click “Add”&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;sign-up-with-sonarqube-and-generate-an-authentication-token&quot;&gt;Sign up with SonarQube and generate an Authentication Token&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Create an account at &lt;a href=&quot;https://sonarqube.com/sessions/new&quot;&gt;sonarqube.com/sessions/new&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Click on &lt;a href=&quot;https://sonarqube.com/account/security/&quot;&gt;sonarqube.com/account/security/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Enter a token name and click “Generate”&lt;/li&gt;
  &lt;li&gt;Make a note of the generated token (&lt;strong&gt;YourSonarQubeToken&lt;/strong&gt; from now on)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;run-sonarqube-analysis-locally&quot;&gt;Run SonarQube Analysis Locally&lt;/h2&gt;

&lt;p&gt;When working with AppVeyor, it always makes sense to test on your own computer first. The feedback is immediate and you iterate very quickly. It takes a lot longer to modify the &lt;code class=&quot;highlighter-rouge&quot;&gt;appveyor.yml&lt;/code&gt; file, push it and wait for a build to go through. Also, if it works locally but doesn’t work on AppVeyor, you know the problem is a configuration difference between your computer and the AppVeyor environment (e.g. a different version of msbuild).&lt;/p&gt;

&lt;p&gt;Instead of committing SonarQube executables to the repo, we will download them during the build using Chocolatey.&lt;/p&gt;

&lt;h3 id=&quot;install-chocolatey&quot;&gt;Install chocolatey&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://chocolatey.org/install&quot;&gt;Install Chocolatey&lt;/a&gt; from an administrator command prompt / powershell.&lt;/li&gt;
  &lt;li&gt;Close the command prompt&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;install-sonarqube-msbuild-runner&quot;&gt;Install SonarQube MSBuild Runner&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Open a new administrator command prompt / powershell.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;choco install &quot;msbuild-sonarqube-runner&quot; -y&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;analyze-and-upload-to-sonarqube&quot;&gt;Analyze and upload to SonarQube&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-batch&quot;&gt;MSBuild.SonarQube.Runner.exe begin /k:&quot;**YourUniqueProjectName**&quot; /d:&quot;sonar.host.url=https://sonarqube.com&quot; /d:&quot;sonar.login=**YourSonarQubeToken**&quot;
&quot;**YourPathToMSBuild**\MSBuild.exe&quot; &quot;**YourProjectName**.sln&quot;
MSBuild.SonarQube.Runner.exe end /d:&quot;sonar.login=**YourSonarQubeToken**&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When finished, you will be able to see the results at &lt;a href=&quot;https://sonarqube.com&quot;&gt;sonarqube.com/&lt;/a&gt;. If it isn’t working, make sure you are using MSBuild 14 and &lt;a href=&quot;http://stackoverflow.com/questions/40249947/msbuild-sonarqube-runner-exe-cant-access-https-sonarqube-com&quot;&gt;Java 1.8 or later&lt;/a&gt;. The SonarQube &lt;a href=&quot;https://about.sonarqube.com/get-started/&quot;&gt;Getting Started&lt;/a&gt; page is excellent if these instructions become out of date.&lt;/p&gt;

&lt;h2 id=&quot;run-sonarqube-analysis-on-appveyor&quot;&gt;Run SonarQube Analysis on AppVeyor&lt;/h2&gt;

&lt;p&gt;Now that this is working locally, we can run it on AppVeyor.&lt;/p&gt;

&lt;p&gt;Add and commit an &lt;strong&gt;appveyor.yml&lt;/strong&gt; file to the root of the repository as follows&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;before_build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nuget restore&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;build_script&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;choco install &quot;msbuild-sonarqube-runner&quot; -y&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MSBuild.SonarQube.Runner.exe begin /k:&quot;YourUniqueProjectName&quot; /d:&quot;sonar.host.url=https://sonarqube.com&quot; /d:&quot;sonar.login=YourSonarQubeToken&quot;&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;msbuild &quot;YourProjectName.sln&quot;&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MSBuild.SonarQube.Runner.exe end /d:&quot;sonar.login=YourSonarQubeToken&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Again, you can check the results at &lt;a href=&quot;https://sonarqube.com/&quot;&gt;sonarqube.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;add-a-sonarqube-badge-to-the-repo&quot;&gt;Add a SonarQube badge to the repo&lt;/h2&gt;

&lt;p&gt;There are are variety of &lt;a href=&quot;https://github.com/QualInsight/qualinsight-plugins-sonarqube-badges/wiki/Quality-Gate-status-badges&quot;&gt;Quality Gate&lt;/a&gt; and &lt;a href=&quot;https://github.com/QualInsight/qualinsight-plugins-sonarqube-badges/wiki/Measure-badges&quot;&gt;Metrics&lt;/a&gt; badges available.&lt;/p&gt;

&lt;p&gt;To add a standard &lt;a href=&quot;https://sonarqube.com/dashboard/index/SonarQubeNemoOnAppveyor&quot;&gt;&lt;img src=&quot;https://sonarqube.com/api/badges/gate?key=SonarQubeNemoOnAppveyor&quot; alt=&quot;Quality Gate&quot; /&gt;&lt;/a&gt; badge, add the following to readme.md.&lt;/p&gt;

&lt;div class=&quot;language-markdown highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;![Quality Gate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;https://sonarqube.com/api/badges/gate?key=YourUniqueProjectName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;](https://sonarqube.com/dashboard/index/YourUniqueProjectName)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;integrate-sonarqube-with-pull-requests&quot;&gt;Integrate SonarQube with Pull Requests&lt;/h2&gt;

&lt;p&gt;SonarQube can analyze Pull Requests for quality issues, which you can see on &lt;a href=&quot;https://github.com/ceddlyburge/sonarqube-nemo-on-appveyor/pull/3&quot;&gt;this pull request&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This requires a GitHub authentication token, which must be secured, secure variables to be enabled in pull requests and a differential build for Pull Requests.&lt;/p&gt;

&lt;h3 id=&quot;get-a-github-authentication-token&quot;&gt;Get a GitHub Authentication token&lt;/h3&gt;

&lt;p&gt;Go to your profile and click &lt;em&gt;“Edit Profile”&lt;/em&gt;. Click on &lt;em&gt;“Personal access tokens”&lt;/em&gt; in the &lt;em&gt;“Developer settings”&lt;/em&gt; section. Give the token any name and tick on the &lt;em&gt;“public_repo”&lt;/em&gt; scope. Make a note of the created token (&lt;strong&gt;GitHubAuthToken&lt;/strong&gt; from now on)&lt;/p&gt;

&lt;h3 id=&quot;secure-the-github-authentication-token&quot;&gt;Secure the GitHub Authentication token&lt;/h3&gt;

&lt;p&gt;Anyone with access to this token can alter your data, contact information and billing data, so we don’t want that.&lt;/p&gt;

&lt;p&gt;On &lt;a href=&quot;https://ci.appveyor.com&quot;&gt;AppVeyor&lt;/a&gt;, click your user name in the top right hand corner and then click &lt;em&gt;“Encrypt data”&lt;/em&gt; from the drop down menu. Enter &lt;strong&gt;GitHubAuthToken&lt;/strong&gt; in to &lt;em&gt;“Value to encrypt”&lt;/em&gt; and click &lt;em&gt;“Encrypt”&lt;/em&gt;. AppVeyor will then display a token which you can use in place of the real value (&lt;strong&gt;EncryptedGitHubAuthToken&lt;/strong&gt; from now on).&lt;/p&gt;

&lt;h3 id=&quot;allowing-secure-variables-in-pull-requests&quot;&gt;Allowing Secure Variables in Pull Requests&lt;/h3&gt;

&lt;p&gt;Normally AppVeyor will not decrypt secure variables in Pull Requests, as in this case a Hacker could send you a PR and then read all of your secure data. However, for SonarQube to analyze Pull Requests, it is necessary. You need to decide whether you can live with this.&lt;/p&gt;

&lt;p&gt;If you can, go to &lt;a href=&quot;https://ci.appveyor.com&quot;&gt;AppVeyor&lt;/a&gt;, click on your project, click &lt;em&gt;“Settings”&lt;/em&gt;, tick &lt;em&gt;“Enable secure variables in Pull Requests from the same repository only”&lt;/em&gt; and click &lt;em&gt;“Save”&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;create-a-pull-request-build&quot;&gt;Create a Pull Request Build&lt;/h3&gt;

&lt;p&gt;Modify &lt;strong&gt;AppVeyor.yml&lt;/strong&gt; to ask SonarQube to publish results on standard builds, and to integrate with pull request builds. To achieve this, extra parameters are given to the SonarQube runner when &lt;code class=&quot;highlighter-rouge&quot;&gt;if ($env:APPVEYOR_PULL_REQUEST_NUMBER)&lt;/code&gt; detects a Pull Request build.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;github_auth_token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;secure&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;EncryptedGitHubAuthToken&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;before_build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nuget restore&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;build_script&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;choco install &quot;msbuild-sonarqube-runner&quot; -y&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;if ($env:APPVEYOR_PULL_REQUEST_NUMBER) { MSBuild.SonarQube.Runner.exe begin /k:&quot;YourUniqueProjectName&quot; /d:&quot;sonar.host.url=https://sonarqube.com&quot; /d:&quot;sonar.login=YourSonarQubeToken&quot; /d:&quot;sonar.analysis.mode=preview&quot; /d:&quot;sonar.github.pullRequest=$env:APPVEYOR_PULL_REQUEST_NUMBER&quot; /d:&quot;sonar.github.repository=YourRepositoryUrl&quot; /d:&quot;sonar.github.oauth=$env:EncryptedGitHubAuthToken&quot; }&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;if (-Not $env:APPVEYOR_PULL_REQUEST_NUMBER) { MSBuild.SonarQube.Runner.exe begin /k:&quot;YourUniqueProjectName&quot; /d:&quot;sonar.host.url=https://sonarqube.com&quot; /d:&quot;sonar.login=YourSonarQubeToken&quot; }&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;msbuild &quot;YourProjectName.sln&quot;&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MSBuild.SonarQube.Runner.exe end /d:&quot;sonar.login=YourSonarQubeToken&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;SonarQube is maturing fast and is becoming industry standard, and happily it is easy to integrate Open Source projects with the publicly available SonarQube server and AppVeyor. The &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=SonarSource.SonarLintforVisualStudio&quot;&gt;SonarLint Visual Studio Plugin&lt;/a&gt; is fantastic at spotting problems before you commit them, and the &lt;a href=&quot;http://docs.sonarqube.org/display/PLUG/GitHub+Plugin&quot;&gt;GitHub integration&lt;/a&gt; allows you to control the quality of contributions.&lt;/p&gt;

&lt;p&gt;Best regards,&lt;br /&gt;
Cedd Burge&lt;/p&gt;

&lt;p&gt;Follow Cedd on Twitter: &lt;a href=&quot;https://twitter.com/cuddlyburger&quot;&gt;@cuddlyburger&lt;/a&gt;&lt;br /&gt;
Follow AppVeyor on Twitter: &lt;a href=&quot;https://twitter.com/appveyor&quot;&gt;@appveyor&lt;/a&gt;&lt;/p&gt;</content><author><name>Feodor Fitsner</name></author><summary type="html">This is a guest post by Cedd Burge, Software Developer Lead at RES.</summary></entry><entry><title type="html">Creating a Signed and ZipAligned APK (for Google Play) from Xamarin</title><link href="https://www.appveyor.com/blog/2016/11/22/create-signed-aligned-xamarin-apk/" rel="alternate" type="text/html" title="Creating a Signed and ZipAligned APK (for Google Play) from Xamarin" /><published>2016-11-22T00:00:00+00:00</published><updated>2016-11-22T00:00:00+00:00</updated><id>https://www.appveyor.com/blog/2016/11/22/create-signed-aligned-xamarin-apk</id><content type="html" xml:base="https://www.appveyor.com/blog/2016/11/22/create-signed-aligned-xamarin-apk/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;This is a guest post by &lt;a href=&quot;https://github.com/ceddlyburge&quot;&gt;Cedd Burge&lt;/a&gt;, Software Developer Lead at &lt;a href=&quot;http://resgroup.github.io/&quot;&gt;RES&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This post is written from the point of view of someone (me) who is already proficient in C#, but was new to Xamarin, Mobile phone development, and AppVeyor.&lt;/p&gt;

&lt;p&gt;It contains from scratch steps to create a Xamarin Android application (in Visual Studio), to build it on AppVeyor and to publish it to the Play Store. You can &lt;a href=&quot;https://github.com/ceddlyburge/create-signed-zipaligned-xamarin-apk-on-appveyor&quot;&gt;look at the repo I created to test this post&lt;/a&gt; if you get stuck.&lt;/p&gt;

&lt;p&gt;First, install Xamarin from &lt;a href=&quot;https://www.xamarin.com/download&quot;&gt;https://www.xamarin.com/download&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;create-a-new-repository-on-github&quot;&gt;Create a new repository on GitHub&lt;/h2&gt;

&lt;p&gt;If you are new to GitHub, see &lt;a href=&quot;https://guides.github.com/activities/hello-world/&quot;&gt;this getting started guide&lt;/a&gt;, otherwise simply create a new repo and git clone it somewhere convenient.&lt;/p&gt;

&lt;h2 id=&quot;create-a-new-xamarin-portable-class-library-pcl-project&quot;&gt;Create a new Xamarin Portable Class Library (PCL) project&lt;/h2&gt;

&lt;p&gt;In my version of Visual Studio (Community 2015), this is done by clicking &lt;em&gt;“File - New - Project”&lt;/em&gt; on the main menu and then selecting &lt;em&gt;“Blank App (Xamarin.Forms Portable)”&lt;/em&gt; from &lt;em&gt;“Templates - Visual C# - Cross-Platform”&lt;/em&gt;. Give it a interesting name, which I will assume to be &lt;strong&gt;YourAppName&lt;/strong&gt; for the rest of this post.&lt;/p&gt;

&lt;h2 id=&quot;run-the-app&quot;&gt;Run the app!&lt;/h2&gt;

&lt;p&gt;Select the &lt;strong&gt;YourAppName.Droid&lt;/strong&gt; project and run it. This should show the bare bones app in an emulator.&lt;/p&gt;

&lt;p&gt;If you have Hyper-V enabled (maybe you use Docker), then you might get an Deployment Error when doing this. &lt;a href=&quot;http://stackoverflow.com/questions/31613607/visual-studio-2015-emulator-for-android-not-working-xde-exe-exit-code-3&quot;&gt;Disable Hyper-V and restart your machine to fix this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You might also run in to compile errors due to &lt;a href=&quot;http://stackoverflow.com/questions/40081826/system-missingmethodexception-method-android-support-v4-widget-drawerlayout-ad&quot;&gt;ridiculous dependency weirdness&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;create-apk-file-manually&quot;&gt;Create APK file manually&lt;/h2&gt;

&lt;p&gt;To tell Google about your app, you have to make some changes to the &lt;em&gt;Properties\AndroidManifest.xml&lt;/em&gt; file of the &lt;strong&gt;YourAppName.Droid&lt;/strong&gt; project.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Add a &lt;code class=&quot;highlighter-rouge&quot;&gt;package=&quot;com.yourappname&quot;&lt;/code&gt; (or similar) attribute to the root &lt;code class=&quot;highlighter-rouge&quot;&gt;manifest&lt;/code&gt; node. The package name must be unique on Google Play and must follow normal &lt;a href=&quot;https://en.wikipedia.org/wiki/Java_package#Package_naming_conventions&quot;&gt;java package name conventions&lt;/a&gt;. Most people use their url in reverse (eg com.yourappname instead of yourappname.com) and stick to lower case.&lt;/li&gt;
  &lt;li&gt;Add an &lt;code class=&quot;highlighter-rouge&quot;&gt;android:versionCode=&quot;1&quot;&lt;/code&gt; attribute to the root &lt;code class=&quot;highlighter-rouge&quot;&gt;manifest&lt;/code&gt; node. This is an integer and it must be incremented every time you upload an apk on Google Play.&lt;/li&gt;
  &lt;li&gt;Add an &lt;code class=&quot;highlighter-rouge&quot;&gt;android:versionName=&quot;0.1&lt;/code&gt; attribute to the root &lt;code class=&quot;highlighter-rouge&quot;&gt;manifest&lt;/code&gt; node. This value can be anything you like and is displayed in Google Play.&lt;/li&gt;
  &lt;li&gt;Change the &lt;code class=&quot;highlighter-rouge&quot;&gt;label&lt;/code&gt; attribute on the &lt;code class=&quot;highlighter-rouge&quot;&gt;application&lt;/code&gt; node to YourAppName.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Visual studio has some tools to create an APK, and they seem to be in constant churn, but at the time of writing, the process is as follows.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Change the &lt;em&gt;“Build Configuration”&lt;/em&gt; to &lt;em&gt;“App Store”&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Select the &lt;strong&gt;YourAppName.droid&lt;/strong&gt; project and click &lt;em&gt;“Build - Archive”&lt;/em&gt; from the main menu.&lt;/li&gt;
  &lt;li&gt;The archive manager window will appear and build your app.&lt;/li&gt;
  &lt;li&gt;Click &lt;em&gt;“Distribute”&lt;/em&gt;, which will pop up the Distribute window.&lt;/li&gt;
  &lt;li&gt;Initially you won’t have a signing identity, so click on the green plus button and fill in the details to create one.&lt;/li&gt;
  &lt;li&gt;Once created, double click on it and note where it is on disk (&lt;strong&gt;YourKeyStoreFilename&lt;/strong&gt; from now on)&lt;/li&gt;
  &lt;li&gt;Click &lt;em&gt;“Save As”&lt;/em&gt; to create an APK.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;upload-the-apk-to-google-play&quot;&gt;Upload the APK to Google Play&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Create a Developer Account on &lt;a href=&quot;https://play.google.com/apps/publish&quot;&gt;Google Play Developer Console&lt;/a&gt; (this costs $25)&lt;/li&gt;
  &lt;li&gt;Click &lt;em&gt;“Add New Application”&lt;/em&gt; and add &lt;strong&gt;YourAppName&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Upload the APK that you saved in the previous step&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;publish-the-app-on-google-play-probably-just-to-alpha-or-beta&quot;&gt;Publish the App on Google Play (probably just to Alpha or Beta)&lt;/h2&gt;

&lt;p&gt;There are some requirements when publishing an application to Google Play, and these are likely to change, but happily google tells you what they all are. If you click on &lt;em&gt;“Why can’t I publish?”&lt;/em&gt;, near the top right corner of the page, you will get a list of things to do.&lt;/p&gt;

&lt;p&gt;It’s all simple stuff that can be done within the Developer Console. Some screenshots and pictures are required. If you just want to get a test version up quickly, then &lt;a href=&quot;https://github.com/ceddlyburge/CanoePoloLeagueOrganiser/tree/master/CanoePoloLeagueOrganiserXamarin/screenshots-etc&quot;&gt;feel free to use mine&lt;/a&gt; temporarily.&lt;/p&gt;

&lt;p&gt;There are a lot of optional things you can do as well, which can be worthwhile if you want to publish a killer app. The &lt;a href=&quot;https://developer.android.com/distribute/tools/launch-checklist.html&quot;&gt;Google Launch Checklist&lt;/a&gt;, is comprehensive, but takes a long time to read.&lt;/p&gt;

&lt;h2 id=&quot;automate-apk-creation-locally&quot;&gt;Automate APK creation locally&lt;/h2&gt;

&lt;p&gt;When working with appveyor, it always makes sense to test on your own computer first. The feedback is immediate and you iterate very quickly. It takes a lot longer to modify the appveyor.yml file, push it and wait for a build to go through. Also, if it works locally but doesn’t work on AppVeyor, you know the problem is a configuration difference between your computer and the AppVeyor environment (eg a different version of msbuild).&lt;/p&gt;

&lt;p&gt;Being as we are making a new version of the apk, we need to increment &lt;code class=&quot;highlighter-rouge&quot;&gt;android:versionCode&lt;/code&gt; in &lt;em&gt;Properties/AndroidManifest.xml&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There are some &lt;a href=&quot;https://developer.xamarin.com/guides/android/under_the_hood/build_process/#22-build-targets&quot;&gt;Xamarin MSBuild targets&lt;/a&gt;, which we can use to create a Signed and ZipAligned apk as below.&lt;/p&gt;

&lt;p&gt;There are 2 passwords required in the command because &lt;a href=&quot;https://docs.oracle.com/javase/7/docs/api/java/security/KeyStore.html&quot;&gt;java KeyStores&lt;/a&gt; can contain multiple Alias’. So the first password is to access the KeyStore, and the second one is to access the specific alias. Visual studio hides this complexity from you and assigns the same password to both places.&lt;/p&gt;

&lt;p&gt;I do a lot of work in GIT Bash, but this statement only works in Batch (the windows command line), I think because of parameter escaping.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-batch&quot;&gt;MSBuild &quot;/t:SignAndroidPackage&quot; &quot;/p:Configuration=Release&quot; &quot;/p:AndroidKeyStore=true&quot; &quot;/p:AndroidSigningKeyAlias=YourKeyAlias&quot; &quot;/p:AndroidSigningKeyPass=YourKeyStorePassword&quot; &quot;/p:AndroidSigningKeyStore=YourKeyStoreFilename&quot; &quot;/p:AndroidSigningStorePass=YourKeyStorePassword&quot; &quot;YourAppName.csproj&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will create &lt;strong&gt;com.yourappname-Signed.apk&lt;/strong&gt; in the &lt;em&gt;bin\release&lt;/em&gt; folder. Upload this to Google Play to make sure that everything is working properly.&lt;/p&gt;

&lt;h2 id=&quot;automate-apk-creation-on-appveyor&quot;&gt;Automate APK creation on AppVeyor&lt;/h2&gt;

&lt;p&gt;You will need to link an AppVeyor account to your GitHub one, so let’s do that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Navigate to your repo in GitHub&lt;/li&gt;
  &lt;li&gt;Click “Settings” on the repo&lt;/li&gt;
  &lt;li&gt;Click “Integrations and services”&lt;/li&gt;
  &lt;li&gt;Click “Browse Directory”&lt;/li&gt;
  &lt;li&gt;Click “AppVeyor”&lt;/li&gt;
  &lt;li&gt;Click “Configure”&lt;/li&gt;
  &lt;li&gt;Click “Grant Access”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now Log in to &lt;a href=&quot;https://ci.appveyor.com&quot;&gt;AppVeyor.com&lt;/a&gt;, probably using your GitHub account&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Click “Projects”&lt;/li&gt;
  &lt;li&gt;Click “New Project”&lt;/li&gt;
  &lt;li&gt;Choose your GitHub repository and click “Add”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MSBuild needs to access your KeyStore file in order to sign the apk, so copy &lt;strong&gt;YourKeyStoreFilename&lt;/strong&gt; in to the folder of &lt;strong&gt;YourAppName.Droid&lt;/strong&gt; project (called &lt;strong&gt;YourKeyStoreLocalFilename&lt;/strong&gt; from now on).&lt;/p&gt;

&lt;p&gt;When we created the apk from the command line, we entered in some passwords, and we obviously can’t save these passwords to a public Git repository. Happily AppVeyor have thought of this, and you can convert passwords in to tokens that can be exposed publically.&lt;/p&gt;

&lt;p&gt;To do this, click your user name in the top right hand corner and then click &lt;em&gt;“Encrypt data”&lt;/em&gt; from the drop down menu. Enter &lt;strong&gt;YourKeyStorePassword&lt;/strong&gt; in to &lt;em&gt;“Value to encrypt”&lt;/em&gt; and click &lt;em&gt;“Encrypt”&lt;/em&gt;. AppVeyor will then display a token which you can use in place of the real value.&lt;/p&gt;

&lt;p&gt;Now that we have everything we need, add an &lt;em&gt;appveyor.yml&lt;/em&gt; file to the root of your repository as below. Note that &lt;strong&gt;YourLocalKeyStoreFilename&lt;/strong&gt; is relative to the csproj file being built (the &lt;strong&gt;YourAppName.Droid&lt;/strong&gt; folder below).&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;keystore-password&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;secure&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;DSwAr4fYt3Q35Sjob5qAN5uj&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# YourPassword for keystore&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;before_build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nuget restore&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;build_script&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;msbuild &quot;/t:SignAndroidPackage&quot; &quot;/p:Configuration=Release&quot; &quot;/p:AndroidKeyStore=true&quot; &quot;/p:AndroidSigningKeyAlias=YourKeyAlias&quot; &quot;/p:AndroidSigningKeyPass=%keystore-password%&quot; &quot;/p:AndroidSigningKeyStore=YourLocalKeyStoreFilename&quot; &quot;/p:AndroidSigningStorePass=%keystore-password%&quot;  &quot;YourAppName.Droid\YourAppName.csproj&quot;&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;artifacts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;YourAppName.Droid\bin\Release\com.yourappname-Signed.apk&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Remember to update &lt;code class=&quot;highlighter-rouge&quot;&gt;android:versionCode&lt;/code&gt; and then push to GitHub. This will trigger a build on AppVeyor. The &lt;code class=&quot;highlighter-rouge&quot;&gt;build_script&lt;/code&gt; section will call msbuild to create the signed and zipaligned apk file, and the &lt;code class=&quot;highlighter-rouge&quot;&gt;artifacts&lt;/code&gt; section will archive the apk file so we can download it later.&lt;/p&gt;

&lt;p&gt;Go to &lt;a href=&quot;https://ci.appveyor.com&quot;&gt;AppVeyor.com&lt;/a&gt;, click on your project, click on &lt;em&gt;“Artifacts”&lt;/em&gt;, download the apk file, and then upload it to google to check that everything has worked properly.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There is a lot to learn to get everything working, and I couldn’t find a single source for all of these things, but having done it once, the process is actually quite simple, and the tools and services involved are generally a pleasure to work with.&lt;/p&gt;

&lt;p&gt;Best regards,&lt;br /&gt;
Cedd Burge&lt;/p&gt;

&lt;p&gt;Follow Cedd on Twitter: &lt;a href=&quot;https://twitter.com/cuddlyburger&quot;&gt;@cuddlyburger&lt;/a&gt;&lt;br /&gt;
Follow AppVeyor on Twitter: &lt;a href=&quot;https://twitter.com/appveyor&quot;&gt;@appveyor&lt;/a&gt;&lt;/p&gt;</content><author><name>Feodor Fitsner</name></author><summary type="html">Introduction</summary></entry><entry><title type="html">AWS Elastic Beanstalk</title><link href="https://www.appveyor.com/blog/2016/11/07/aws-elastic-beanstalk/" rel="alternate" type="text/html" title="AWS Elastic Beanstalk" /><published>2016-11-07T00:00:00+00:00</published><updated>2016-11-07T00:00:00+00:00</updated><id>https://www.appveyor.com/blog/2016/11/07/aws-elastic-beanstalk</id><content type="html" xml:base="https://www.appveyor.com/blog/2016/11/07/aws-elastic-beanstalk/">&lt;p&gt;Appveyor does not support AWS Elastic Beanstalk deployment out of the box right now.
However it can be automated in Appveyor with help of some scripting.
Here is small guide based on &lt;a href=&quot;https://github.com/appveyor/ci/issues/45#issuecomment-165571187&quot;&gt;this support forum discussion&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;In the root folder of your web application create text file named &lt;code class=&quot;highlighter-rouge&quot;&gt;awsdeploy.txt&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Add the following to &lt;code class=&quot;highlighter-rouge&quot;&gt;awsdeploy.txt&lt;/code&gt;:&lt;/p&gt;

    &lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Template = ElasticBeanstalk
Container.ApplicationHealthcheckPath = /healthcheck
&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Add &lt;code class=&quot;highlighter-rouge&quot;&gt;AWSAccessKeyId&lt;/code&gt; as environment variable and &lt;code class=&quot;highlighter-rouge&quot;&gt;AWSSecretKey&lt;/code&gt; as secure environment variable.&lt;/li&gt;
  &lt;li&gt;Set &lt;strong&gt;Package Web Applications for XCopy deployment&lt;/strong&gt; in build stage.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Set the following as a deployment script:&lt;/p&gt;

    &lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$packageweb = $artifacts.values | Where-Object { $_.path -like '*WebApplication1.zip' }
$exe = &quot;C:\Program Files (x86)\AWS Tools\Deployment Tool\awsdeploy.exe&quot;
&amp;amp;$exe -r &quot;-DDeploymentPackage=$($packageweb.path)&quot; &quot;-DEnvironment.Name=MyAppWeb-test123&quot; &quot;-DApplication.Name=MyAppWeb123&quot; &quot;-DRegion=eu-west-1&quot; &quot;-DAWSAccessKey=$env:AWSAccessKeyId&quot; &quot;-DAWSSecretKey=$env:AWSSecretKey&quot; &quot;C:\projects\WebApplication1\awsdeploy.txt&quot;
&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that this script assumes that application was already deployed at least once to Beanstalk, otherwise you need to replace -r switch with -w for single first deployment.&lt;/p&gt;

&lt;p&gt;Here is an example YAML (only relevant parts):&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;AWSAccessKeyId&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;AKIAIODIUCY3ETD6TEST&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;AWSSecretKey&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;secure&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;LEvzbXpiLkWVvswonFHnAYV9ZS6fEFL3wswjTcIQ6ZXC5j1nynd6N0Bs/VFtest&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;publish_wap_xcopy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;deploy_script&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;$packageweb = $artifacts.values | Where-Object { $_.path -like '*WebApplication1.zip' }&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;$exe = &quot;C:\Program Files (x86)\AWS Tools\Deployment Tool\awsdeploy.exe&quot;&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;&amp;amp;$exe -r &quot;-DDeploymentPackage=$($packageweb.path)&quot; &quot;-DEnvironment.Name=MyAppWeb-test123&quot; &quot;-DApplication.Name=MyAppWeb123&quot; &quot;-DRegion=eu-west-1&quot; &quot;-DAWSAccessKey=$env:AWSAccessKeyId&quot; &quot;-DAWSSecretKey=$env:AWSSecretKey&quot; &quot;C:\projects\WebApplication1\awsdeploy.txt&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Here is an example web application folder structure:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Directory of C:\Projects\WebApplication1

09/15/2016  02:48 AM    &amp;lt;DIR&amp;gt;          .
09/15/2016  02:48 AM    &amp;lt;DIR&amp;gt;          ..
07/17/2016  12:34 PM               505 .gitattributes
07/17/2016  12:34 PM             2,858 .gitignore
09/15/2016  02:40 AM                80 awsdeploy.txt
08/30/2016  03:22 PM    &amp;lt;DIR&amp;gt;          WebApplication1
07/21/2016  06:51 PM             1,012 WebApplication1.sln
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;</content><author><name>Feodor Fitsner</name></author><summary type="html">Appveyor does not support AWS Elastic Beanstalk deployment out of the box right now. However it can be automated in Appveyor with help of some scripting. Here is small guide based on this support forum discussion.</summary></entry><entry><title type="html">The new build cache</title><link href="https://www.appveyor.com/blog/2016/09/28/the-new-build-cache/" rel="alternate" type="text/html" title="The new build cache" /><published>2016-09-28T00:00:00+00:00</published><updated>2016-09-28T00:00:00+00:00</updated><id>https://www.appveyor.com/blog/2016/09/28/the-new-build-cache</id><content type="html" xml:base="https://www.appveyor.com/blog/2016/09/28/the-new-build-cache/">&lt;p&gt;AppVeyor runs every build on a clean virtual machine. Virtual machine state is not preserved between builds which means every build downloads sources,
installs NuGet packages, Node.js modules, Ruby gems or pulls dependencies.
&lt;em&gt;Build cache&lt;/em&gt; allows you to preserve contents of selected directories and files between project builds.&lt;/p&gt;

&lt;p&gt;AppVeyor was the first hosted CI to introduce a build cache and over the time it became a very popular build tool and important infrastructure component.
There were some limitations though, such as maximum cache entry size of 500 MB and intermittent save/restore lags due to ever changing networking conditions.&lt;/p&gt;

&lt;p&gt;Increasing requirements from larger customers running builds with “heavy” dependencies made us to re-visit cache architecture and thus the new and updated build cache was born!
The new build cache lives close to build worker VMs, it’s fast and offers virtually unlimited possibilities for scale and has lower update/restore times.&lt;/p&gt;

&lt;h2 id=&quot;cache-size&quot;&gt;Cache size&lt;/h2&gt;

&lt;p&gt;With the introduction of the new cache we are also changing the way it’s metered.&lt;/p&gt;

&lt;p&gt;The total size of build cache is limited per account and depends on the plan:&lt;/p&gt;

&lt;table class=&quot;centered&quot;&gt;
&lt;tr&gt;
    &lt;th&gt;Free&lt;/th&gt;
    &lt;th&gt;Basic&lt;/th&gt;
    &lt;th&gt;Pro&lt;/th&gt;
    &lt;th&gt;Premium&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;1 GB&lt;/td&gt;
    &lt;td&gt;1 GB&lt;/td&gt;
    &lt;td&gt;5 GB&lt;/td&gt;
    &lt;td&gt;20 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;It’s a hard quota which means the build will fail while trying to upload cache item exceeding the quota.
The maximum size of a single cache entry cannot be larger than the size of cache.&lt;/p&gt;

&lt;h2 id=&quot;cache-speed-vs-size&quot;&gt;Cache speed vs size&lt;/h2&gt;

&lt;p&gt;The new cache uses &lt;code class=&quot;highlighter-rouge&quot;&gt;7z&lt;/code&gt; to compress/uncompress files before transferring them to the cache storage.
We chose &lt;code class=&quot;highlighter-rouge&quot;&gt;7z&lt;/code&gt; over built-in .NET compression library because it’s generally faster, produces smaller archives and works with hidden files out-of-the-box.&lt;/p&gt;

&lt;p&gt;While compressing cache item, by default AppVeyor uses &lt;code class=&quot;highlighter-rouge&quot;&gt;7z&lt;/code&gt; with &lt;code class=&quot;highlighter-rouge&quot;&gt;zip&lt;/code&gt; algorithm and compression level &lt;code class=&quot;highlighter-rouge&quot;&gt;1&lt;/code&gt; (“Fastest”) thus producing archive faster, but with larger size (&lt;code class=&quot;highlighter-rouge&quot;&gt;-tzip -mx=1&lt;/code&gt; args).
However, you can change compression behavior of &lt;code class=&quot;highlighter-rouge&quot;&gt;7z&lt;/code&gt; by providing your own command line args in &lt;code class=&quot;highlighter-rouge&quot;&gt;APPVEYOR_CACHE_ENTRY_ZIP_ARGS&lt;/code&gt; environment variable.
For example, to enable &lt;code class=&quot;highlighter-rouge&quot;&gt;LZMA&lt;/code&gt; compression method with the highest possible compression ratio set this variable to &lt;code class=&quot;highlighter-rouge&quot;&gt;-t7z -m0=lzma -mx=9&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;availability&quot;&gt;Availability&lt;/h2&gt;

&lt;p&gt;The new build cache is currently in beta. It’s automatically enabled for all new accounts.&lt;/p&gt;

&lt;p&gt;We are rolling out new cache to existing accounts in batches while observing performance.
If you want participate in beta sooner or noticed any issues with the build cache please
&lt;a href=&quot;mailto:team@appveyor.com&quot;&gt;let us know&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Best regards,&lt;br /&gt;
AppVeyor team&lt;/p&gt;

&lt;p&gt;Follow us on Twitter: &lt;a href=&quot;https://twitter.com/appveyor&quot;&gt;@appveyor&lt;/a&gt;&lt;/p&gt;</content><author><name>Feodor Fitsner</name></author><summary type="html">AppVeyor runs every build on a clean virtual machine. Virtual machine state is not preserved between builds which means every build downloads sources, installs NuGet packages, Node.js modules, Ruby gems or pulls dependencies. Build cache allows you to preserve contents of selected directories and files between project builds.</summary></entry><entry><title type="html">Migrating build environment to RackSpace</title><link href="https://www.appveyor.com/blog/2016/07/16/migration-to-rackspace/" rel="alternate" type="text/html" title="Migrating build environment to RackSpace" /><published>2016-07-16T00:00:00+00:00</published><updated>2016-07-16T00:00:00+00:00</updated><id>https://www.appveyor.com/blog/2016/07/16/migration-to-rackspace</id><content type="html" xml:base="https://www.appveyor.com/blog/2016/07/16/migration-to-rackspace/">&lt;p&gt;Dear customers,&lt;/p&gt;

&lt;p&gt;We have great news! Today we moved all open-source and most private accounts to a new build environment hosted at RackSpace.&lt;/p&gt;

&lt;p&gt;For open-source projects that means their builds will start and run faster and private projects may notice better performance as well.&lt;/p&gt;

&lt;p&gt;Virtual machines in the new environment have 2 CPU cores and up to 4 GB of RAM. The new public IP address for that environment is &lt;code class=&quot;highlighter-rouge&quot;&gt;74.205.54.20&lt;/code&gt; - you may need to update your firewalls.&lt;/p&gt;

&lt;p&gt;We are still going to maintain Google Compute Engine (GCE) environment for selected accounts and as a backup build cloud.
If your private builds were previously running on GCE they will remain there.&lt;/p&gt;

&lt;p&gt;Some open-source projects may experience issues while building on a new environment.
Due to implementation differences between GCE and Hyper-V platforms we have separate build worker images for GCE and Hyper-V environments, so there might be minor discrepancies in installed software.
Please report any issues you notice - your help with fixing those issues is much appreciated.&lt;/p&gt;

&lt;p&gt;We have a good reason for this move as some customers already reported 10x performance increase!&lt;/p&gt;

&lt;p&gt;We would love to hear your feedback!&lt;/p&gt;

&lt;p&gt;Best regards,&lt;br /&gt;
AppVeyor team&lt;/p&gt;

&lt;p&gt;Follow us on Twitter: &lt;a href=&quot;https://twitter.com/appveyor&quot;&gt;@appveyor&lt;/a&gt;&lt;/p&gt;</content><author><name>Feodor Fitsner</name></author><summary type="html">Dear customers,</summary></entry><entry><title type="html">Deployment projects</title><link href="https://www.appveyor.com/blog/2015/11/04/deployment-projects/" rel="alternate" type="text/html" title="Deployment projects" /><published>2015-11-04T00:00:00+00:00</published><updated>2015-11-04T00:00:00+00:00</updated><id>https://www.appveyor.com/blog/2015/11/04/deployment-projects</id><content type="html" xml:base="https://www.appveyor.com/blog/2015/11/04/deployment-projects/">&lt;p&gt;Sometimes your deployment requirements cannot fit into AppVeyor built-in deployment providers such as FTP, Web Deploy, S3 and others, for example, you are deploying to Elastic Beanstalk, or you have to recycle application pool during the deployment.&lt;/p&gt;

&lt;p&gt;You can write a script doing custom deployment job, however this script can be run only on build worker VM during the build. “Environments” do not support custom scripts and there is no “Script” provider. This is because “Environment” deployments run on a shared background worker severs where potentially insecure custom scripting is not allowed.&lt;/p&gt;

&lt;p&gt;This article demonstrates how you can simulate “Script” environment with regular builds and deploy project artifacts to any environment with your own custom script.&lt;/p&gt;

&lt;h2 id=&quot;solution-overview&quot;&gt;Solution overview&lt;/h2&gt;

&lt;p&gt;The basic idea is having two AppVeyor projects:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Main project&lt;/strong&gt; - this is your main project running tests and &lt;em&gt;producing artifacts&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Deployment project&lt;/strong&gt; - helper project &lt;em&gt;downloading artifacts&lt;/em&gt; from specific build of “Main project” and deploying them with your custom script. Here, to “deploy” the build of “Main project” you could either manually run new build of deployment project from UI or use &lt;a href=&quot;/docs/build-worker-api#start-new-build&quot;&gt;AppVeyor API&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;deployment-project&quot;&gt;Deployment project&lt;/h2&gt;

&lt;p&gt;The “core” of deployment project is &lt;a href=&quot;https://github.com/appveyor/ci/blob/master/scripts/deploy.ps1&quot;&gt;PowerShell script&lt;/a&gt; downloading artifacts. The script uses AppVeyor API to find specific build and download its artifacts. Artifacts are downloaded to the root of build directory (&lt;code class=&quot;highlighter-rouge&quot;&gt;%APPVEYOR_BUILD_FOLDER%&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The following environment variables must be set for script to work:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;api_token&lt;/code&gt; - AppVeyor REST API authentication token. Can be found/generated on &lt;a href=&quot;https://ci.appveyor.com/api-token&quot;&gt;this page&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;deploy_project&lt;/code&gt; - project slug to download artifacts from. Project slug can be seen in the project URL.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;deploy_version&lt;/code&gt; - build version to deploy. If not specified artifacts from the most recent version will be downloaded.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;deploy_artifact&lt;/code&gt; - file name or deployment name of artifact to download. If not specified all artifacts will be downloaded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These environment variables can be set on &lt;em&gt;Environment&lt;/em&gt; tab of deployment project settings or in &lt;code class=&quot;highlighter-rouge&quot;&gt;appveyor.yml&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;api_token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;secure&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ABC123==&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;deploy_project&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;my-web&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;deploy_version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# download artifacts from latest build if no version specified&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;deploy_artifact&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;# download all artifacts if empty&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;To download artifacts add the following PS script into “Before deploy” section of your project settings or &lt;code class=&quot;highlighter-rouge&quot;&gt;before_deploy&lt;/code&gt; scripts of &lt;code class=&quot;highlighter-rouge&quot;&gt;appveyor.yml&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;before_deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/deploy.ps1'))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Your own deployment logic can be put under &lt;code class=&quot;highlighter-rouge&quot;&gt;deploy_script&lt;/code&gt; section, for example:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;deploy_script&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;command stopping app pool&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;C:\Program&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Files&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;(x86)\IIS\Microsoft&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Deploy&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;V3\msdeploy.exe&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-verb:sync&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-source:package=&quot;%webdeploy_package%&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-dest:auto,ComputerName=&quot;%webdeploy_server%&quot;,UserName=&quot;%webdeploy_username%&quot;,Password=&quot;%webdeploy_password%&quot;,AuthType=&quot;Basic&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-setParam:&quot;IIS&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Application&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Name&quot;=&quot;%webdeploy_site%&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-allowUntrusted'&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;command starting app pool&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Add these to disable automatic build and test phases:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;off&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;off&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Setup notifications if required:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;notifications&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;provider_1&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Complete &lt;code class=&quot;highlighter-rouge&quot;&gt;appveyor.yml&lt;/code&gt; example:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# AppVeyor API token for your account, project, version and artifact(s) to download&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;api_token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;secure&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ABC123==&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;deploy_project&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;my-web&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;deploy_version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# download artifacts from latest build if no version specified&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;deploy_artifact&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;# download all artifacts if empty&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# deployment-specific settings&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# we are going to deploy using Web Deploy, so...&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;webdeploy_package&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%appveyor_build_folder%\MyWebApp.zip'&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;webdeploy_server&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;https://test.scm.azurewebsites.net:443/msdeploy.axd?site=test&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;webdeploy_site&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;test&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;webdeploy_username&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$test&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;webdeploy_password&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;secure&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;AAABBBCCC123==&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# download project artifacts&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;before_deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/deploy.ps1'))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# here is your own custom deployment code&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;deploy_script&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;C:\Program&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Files&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;(x86)\IIS\Microsoft&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Deploy&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;V3\msdeploy.exe&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-verb:sync&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-source:package=&quot;%webdeploy_package%&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-dest:auto,ComputerName=&quot;%webdeploy_server%&quot;,UserName=&quot;%webdeploy_username%&quot;,Password=&quot;%webdeploy_password%&quot;,AuthType=&quot;Basic&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-setParam:&quot;IIS&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Application&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Name&quot;=&quot;%webdeploy_site%&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-allowUntrusted'&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# notifications&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;notifications&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;provider_1&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# disable build and test pahses&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;off&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;off&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;deployyml&quot;&gt;deploy.yml&lt;/h2&gt;

&lt;p&gt;If main and deployment projects share the same repository (most probably they do) you can put YAML deployment settings to a separate &lt;code class=&quot;highlighter-rouge&quot;&gt;deploy.yml&lt;/code&gt; file, next to &lt;code class=&quot;highlighter-rouge&quot;&gt;appveyor.yml&lt;/code&gt; and then set “Custom configuration .yml file name” on General tab to &lt;code class=&quot;highlighter-rouge&quot;&gt;deploy.yml&lt;/code&gt;. To disable automatic triggering of deployment project on webhook you can either remove its webhook from repository or set branch filter to some non-existent branch, for example:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;only&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;deployment-project&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;main-project&quot;&gt;Main project&lt;/h2&gt;

&lt;p&gt;Main project is the project creating application packages and uploading them to build artifacts. With artifacts in place you can call deployment project (either manually or via API) to download and deploy artifacts.&lt;/p&gt;

&lt;p&gt;To start a new build of deployment project during the build use &lt;a href=&quot;/docs/build-worker-api#start-new-build&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;Start-AppveyorBuild&lt;/code&gt;&lt;/a&gt; cmdlet:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;api_token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;secure&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ABC123==&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;deploy_script&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Start-AppveyorBuild -ApiKey $env:api_token -ProjectSlug deploy-project -EnvironmentVariables @{ &quot;deploy_version&quot; = $env:appveyor_build_version }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;p&gt;Follow us on Twitter: &lt;a href=&quot;https://twitter.com/appveyor&quot;&gt;@appveyor&lt;/a&gt;&lt;/p&gt;</content><author><name>Feodor Fitsner</name></author><summary type="html">Sometimes your deployment requirements cannot fit into AppVeyor built-in deployment providers such as FTP, Web Deploy, S3 and others, for example, you are deploying to Elastic Beanstalk, or you have to recycle application pool during the deployment.</summary></entry><entry><title type="html">Visual Studio 2015 RTM on Pro environment</title><link href="https://www.appveyor.com/blog/2015/08/02/visual-studio-2015-rtm/" rel="alternate" type="text/html" title="Visual Studio 2015 RTM on Pro environment" /><published>2015-08-02T00:00:00+00:00</published><updated>2015-08-02T00:00:00+00:00</updated><id>https://www.appveyor.com/blog/2015/08/02/visual-studio-2015-rtm</id><content type="html" xml:base="https://www.appveyor.com/blog/2015/08/02/visual-studio-2015-rtm/">&lt;p&gt;Great news for AppVeyor customers! We’ve finally managed to run &lt;code class=&quot;highlighter-rouge&quot;&gt;Visual Studio 2015&lt;/code&gt; image on Pro environment!&lt;/p&gt;

&lt;p&gt;If you are on a paid plan use &lt;code class=&quot;highlighter-rouge&quot;&gt;Visual Studio 2015&lt;/code&gt; image (“OS” setting on Environment tab of project settings or &lt;code class=&quot;highlighter-rouge&quot;&gt;os: Visual Studio 2015&lt;/code&gt; in &lt;code class=&quot;highlighter-rouge&quot;&gt;appveyor.yml&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;It still takes around 40-50 seconds before build starts - this is the time required to boot up build worker VM with Visual Studio 2015 image. But everything is going on Pro environment and build start time is quite predictable there. We hope it’s acceptable trade-off between performance and convenience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Those customer accounts that were moved to a “new” faster OSS environment where Visual Studio 2015 is installed on build workers by default can be moved back to Pro environment, so make sure you switch your builds to use &lt;code class=&quot;highlighter-rouge&quot;&gt;Visual Studio 2015&lt;/code&gt; image.&lt;/strong&gt;&lt;/p&gt;</content><author><name>Feodor Fitsner</name></author><summary type="html">Great news for AppVeyor customers! We’ve finally managed to run Visual Studio 2015 image on Pro environment!</summary></entry><entry><title type="html">How AppVeyor Helps Snipcart Automate Product Development &amp;amp; Deployment</title><link href="https://www.appveyor.com/blog/2015/07/30/how-appveyor-helps-snipcart-automate-product-development-and-deployment/" rel="alternate" type="text/html" title="How AppVeyor Helps Snipcart Automate Product Development &amp; Deployment" /><published>2015-07-30T00:00:00+00:00</published><updated>2015-07-30T00:00:00+00:00</updated><id>https://www.appveyor.com/blog/2015/07/30/how-appveyor-helps-snipcart-automate-product-development-and-deployment</id><content type="html" xml:base="https://www.appveyor.com/blog/2015/07/30/how-appveyor-helps-snipcart-automate-product-development-and-deployment/">&lt;p&gt;&lt;em&gt;This is a guest blog post from Charles Ouellet of &lt;a href=&quot;https://snipcart.com&quot;&gt;Snipcart&lt;/a&gt;. Charles is a co-founder and lead engineer at &lt;a href=&quot;https://snipcart.com&quot;&gt;Snipcart&lt;/a&gt;, a solution empowering developers to turn any website into a customizable e-commerce platform. He likes code, scotch, and colourful socks. You can follow him on &lt;a href=&quot;https://twitter.com/couellet&quot;&gt;Twitter&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;When we launched our developer-centric e-commerce platform, finding a premium cloud-based continuous integration solution was a top priority. We used Jenkins at first, and, while we liked it, we were also looking forward to handling those operations directly in the cloud. For months, we kept our eyes and ears opened, searching for such a solution as we kept developing our product and growing our business.&lt;/p&gt;

&lt;p&gt;A few months ago, I stumbled upon AppVeyor while exploring the Tweetosphere one night. Upon skimming through their home page and documentation, I quickly realized this was exactly what our team and product needed. Since Snipcart’s API is built on top of &lt;strong&gt;ASP.NET Web API&lt;/strong&gt;, we needed to find a web-based solution that was supporting &lt;strong&gt;.NET&lt;/strong&gt;. And that’s exactly what I found that night with AppVeyor.&lt;/p&gt;

&lt;p&gt;The day after that, we spent maybe an hour setting it up, and it worked like a real charm.&lt;/p&gt;

&lt;h2 id=&quot;how-we-use-appveyor-exactly-for-our-snipcart-application&quot;&gt;How we use AppVeyor exactly for our Snipcart application&lt;/h2&gt;

&lt;p&gt;One of AppVeyor’s killer feature is that it gives you the ability to configure your whole build with a &lt;strong&gt;YAML&lt;/strong&gt; file. This allows us to have the build configuration in our source control, making it very easy to maintain.&lt;/p&gt;

&lt;p&gt;To give you a little context: Snipcart is basically a web application, a worker process that processes queued events, and two JavaScript applications that consume our API. Let’s get more specific with each of these components.&lt;/p&gt;

&lt;h3 id=&quot;web-application&quot;&gt;Web application&lt;/h3&gt;

&lt;p&gt;Like I mentioned earlier, our web application is an ASP.NET Web API. Once the build is completed and all our tests have passed (yep, AppVeyor supports running unit tests too!), we deploy our application to our &lt;a href=&quot;https://azure.microsoft.com/en-us/&quot;&gt;Azure&lt;/a&gt; web apps via WebDeploy. The build process and the deployment process are all configured in the YAML file. We just push to our &lt;code class=&quot;highlighter-rouge&quot;&gt;production&lt;/code&gt; git branch, and it triggers a build and a deployment.&lt;/p&gt;

&lt;p&gt;Once it’s deployed, Azure takes care of spawning multiple instances when needed.&lt;/p&gt;

&lt;h3 id=&quot;worker&quot;&gt;Worker&lt;/h3&gt;

&lt;p&gt;Our worker is a Cloud Service hosted on Azure. Once the build is completed, it is automatically deployed by AppVeyor as well, which supports a wide range of deployment processes, including Cloud Services. Before making the switch to AppVeyor, this was a pain for us because our developers needed to deploy the worker through Visual Studio directly; it wasn’t automated, which could have led to errors.&lt;/p&gt;

&lt;h3 id=&quot;javascript-applications&quot;&gt;JavaScript applications&lt;/h3&gt;

&lt;p&gt;All of our client applications are single page apps built on top of Backbone.js. We use &lt;a href=&quot;http://webpack.github.io/&quot;&gt;webpack&lt;/a&gt; to bundle our application. We have a &lt;a href=&quot;http://gulpjs.com/&quot;&gt;gulp&lt;/a&gt; task that does all the job, bundling the numerous JavaScript files into a single file and uglifying the output. AppVeyor also allows us to run this gulp task inside our build process, which is pretty amazing. It doesn’t only allow to build .NET applications: you can use npm, gem, and any NodeJS modules.&lt;/p&gt;

&lt;p&gt;We also have unit tests for these two applications; we run those in AppVeyor as well, using a gulp task.&lt;/p&gt;

&lt;h3 id=&quot;cdn&quot;&gt;CDN&lt;/h3&gt;

&lt;p&gt;Once our JavaScript applications are built, we automatically push all of our assets on an Azure Blob Storage container. This is another deployment option provided by AppVeyor. We upload all of the static files that are included on our customers websites, such as our default stylesheet, our &lt;code class=&quot;highlighter-rouge&quot;&gt;snipcart.js&lt;/code&gt; file and our custom web fonts.&lt;/p&gt;

&lt;p&gt;On top of the storage, we are also using &lt;a href=&quot;https://www.keycdn.com/&quot;&gt;KeyCDN&lt;/a&gt;. We have a pull zone that fetches the content of our Blob storage. KeyCDN takes care of the caching and everything needed to make sure our static files are served as fast as possible. We discuss it further in &lt;a href=&quot;https://snipcart.com/blog/snipcart-infrastructure-upgrade-new-cdn&quot;&gt;this blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When we make changes to &lt;code class=&quot;highlighter-rouge&quot;&gt;snipcart.js&lt;/code&gt; or to any other static file that is cached by the CDN, we need to invalidate the cache. If we don’t, customers would need to hit refresh multiple times, which would not make any sense. With AppVeyor, we make an HTTP request to the KeyCDN API to purge our cache zone after the Blob storage has been updated. By doing so, we are sure our customers always have the latest version of our static files.&lt;/p&gt;

&lt;h2 id=&quot;conclusion-we-friggin-love-appveyor&quot;&gt;Conclusion? We friggin’ love AppVeyor&lt;/h2&gt;

&lt;p&gt;Since we automated everything with AppVeyor, we are &lt;em&gt;much more&lt;/em&gt; confident with our deployments. Sometimes, we even start a build and go play a few ping pong games at the office while it deploys. We know it’ll just work. With our solid test suite in place, we trust AppVeyor won’t deploy something that is broken.&lt;/p&gt;

&lt;p&gt;As I finish writing this post, I realize that I don’t see how we could work without this amazing tool today. It’s a crucial part of our product development process.&lt;/p&gt;</content><author><name>Feodor Fitsner</name></author><summary type="html">This is a guest blog post from Charles Ouellet of Snipcart. Charles is a co-founder and lead engineer at Snipcart, a solution empowering developers to turn any website into a customizable e-commerce platform. He likes code, scotch, and colourful socks. You can follow him on Twitter.</summary></entry></feed>