<?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>Forem: João Gomes</title>
    <description>The latest articles on Forem by João Gomes (@kenvontucky).</description>
    <link>https://forem.com/kenvontucky</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F106918%2Feca4aa77-724b-4e62-ac45-018562b2d0f1.png</url>
      <title>Forem: João Gomes</title>
      <link>https://forem.com/kenvontucky</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kenvontucky"/>
    <language>en</language>
    <item>
      <title>Starting with AWS DynamoDB using Python</title>
      <dc:creator>João Gomes</dc:creator>
      <pubDate>Tue, 10 Mar 2020 10:08:07 +0000</pubDate>
      <link>https://forem.com/runtime-revolution/starting-with-aws-dynamodb-using-python-1blm</link>
      <guid>https://forem.com/runtime-revolution/starting-with-aws-dynamodb-using-python-1blm</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IJY8LWLB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/680/1%2AqKw_ICEQ8Aw202wAEroxhw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IJY8LWLB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/680/1%2AqKw_ICEQ8Aw202wAEroxhw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Amazon &lt;strong&gt;DynamoDB&lt;/strong&gt; is a &lt;em&gt;key-value and document database that delivers single-digit millisecond performance at any scale.&lt;/em&gt; &lt;a href="https://aws.amazon.com/dynamodb/"&gt;https://aws.amazon.com/dynamodb/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This guide is meant to provide a base, or a quick start, for interfacing with AWS DynamoDB using Python, its contents are based on the repo &lt;a href="https://github.com/5thempire/aws-dynamodb"&gt;https://github.com/5thempire/aws-dynamodb&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The chosen examples are meant to illustrate the breadth of options available, even though they’re not the typical use case.&lt;/p&gt;

&lt;p&gt;We are going to create two tables: one for storing URLs and their corresponding domain, and another for storing logs, which have a timestamp, a log status and a message. The URLs data model will be using a key-value configuration, while the logs data model will use a document configuration.&lt;/p&gt;

&lt;p&gt;First things first, let’s define the data models.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key-Value — URL data model
&lt;/h3&gt;

&lt;p&gt;The key-value configuration is a very simple implementation, where the only requirement is to specify the key or index. In DynamoDB this is set under the attribute definition and the key schema.&lt;/p&gt;

&lt;p&gt;The attribute definition stores the name of the keys and their corresponding type.&lt;/p&gt;

&lt;p&gt;The key schema defines the type of primary keys we’re using, in DynamoDB they can be one of two types, hash or range. We could have one of each, but for the current example we’ll only be using hash, leaving out range for you to play with.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Document — Log data model
&lt;/h3&gt;

&lt;p&gt;The document configuration is a bit more complex. To query the log documents we’ll use two indexes, one will be the timestamp and the other the status of the log, the latter of which is set as a global secondary index.&lt;/p&gt;

&lt;p&gt;The global secondary index also includes a projection attribute. This configuration is very important, since it defines what will be retrieved when we query using the secondary index. In our definition we’re retrieving the complete document.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Python DynamoDB base class
&lt;/h3&gt;

&lt;p&gt;This approach has one base class to interact with DynamoDB, which is not meant to be used on its own, but to provide a solid base for the table specific definitions. These specificities are set by overriding the abstract methods for get, put, update and remove.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Python URL class
&lt;/h3&gt;

&lt;p&gt;This class overrides the base class by defining what’s specific to the domain data model interaction.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Python Log class
&lt;/h3&gt;

&lt;p&gt;This class overrides the base class by defining what’s specific to the log data model interaction, but also adds filtering methods. There are two filters defined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;filter_by_timestamp_status&lt;/strong&gt; : which uses both timestamp and status keys to filter results&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;filter_by_status&lt;/strong&gt; : which filters by a specific status (i.e.: INFO)&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;Don’t forget there are a few options out there that provide the typical level of abstraction a database model normally requires. However, sometimes a more hands on approach is preferred.&lt;/p&gt;

&lt;p&gt;For those who want to experience a running example visit &lt;a href="https://github.com/5thempire/aws-dynamodb"&gt;https://github.com/5thempire/aws-dynamodb&lt;/a&gt;. There you’ll find the samples mentioned here along with the corresponding set of tests, that can be used as a basis for further experiments.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html"&gt;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://amazon-dynamodb-labs.com/"&gt;https://amazon-dynamodb-labs.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;At&lt;/em&gt; &lt;a href="http://www.runtime-revolution.com/"&gt;&lt;em&gt;Runtime Revolution&lt;/em&gt;&lt;/a&gt; &lt;em&gt;we take our craft seriously and always go the extra mile to deliver a reliable, maintainable, and testable product. Do you have a project to move forward or a product you’d like to launch? We would love to help you!&lt;/em&gt;&lt;/p&gt;




