<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ CircleCI - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ CircleCI - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 24 Jun 2026 10:06:35 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/circleci/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Popular Front End Development Tools You Should Know ]]>
                </title>
                <description>
                    <![CDATA[ By Yiğit Kemal Erinç If you are just getting started with JavaScript, the number of tools and technologies you'll hear about may be overwhelming. And you might have a hard time deciding which tools you actually need. Or maybe you're familiar with the... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/front-end-development-tools-you-should-know/</link>
                <guid isPermaLink="false">66d45e4273634435aafcef82</guid>
                
                    <category>
                        <![CDATA[ Babel ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CircleCI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ eslint ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Front-end Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ npm ]]>
                    </category>
                
                    <category>
                        <![CDATA[ webpack ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 03 Nov 2020 02:35:19 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/11/frontend-dev-tools.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Yiğit Kemal Erinç</p>
<p>If you are just getting started with JavaScript, the number of tools and technologies you'll hear about may be overwhelming. And you might have a hard time deciding which tools you actually need.</p>
<p>Or maybe you're familiar with the tools, but you haven't given much thought to what problems they solve and how miserable your life would be without their help.</p>
<p>I believe it is important for Software Engineers and Developers to understand the purpose of the tools we use every day. </p>
<p>That's why, in this article, I look at NPM, Babel, Webpack, ESLint, and CircleCI and I try to clarify the problems they solve and how they solve them. </p>
<h2 id="heading-npm">NPM</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>NPM is the default package manager for JavaScript development. It helps you find and install packages (programs) that you can use in your programs.</p>
<p>You can add npm to a project simply by using the "<strong>npm init</strong>" command. When you run this command it creates a "<strong>package.json</strong>" file in the current directory. This is the file where your dependencies are listed, and npm views it as the ID card of the project. </p>
<p>You can add a dependency with the "<strong>npm install (package_name)</strong>" command. </p>
<p>When you run this command, npm goes to the remote registry and checks if there is a package identified by this package name. If it finds it, a new dependency entry is added to your <strong>package.json</strong> and the package, with it's internal dependencies, is downloaded from the registry.</p>
<p>You can find downloaded packages or dependencies under the <strong>"node_modules"</strong> folder. Just keep in mind that it usually gets pretty big – so make sure to add it to <strong>.gitignore</strong>.</p>
<p><img src="https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2020/06/node-modules-meme.jpeg?resize=730%2C525&amp;ssl=1" alt="How to keep your JavaScript libraries up to date - LogRocket Blog" width="730" height="525" loading="lazy"></p>
<p>NPM does not only ease the process of finding and downloading packages but also makes it easier to work collaboratively on a project. </p>
<p>Without NPM, it would be hard to manage external dependencies. You would need to download the correct versions of every dependency by hand when you join an existing project. And that would be a real hassle. </p>
<p>With the help of npm, you can just run <strong>"npm install"</strong> and it will install all external dependencies for you. Then you can just run it again anytime someone on your team adds a new one.</p>
<h2 id="heading-babel">Babel</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Babel is a JavaScript compiler or transpiler which translates the ECMAScript 2015+ code into code that can be understood by older JavaScript engines.</p>
<p>Babel is the most popular Javascript compiler, and frameworks like Vue and React use it by default. That said, concepts we will talk about here are not only related to Babel and will apply to any JavaScript compiler.</p>
<h3 id="heading-why-do-you-need-a-compiler">Why do you need a compiler?</h3>
<p>"Why do we need a compiler, isn't JavaScript an interpreted language?" you may ask if you are familiar with the concepts of compiled and interpreted languages. </p>
<p>It's true that we usually call something a "compiler" if it translates our human-readable code to an executable binary that can be understood by the CPU. But that is not the case here. </p>
<p>The term transpiler may be more appropriate since it is a subset of a compiler: Transpilers are compilers that translate the code from a programming language to another language (in this example, from modern JS to an older version).</p>
<p>JavaScript is the language of browsers. But there is a problem with browsers: Cross compatibility. JavaScript tools and the language itself are evolving rapidly and many browsers fail to match that pace. This results in compatibility issues.</p>
<p>You probably want to write code in the most recent versions of JavaScript so you can use its new features. But if the browser that your code is running has not implemented some of the new features in its JavaScript engine, the code will not execute properly on that browser.</p>
<p>This is a complex problem because every browser implements the features at a different speed. And even if they do implement those new features, there will always be people who use an older version of their browser. </p>
<p>So what if you want to be able to use the recent features but also want your users to view those pages without any problems?</p>
<p>Before Babel, we used polyfills to run older versions of certain code if the browser did not support the modern features. And when you use Babel, it uses polyfills behind the scenes and does not require you to do anything.</p>
<h3 id="heading-how-do-transpilerscompilers-work">How do transpilers/compilers work?</h3>
<p>Babel works similar to other compilers. It has parsing, transformation, and code generation stages. </p>
<p>We won't go in-depth here into how it works, since compilers are complicated things. But to understand the basics of how compilers work, you can check out the <a target="_blank" href="https://github.com/jamiebuilds/the-super-tiny-compiler">the-super-tiny-compiler project</a>. It is also mentioned in Babel's official documentation as being helpful in understanding how Babel works.</p>
<p>We can usually get away with knowing about Babel plugins and presets. Plugins are the snippets that Babel uses behind the scenes to compile your code to older versions of JavaScript. You can think of each modern feature as a plugin. You can go to <a target="_blank" href="https://babeljs.io/docs/en/plugins/">this</a> link to check out the full list of plugins.</p>
<p><img src="https://erinc.io/wp-content/uploads/2020/10/image.png" alt="Image" width="600" height="400" loading="lazy">
<em>List of plugins for ES5</em></p>
<p>Presets are collections of plugins. If you want to use Babel for a React project you can use the pre-made <strong>@babel/preset-react</strong> which contains the necessary plugins.</p>
<p><img src="https://erinc.io/wp-content/uploads/2020/10/image-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>React Preset Plugins</em></p>
<p>You can add plugins by editing the Babel config file.</p>
<h3 id="heading-do-you-need-babel-for-your-react-app">Do you need Babel for your React App?</h3>
<p>For React, you need a compiler because React code generally uses JSX and JSX needs to be compiled. Also the library is built on the concept of using ES6 syntax. </p>
<p>Luckily, when you create a project with <strong>create-react-app</strong>, it comes with Babel already configured and you usually do not need to modify the config.</p>
<h3 id="heading-examples-of-a-compiler-in-action">Examples of a compiler in action</h3>
<p>Babel's website has an online compiler and it is really helpful to understand how it works. Just plug in some code and analyze the output.</p>
<p><img src="https://erinc.io/wp-content/uploads/2020/10/image-4.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://erinc.io/wp-content/uploads/2020/10/image-5.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-webpack">Webpack</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Webpack is a static module bundler. When you create a new project, most JavaScript frameworks/libraries use it out of the box nowadays. </p>
<p>If the phrase "static module bundler" sounds confusing, keep reading because I have some great examples to help you understand.</p>
<h3 id="heading-why-do-you-need-a-bundler">Why do you need a bundler?</h3>
<p>In web apps you're going to have a lot of files. This is especially the case for Single Page Applications (React, Vue, Angular), with each having their own dependencies. </p>
<p>What I mean by a dependency is an import statement – if file A needs to import file B to run properly, then we say A depends on B. </p>
<p>In small projects, you can handle the module dependencies with <code>&lt;script&gt;</code> tags. But when the project gets larger, the dependencies rapidly become hard to manage. </p>
<p>Maybe, more importantly, dividing the code into multiple files makes your website load more slowly. This is because the browser needs to send more requests compared to one large file, and your website starts to consume a ton of bandwidth, because of HTTP headers.</p>
<p>We, as developers want our code to be modular. We divide it into multiple files because we do not want to work with one file with thousands of lines. Still, we also want our websites to be performant, to use less bandwidth, and to load fast. </p>
<p>So now, we'll see how Webpack solves this issue.</p>
<h3 id="heading-how-webpack-works">How Webpack works</h3>
<p>When we were talking about Babel, we mentioned that JavaScript code needs to be transpiled before the deployment. </p>
<p>But compiling with Babel is not the only operation you need before deploying your project. </p>
<p>You usually need to uglify it, transpile it, compile the SASS or SCSS to CSS if you are using any preprocessors, compile the TypeScript if you are using it...and as you can see, this list can get long easily. </p>
<p>You do not want to deal with all those commands and operations before every deployment. It would be great if there was a tool that did all that for you in the correct order and correct way. </p>
<p>The good news – there is: Webpack.</p>
<p>Webpack also provides features like a local server with hot reload (they call it hot module replacement) to make your development experience better. </p>
<p>So what's hot reloading? It means that whenever you save your code, it gets compiled and deployed to the local HTTP server running on your machine. And whenever a file changes, it sends a message to your browser so you do not even need to refresh the page. </p>
<p>If you have ever used "npm run serve", "npm start" or "npm run dev", those commands also start Webpack's dev server behind the scenes.</p>
<p>Webpack starts from the entry point of your project (index) and generates the Abstract Syntax Tree of the file. You can think of it as parsing the code. This operation is also done in compilers, which then look for import statements recursively to generate a graph of dependencies.</p>
<p>It then converts the files into [IIFEs](https://developer.mozilla.org/en-US/docs/Glossary/IIFE#:~:text=An%20IIFE%20(Immediately%20Invoked%20Function,soon%20as%20it%20is%20defined.) to modularize them (remember, putting code inside a function restricts its scope). By doing this, they modularize the files and make sure the variables and functions are not accessible to other files. </p>
<p>Without this operation, it would be like copying and pasting the code of the imported file and that file would have the same scope.</p>
<p>Webpack does many other advanced things behind the scenes, but this is enough to understand the basics.</p>
<h2 id="heading-bonus-eslint">Bonus – ESLint</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Code quality is important and helps keep your projects maintainable and easily extendable. While most of us developers recognize the significance of clean coding, we sometimes tend to ignore the long term consequences under the pressure of deadlines.</p>
<p>Many companies decide on coding standards and encourage developers to obey those standards. But how can you make sure that your code meets the standards? </p>
<p>Well, you can use a tool like ESLint to enforce rules in the code. For example, you can create a rule to enforce or disallow the usage of semicolons in your JavaScript code. If you break a rule, ESLint shows an error and the code does not even get compiled – so it is not possible to ignore that unless you disable the rule.</p>
<p>Linters can be used to enforce standards by writing custom rules. But you can also use the pre-made ESLint configs established by big tech companies to help devs get into the habit of writing clean code. </p>
<p>You can take a look at Google's ESLint config <a target="_blank" href="https://github.com/google/eslint-config-google">here</a> – it is the one I prefer.</p>
<p>ESLint helps you get used to best practices, but that's not its only benefit. ESLint also warns you about possible bugs/errors in your code so you can avoid common mistakes.</p>
<p><img src="https://erinc.io/wp-content/uploads/2020/11/image-1024x717.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-bonus-cicd-circleci">Bonus – CI/CD (CircleCI)</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-4.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Continuous Integration/Development has gained a lot of popularity in recent years as many companies have adopted Agile principles. </p>
<p>Tools like Jenkins and CircleCI allow you to automate the deployment and testing of your software so you can deploy more often and reliably without going through difficult and error-prone build processes by yourselves. </p>
<p>I mention CircleCI as the product here because it is free and used frequently in JavaScript projects. It's also quite easy to use.</p>
<p>Let's go over an example: Say you have a deployment/QA server and your Git repository. You want to deploy your changes to your deployment/QA server, so here is an example process:</p>
<ol>
<li>Push the changes to Git</li>
<li>Connect to the server</li>
<li>Create a Docker container and run it</li>
<li>Pull the changes to the server, download all the dependencies (npm install)</li>
<li>Run the tests to make sure nothing is broken</li>
<li>Use a tool like ESLint/Sonar to ensure code quality</li>
<li>Merge the code if everything is fine</li>
</ol>
<p>With the help of CircleCI, you can automatically do all these operations. You can set it up and configure to do all of the above operations whenever you push a change to Git. It will reject the push if anything goes wrong, for example a failing test.</p>
<p>I will not get into the details of how to configure CircleCI because this article is more about the "Why?" of each tool. But if you are interested in learning more and seeing it in action, you can check out <a target="_blank" href="https://www.youtube.com/watch?v=CB7vnoXI0pE&amp;ab_channel=TheCodingTrain">this tutorial series</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The world of JavaScript is evolving rapidly and new tools are gaining popularity every year. </p>
<p>It's easy to react to this change by just learning how to use the tool – we are often too busy to take our time and think about the reason why that tool became popular or what problem it solves.</p>
<p>In this article, I picked the tools I think are most popular and shared my thoughts on their significance. I also wanted to make you think about the problems they solve rather than just the details of how to use them.</p>
<p>If you liked the article you can check out and subscribe to my <a target="_blank" href="https://erinc.io/">blog</a> where I try to write frequently. Also, let me know what you think by commenting so we can brainstorm or you can tell me what other tools you love to use :)</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to use Lighthouse in CircleCI ]]>
                </title>
                <description>
                    <![CDATA[ By Adam Henson CircleCI is a popular tool for orchestrating CI/CD pipelines. Lighthouse is an open-source project from Google for improving the quality of web pages. It provides user-centric metrics to audit SEO, performance, accessibility, best prac... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-lighthouse-in-circleci/</link>
                <guid isPermaLink="false">66d45d6151f567b42d9f841f</guid>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CircleCI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Lighthouse ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SEO ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Website performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 06 Jan 2020 12:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/01/nyc-building-in-midtown-east.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Adam Henson</p>
<p><a target="_blank" href="https://circleci.com/">CircleCI</a> is a popular tool for orchestrating CI/CD pipelines. Lighthouse is an open-source project from Google for improving the quality of web pages. It provides user-centric metrics to audit SEO, performance, accessibility, best practices, and progressive web apps. </p>
<p>For a deeper dive about Lighthouse you can read “<a target="_blank" href="https://www.freecodecamp.org/news/three-ways-to-analyze-website-performance-with-lighthouse-8d100966c04b/">How to analyze website performance with Lighthouse</a>”. </p>
<p>By combining these forces, we can establish website quality automation. This post will demonstrate the following:</p>
<ul>
<li>Basic implementation of Lighthouse in a CircleCI workflow.</li>
<li>Advanced setup to display Lighthouse results in pull request comments.</li>
<li>S3 Lighthouse report uploads.</li>
<li>Slack notifications.</li>
</ul>
<h1 id="heading-lighthouse-check-circleci-orb">Lighthouse Check CircleCI Orb</h1>
<p><a target="_blank" href="https://circleci.com/docs/2.0/orb-intro/#section=configuration">CircleCI Orbs</a> are shareable packages of configuration elements, including jobs, commands, and executors you use in your workflows. This post will provide a guide for using the <a target="_blank" href="https://circleci.com/orbs/registry/orb/foo-software/lighthouse-check">Lighthouse Check CircleCI Orb</a> for automating Lighthouse audits.</p>
<h3 id="heading-basic-example">Basic Example</h3>
<p>Below is a minimal example and all we need to run Lighthouse automatically on any code change ? In this example both <a target="_blank" href="https://www.foo.software"><code>https://www.foo.software</code></a> and <a target="_blank" href="https://www.foo.software/contact"><code>https://www.foo.software/contact</code></a> will be audited.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">version:</span> <span class="hljs-number">2.1</span>

<span class="hljs-attr">orbs:</span>
  <span class="hljs-attr">lighthouse-check:</span> <span class="hljs-string">foo-software/lighthouse-check@0.0.8</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">test:</span> 
    <span class="hljs-attr">executor:</span> <span class="hljs-string">lighthouse-check/default</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">lighthouse-check/audit:</span>
          <span class="hljs-attr">urls:</span> <span class="hljs-string">https://www.foo.software,https://www.foo.software/contact</span>

<span class="hljs-attr">workflows:</span>
  <span class="hljs-attr">test:</span>
    <span class="hljs-attr">jobs:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">test</span>
</code></pre>
<p>With this minimal setup we have a summary provided in the output of our job. We also have full HTML reports saved as <a target="_blank" href="https://circleci.com/docs/2.0/artifacts/">CircleCI "artifacts"</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/01/circleci-orb-lighthouse-check-output.png" alt="Image" width="600" height="400" loading="lazy">
<em>Lighthouse Check Orb output</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/01/circleci-orb-lighthouse-check-artifacts.png" alt="Image" width="600" height="400" loading="lazy">
<em>Lighthouse Check Orb save artifacts</em></p>
<h3 id="heading-advanced-example">Advanced Example</h3>
<p>Lighthouse Check CircleCI Orb offers a complete set of bells and whistles by utilizing <code>[lighthouse-check](https://github.com/foo-software/lighthouse-check)</code> <a target="_blank" href="https://github.com/foo-software/lighthouse-check">NPM module</a> under the hood. There’s so much more we can do with this. Let’s proceed!</p>
<h2 id="heading-pull-request-comments">Pull Request Comments</h2>
<p>By utilizing this feature, comments are posted with Lighthouse results on every commit. We can do so by following the steps below.</p>
<ol>
<li>Create a new user or find an existing one to act as a “bot”.</li>
<li><a target="_blank" href="https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line">Create a personal access token</a> from this user account.</li>
<li><a target="_blank" href="https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-project">Create a CircleCI environment variable in your project</a> to hold the encrypted value from above. In our example we name it <code>LIGHTHOUSE_CHECK_GITHUB_ACCESS_TOKEN</code>.</li>
<li>Update our config file with the diff shown below.</li>
</ol>
<pre><code class="lang-diff"><span class="hljs-addition">+ prCommentAccessToken: $LIGHTHOUSE_CHECK_GITHUB_ACCESS_TOKEN</span>
<span class="hljs-addition">+ prCommentUrl: https://api.github.com/repos/foo-software/lighthouse-check-orb/pulls/${CIRCLE_PULL_REQUEST##*/}/reviews</span>
urls: https://www.foo.software,https://www.foo.software/contact
</code></pre>
<p>The updates above provides a token to authorize comments on a corresponding pull request. <code>prCommentUrl</code> should be an endpoint in the <a target="_blank" href="https://developer.github.com/v3/pulls/reviews/#create-a-pull-request-review">format specified by the GitHub API</a>. Your endpoint will be similar but with <code>owner</code> and <code>repo</code> params replaced ( <code>foo-software/lighthouse-check-orb</code> ). With this, we’ve created a bot to post Lighthouse results on pull requests ?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/01/lighthouse-check-pr-comment.png" alt="Image" width="600" height="400" loading="lazy">
<em>Lighthouse Check PR comments</em></p>
<h2 id="heading-s3-report-uploads">S3 Report Uploads</h2>
<p>In our example we persist results by uploading reports as artifacts in our job. This solution could be sufficient in some cases, but artifacts aren’t stored permanently. In order to view reports, we need to navigate into the workflow and manually download reports from the artifact view. </p>
<p>But what if we want a more dependable way of storing and referencing reports? This is where the S3 feature comes into play. We can configure AWS S3 storage by following the below steps.</p>
<ol>
<li><a target="_blank" href="https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/">Create an AWS account</a> if you don’t already have one.</li>
<li><a target="_blank" href="https://docs.aws.amazon.com/AmazonS3/latest/gsg/SigningUpforS3.html">Create an S3 bucket</a> if you don’t already have one.</li>
<li><a target="_blank" href="https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html">Acquire an AWS access key id and secret access key</a>.</li>
<li><a target="_blank" href="https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-project">Create a CircleCI environment variables</a> for these two values. In our example we’ll use <code>LIGHTHOUSE_CHECK_AWS_ACCESS_KEY_ID</code> and <code>LIGHTHOUSE_CHECK_AWS_SECRET_ACCESS_KEY</code>, respectively.</li>
<li>Add the bucket name and <a target="_blank" href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html">region</a> (example: <code>us-east-1</code>) as CircleCI environment variables: <code>LIGHTHOUSE_CHECK_AWS_BUCKET</code> and <code>LIGHTHOUSE_CHECK_AWS_REGION</code>.</li>
</ol>
<p>Next, we’ll update our configuration with the following diff.</p>
<pre><code class="lang-diff"><span class="hljs-addition">+ awsAccessKeyId: $LIGHTHOUSE_CHECK_AWS_ACCESS_KEY_ID</span>
<span class="hljs-addition">+ awsBucket: $LIGHTHOUSE_CHECK_AWS_BUCKET</span>
<span class="hljs-addition">+ awsRegion: $LIGHTHOUSE_CHECK_AWS_REGION</span>
<span class="hljs-addition">+ awsSecretAccessKey: $LIGHTHOUSE_CHECK_AWS_SECRET_ACCESS_KEY</span>
prCommentUrl: https://api.github.com/repos/foo-software/lighthouse-check-orb/pulls/${CIRCLE_PULL_REQUEST##*/}/reviews
</code></pre>
<p>In our next commit and push, reports are automatically uploaded to S3 ✅! We also have a them linked in our PR comments.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/01/pr-comment-lighthouse.png" alt="Image" width="600" height="400" loading="lazy">
<em>Lighthouse result PR comment with S3 report linked</em></p>
<h2 id="heading-slack-notifications">Slack Notifications</h2>
<p>What’s a new feature in a DevOps workflow without Slack notifications? A sad one indeed. Let’s ramp things up by adding notifications to a Slack channel for our whole team to see. We can accomplish this in the below steps.</p>
<ol>
<li><a target="_blank" href="https://api.slack.com/messaging/webhooks">Create an “Incoming Webhook” in your Slack workspace and authorize a channel</a>.</li>
<li>Add the Webhook URL as a CircleCI environment variable — <code>LIGHTHOUSE_CHECK_SLACK_WEBHOOK_URL</code>.</li>
</ol>
<pre><code class="lang-diff"><span class="hljs-addition">+ slackWebhookUrl: $LIGHTHOUSE_CHECK_SLACK_WEBHOOK_URL</span>
urls: https://www.foo.software,https://www.foo.software/contact
</code></pre>
<p>Our next commit and push introduces Slack notifications! The “Lighthouse audit” link in the below screenshot navigates to the S3 report as configured ✨</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/01/circleci-orb-lighthouse-check-slack.png" alt="Image" width="600" height="400" loading="lazy">
<em>Lighthouse Slack notification</em></p>
<p>At this point our complete "advanced example" configuration looks like the below.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">usage:</span>
  <span class="hljs-attr">version:</span> <span class="hljs-number">2.1</span>

  <span class="hljs-attr">orbs:</span>
    <span class="hljs-attr">lighthouse-check:</span> <span class="hljs-string">foo-software/lighthouse-check@0.0.8</span>

  <span class="hljs-attr">jobs:</span>
    <span class="hljs-attr">test:</span> 
      <span class="hljs-attr">executor:</span> <span class="hljs-string">lighthouse-check/default</span>
      <span class="hljs-attr">steps:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">lighthouse-check/audit:</span>
            <span class="hljs-attr">awsAccessKeyId:</span> <span class="hljs-string">$LIGHTHOUSE_CHECK_AWS_ACCESS_KEY_ID</span>
            <span class="hljs-attr">awsBucket:</span> <span class="hljs-string">$LIGHTHOUSE_CHECK_AWS_BUCKET</span>
            <span class="hljs-attr">awsRegion:</span> <span class="hljs-string">$LIGHTHOUSE_CHECK_AWS_REGION</span>
            <span class="hljs-attr">awsSecretAccessKey:</span> <span class="hljs-string">$LIGHTHOUSE_CHECK_AWS_SECRET_ACCESS_KEY</span>
            <span class="hljs-attr">prCommentAccessToken:</span> <span class="hljs-string">$LIGHTHOUSE_CHECK_GITHUB_ACCESS_TOKEN</span>
            <span class="hljs-attr">prCommentUrl:</span> <span class="hljs-string">https://api.github.com/repos/foo-software/lighthouse-check-orb/pulls/${CIRCLE_PULL_REQUEST##*/}/reviews</span>
            <span class="hljs-attr">slackWebhookUrl:</span> <span class="hljs-string">$LIGHTHOUSE_CHECK_SLACK_WEBHOOK_URL</span>
            <span class="hljs-attr">urls:</span> <span class="hljs-string">https://www.foo.software,https://www.foo.software/contact</span>

  <span class="hljs-attr">workflows:</span>
    <span class="hljs-attr">test:</span>
      <span class="hljs-attr">jobs:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">test</span>
</code></pre>
<h2 id="heading-maintaining-a-historical-record">Maintaining a Historical Record</h2>
<p><a target="_blank" href="https://www.foo.software/lighthouse">Foo’s Automated Lighthouse Check</a> is tool we can use to manage a historical record of Lighthouse audits. We can connect to it with the Lighthouse Check Orb! By doing so you can run Lighthouse remotely versus in a local, dockerized CircleCI environment. With this we can be assured our Lighthouse results aren't flaky from CircleCI infrastructure change. Follow the <a target="_blank" href="https://github.com/foo-software/lighthouse-check-orb#usage-automated-lighthouse-check-api">documented steps to connect with Automated Lighthouse Check</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/01/automated-lighthouse-check.png" alt="Image" width="600" height="400" loading="lazy">
<em>A historical record of Lighthouse audits with "Automated Lighthouse Check"</em></p>
<h1 id="heading-what-now">What Now?</h1>
<p>You can find other of examples of <a target="_blank" href="https://github.com/foo-software/lighthouse-check-orb/tree/master/src/examples">Lighthouse Check Orb usage on GitHub</a>. I hope this article has provided a helpful addition to your DevOps workflow! With Lighthouse integrated in a CI/CD pipeline, we can stay fully equipped to ensure high quality in website SEO, performance, accessibility, best practice, and progressive web apps.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to split the deployment of your front end and back end with the help of Consumer Driven Contract Testing ]]>
                </title>
                <description>
                    <![CDATA[ By Mario Fernandez Consumer driven contract testing is a great way to improve the reliability of interconnected systems. Integration testing becomes way easier and more self contained. It opens the door for independent deployments, and leads to faste... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/split-frontend-backend-deployment-with-cdcs/</link>
                <guid isPermaLink="false">66d460f27df3a1f32ee7f893</guid>
                
                    <category>
                        <![CDATA[ CircleCI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ continuous delivery ]]>
                    </category>
                
                    <category>
                        <![CDATA[ contract-testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Jest ]]>
                    </category>
                
                    <category>
                        <![CDATA[ pact ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 12 Nov 2019 08:06:54 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/11/simple-cdc-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Mario Fernandez</p>
<p><a target="_blank" href="https://www.thoughtworks.com/de/radar/techniques/consumer-driven-contract-testing">Consumer driven contract testing</a> is a great way to improve the reliability of interconnected systems. Integration testing becomes way easier and more self contained. It opens the door for independent deployments, and leads to faster iterations and more granular feedback. Unlike your insurance, it doesn't have any fine print. This article is about setting it up in a delivery pipeline, in the context of doing <a target="_blank" href="https://continuousdelivery.com/">continuous delivery</a>.</p>
<p>I want to show how <em>Contract Tests</em> help split the deployment of the front end and the back end of a small application. I have a React client and a Spring Boot backend written in Kotlin.</p>
<h2 id="heading-what-is-a-contract-test">What is a Contract Test?</h2>
<p>I am not talking about <a target="_blank" href="https://en.wikipedia.org/wiki/Smart_contract">smart contracts</a>. There is no blockchain whatsoever in this article. Sorry for that (Contract Tests for Smart Contracts sounds like a conference talk that the world badly needs, though!).</p>
<p>In a nutshell, a Contract Test is a specification of the interactions between a consumer and a provider. In our case, the communication happens using REST. The consumer defines the actions sent to the provider and the responses that will be returned. In our case, the frontend is the consumer and the backend is the provider. A <em>contract</em> is generated. Both sides test against this contract.</p>
<p>It is not really about any particular technology. There are a bunch of different frameworks, but some simple scripts could do the trick.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/simple-cdc.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-why-have-it-as-part-of-the-delivery-pipeline">Why have it as part of the delivery pipeline?</h3>
<p>First of all, running these tests continuously ensures that they keep working at all times. The big benefit, however, is that we can separate the deployment of the front end and back end. If both sides are fulfilling the contract, it is likely that they work together correctly. Thus, we can consider avoiding expensive integrated tests. They tend to work pretty badly anyways.</p>
<h2 id="heading-setting-up-some-contracts">Setting up some contracts</h2>
<p>There are two sides to set up, consumer and provider. The tests will run in the pipelines that build the front end and the back end, respectively. We are going to use the <a target="_blank" href="https://docs.pact.io/">Pact framework</a> for our examples, which is the tool that I am most familiar with. Because of that, I tend to use pact and contract interchangeably. Our pipelines are written for <a target="_blank" href="https://circleci.com/">CircleCI</a>, but they should be fairly easy to port to other CI Tools.</p>
<h3 id="heading-the-consumer-side">The consumer side</h3>
<p>As mentioned, the consumer leads the creation of the contract. Having the client driving this might sound counterintuitive. Often, APIs are created before the clients that will use them. Flipping it around is a nice habit to get into. It forces you to really think in terms of what the client will actually do, instead of bikeshedding a super generic API that will never need most of its features. You should give it a try!</p>
<p>The pact is defined through interactions specified in unit tests. We specify what we expect to be sent to the back end, and then use the client code to trigger requests. Why? We can compare expectations against actual requests, and fail the tests if they don't match. </p>
<p>Let's have a look at an example. We are using <a target="_blank" href="https://jestjs.io/">Jest</a> to run the tests. We'll start with some initialization code:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> path <span class="hljs-keyword">from</span> <span class="hljs-string">'path'</span>
<span class="hljs-keyword">import</span> Pact <span class="hljs-keyword">from</span> <span class="hljs-string">'pact'</span>

<span class="hljs-keyword">const</span> provider = <span class="hljs-function">() =&gt;</span>
  Pact({
    port: <span class="hljs-number">8990</span>,
    log: path.resolve(process.cwd(), <span class="hljs-string">'logs'</span>, <span class="hljs-string">'pact.log'</span>),
    dir: path.resolve(process.cwd(), <span class="hljs-string">'pacts'</span>),
    spec: <span class="hljs-number">2</span>,
    consumer: <span class="hljs-string">'frontend'</span>,
    provider: <span class="hljs-string">'backend'</span>
  })

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> provider
</code></pre>
<p>Then we have the code for an actual test. The test consists of two parts. First we define the expected interaction. This is not very different from mocking an http library, with something like <a target="_blank" href="https://github.com/ctimmerm/axios-mock-adapter">axios</a>. It specifies the request that we will send (URL, headers, body and so forth), and the response that we will get.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> interaction: InteractionObject = {
  state: <span class="hljs-string">'i have a list of recipes'</span>,
  uponReceiving: <span class="hljs-string">'a request to get recipes'</span>,
  withRequest: {
    method: <span class="hljs-string">'GET'</span>,
    path: <span class="hljs-string">'/rest/recipes'</span>,
    headers: {
      Accept: <span class="hljs-string">'application/json'</span>,
      <span class="hljs-string">'X-Requested-With'</span>: <span class="hljs-string">'XMLHttpRequest'</span>
    }
  },
  willRespondWith: {
    status: <span class="hljs-number">200</span>,
    headers: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json; charset=utf-8'</span> },
    body: [
      {
        id: <span class="hljs-number">1</span>,
        name: <span class="hljs-string">'pasta carbonara'</span>,
        servings: <span class="hljs-number">4</span>,
        duration: <span class="hljs-number">35</span>
      }
    ]
  }
}
</code></pre>
<p>Then we have the test itself, where we call the actual client code that will trigger the request. I like to encapsulate these requests in services that convert the raw response into the domain model that will be used by the rest of the app. Through some assertions, we make sure that the data that we are delivering from the service is exactly what we expect.</p>
<pre><code class="lang-typescript">it(<span class="hljs-string">'works'</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> recipeList()

  expect(response.data.length).toBeGreaterThan(<span class="hljs-number">0</span>)
  expect(response.data[<span class="hljs-number">0</span>]).toEqual({
    id: <span class="hljs-number">1</span>,
    name: <span class="hljs-string">'pasta carbonara'</span>,
    servings: <span class="hljs-number">4</span>,
    duration: <span class="hljs-number">35</span>
  })
})
</code></pre>
<p>Note that even if <code>recipeList</code> is properly typed with <code>TypeScript</code>, that won't help us here. Types disappear at runtime, so if the method is returning an invalid <code>Recipe</code> we won't realize it, unless we explicitly test for it.</p>
<p>Finally we need to define some extra methods that will ensure that the interactions are verified. If there are interactions missing, or they don't look like they should, the test will fail here. After that, all that remains is writing the pact to disk.</p>
<pre><code class="lang-typescript">beforeAll(<span class="hljs-function">() =&gt;</span> provider.setup())
afterEach(<span class="hljs-function">() =&gt;</span> provider.verify())
afterAll(<span class="hljs-function">() =&gt;</span> provider.finalize())
</code></pre>
<p>In the end, the pact gets generated as a JSON file, reflecting all the interactions that we have defined throughout all our tests.</p>
<h4 id="heading-flexible-matching">Flexible matching</h4>
<p>Our pact thus far is specifying the exact values that it will get from the backend. That won't be maintainable in the long run. Certain things are inherently harder to pin down to exact values (for example, dates). </p>
<p>A pact that breaks constantly will lead to frustration. We are going through this whole process to make our life easier, not harder. We'll avoid that by using <a target="_blank" href="https://docs.pact.io/getting_started/matching">matchers</a>. We can be more flexible and define how things will look like, without having to provide exact values. Let's rewrite our previous body:</p>
<pre><code class="lang-typescript">willRespondWith: {
  status: <span class="hljs-number">200</span>,
  headers: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json; charset=utf-8'</span> },
  body: Matchers.eachLike({
    id: Matchers.somethingLike(<span class="hljs-number">1</span>),
    name: Matchers.somethingLike(<span class="hljs-string">'pasta carbonara'</span>),
    servings: Matchers.somethingLike(<span class="hljs-number">4</span>),
    duration: Matchers.somethingLike(<span class="hljs-number">35</span>)
  })
}
</code></pre>
<p>You can be more specific. You can set the expected length of a list, use regexes and a bunch of other things.</p>
<h4 id="heading-integrating-it-in-the-pipeline">Integrating it in the pipeline</h4>
<p>The pact tests rely on an external process, and having multiple tests hitting it can lead to non deterministic behavior. One solution is to run all the tests sequentially:</p>
<pre><code class="lang-bash">npm <span class="hljs-built_in">test</span> --coverage --runInBand
</code></pre>
<p>If you want to run the pact tests independently, we can build our own task to run them separately:</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
  <span class="hljs-attr">"pact"</span>: <span class="hljs-string">"jest --transform '{\"^.+\\\\.ts$\": \"ts-jest\"}' --testRegex '.test.pact.ts$' --runInBand"</span>
}
</code></pre>
<p>Which will become an extra step in our pipeline:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">check:</span>
    <span class="hljs-attr">working_directory:</span> <span class="hljs-string">~/app</span>

    <span class="hljs-attr">docker:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">image:</span> <span class="hljs-string">circleci/node:12.4</span>

    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">checkout</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">linter:js</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">test</span> <span class="hljs-string">--coverage</span> <span class="hljs-string">--runInBand</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">pact</span>
</code></pre>
<h4 id="heading-storing-the-pact">Storing the pact</h4>
<p>Our pact is a json file that we are going to commit directly in the frontend repository, after running the tests locally. I've found that this tends to work well enough. Making the pipeline itself commit the pact to <code>git</code> does not seem to be necessary.<br>We'll get to extending the pact and in a second.</p>
<h3 id="heading-the-provider-side">The provider side</h3>
<p>At this point we have a working pact, that is being verified by the consumer. But that is only half of the equation. Without a verification from the provider side, we haven't accomplished anything. Maybe even less than that, because we might get a false sense of security!</p>
<p>To do this, we are going to start the back end as a development server and run the pact against it. There is a <code>gradle</code> provider that takes care of this. We need to configure it and provide a way of finding the pact (which is stored in the front end repository). You can fetch the pact from the internet, or from a local file, whichever is more convenient.</p>
<pre><code class="lang-groovy">buildscript {
    dependencies {
        classpath 'au.com.dius:pact-jvm-provider-gradle_2.12:3.6.14'
    }
}

apply plugin: 'au.com.dius.pact'

pact {
    serviceProviders {
        api {
            port = 4003

            hasPactWith('frontend') {
                pactSource = url('https://path-to-the-pact/frontend-backend.json')
                stateChangeUrl = url("http://localhost:$port/pact")
            }
        }
    }
}
</code></pre>
<p>What remains is starting the server and running the pact against it, which we do with a small script:</p>
<pre><code class="lang-bash">goal_test-<span class="hljs-function"><span class="hljs-title">pact</span></span>() {
  <span class="hljs-built_in">trap</span> <span class="hljs-string">"stop_server"</span> EXIT

  goal_build
  start_server

  ./gradlew pactVerify
}

<span class="hljs-function"><span class="hljs-title">start_server</span></span>() {
  artifact=app.jar
  port=4003

  <span class="hljs-keyword">if</span> lsof -i -P -n | grep LISTEN | grep :<span class="hljs-variable">$port</span> &gt; /dev/null ; <span class="hljs-keyword">then</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Port[<span class="hljs-variable">${port}</span>] is busy. Server won't be able to start"</span>
    <span class="hljs-built_in">exit</span> 1
  <span class="hljs-keyword">fi</span>

  nohup java -Dspring.profiles.active=pact -jar ./build/libs/<span class="hljs-variable">${artifact}</span> &gt;/dev/null 2&gt;&amp;1 &amp;

  <span class="hljs-comment"># Wait for server to answer requests</span>
  until curl --output /dev/null --silent --fail http://localhost:<span class="hljs-variable">$port</span>/actuator/health; <span class="hljs-keyword">do</span>
    <span class="hljs-built_in">printf</span> <span class="hljs-string">'.'</span>
    sleep 3
  <span class="hljs-keyword">done</span>
}

<span class="hljs-function"><span class="hljs-title">stop_server</span></span>() {
  pkill -f <span class="hljs-string">'java -Dspring.profiles.active=pact -jar'</span>
}
</code></pre>
<h4 id="heading-fixtures">Fixtures</h4>
<p>If you are running your back end in development mode, it will have to deliver some data, so that the contract is fulfilled. Even if we are not using exact matching, we have to return something, otherwise it won't be possible to verify it.</p>
<p>You can use mocks, but I've found that avoiding them as much as possible leads to more trustworthy results. Your app is closer to what will happen in production. So what other options are there? Remember that when we were defining interactions, we had a <code>state</code>. That's the cue for the provider. One way of using it is the <code>stateChangeUrl</code>. We can provide a special controller to initialize our back end based on the <code>state</code>:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">val</span> PATH = <span class="hljs-string">"/pact"</span>

<span class="hljs-keyword">data</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Pact</span></span>(<span class="hljs-keyword">val</span> state: String)

<span class="hljs-meta">@RestController</span>
<span class="hljs-meta">@RequestMapping(PATH, consumes = [MediaType.APPLICATION_JSON_VALUE])</span>
<span class="hljs-meta">@ConditionalOnExpression(<span class="hljs-meta-string">"\${pact.enabled:true}"</span>)</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PactController</span></span>(<span class="hljs-keyword">val</span> repository: RecipeRepository) {
    <span class="hljs-meta">@PostMapping</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">setup</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> body: <span class="hljs-type">Pact</span>)</span></span>: ResponseEntity&lt;Map&lt;String,String&gt;&gt; {
        <span class="hljs-keyword">when</span>(body.state) {
            <span class="hljs-string">"i have a list of recipes"</span> -&gt; initialRecipes()
            <span class="hljs-keyword">else</span> -&gt; doNothing()
        }

        <span class="hljs-keyword">return</span> ResponseEntity.ok(mapOf())
    }
}
</code></pre>
<p>Note that this controller is only active for a specific profile, and won't exist outside of it.</p>
<h4 id="heading-integrating-it-in-the-pipeline-1">Integrating it in the pipeline</h4>
<p>As with the provider, we will run the check as part of our pipeline</p>
<pre><code class="lang-yaml"><span class="hljs-attr">version:</span> <span class="hljs-number">2</span>
<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>

    <span class="hljs-attr">working_directory:</span> <span class="hljs-string">~/app</span>

    <span class="hljs-attr">docker:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">image:</span> <span class="hljs-string">circleci/openjdk:8-jdk</span>

    <span class="hljs-attr">steps:</span>

      <span class="hljs-bullet">-</span> <span class="hljs-string">checkout</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">./go</span> <span class="hljs-string">linter-kt</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">./go</span> <span class="hljs-string">test-unit</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">./go</span> <span class="hljs-string">test-pact</span>
</code></pre>
<p>There is a slight difference, though. Our contract gets generated by the consumer. That means that a change in the front end could lead to a pact that does not verify properly anymore, even though no code was changed in the back end. So ideally, a change in the pact should trigger the back end pipeline as well. I haven't found a way to represent this elegantly in <em>CircleCI</em>, unlike say <a target="_blank" href="https://concourse-ci.org/">ConcourseCI</a>.</p>
<h2 id="heading-how-the-contract-influences-the-relationship-between-front-end-and-back-end">How the contract influences the relationship between front end and back end</h2>
<p>It's nice that we got this set up. <a target="_blank" href="https://en.wiktionary.org/wiki/never_change_a_running_system">Never touch a running system</a>, right? Well, we might! After all, quick change is why we invest in all this tooling. How would you introduce a change that requires extending the API?</p>
<ol>
<li>We start with the client. We want to define what the client will get that is not there yet. As we learned, we do that through a test in the front end that defines the expectation for the new route, or the new fields. That will create a new version of the pact.</li>
<li>Note that at this point the back end <em>does not</em> fulfill the pact. A new deployment of the back end will fail. But also, the <em>existing</em> backend does not fulfill the pact either right now. The change you introduced has to be backwards compatible. The front end should not be relying on the changes, either.</li>
<li>Now it's time to fulfill the new pact from the back end side. If this takes a long time, you will block your deployment process, which is not good. Consider doing smaller increments in that case. Anyways, you've got to implement the new functionality. The pact test will verify that your change is what's actually expected.</li>
<li>Now that the back end is providing the new functionality, you can freely integrate it in your front end.</li>
</ol>
<p>This flow can get a bit awkward in the beginning. It is really important to work with the smallest quantum of functionality. You don't want to block your deployment process.</p>
<h2 id="heading-next-steps">Next steps</h2>
<p>For the integration between your own front end and back end I have found this setup to be sufficient in practice. However, as complexity grows, versioning will become important. You'll want to help multiple teams collaborate more easily. For that, we can use a <a target="_blank" href="https://docs.pact.io/pact_broker">broker</a>. This is a lot harder to implement, so you should ask yourself if you really need it. Don't fix problems that you don't have yet.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>To summarize, this is the setup we arrived at:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/pipelines-full.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Think about all the time you have spent writing tests to check that your back end is sending the right data. That is a lot more convenient to do with a contract. Moreover, releasing front end and back end independently means being faster, releasing smaller pieces of functionality. It might feel scary at first, but you will realize that you actually are much more aware of what's going out that way.</p>
<p>Once you have adopted this for one service, there is no reason not to do it for all of them. I really don't miss running costly end to end test suites just to verify that my back end is working. Here is the code that I used in the examples for the <a target="_blank" href="https://github.com/sirech/cookery2-frontend">front end</a> and the <a target="_blank" href="https://github.com/sirech/cookery2-backend">back end</a>. It is a full running (albeit small) application. Good luck with your contracts!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Laravel Continuous Deployment With CircleCI and Deployer ]]>
                </title>
                <description>
                    <![CDATA[ By Bryan Lee There are many deployment solutions out there with deploying Laravel, ranging from SSH’ing into your machine and git pulling the files (?) to time-savers like Envoyer or rolling your own with Deployer. I personally love Deployer as it is... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/laravel-continuous-deployment-with-circleci-and-deployer-c70b27fa70d2/</link>
                <guid isPermaLink="false">66c35986cf1314a450f0d707</guid>
                
                    <category>
                        <![CDATA[ CircleCI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Laravel ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 09 Jan 2019 19:21:13 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*FM9PcX3sA-6NyQtKujjblQ.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Bryan Lee</p>
<p>There are many deployment solutions out there with deploying Laravel, ranging from SSH’ing into your machine and <code>git pull</code>ing the files (?) to time-savers like <a target="_blank" href="https://envoyer.io/">Envoyer</a> or rolling your own with Deployer. I personally love Deployer as it is free, very flexible and can support your projects from infancy to when you scale to multiple machines.</p>
<p>Deployer works by running your deployment scripts locally and we can make this even more convenient by integrating Deployer into your CI pipeline. For a recent project, I used CircleCI to run all my tests and automatically deploy.</p>
<h3 id="heading-setup-deployer-locally">Setup Deployer Locally</h3>
<p>To save time, I will highly recommend that you have <a target="_blank" href="https://deployer.org/">Deployer</a> installed locally and configured and working for your app. This saves a lot of time in having to do debugging on your Deployer config when your CircleCI build fails.</p>
<h3 id="heading-laravel-and-circleci">Laravel and CircleCI</h3>
<p>If you already have CircleCI setup for your Laravel project tests, skip to the next section. Otherwise, I assume that you at least already have a CircleCI account and a basic project created inside.</p>
<p>Create a <code>.circleci/config.yml</code> and with the below</p>
<pre><code class="lang-yml">
<span class="hljs-attr">version:</span> <span class="hljs-number">2</span>
<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>
    <span class="hljs-attr">docker:</span>
      <span class="hljs-comment"># Specify the version you desire here</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">image:</span> <span class="hljs-string">circleci/php:7.1-browsers</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">image:</span> <span class="hljs-string">circleci/mysql:5.7</span>
        <span class="hljs-attr">environment:</span>
          <span class="hljs-attr">MYSQL_ALLOW_EMPTY_PASSWORD:</span> <span class="hljs-literal">yes</span>
          <span class="hljs-attr">MYSQL_USER:</span> <span class="hljs-string">root</span>
          <span class="hljs-attr">MYSQL_ROOT_PASSWORD:</span> <span class="hljs-string">''</span>
          <span class="hljs-attr">MYSQL_DATABASE:</span> <span class="hljs-string">laravel</span>

    <span class="hljs-attr">working_directory:</span> <span class="hljs-string">~/laravel</span>

    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">checkout</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span>
          <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">PHP</span> <span class="hljs-string">exts</span>
          <span class="hljs-attr">command:</span> <span class="hljs-string">|
            sudo docker-php-ext-install zip
            sudo docker-php-ext-install pdo_mysql
            sudo apt install -y mysql-client
</span>      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">sudo</span> <span class="hljs-string">composer</span> <span class="hljs-string">self-update</span>

      <span class="hljs-comment"># Download and cache dependencies</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">restore_cache:</span>
          <span class="hljs-attr">keys:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">v1-dependencies-{{</span> <span class="hljs-string">checksum</span> <span class="hljs-string">"composer.json"</span> <span class="hljs-string">}}</span>
          <span class="hljs-comment"># fallback to using the latest cache if no exact match is found</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">v1-dependencies-</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">composer</span> <span class="hljs-string">install</span> <span class="hljs-string">-n</span> <span class="hljs-string">--prefer-dist</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">save_cache:</span>
          <span class="hljs-attr">paths:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-string">./vendor</span>
          <span class="hljs-attr">key:</span> <span class="hljs-string">v1-dependencies-{{</span> <span class="hljs-string">checksum</span> <span class="hljs-string">"composer.json"</span> <span class="hljs-string">}}</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span>
          <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">Laravel</span> <span class="hljs-string">stuffs</span>
          <span class="hljs-attr">command:</span> <span class="hljs-string">|
            php artisan migrate --force
</span>      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">./vendor/bin/phpunit</span>

<span class="hljs-attr">workflows:</span>
  <span class="hljs-attr">version:</span> <span class="hljs-number">2</span>
  <span class="hljs-attr">notify_deploy:</span>
    <span class="hljs-attr">jobs:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">build</span>
</code></pre>
<p>This is a very basic <code>config.yml</code> for Laravel. It will install PHP, MySQL and run PHPunit tests. Feel free to modify this to suit your needs.</p>
<h3 id="heading-circleci-deployment">CircleCI Deployment</h3>
<p>After our tests are run, we want CircleCI to automatically start deploying to our server. Remember that Deployer uses SSH, so in our remote server, we want to create a SSH keypair <code>ssh-keygen -t rsa -b 4096 -C “your@email.com"</code>. We want to add this key we created into CircleCI as a <a target="_blank" href="https://circleci.com/docs/2.0/add-ssh-key/">deployment key</a>. Take note of the fingerprint, as we will need to add this into our config file later.</p>
<p>Let’s create a new job in our config file:</p>
<pre><code>jobs:
  build: ... # <span class="hljs-keyword">from</span> above

  <span class="hljs-attr">deploy</span>:
    docker:
      - image: circleci/php:<span class="hljs-number">7.2</span>-browsers
    <span class="hljs-attr">working_directory</span>: ~/laravel
    <span class="hljs-attr">steps</span>:
      - checkout
</code></pre><p>This tells CircleCI that we have a new job called <code>deploy</code> and to build it based on the php-7.2-browsers docker image.</p>
<p>Remember the fingerprint that we took note of when we added it into CircleCI? We need to reference this in in our config so that the SSH key will be present in our container.</p>
<pre><code>jobs:
  build: ... # <span class="hljs-keyword">from</span> above

  <span class="hljs-attr">deploy</span>:
    docker:
      - image: circleci/php:<span class="hljs-number">7.2</span>-browsers
    <span class="hljs-attr">working_directory</span>: ~/laravel
    <span class="hljs-attr">steps</span>:
      - checkout
      - add_ssh_keys:
          fingerprints:
            - <span class="hljs-string">"YOUR_FINGERPRINT"</span>
</code></pre><p>So now, CircleCI knows to add this key via the fingerprint into the docker container and this will allow us to run Deployer and SSH into our remote server to deploy.</p>
<pre><code>jobs:
  build: ... # <span class="hljs-keyword">from</span> above

  <span class="hljs-attr">deploy</span>:
    docker:
      - image: circleci/php:<span class="hljs-number">7.2</span>-browsers
    <span class="hljs-attr">working_directory</span>: ~/laravel
    <span class="hljs-attr">steps</span>:
      - checkout
      - add_ssh_keys:
          fingerprints:
            - <span class="hljs-string">"YOUR_FINGERPRINT"</span>
      - run:
          name: Install Deployer
          <span class="hljs-attr">command</span>: |
            curl -LO https:<span class="hljs-comment">//deployer.org/deployer.phar</span>
            sudo mv deployer.phar /usr/local/bin/dep
            sudo chmod +x /usr/local/bin/dep
      - run:
          name: Deploy
          <span class="hljs-attr">command</span>: |
            dep deploy www.your_server.com
</code></pre><p>With the <code>deploy</code> job defined, the last step would be to tell CircleCI to run it after our tests pass. That’s simple, we already have a basic workflow named <code>notify_deploy</code> that we can build upon.</p>
<pre><code>workflows:
  version: <span class="hljs-number">2</span>
  <span class="hljs-attr">notify_deploy</span>:
    jobs:
      - build
      - deploy:
          requires:
            - build
          <span class="hljs-attr">filters</span>:
            branches:
              only: master
</code></pre><p>This tells CircleCI that in our <code>notify_deploy</code> workflow, aside from running <code>build</code>, we want to run <code>deploy</code> after it is finished, and to only do it on the <code>master</code> branch.</p>
<p>With everything done, we can now push the config file to our git repository and watch it test and deploy on its own. Do you use a different way of deploying Laravel? Let me know, I’d love to hear about it!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to setup Continuous Deployment to AWS S3 using CircleCI in just 30 minutes ]]>
                </title>
                <description>
                    <![CDATA[ By Adam Watt Continuous Deployment might seem complicated at first, but don’t be intimidated. In this tutorial, I’ll show you how to implement Continuous Deployment to AWS S3 for a static website using CircleCI in less than 30 minutes. You’ll need bo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-set-up-continuous-deployment-to-aws-s3-using-circleci-in-under-30-minutes-a8e268284098/</link>
                <guid isPermaLink="false">66c3547911526e205ba67895</guid>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CircleCI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Devops ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 28 Apr 2017 18:01:39 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*iEPDwncshci0-coGQn96Cg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Adam Watt</p>
<p>Continuous Deployment might seem complicated at first, but don’t be intimidated. In this tutorial, I’ll show you how to implement Continuous Deployment to AWS S3 for a static website using CircleCI in less than 30 minutes.</p>
<p>You’ll need both an AWS account and a CircleCI account. If you don’t have these yet, start by opening a free account for AWS <a target="_blank" href="https://aws.amazon.com/free">here</a> and a free CircleCI account <a target="_blank" href="https://circleci.com/signup/">here</a> . Both AWS and CircleCI have a free tier that’s more than enough for what you will need for this tutorial.</p>
<h3 id="heading-getting-the-code">Getting the code</h3>
<p>First you will start by forking and cloning the following project repo on Github: <a target="_blank" href="https://github.com/AWattNY/S3ContinuousDeploy">S3ContinuousDeploy</a> or if you prefer you can try this tutorial with one of your own repos as long as it’s a static site.</p>
<p>Next you will add the project to your CircleCI account.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*rpHcpF4I7W0mDu1H0WvgUg.png" alt="Image" width="800" height="544" loading="lazy"></p>
<p>Next select the S3ContinuousDeploy repo you just cloned and click build project.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*_dnV50_unj8H9RODMVQQYg.png" alt="Image" width="800" height="315" loading="lazy">
<em>Choose the S3ContinuousDeploy repo and click build project</em></p>
<p>At this point the build will run, but you will be getting an error message warning you that the settings for your project couldn’t be detected. Which is normal since we don’t have a circle.yml configuration file in place, which is what you will be doing next.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*PDeB4RAPCc2_kmD3dBS92g.png" alt="Image" width="800" height="537" loading="lazy"></p>
<p>Looking at the docs at CircleCI you can get an idea of what the circle.yml should look like. Unfortunately the circle.yml file example provided will not work as is and will need some tweaking, so let’s do that.</p>
<p>Below is the modified circle.yml file you will be using:</p>
<p>Basically CircleCI creates the build within a Docker container, and the override under dependencies property (line 3) that I added instructs CircleCI to install the AWS command line interface (awscli) that will be used in this case to help manage and facilitate deployment to AWS S3.</p>
<p>So make sure you add the file and commit it to your repo. Finally make sure you push this and other commits you might have made before you proceed to the next step.</p>
<p>As per CircleCI documentation the command for deploying is:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*ZUGQqjk7ozjUk6pnXu-LOg.png" alt="Image" width="800" height="75" loading="lazy"></p>
<p>The path-to-file was a bit tricky to figure out but by looking at the error logs I was able to finally get it right: home\ubuntu\projectName. So just replace projectName with the name of your project, in my case that will be S3ContinuousDeploy.</p>
<p>The S3://bucket-URL on the other hand is not correct and should be S3://bucket-Name. Right now we don’t have a bucket name, so let’s get ourselves a bucket.</p>
<h3 id="heading-creating-the-s3-bucket">Creating the S3 bucket</h3>
<p>In this step we will be heading to the AWS Console to create the S3 bucket for this project:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*09G_AT9IHbI6tNiLGew1Sg.png" alt="Image" width="800" height="869" loading="lazy">
<em>In Your Console go to Storage and then to S3</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*R1EUamf6tJuw1mdjTOXAbg.png" alt="Image" width="800" height="533" loading="lazy">
<em>Press Create bucket</em></p>
<p>Enter the bucket name you would like to use for this project as well as the region. (The best practice is to use the region nearest to your site’s audience.)</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*gs2tyd8N7P3N8LRAbfvzoQ.png" alt="Image" width="800" height="770" loading="lazy"></p>
<p>You will skip the other steps for now so press “Next” and then press “Create bucket” on the review screen.</p>
<p>At this point if you go back to CircleCI and try to run the build again CircleCI will return a fatal error: Unable to locate credentials. So why don’t we fix that next.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*vfzxm4Ob1NzwGbFLu9MNZg.png" alt="Image" width="800" height="93" loading="lazy"></p>
<p>We need to first get the credentials from AWS and then provide them to CircleCI in order to allow the AWS cli to access and manage the S3 bucket. Best practice for this is to create a new Identity and Access Management (IAM) user specifically for CircleCI.</p>
<p>On the AWS console go to Security, Identity &amp; Compliance and press IAM and then Add user.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*5URhjWCf_Cva14j10iC9lQ.png" alt="Image" width="800" height="358" loading="lazy"></p>
<p>In the Add User window type in CircleCI for User name, I already have an IAM user named CircleCI setup, So for the purposes of this tutorial and to illustrate these steps I will be using CircleCI2. Make sure you check Programmatic access for Access type.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*8E2Zq-4Rf6zayOnXlu0xiw.png" alt="Image" width="800" height="387" loading="lazy"></p>
<p>For permissions choose Attach existing policies directly, and under Policy name check ‘AdministratorAccess’ and then click Create policy. This will provide your IAM user full access to your AWS S3 bucket.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*mSW3jMhrBXujFE1RbfcdnA.png" alt="Image" width="800" height="544" loading="lazy"></p>
<p>After creating the IAM user, make sure you keep both the Access key ID and the Secret access key, as we will need them in the next step.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*N58N_nM1aeh2TV2K0nB1EA.png" alt="Image" width="800" height="389" loading="lazy"></p>
<p>Now back to CircleCI, click on the settings button next to your project name to reveal the project settings menu then click on AWS Permissions. This is where you will paste the ID and Key from the previous step and then click “Save AWS keys.”</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*nL8EUSt2c0udyOdQQ-NC0A.png" alt="Image" width="800" height="322" loading="lazy"></p>
<p>Now our CircleCI Container has both the AWS Command Line Interface tool and the credentials to access the AWS S3 bucket. The following steps will show you how to reveal your static site to the world.</p>
<p>In the AWS console go to Storage and then click on S3 and then click on the bucket we created earlier in this tutorial.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*2HqAqD8aNKhIrJlKuT25nw.png" alt="Image" width="800" height="687" loading="lazy"></p>
<p>You will notice that the code from the repo has already been successfully deployed.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*IVZMtV4e7Txu4l6FFW0SOg.png" alt="Image" width="800" height="812" loading="lazy"></p>
<p>Now before you can access this static site you need to configure your S3 bucket for website hosting.</p>
<p>On the same screen click on Properties and then on Static website hosting.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*cdQFxfsKAfLu3pUqb-bUGw.png" alt="Image" width="800" height="341" loading="lazy"></p>
<p>In the following screen select Use this bucket to host a website and make sure you type in index.html for Index document.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*YbdCVHxvWBpxyA-Q6B8eTQ.png" alt="Image" width="800" height="862" loading="lazy"></p>
<p>By the way, the HTTP address provided above is your access endpoint. But if you try it in the browser unfortunately it won’t work and you will get an access denied error message. But that’s normal you still have one step to do: Set up your bucket policy.</p>
<p>This Bucket policy will allow access to the AWS S3 bucket to anyone via a browser.</p>
<p>You can read up <a target="_blank" href="http://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html">here</a> on bucket policies and examples if you want to learn more.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*CJ0YNFnZWV3WA4wrP-uwKQ.png" alt="Image" width="800" height="417" loading="lazy"></p>
<p>Now you can copy the code snippet above and paste it in your Bucket policy Editor and Voila!</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*gD8DcazPynHucGTlBGu5dg.png" alt="Image" width="800" height="435" loading="lazy"></p>
<p>If you see the screen above, then Congratulations! You have successfully set up Continuous Deployment to an AWS S3 bucket using CircleCI.</p>
<p>Now every time you push changes to your Github repo, CircleCI will automatically deploy the changes to your AWS S3 bucket.</p>
<p>You might have noticed that even though the deployment was successful CircleCI shows you a red NO TESTS warning.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*QPWUzhV3CetGhRarc2HEaQ.png" alt="Image" width="800" height="66" loading="lazy"></p>
<p>This is normal because in a Test Driven Development (TDD) environment you would write tests first, and then before going to production your code needs to pass all the tests. An example with tests is beyond the scope of this tutorial, but suffice it to say that had we written tests, CircleCI would only have deployed if all our tests passed.</p>
<p>Using your own domain name to access this static site is also beyond the scope of this tutorial, but feel free to look <a target="_blank" href="http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/setting-up-route-53.html">here</a> for instructions on how to configure Amazon Route 53 to route Internet traffic to your new site.</p>
<p>I am hoping to do a tutorial involving a Continuous Integration/Deployment example with a full battery of tests sometimes in the future. Meanwhile, if you have a moment, answer a short survey about this tutorial <a target="_blank" href="https://goo.gl/forms/aJl610F4ltAvMDBv1">here</a>, like it on <a target="_blank" href="https://www.linkedin.com/pulse/how-set-up-continuous-deployment-aws-s3-using-circleci-adam-watt">LinkedIn</a> or post a comment in the comments section.</p>
<p>Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
