<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Foci Solutions</title>
    <description>The latest articles on DEV Community by Foci Solutions (@focisolutions).</description>
    <link>https://dev.to/focisolutions</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F2228%2F37a1133c-96f4-4182-b9ec-8f5ab8f6dbb7.png</url>
      <title>DEV Community: Foci Solutions</title>
      <link>https://dev.to/focisolutions</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/focisolutions"/>
    <language>en</language>
    <item>
      <title>Increasing Velocity the Right Way and the Wrong Way</title>
      <dc:creator>Daniel McCrady</dc:creator>
      <pubDate>Thu, 23 Feb 2023 19:37:57 +0000</pubDate>
      <link>https://dev.to/focisolutions/increasing-velocity-the-right-way-and-the-wrong-way-532h</link>
      <guid>https://dev.to/focisolutions/increasing-velocity-the-right-way-and-the-wrong-way-532h</guid>
      <description>&lt;p&gt;We love agile development at Foci Solutions. One of our main offerings is to coach clients on how to use agile to deliver quality products to their customers. Along this journey we often get asked the question "How do we increase velocity". This question is complex and often times misunderstood.&lt;/p&gt;

&lt;p&gt;Velocity is a metric that is critically important, and yet can be fairly arbitrary. What I mean by that is velocity is used to drive priority decisions, estimate the time a feature will take, and is used to measure the business value that a team is delivering. At the same time velocity will be different for every team, has a variance of uncertainty built into it, and can take multiple sprints for velocity to even have a use.&lt;/p&gt;

&lt;p&gt;Its critical then to understand what velocity is and be aware of how velocity can move. &lt;a href="https://www.scrum.org/resources/blog/agile-metrics-velocity#:~:text=Velocity%20is%20an%20indication%20of,Velocity%20or%20a%20Bad%20Velocity."&gt;scurm.org&lt;/a&gt; describes velocity as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;an indication of the average amount of Product Backlog turned into an Increment of product during a Sprint by a Scrum Team, tracked by the Development Team for use within the Scrum Team. There is no such thing as a Good Velocity or a Bad Velocity. Remember, it is based on relative estimations&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What this means is that velocity is a number used by the development team to track how much value they are delivering to the client. What is important to take from this is that it's tracked by the development team, for the scrum team. This means that the development team has sole responsibility to how the velocity moves inside the team.&lt;/p&gt;

&lt;p&gt;As a manager or product owner if you only care about raising velocity at any and all costs developers will achieve this in the following ways&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Developers can begin to sand bag estimates during backlog grooming. What used to be a 2 point story is now an 8 point story.&lt;/li&gt;
&lt;li&gt;Developers start to cut corners. Maybe their unit tests aren't as robust, There error handling doesn't handle as many errors, Or they don't consider edge cases as much.&lt;/li&gt;
&lt;li&gt;Developers start to work longer hours, take less breaks, and eventually burn out.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of these scenarios cause a bump in velocity, however the outcomes of these scenarios are often disastrous. By sand bagging estimates, developers stop feeling like their input matters, no extra value is actually being delivered with the increased velocity which makes the metric significantly less useful. If the developers begin to cut corners it will become hard to know when software is ready, increase the bug rate, increase technical debt, and make software more expensive to deliver. Worst of all if developers start to work longer hours then the velocity bump is truly temporary. The velocity will drop as developers stop having as much passion for the code they develop and the work slowly takes a toll on their mental state. This continues until inevitably the developer crashes and decides to look beyond the company to change jobs.&lt;/p&gt;

&lt;p&gt;So how do we responsibly increase velocity without incurring negative side effects? We can find a great example of this inside of UPS. An optimization occurred at UPS where they recalculated all of their trucks routes to eliminate as many &lt;a href="https://www.cnn.com/2017/02/16/world/ups-trucks-no-left-turns"&gt;left hand turns&lt;/a&gt; as possible. The effects of this decision were staggering. It's estimated that this decision saved UPS over 100 million gallons of fuel every year. This kind of decision is the true way to increase velocity, by looking into the way we deliver value and doing it differently. We need to find things that can be done to increase velocity and at the same time increase value to customers now and forever. We can do this&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Through automation&lt;/li&gt;
&lt;li&gt;Through process optimization&lt;/li&gt;
&lt;li&gt;Through planning&lt;/li&gt;
&lt;li&gt;Through collaboration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can spend some velocity now to increase velocity tomorrow by working to automate work developers are doing on a regular basis. Add more automation to CI/CD pipelines so developers can spend less time completing Pull Requests. Look to automate complex deployments so that a developer doesn't need to do it. Automate complicated testing plans so the a QA team can spend their time elsewhere.&lt;/p&gt;