</description>
      <category>python</category>
      <category>softwareengineering</category>
      <category>aws</category>
      <category>dynamodb</category>
    </item>
    <item>
      <title>Getting started with Angular 6, GitLab CI/CD and Google App Engine </title>
      <dc:creator>João Gomes</dc:creator>
      <pubDate>Tue, 16 Oct 2018 09:51:21 +0000</pubDate>
      <link>https://forem.com/runtime-revolution/getting-started-with-angular-6-gitlab-cicd-and-google-app-engine--2okk</link>
      <guid>https://forem.com/runtime-revolution/getting-started-with-angular-6-gitlab-cicd-and-google-app-engine--2okk</guid>
      <description>&lt;p&gt;This article will provide an initial setup to better understand and configure a continuous integration and delivery architecture (CI/CD). In a world where each tool overlaps the next, we want something simple, reliable, and easy to maintain. That’s why GitLab was chosen, as it provides a set of tools that would have to be externally added otherwise.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This guide assumes none of the tools mentioned in the title were either installed or configured.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Angular 6
&lt;/h2&gt;

&lt;p&gt;Let’s start by installing the Angular CLI globally. Check &lt;a href="https://nodejs.org/en/download/"&gt;https://nodejs.org/en/download/&lt;/a&gt; if NodeJS and npm are not installed.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install -g @angular/cli
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create a new Angular application&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ng new demo-app
$ cd demo-app/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Angular will set up everything you need for your application, including initial test setup.&lt;/p&gt;

&lt;p&gt;Run the following, to run the unit tests.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ng test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And the following, for the end to end tests.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ng e2e
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To run a server.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ng serve --open
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When an application is created with the Angular CLI, a git repository is also created.&lt;/p&gt;

&lt;p&gt;Let’s move to GitLab configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitLab
&lt;/h2&gt;

&lt;p&gt;Create an account at &lt;a href="https://about.gitlab.com/"&gt;https://about.gitlab.com/&lt;/a&gt; and then a &lt;strong&gt;&lt;em&gt;New Project&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E1sNEhTx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2APhZ-aMYorUXQN0I68UHtew.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E1sNEhTx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2APhZ-aMYorUXQN0I68UHtew.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve set up your empty repository, a list with several options regarding your local git configuration will show up.&lt;/p&gt;

&lt;p&gt;Do not forget to set your &lt;strong&gt;ssh keys&lt;/strong&gt;, check the following links for more information &lt;a href="https://docs.gitlab.com/ee/ssh/README.html"&gt;https://docs.gitlab.com/ee/ssh/README.html&lt;/a&gt; and &lt;a href="https://docs.gitlab.com/ee/gitlab-basics/create-your-ssh-keys.html"&gt;https://docs.gitlab.com/ee/gitlab-basics/create-your-ssh-keys.html&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s configure the previously created GitLab repository to be our &lt;strong&gt;Angular application origin&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git remote add origin git@gitlab.com:&amp;lt;your_account&amp;gt;/demo-app.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Push it.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git push --set-upstream origin master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Google App Engine
&lt;/h2&gt;

&lt;p&gt;This is a serverless platform that allows you to build highly scalable applications. Create an account at &lt;a href="https://cloud.google.com/appengine/"&gt;https://cloud.google.com/appengine/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Similarly to other services, Google Cloud asks for a credit card upon the creation of an account, and also, as other services do, they provide an amount of credit ($300) for you to explore the platform. The trial period lasts for one year, or until the provided credit is used up.&lt;/p&gt;