&lt;p&gt;Look to the process and find ways to reduce the process burden on the peoples time. This is going to vary widely based on the process you and your team has, however burdensome processes like Change Review Boards, Approval Gates, and long drawn out testing phases are often good places to look. This doesn't mean you need to make deployments riskier, however your team may need to introduce different tools, look to automation, or think outside the box to make the process less restrictive in delivering value.&lt;/p&gt;

&lt;p&gt;Often times agile software development is often tied to doing now and thinking as we go. Taking time to come up with a solid short term plan can help in finding blockers earlier, and ensuring that the team is on the same page.&lt;/p&gt;

&lt;p&gt;Everyone needs to come to the table and be willing to change how they work today in order to find velocity. Product Owners, QA, Managers, and even executives should be available for these discussions. Collaboration is critical to finding the largest velocity gains.&lt;/p&gt;

&lt;p&gt;I'm sure there are other areas in your company that velocity can be found as well. Just ensure that the change is long lasting and real. Make sure the you are gaining velocity the right way.&lt;/p&gt;

</description>
      <category>agile</category>
      <category>productivity</category>
    </item>
    <item>
      <title>What is Lean Inception?</title>
      <dc:creator>Joe Pound</dc:creator>
      <pubDate>Thu, 16 Feb 2023 16:35:37 +0000</pubDate>
      <link>https://dev.to/focisolutions/what-is-lean-inception-5gbn</link>
      <guid>https://dev.to/focisolutions/what-is-lean-inception-5gbn</guid>
      <description>&lt;p&gt;&lt;em&gt;This article is the first in a series of articles about our experience with Lean Inception. Be sure to check out our other posts.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Lean Inception is the combination of Design Thinking and Lean StartUp to decide the Minimum Viable Product (MVP). It is a workshop divided into several steps and activities that will guide the team in building the ideal product” (Lean Inception, &lt;a href="http://caroli.org/en/livro/lean-inception-how-to-align-people-and-build-the-right-product/" rel="noopener noreferrer"&gt;caroli.org/en/livro/lean-inception-how-to-align-people-and-build-the-right-product/&lt;/a&gt;). It is the creation of Paulo Caroli, a software engineer who wanted to find a way to condense a four-week inception program run by Thoughtworks. What he produced was a methodology, which included a series of activities executed over one week that allows a team to set the direction and scope of a product at the outset.&lt;/p&gt;

&lt;p&gt;In the years since its creation, the Lean Inception methodology has undergone various modifications, including adapting in-person exercises to a Miro template for remote teams. More details about the process of &lt;a href="https://caroli.org/en/livro/lean-inception-how-to-align-people-and-build-the-right-product/" rel="noopener noreferrer"&gt;Lean Inception&lt;/a&gt; can be found at Paulo Caroli’s website.&lt;/p&gt;

&lt;p&gt;At Foci, we have been running Lean Inception for our own internal R&amp;amp;D product to improve our overall understanding of the Lean Inception process—and ultimately using this process to help our clients through better product development, and help our readers with their own application of Lean Inception by sharing our experiences.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.focisolutions.com/wp-content/uploads/2023/02/fortytwo-67kCaNkqVwI-unsplash-scaled.jpg" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fift3j4jydhohu4xh3ybg.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Lean Startup
&lt;/h3&gt;

&lt;p&gt;Before Lean Inception, there was &lt;a href="http://theleanstartup.com/" rel="noopener noreferrer"&gt;&lt;em&gt;The Lean Startup&lt;/em&gt; by Eric Ries&lt;/a&gt;. In &lt;em&gt;The Lean Startup&lt;/em&gt;, Ries describes the Build–Measure–Learn methodology. This methodology assumes your products are validated frequently during development with actual customers, enabling you to understand what holds the most value for them and, ultimately, what will best meet their needs. Caroli designed Lean Inception to find the first increment that could be built in an effective Measure and Learn cycle. &lt;/p&gt;

&lt;h3&gt;
  
  
  MVP
&lt;/h3&gt;

&lt;p&gt;For Caroli, this first increment was the Minimum Viable Product (MVP). MVP has become a loaded term in software development (as we’ll discuss in our future posts), but Caroli seeks to emphasize that an MVP should be developed only just enough to allow you to test your product hypothesis.&lt;/p&gt;