&lt;p&gt;Create a new project. Below is our project’s definition.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nZ-r4A8J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A8p7AaBdotPk2jOwbyH8abg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nZ-r4A8J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A8p7AaBdotPk2jOwbyH8abg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the project is ready, a set of options similar to the ones below will be available.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I0l25pbA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3360/1%2Aa_Dx5QbzDuuN7qv1k-7LBQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I0l25pbA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3360/1%2Aa_Dx5QbzDuuN7qv1k-7LBQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we’re going to create an application. Click **Create Application and **choose a region for your app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d6VV1TVB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AQEKJ3y3cck6MTZrFPVFeeA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d6VV1TVB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AQEKJ3y3cck6MTZrFPVFeeA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Define the &lt;strong&gt;language&lt;/strong&gt; and the &lt;strong&gt;environment&lt;/strong&gt;. The &lt;strong&gt;language&lt;/strong&gt; will be &lt;strong&gt;Node.js&lt;/strong&gt; and the &lt;strong&gt;environment&lt;/strong&gt; will be &lt;strong&gt;Standard&lt;/strong&gt;. To learn more about this topic check &lt;a href="https://cloud.google.com/appengine/docs/the-appengine-environments"&gt;https://cloud.google.com/appengine/docs/the-appengine-environments&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_IBtpqaZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A3WXOW1cyhZFcXXKVEzXbfA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_IBtpqaZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A3WXOW1cyhZFcXXKVEzXbfA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Et voilà! We have created our application!&lt;/p&gt;

&lt;p&gt;Before continuing, we want to make sure the deploys are working properly, so we’re going to deploy our &lt;strong&gt;Angular Application,&lt;/strong&gt; using two different configurations, via command line.&lt;/p&gt;

&lt;p&gt;First, we need to build our application.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ng build --prod --aot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We also need to create an &lt;strong&gt;app.yaml.&lt;/strong&gt; This is the deployment configuration for Google App Engine.&lt;/p&gt;

&lt;p&gt;To learn a bit more about the available configuration options take a look at &lt;a href="https://cloud.google.com/appengine/docs/standard/python/config/appref"&gt;https://cloud.google.com/appengine/docs/standard/python/config/appref&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Second step, is to install the &lt;strong&gt;Google&lt;/strong&gt; &lt;strong&gt;Cloud SDK.&lt;/strong&gt; Follow the steps at &lt;a href="https://cloud.google.com/sdk/"&gt;https://cloud.google.com/sdk/&lt;/a&gt; so that we can &lt;strong&gt;deploy our application via command line&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  gcloud deploy with user credentials
&lt;/h3&gt;

&lt;p&gt;Run the following command to initialise and set a new configuration. Choose one that’s associated with your user.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ gcloud init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once that’s set, run the command below to deploy and follow the instructions.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ gcloud app deploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  gcloud deploy with service account
&lt;/h3&gt;

&lt;p&gt;Navigate to &lt;strong&gt;Google App Engine console&lt;/strong&gt;, go to &lt;strong&gt;IAM &amp;amp; admin. **There we’ll find a list of users/members and their respective roles. Since we want to deploy our Angular application via GitLab’s CD, we need to add a **service account&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to Service Accounts menu.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bCf5gzTC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AnZvsM-UmM1WadjHA7MxmgA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bCf5gzTC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AnZvsM-UmM1WadjHA7MxmgA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a service account for GitLab.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cQGlQRRD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AeUdqVnYSciwcHdngF14TfA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cQGlQRRD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AeUdqVnYSciwcHdngF14TfA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a key for that account and save the json.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PCUaew4a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Al63hV4mDEMnmKEIzzxhI7A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PCUaew4a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Al63hV4mDEMnmKEIzzxhI7A.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PK0io_Jk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AaahbblNk8LW8eIXci-8bMA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PK0io_Jk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AaahbblNk8LW8eIXci-8bMA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to IAM where the members and their roles are listed, and add the following roles to the service account we’ve just created: &lt;strong&gt;App Engine&lt;/strong&gt; &lt;strong&gt;Admin&lt;/strong&gt;, &lt;strong&gt;Cloud Build Editor&lt;/strong&gt; and &lt;strong&gt;Storage Admin&lt;/strong&gt;. To better understand roles check &lt;a href="https://cloud.google.com/iam/docs/understanding-roles"&gt;https://cloud.google.com/iam/docs/understanding-roles&lt;/a&gt; .&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5Efi4ZbQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3664/1%2ATNrbHjtWnwRVAuXTOJCKcA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5Efi4ZbQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3664/1%2ATNrbHjtWnwRVAuXTOJCKcA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we’ve set up our Google App Engine side of things, we can deploy our Angular application using the &lt;strong&gt;Service Account&lt;/strong&gt;. Run the following commands, the first is to authenticate using the service account, and the second is to deploy the Angular application. The option “— project” is the &lt;strong&gt;Project ID&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ gcloud auth activate-service-account --key-file &amp;lt;service-acc-key.json&amp;gt;
$ gcloud app deploy --project=elite-academy-217722
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Angular 6 + GitLab CI
&lt;/h2&gt;