&lt;p&gt;He uses the example of EasyTaxi, a Brazilian business that allows users to request taxis online. To verify if people would actually use such a service, the original application was a simple webpage that would send an email to the EasyTaxi founder at the user’s request, at which point the founder would call a taxi for the user. While very rudimentary, it demonstrated to the founders that their project was in demand and had the potential to become a viable product.&lt;/p&gt;

&lt;p&gt;Caroli emphasizes that the MVP is not a complete layer (like building all your infrastructure first, for example); he describes it as a cupcake—instead of a complete cake with icing (the UX ‘wow factor’), it has been scaled down to a manageable size. This approach is also commonly referred to as a ‘vertical slice’, referencing slicing a cake through all its layers, top to bottom, rather than one layer at a time. As we will see, these core concepts are essential to the success of Lean Inception activities. There are many times when Lean Inception can easily get sidetracked, at which point returning to these core concepts can help realign the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Involved?
&lt;/h2&gt;

&lt;p&gt;Over a period of one week, our team went through a series of activities that established the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product vision&lt;/li&gt;
&lt;li&gt;What the product does and does not do&lt;/li&gt;
&lt;li&gt;Initial product goals&lt;/li&gt;
&lt;li&gt;Personas&lt;/li&gt;
&lt;li&gt;Prioritization of product goals by persona&lt;/li&gt;
&lt;li&gt;User journeys&lt;/li&gt;
&lt;li&gt;Feature brainstorming&lt;/li&gt;
&lt;li&gt;Initial technical, business, and UX review of features&lt;/li&gt;
&lt;li&gt;Sequence and iterations for features to be delivered as part of the MVP.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why We Did It
&lt;/h2&gt;