&lt;p&gt;Before activating the GitLab’s CI let’s change the way tests are run. If you recall, when you ran&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ng test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ng e2e
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A browser is opened and the test is performed. However, this is not supported by the GitLab’s CI. To overcome this we’re going to use a headless browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test with Headless browser via Puppeteer
&lt;/h3&gt;

&lt;p&gt;Install puppeteer and it will also install headless Chromium.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install puppeteer --save
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we need to update &lt;strong&gt;karma.conf.js&lt;/strong&gt; that is responsible for &lt;strong&gt;ng test&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And also &lt;strong&gt;protractor.conf.js&lt;/strong&gt; responsible for &lt;strong&gt;ng e2e&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To automatically activate GitLab’s CI we need to add a file with the jobs to run. In this particular case we’re going to run two jobs, one for each test command.&lt;/p&gt;

&lt;h3&gt;
  
  
  CI jobs
&lt;/h3&gt;

&lt;p&gt;Create a file with the name **.gitlab-ci.yml **at the root of demo-app, with the following content.&lt;/p&gt;

&lt;p&gt;Let’s go through the above configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;image&lt;/strong&gt; : this defines the docker image that’s going to be run by GitLab’s runners. Our base is NodeJS, so this defines that we’re going to use the latest NodeJS image.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;**cache: **whenever a release is built, a cache is created. In this case, we’re caching node_modules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;**before_script: **this option defines the operations that we must run before executing a job. The first line defines all the additional packages that are required by Chromium, and the second line installs all the saved NodeJS packages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;stages: **here we define job groups. All jobs within a group are run in parallel. **Stage test&lt;/strong&gt; runs first and, if it succeeds, &lt;strong&gt;stage build&lt;/strong&gt; runs afterwords.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;job 1:&lt;/strong&gt; is the job responsible for running the unit tests. The stage where it runs is defined and also the script that’s going to perform the test. The relative path towards the project must be set, otherwise the executable won’t be found.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;job 2:&lt;/strong&gt; is the job responsible for the end-to-end tests. The configuration is very similar to the previous job.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;release_job: **besides the already mentioned options, the release includes an artifact and a requirement tag. **Artifact&lt;/strong&gt; is the result of the angular build, in this case it is set for production and compiled with the ahead of time option for better performance. The requirement tag is &lt;strong&gt;only&lt;/strong&gt;, and is set to &lt;strong&gt;tags&lt;/strong&gt;. This configuration means that release_job is only available whenever a release is created.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Push all the previous updates to the repository and check GitLab’s &lt;strong&gt;Pipeline&lt;/strong&gt; under &lt;strong&gt;CI/CD&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b4SDMPjk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4076/1%2AYNWsZjoPCgoiy31CNPP8Eg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b4SDMPjk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4076/1%2AYNWsZjoPCgoiy31CNPP8Eg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the icon on the left that says &lt;strong&gt;passed&lt;/strong&gt;, to access the jobs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KQiR07Mi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Aq0oCWj45gQFTYu1eQ_XsrA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KQiR07Mi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Aq0oCWj45gQFTYu1eQ_XsrA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Release
&lt;/h3&gt;

&lt;p&gt;Let’s create a release to check our release job. In GitLab, on the side menu under &lt;strong&gt;Repository&lt;/strong&gt; you’ll find &lt;strong&gt;Tags&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PwoJh2qX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4060/1%2A0p0JJtz6noRv_qZGvF8mUA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PwoJh2qX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4060/1%2A0p0JJtz6noRv_qZGvF8mUA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our first release is created&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TXhsxsRw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A574LOcpsYgFLQOCycMgk6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TXhsxsRw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A574LOcpsYgFLQOCycMgk6g.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s click the link within the git reference associated with the release, and then click the pipeline option. Our pipeline now has an additional step, &lt;strong&gt;build&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2XsonISq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AM3sV96VRqaHCc1HwsznS0A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2XsonISq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AM3sV96VRqaHCc1HwsznS0A.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under tags you have the option to download your newly built release. You can do so by choosing &lt;strong&gt;Download ‘release_job’&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HMXzubFi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4052/1%2Ar7i31s3m3jdILOkCnexPcA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HMXzubFi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4052/1%2Ar7i31s3m3jdILOkCnexPcA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Angular 6 + GitLab + Google App Engine
&lt;/h2&gt;

&lt;p&gt;Now that everything is set, we are going to configure &lt;strong&gt;Manual&lt;/strong&gt; deploys from &lt;strong&gt;GitLab **to&lt;/strong&gt; Google App Engine**. It could be automatic whenever a release is built, but people make mistakes, so we’re going to set it to manual mode.&lt;/p&gt;

&lt;p&gt;To do that, there are two things we need to do: configure environment variables and update .gitlab-ci.yml to run our deploy commands.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set environment variables in GitLab
&lt;/h3&gt;

&lt;p&gt;Under the settings menu in our GitLab project we’ll find the &lt;strong&gt;Variables&lt;/strong&gt; menu, click expand.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LLUve7Rb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3132/1%2AmJUnzWerg6vNahS-ZRcXuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LLUve7Rb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3132/1%2AmJUnzWerg6vNahS-ZRcXuw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create two variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GAE_KEY_FILE&lt;/strong&gt;: copy the content of the json file associated with the &lt;strong&gt;Google App Engine service account&lt;/strong&gt; and paste it in the value field.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GAE_PROJECT_ID&lt;/strong&gt;: the project id, in this case it’s value is &lt;strong&gt;elite-academy-217722&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Save variables.&lt;/p&gt;

&lt;h3&gt;
  
  
  .gitlab-ci.yml update
&lt;/h3&gt;

&lt;p&gt;The main addition was the deploy stage, however some other changes were introduced regarding the job names and script execution.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;before_script&lt;/strong&gt; was moved inside each job, this means it will run for &lt;strong&gt;job:test&lt;/strong&gt; and &lt;strong&gt;job:e2e&lt;/strong&gt; but not for &lt;strong&gt;deploy:production&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s go through the job &lt;strong&gt;deploy:production&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;stage&lt;/strong&gt;: stage that’s associated with it, in this case &lt;strong&gt;deploy&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;environment&lt;/strong&gt;: this allows us to rollback if necessary. When a deploy is successful it will appear under &lt;strong&gt;GitLab’s Operations &amp;gt; Environments&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xkWhDNqo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3860/1%2AOfi99QMOcfbGhDPgKgB3ig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xkWhDNqo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3860/1%2AOfi99QMOcfbGhDPgKgB3ig.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;before_script&lt;/strong&gt;: only has the necessary scripts for deployment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;dependencies&lt;/strong&gt;: it will depend on the job &lt;strong&gt;release:build&lt;/strong&gt;, meaning that the &lt;strong&gt;artifact&lt;/strong&gt; that was created under the dependency will be available in this job. Also means that the build only runs once.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;scripts&lt;/strong&gt;: scripts used for deployment. As you can see, they are the same as the ones we tested earlier with &lt;strong&gt;service account&lt;/strong&gt;. Both service account key file and project ID are set in GitLab’s environment variables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;when&lt;/strong&gt;: set to &lt;strong&gt;manual&lt;/strong&gt;, so that the deploy does not occur automatically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;only&lt;/strong&gt;: similarly to the build, this job is only available when a release/tag is created.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The next time we &lt;strong&gt;create a release/tag&lt;/strong&gt;, we’ll have something new in our &lt;strong&gt;pipeline&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C_bBS-d3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2448/1%2AO84mXoZxo3JtZWwnkzmTAA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C_bBS-d3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2448/1%2AO84mXoZxo3JtZWwnkzmTAA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Press &lt;strong&gt;&lt;em&gt;play&lt;/em&gt;&lt;/strong&gt; and the &lt;strong&gt;Angular&lt;/strong&gt; application will be deployed to &lt;strong&gt;Google App Engine&lt;/strong&gt; via &lt;strong&gt;GitLab’s CD.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That’s it! Hope you’ve found this guide helpful. Fell free to share your thoughts, problems or suggestions and don’t forget there’s always room for improvement!&lt;/p&gt;

&lt;p&gt;Take it away!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;At &lt;a href="http://www.runtime-revolution.com/"&gt;Runtime Revolution&lt;/a&gt; we take our craft seriously and always go the extra mile to deliver a reliable, maintainable, and testable product. Do you have a project to move forward or a product you’d like to launch? We would love to help you!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>angular</category>
      <category>gitlab</category>
      <category>googleappengine</category>
    </item>
  </channel>
</rss>