&lt;p&gt;As consultants, we have experience working through tough challenges across multiple and varied projects. Clients often assign a series of requirements or tasks to engineering teams; however, these teams will struggle to deliver the right product when they cannot answer basic product questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What are the vision and goals for the product? &lt;/li&gt;
&lt;li&gt;What are the stakeholder expectations behind these requirements?&lt;/li&gt;
&lt;li&gt;What kind of users are you targeting? &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many clients have difficulty documenting these answers and even those who do document their work often do not share it with the teams building the product. According to Asana, the “2021 Anatomy of Work Index, which surveyed over 10,000 knowledge workers, found that less than half of all employees understood how their day-to-day work contributed to broader goals.” (&lt;a href="https://asana.com/resources/why-projects-fail" rel="noopener noreferrer"&gt;Why Projects Fail&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;At Foci, when we first heard of Lean Inception, we saw it as an opportunity to coach our clients through some of the most important discovery processes in a project lifecycle. Lean Inception would ensure that their whole team has a clear shared understanding and vision of the product, resulting in more collaboration, less conflict, and greater value earlier in product delivery. &lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Next?
&lt;/h2&gt;

&lt;p&gt;Stay tuned for our following blog posts. There we will explain our own experience running Lean Inception on an internal project as well as some lessons we learned and suggestions on how you can improve your first Lean Inception.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://www.focisolutions.com/2023/02/what-is-lean-inception/" rel="noopener noreferrer"&gt;What is Lean Inception?&lt;/a&gt; appeared first on &lt;a href="https://www.focisolutions.com" rel="noopener noreferrer"&gt;Foci Solutions&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>peopleandculture</category>
      <category>ideation</category>
      <category>kickoff</category>
      <category>leaninception</category>
    </item>
    <item>
      <title>Nullable reference types in C# 8.0</title>
      <dc:creator>Alex Yorke</dc:creator>
      <pubDate>Mon, 12 Apr 2021 15:29:42 +0000</pubDate>
      <link>https://dev.to/focisolutions/nullable-reference-types-in-c-8-0-17kd</link>
      <guid>https://dev.to/focisolutions/nullable-reference-types-in-c-8-0-17kd</guid>
      <description>&lt;p&gt;Nullable reference types are a new feature in C# 8.0. They allow you to spot places where you’re unintentionally dereferencing a null value (or not checking it.) You may have seen these types of checks being performed before C# 8.0 in &lt;a href="https://www.jetbrains.com/help/resharper/Code_Analysis__Value_Analysis.html"&gt;ReSharper&lt;/a&gt;’s Value and Nullability Analysis checks.&lt;/p&gt;

&lt;p&gt;These are potential sources for bugs, and can cause application crashes and NullReferenceExceptions. C# 8.0’s compiler supports nullable types, and can warn you when you are dereferencing a null value without first checking if it is null if the type ends with a “?”; consequently, any type without a “?” added to the end is a non-nullable reference type. For everything else, it’ll use flow analysis. In this article, I will explain how you can use nullable reference types to help make your code less prone to NullReferenceExceptions, and to make it more consumable by other APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Null attributes
&lt;/h3&gt;

&lt;p&gt;There are also a few attributes you can use to declare the arguments and return values for null-related code. These attributes extend the nullable types and allows the compiler to make more judgements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.allownullattribute?view=net-5.0"&gt;AllowNull&lt;/a&gt;, the argument could be null, even if the type doesn’t allow it. For example, we are setting a string inside of a getter/setter to null. In C# 8.0, strings are known as a nullable “string!”, and so the AllowNull annotation allows setting it to null, even though the string that we return isn’t null (for example, we do a comparison check and set it to a default value if null.) This is a precondition.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.disallownullattribute?view=net-5.0"&gt;DisallowNull&lt;/a&gt;, the argument isn’t null, even if the type allows it. This is a precondition.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.maybenullattribute?view=net-5.0"&gt;MaybeNull&lt;/a&gt;, the output might be null. So, the callers have to check if the output is null. This is a postcondition.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.notnullattribute?view=net-5.0"&gt;NotNull&lt;/a&gt;, which means that the input wasn’t null when the call returns, even if the type allows it to be null. This is a postcondition.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.notnullwhenattribute?view=net-5.0"&gt;NotNullWhen&lt;/a&gt;, which is a post condition that asserts the argument isn’t null depending on the boolean value of the return of the method. For example, say my method is bool MethodA([MaybeNullWhen(false) out string outVal], and it returns true. Then outVal isn’t null. If it returns false, then outVal could be null.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devblogs.microsoft.com/dotnet/try-out-nullable-reference-types/"&gt;MaybeNullWhen&lt;/a&gt;, “signifies that a parameter could be null even if the type disallows it, conditional on the bool returned value of the method.” This means that if I were to annotate an argument with [MaybeNullWhen(false)], then the output (signified through the “out” keyword) could be null if the method returns false. This is a postcondition.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devblogs.microsoft.com/dotnet/try-out-nullable-reference-types/"&gt;NotNullIfNotNull&lt;/a&gt;, “signifies that any output value is non-null conditional on the nullability of a given parameter whose name is specified”. What this means is that if I pass in a “string?” the output’s nullability is true, and vice-versa. This is a postcondition.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are some other conditions, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.doesnotreturnattribute"&gt;DoesNotReturn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.doesnotreturnifattribute"&gt;DoesNotReturnIf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.membernotnullattribute"&gt;MemberNotNull&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.membernotnullwhenattribute"&gt;MemberNotNullWhen&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why are these checks important?
&lt;/h3&gt;

&lt;p&gt;These checks help ensure the safety of the code you write, and also allows other consumers of your library to know when to use null checks (and where to omit them.) While it is possible to null check every call that is null-ambiguous, it can be error-prone because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Too many null checks clutter the code and wastes time trying to create error handlers to safely stop program execution.&lt;/li&gt;
&lt;li&gt;You might forget to write a null check, and because there are null checks for everything else, it is unclear which method is missing a null check.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an excellent example from &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis"&gt;Microsoft’s docs&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;string? userInput = GetUserInput();if (!string.IsNullOrEmpty(userInput)){   int messageLength = userInput.Length; // no null check needed.}// null check needed on userInput here.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this case, they annotated the string.IsNullOrEmpty method with [NotNullWhen(false)], which means that if the method returns false, then no null checks are needed. The annotation can be read as “it’s not null when the output is false”. These higher-level logical statements help the compiler make inferences about the code. While this sounds like a trivial comparison to do through the compiler only without annotations, it’s actually a very complex research topic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.microsoft.com/en-us/research/publication/pex-white-box-test-generation-for-net/"&gt;Microsoft Pex&lt;/a&gt;, a &lt;a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2008/04/fulltext.pdf"&gt;“White-Box test generation for .NET”&lt;/a&gt; is a program that analyses every possible path through your program symbolically to discover edge cases and missing conditionals that can cause NullReferenceExceptions (and more.) While it is extremely interesting, it’s a bit outside the scope of this post.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I use them?
&lt;/h3&gt;

&lt;p&gt;If you are upgrading a legacy project, Microsoft recommends that you don’t turn it on for &lt;em&gt;everything&lt;/em&gt; at once, but there might be a lot of warnings and it could be overwhelming. This is especially true if your team treats warnings as errors (a compiler option), as development would have to cease for several days to fix the null warnings. This isn’t a great strategy, and so incrementally enabling null checks helps prevent an explosion of warnings that could go ignored if not addressed promptly.&lt;/p&gt;

&lt;p&gt;There are a few ways you can prioritize adding null annotations for the first set of checks. One of the ways is to start with the very small, straightforward methods. If the method is easy to reason about, then adding the null annotations can be easier to do, and if the small method is used throughout the code many times, then it can help infer what null checks are and are not needed in larger methods. While there are potentially infinite many ways to prioritize null checks, this approach can be helpful if you are not familiar with null checking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Null reference types can help make your code more maintenance friendly and easier to spot bugs, as nulls can cause unexpected problems and application crashes. While nullable reference types aren’t a panacea (as it is possible to ignore the warnings), they can help provide the compiler with extra information. This extra information can be used to deduce errors and find logic errors. Gradually implementing nullable reference types helps find potential errors without overwhelming the developers with warnings. If there are too many warnings, they could be disregarded, further causing more problems down the line.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://focisolutions.com/2021/04/nullable-reference-types-in-c-8-0/"&gt;Nullable reference types in C# 8.0&lt;/a&gt; appeared first on &lt;a href="https://focisolutions.com"&gt;Foci Solutions&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>csharp</category>
    </item>
    <item>
      <title>K8s in KIND</title>
      <dc:creator>Daniel McCrady</dc:creator>
      <pubDate>Thu, 01 Apr 2021 02:40:20 +0000</pubDate>
      <link>https://dev.to/focisolutions/k8s-in-kind-1c</link>
      <guid>https://dev.to/focisolutions/k8s-in-kind-1c</guid>
      <description>&lt;p&gt;I have been playing around with Kubernetes lately and was looking for an easy way to get a cluster going locally. I came across &lt;a href="https://kind.sigs.k8s.io/" rel="noopener noreferrer"&gt;Kind&lt;/a&gt; when looking for this solution and found it really easy to use.&lt;/p&gt;

&lt;p&gt;It's super easy to get a cluster going especially if you already have kubectl installed. It's fast to install kind as you can just download the executable and include it in your path. &lt;/p&gt;

&lt;p&gt;In PowerShell for example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl.exe &lt;span class="nt"&gt;-Lo&lt;/span&gt; kind-windows-amd64.exe https://kind.sigs.k8s.io/dl/v0.10.0/kind-windows-amd64
Move-Item .&lt;span class="se"&gt;\k&lt;/span&gt;ind-windows-amd64.exe c:&lt;span class="se"&gt;\s&lt;/span&gt;ome-dir-in-your-PATH&lt;span class="se"&gt;\k&lt;/span&gt;ind.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Getting a cluster going after installation is just as easy&lt;/p&gt;

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

&lt;p&gt;Commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
kind create cluster
docker ps
watch kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a few seconds you will have a control plane up and ready to accept commands. I think it will be really fun to explore what can be done by having a Kubernetes cluster available in such a short amount of time.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>docker</category>
    </item>
    <item>
      <title>GitHub Actions – Deploying an Angular App</title>
      <dc:creator>Hannah Sun</dc:creator>
      <pubDate>Tue, 21 Apr 2020 16:26:21 +0000</pubDate>
      <link>https://dev.to/focisolutions/github-actions-deploying-an-angular-app-mj1</link>
      <guid>https://dev.to/focisolutions/github-actions-deploying-an-angular-app-mj1</guid>
      <description>&lt;p&gt;Recently I built an &lt;a href="https://github.com/FociSolutions/angular-demo"&gt;Angular demo application&lt;/a&gt; that showcases some of the features provided by Angular. I will deploy this application to GitHub pages using GitHub Actions, a newly released CI/CD platform that can be used by open source repositories for free.&lt;/p&gt;

&lt;p&gt;Since I already have a completed Angular project pushed to GitHub, all I need to do is to create a GitHub workflow to build, test, and deploy the Angular application to GitHub Pages. Before I start, I need to create a folder named &lt;code&gt;.github/workflows&lt;/code&gt; at the root of my repository.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;To learn more about GitHub workflow, please read &lt;a href="https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions"&gt;workflow syntax for GitHub Actions article&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a GitHub Actions Workflow File
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;.github/workflows&lt;/code&gt;, I added a &lt;code&gt;yaml&lt;/code&gt; file for the workflow. And inside the workflow file, you can choose to add the name of your workflow by adding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;workflow name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you omit &lt;code&gt;name&lt;/code&gt; inside the workflow file, GitHub will set workflow name to the workflow file path relative to the root of the repository.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;GitHub is flexible with however you want to name your workflow file, but the file has to be a &lt;code&gt;yaml&lt;/code&gt; file and it has to be in the &lt;code&gt;.github/workflows&lt;/code&gt; folder.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Workflow Trigger
&lt;/h2&gt;

&lt;p&gt;A workflow trigger is required for a workflow. I configured the workflow to trigger on pushes to the &lt;code&gt;master&lt;/code&gt; branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;master'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you want to use a different trigger for your workflow, please take a look at &lt;a href="https://help.github.com/en/actions/reference/events-that-trigger-workflows"&gt;events that trigger workflows article&lt;/a&gt; and &lt;a href="https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#on"&gt;&lt;code&gt;on&lt;/code&gt; section of workflow syntax for GitHub Actions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Angular Build And Test Job
&lt;/h2&gt;

&lt;p&gt;In GitHub Actions, jobs are defined by a series of steps that are executed on a runner. Each job runs on a different workspace, meaning that files and job side effects are not kept between jobs. In order to reduce build time and build complexity, I will keep as much work inside one job as possible.&lt;/p&gt;

&lt;p&gt;Thus, the job below is created to build and test the Angular application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and Test&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The latest version of Ubuntu GitHub-hosted runner is utilized for this job. But if you want to use a different Github-hosted runner, pease read &lt;a href="https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners"&gt;virtual environments for GitHub-hosted runners article&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking out source code
&lt;/h3&gt;

&lt;p&gt;Since jobs do not pull down the source code by default, you need to explicitly tell the job to do so. Therefore, I add the following to &lt;code&gt;steps&lt;/code&gt; of build and test job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup Node.js
&lt;/h3&gt;

&lt;p&gt;To setup Node.js used by the job, add the following under &lt;code&gt;steps&lt;/code&gt; of the job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node 12.x&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;12.x'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Build and test job is configured to use Node.js version 12.x. If you wish to use a different version, please take a look at &lt;a href="https://help.github.com/en/actions/language-and-framework-guides/using-nodejs-with-github-actions"&gt;using Node.js with GitHub Actions article&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run build and test
&lt;/h3&gt;

&lt;p&gt;To build and test the Angular application, I added some supporting scripts to the application’s &lt;code&gt;package.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;build:ci"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ng&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--prod&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--sourceMap=false&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--base-href&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/YOUR_REPOSITORY_NAME_HERE/"&lt;/span&gt;
&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test:ci"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ng&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--watch=false&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--code-coverage&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--source-map&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see, the &lt;code&gt;test:ci&lt;/code&gt; script will also generate code coverage results for us, which will be used later down the line.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: To avoid MIME type error due to invalid path, you need to set your &lt;code&gt;base-href&lt;/code&gt; to your repository name&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then, I add the following to the job to build and test our application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build:ci&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run test:ci&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Upload artifacts
&lt;/h3&gt;

&lt;p&gt;To expose the results of the current job to the next job, I need to configure build and test job to upload the build artifacts. I also configured the job to upload the code coverage results, so they can be reviewed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Archive build&lt;/span&gt;
  &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;success()&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v1&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy_dist&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dist&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Archive code coverage result&lt;/span&gt;
  &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;success()&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v1&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy_coverage&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coverage&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;code&gt;if: success()&lt;/code&gt; is used to make sure upload artifact only runs if all the previous steps passed. For more information, read &lt;a href="https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions"&gt;context and expression syntax for GitHub Actions article&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Deploy Job
&lt;/h2&gt;

&lt;p&gt;With build and test job completed, I can create the job that will deploy the Angular application to GitHub Pages. I add the following &lt;code&gt;yaml&lt;/code&gt; below build and test job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
  &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;
      &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;code&gt;needs: build&lt;/code&gt; is used to tell GitHub to only execute deploy job when build and test job completed successfully.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Download build artifact
&lt;/h3&gt;

&lt;p&gt;I add the following under &lt;code&gt;steps&lt;/code&gt; in the deploy job to download build artifact from build and test job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Download build&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/download-artifact@v1&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy_dist&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;To learn more, take a look at &lt;a href="https://help.github.com/en/actions/configuring-and-managing-workflows/persisting-workflow-data-using-artifacts"&gt;persisting workflow data using artifacts article&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy to GitHub Pages
&lt;/h3&gt;

&lt;p&gt;I use &lt;a href="https://github.com/JamesIves/github-pages-deploy-action"&gt;GitHub Pages Deploy Action&lt;/a&gt; to deploy our Angular build to &lt;code&gt;gh-pages&lt;/code&gt; branch of the project repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to GitHub Pages&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JamesIves/github-pages-deploy-action@releases/v3&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
    &lt;span class="na"&gt;BRANCH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh-pages&lt;/span&gt;
    &lt;span class="na"&gt;FOLDER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy_dist/YOUR_PROJECT_NAME_HERE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;code&gt;GITHUB_TOKEN&lt;/code&gt; is used to avoid providing a personal access token, to learn more about &lt;code&gt;GITHUB_TOKEN&lt;/code&gt;, read &lt;a href="https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token"&gt;authenticating with the GITHUB_TOKEN article&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Once you check in your workflow file, which should look similar to the &lt;code&gt;yaml&lt;/code&gt; below, to your &lt;code&gt;master&lt;/code&gt; branch, you should see a GitHub workflow starting in the GitHub Actions page. When the workflow is complete, you will see the build output and test coverage results in the artifacts section and a branch called &lt;code&gt;gh-pages&lt;/code&gt; will be created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;workflow name&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;master'&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and Test&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node 12.x&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;12.x'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build:ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run test:ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Archive build&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;success()&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy_dist&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dist&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Archive code coverage result&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;success()&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy_coverage&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coverage&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Download build&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/download-artifact@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy_dist&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to GitHub Pages&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JamesIves/github-pages-deploy-action@releases/v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;BRANCH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh-pages&lt;/span&gt;
          &lt;span class="na"&gt;FOLDER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy_dist/angular-demo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Ensure that your repository has GitHub Pages enabled and the deployment is based off &lt;code&gt;gh-pages&lt;/code&gt; branch. If this is set up properly, your Angular application should be deployed!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://focisolutions.com/2020/04/github-actions-deploying-an-angular-app/"&gt;GitHub Actions – Deploying an Angular App&lt;/a&gt; appeared first on &lt;a href="https://focisolutions.com"&gt;Foci Solutions&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>github</category>
      <category>angular</category>
    </item>
    <item>
      <title>MULTI STAGE PIPELINES &amp; AZURE DEVOPS</title>
      <dc:creator>Daniel McCrady</dc:creator>
      <pubDate>Fri, 17 Apr 2020 16:36:32 +0000</pubDate>
      <link>https://dev.to/focisolutions/multi-stage-pipelines-azure-devops-2b3p</link>
      <guid>https://dev.to/focisolutions/multi-stage-pipelines-azure-devops-2b3p</guid>
      <description>&lt;p&gt;Many years ago, I wrote a blog post about TFS and DevOps. A lot has changed since then, with multiple versions of the build pipeline being released, but it continues to be one of the most trafficked articles on our site.   Microsoft has worked hard to create a better experience for build automation and continuous integration – so I worked hard on updating this walkthrough. Recently, Microsoft released the idea of multi stage pipelines that work and feel much like how GitLab CI works.&lt;/p&gt;

&lt;p&gt;In this post I’ll walk through a basic YAML file and show how you can get a C# project up, built, and tested quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;We need to have a project that is checked into DevOps before we begin. I have a repository that I made for this blog up on DevOps. that is a basic dotnet core console application and a unit test project that goes along with it. At the time of writing this blog post you will also need to turn on the multi-stage pipelines Preview Feature in order to get the best view for these pipelines. You can do that by clicking on the user settings button&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc59dza23dre4ifm04ol0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc59dza23dre4ifm04ol0.png" alt="User Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then click on preview features&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flz4lqb0urx96vuk6x7xv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flz4lqb0urx96vuk6x7xv.png" alt="Preview Features"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then ensure that multi-stage pipelines are enabled&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F50nu1bks6748o74wndyw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F50nu1bks6748o74wndyw.png" alt="Multi stage pipelines enabled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  First Steps
&lt;/h2&gt;

&lt;p&gt;First we need to add a YAML file into our project. I tend to put this file directly at root and name it azure-pipelines.yaml. Then we need to define our stages. A stage is a collection of jobs and can be run concurrently or can be dependent on another stage successfully completing. For this quick project we will have two different stages&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build&lt;/li&gt;
&lt;li&gt;Test&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to define these stages in our pipeline we need to write some YAML like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
    &lt;span class="na"&gt;dependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this will give us building blocks to add our jobs. If you check this file into DevOps and navigate to pipelines you can see that we have a pipeline defined without any runs associated to it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnt2pa55fy7p3hrvb4c9v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnt2pa55fy7p3hrvb4c9v.png" alt="multi stage pipeline showing in dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Job
&lt;/h2&gt;

&lt;p&gt;A job runs on a build agent. By default DevOps provides hosted build agents. These agents are a pre-configured VM that have a lot of different development tools pre-installed. I’ll be using the hosted agents for this post.&lt;/p&gt;

&lt;p&gt;Let’s add in some YAML to add a job that will build our dotnet solution. We can do this in one of two ways, we can use a DevOps “task” or we can write a script. Tasks can provide a lot of features that you would normally need to script yourself. These can be very helpful, however it also hides a lot of what is being run. I tend to try and use tasks as they get updated regularly to add additional features and fix bugs. Microsoft hasn’t made tasks to solve every problem however so you will need to write some scripts eventually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example as Task&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;buildConfiguration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Release"&lt;/span&gt;

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
  &lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ubuntu&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;16.04"&lt;/span&gt;    
  &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build_dotnet_solution&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build dotnet solution&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DotNetCoreCLI@2&lt;/span&gt;
      &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
        &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--configuration&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(buildConfiguration)'&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
  &lt;span class="na"&gt;dependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example as script&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;buildConfiguration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Release"&lt;/span&gt;

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
  &lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ubuntu&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;16.04"&lt;/span&gt;    
  &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build_dotnet_solution&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build dotnet solution&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;dotnet build --configuration $(buildConfiguration)&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
  &lt;span class="na"&gt;dependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both examples I have added a variable to set the build configuration setting for the pipeline. Variables are very helpful and DevOps also provides a lot of pre-defined variables for you. You can ready about them here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Artifacts
&lt;/h2&gt;

&lt;p&gt;Now that we have our job running and our solution is being built. We will probably want to retain these files. We will need to artifact these files if we want to use them in a different job, or we can download them later for manually testing the build.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;buildConfiguration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Release"&lt;/span&gt;

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
  &lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ubuntu&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;16.04"&lt;/span&gt;    
  &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build_dotnet_solution&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build dotnet solution&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DotNetCoreCLI@2&lt;/span&gt;
      &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
        &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--configuration&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(buildConfiguration)'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$(System.DefaultWorkingDirectory)/src/demo-project/bin/$(buildConfiguration)/netcoreapp3.0/&lt;/span&gt;
      &lt;span class="na"&gt;artifact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;source&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
  &lt;span class="na"&gt;dependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the build is completed you should see the artifacts on the build page. You can download them and use them in different jobs now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fovx0h1iq5ngvayzdplv9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fovx0h1iq5ngvayzdplv9.png" alt="multi stage pipeline artifacts published"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Now that we have our code built, we can go ahead and run the tests for our application. DevOps also has the ability to show us test results through its dashboards. It’s easiest to use the task for this, as the task has capabilities to upload the tests results for us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;buildConfiguration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Release"&lt;/span&gt;

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
  &lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ubuntu&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;16.04"&lt;/span&gt;    
  &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build_dotnet_solution&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build dotnet solution&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DotNetCoreCLI@2&lt;/span&gt;
      &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
        &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--configuration&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(buildConfiguration)'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$(System.DefaultWorkingDirectory)/src/demo-project/bin/$(buildConfiguration)/netcoreapp3.0/&lt;/span&gt;
      &lt;span class="na"&gt;artifact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;source&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
  &lt;span class="na"&gt;dependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test_dotnet_solution&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test dotnet solution&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DotNetCoreCLI@2&lt;/span&gt;
      &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;        
        &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--configuration&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$(buildConfiguration)'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6d41ixo7wgt1ng79wzrx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6d41ixo7wgt1ng79wzrx.png" alt="multi stage pipeline tests successful"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this, you now have a basic build and test pipeline that will run with every check-in to your repository. There is a lot more that can be done, such as managing environments and performing releases. I hope that this is a good starting block to get you moving with DevOps.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>azure</category>
      <category>dotnet</category>
    </item>
  </channel>
</rss>
