{"id":1821,"date":"2022-04-09T20:55:36","date_gmt":"2022-04-09T18:55:36","guid":{"rendered":"https:\/\/nguenkam.com\/blog\/?p=1821"},"modified":"2022-04-09T20:55:36","modified_gmt":"2022-04-09T18:55:36","slug":"setup-gitlab-ci-cd-pipeline-for-angular","status":"publish","type":"post","link":"https:\/\/nguenkam.com\/blog\/index.php\/2022\/04\/09\/setup-gitlab-ci-cd-pipeline-for-angular\/","title":{"rendered":"Setup Gitlab CI\/CD Pipeline For Angular"},"content":{"rendered":"\n<p><span class=\"has-inline-color has-vivid-cyan-blue-color\"><strong><em>Gitlab<\/em><\/strong><\/span>, one of the famous Git repository manager which comes with a\u00a0<strong>web-based DevOps<\/strong>\u00a0life cycle tool, inbuilt wiki, container registry, issue tracking,\u00a0<strong>continuous integration, and deployment pipeline<\/strong>\u00a0features.<\/p>\n\n\n\n<p>We can use<strong>\u00a0GitLab as a Saas<\/strong>\u00a0or else\u00a0<strong>Self-managed installation on our own host<\/strong>\u00a0with Linux for free.<\/p>\n\n\n\n<p>Let\u00b4s see \u00a0how we can set up CI\/CD (Continuous Integration\/Deployment) pipeline with GitLab for an Angular frontend application.<\/p>\n\n\n\n<h4>Gitlab CI Pipeline Stages<\/h4>\n\n\n\n<p>Let us assume the base application comes with Linter integration with\u00a0<a rel=\"noreferrer noopener\" href=\"https:\/\/eslint.org\/\" target=\"_blank\">EsLint<\/a>\u00a0and Unit testings with\u00a0<a rel=\"noreferrer noopener\" href=\"https:\/\/angular.io\/guide\/testing\" target=\"_blank\">Karma<\/a>. So In this pipeline setup, we are going to integrate stages for both\u00a0<strong>Lint<\/strong>\u00a0and\u00a0<strong>Unit Test\u00a0<\/strong>as well.<\/p>\n\n\n\n<p>So stages for this pipeline setup will be,<\/p>\n\n\n\n<ul><li><strong>dependencies<\/strong>\u00a0\u2014 In this stage pipeline will run npm install and cache the node_modules share between other stages in this setup.<\/li><li><strong>test \u2014\u00a0<\/strong>Covering unit test and lint for the angular application at this stage.<\/li><li><strong>build<\/strong>\u00a0\u2014 Build the angular application for production and mark dist\/folder content as artifacts for final publishing.<\/li><li><strong>publish \u2014\u00a0<\/strong>Building and publishing docker images with Nginx to Gitlab inbuilt docker registry to run this angular application in a docker environment.<\/li><\/ul>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-19.png\" alt=\"\" class=\"wp-image-1822\" width=\"554\" height=\"193\" srcset=\"https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-19.png 889w, https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-19-300x105.png 300w\" sizes=\"(max-width: 554px) 100vw, 554px\" \/><\/figure><\/div>\n\n\n\n<h4 id=\"4f3e\">Gitlab CI File<\/h4>\n\n\n\n<p id=\"5ca7\">Now we can check how we could achieve the above stages on downloaded angular application with gitlab CI.<\/p>\n\n\n\n<p id=\"771a\">Here in this setup, we need to include a new file on the project root, named\u00a0<strong>.gitlab-ci.yml.\u00a0<\/strong>This file should include all the instructions on what are the stages and separate instructions to run on those stages while running the pipeline.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-20.png\" alt=\"\" class=\"wp-image-1823\" width=\"370\" height=\"375\" srcset=\"https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-20.png 608w, https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-20-296x300.png 296w, https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-20-24x24.png 24w, https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-20-48x48.png 48w, https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-20-96x96.png 96w\" sizes=\"(max-width: 370px) 100vw, 370px\" \/><\/figure><\/div>\n\n\n\n<h4 id=\"db2f\">Defining Stages<\/h4>\n\n\n\n<p id=\"2580\">Here we are defining pipeline stages which will be used on pipeline instructions later, Open gitlab-ci.yml and add the following lines,<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>stages:\r\n  - dependencies\r\n  - test\r\n  - build\r\n  - publish<\/code><\/pre>\n\n\n\n<h4 id=\"e2a7\">Dependencies Stage<\/h4>\n\n\n\n<p id=\"17e7\">In this stage, we can run npm install to set up the core application, since we are not committing any changes related to node_modules and it should be dynamically built on the pipeline for every execution.<\/p>\n\n\n\n<p id=\"0b2c\">But Gitlab CI gives us a chance to reuse the node_modules folder using cache and update it upon changes to a given file. Eg:- package.json or package-lock.json<\/p>\n\n\n\n<p id=\"f789\">Just add the following line to the .gitlab-ci.yml,<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>install_dependencies:\r\n  image: node:12-alpine\r\n  stage: dependencies\r\n  script:\r\n    - npm install\r\n  only:\r\n    - master\r\n  cache:\r\n    key:\r\n      files:\r\n        - package-lock.json\r\n    paths:\r\n      - node_modules<\/code><\/pre>\n\n\n\n<ul><li><strong>Image<\/strong>: This stage will run on node:12-alpine docker image and it will be dynamically allocated from gitlab runner machines.<\/li><li><strong>stage:&nbsp;<\/strong>Here we are defining where we should run this instruction from the defined stage list.<\/li><li><strong>script:&nbsp;<\/strong>This script will run on a given image using the given package.json file.<\/li><li><strong>cache<\/strong>: This cache will be triggered upon any changes on package-lock.json (eg:- added or removed any dependency) and cache everything under node_modules to use with other stages.<\/li><\/ul>\n\n\n\n<h4 id=\"ba15\">Lint Stage<\/h4>\n\n\n\n<p id=\"4695\">This pipeline setup will run linter for the given source code using node and ng modules. We need to&nbsp;<strong>link @angular\/cli<\/strong>&nbsp;to this stage since we are directly using ng-based commands to run lint.<\/p>\n\n\n\n<p id=\"1f9d\">In addition to that in this stage, we can use the cache we created on the dependencies stage since we need to have node_modules included in the setup to run lint. So using cache we could pull the cache created in the early stage.<\/p>\n\n\n\n<p id=\"cfc1\">Add the following step into the gitlab-ci.yml,<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>lint:\r\n  image: node:12-alpine\r\n  stage: test\r\n  script:\r\n    - npm link @angular\/cli@11.2.6\r\n    - ng lint\r\n  cache:\r\n    key:\r\n      files:\r\n        - package-lock.json\r\n    paths:\r\n      - node_modules\r\n    policy: pull<\/code><\/pre>\n\n\n\n<ul><li><strong>policy:\u00a0<\/strong>This will pull cache created with node_modules on early stage.<\/li><\/ul>\n\n\n\n<h4 id=\"5cf9\">Test Stage<\/h4>\n\n\n\n<p id=\"a822\">We are going to run unit testing for this angular source code at this stage. Additionally, this unit test instructions will be running parallel to the lint instructions. Hence we should use the same stage which we have used for lint.<\/p>\n\n\n\n<p id=\"4f8e\">Here I\u2019m using\u00a0<a rel=\"noreferrer noopener\" href=\"https:\/\/hub.docker.com\/r\/markhobson\/node-chrome\/\" target=\"_blank\"><strong>markhobson\/node-chrome<\/strong><\/a> docker image which allows us to do\u00a0<strong>automated UI tests<\/strong>.<\/p>\n\n\n\n<p id=\"4c62\">You are free to use alternatives like&nbsp;<a href=\"https:\/\/hub.docker.com\/u\/selenium\" rel=\"noreferrer noopener\" target=\"_blank\"><strong>selenium<\/strong><\/a>&nbsp;if you need to do UI automation tests using various browsers.<\/p>\n\n\n\n<p id=\"d918\">Add the following step into the gitlab-ci.yml,<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>test:\r\n  image: markhobson\/node-chrome:latest\r\n  stage: test\r\n  script:\r\n    - npm link @angular\/cli@11.2.6\r\n    - npm test -- --browsers=ChromeHeadless --watch=false\r\n  cache:\r\n    key:\r\n      files:\r\n        - package-lock.json\r\n    paths:\r\n      - node_modules\r\n    policy: pull<\/code><\/pre>\n\n\n\n<p id=\"5c20\"><em><span class=\"has-inline-color has-vivid-red-color\">In this stage, there are few things we need to set up to run this test stage on the gitlab pipeline. Let\u2019s check those things from here before proceeding with other pending stuff.<\/span><\/em><\/p>\n\n\n\n<p id=\"af19\">Angular unit tests with jasmine will use the Chrome browser for automated UI tests by default. But if we are running any tests on a&nbsp;<strong>CI environment like gitlab-ci, there is no graphical user interface available to run a browser in it.&nbsp;<\/strong>Hence we need to set up&nbsp;<strong>ChromeHeadless<\/strong>&nbsp;in the browsers in karma.conf.js in app root.<\/p>\n\n\n\n<p>Add or change browsers list like below to add\u00a0<strong>ChromeHeadless,<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>browsers: &#91;'Chrome', 'ChromeHeadless'],<\/code><\/pre>\n\n\n\n<p><span class=\"has-inline-color has-vivid-cyan-blue-color\">\u2014 watch=false <\/span>will ensure that not open any automated browser window to run testings in this phase. and<span class=\"has-inline-color has-vivid-cyan-blue-color\"> \u2014 browsers=ChromeHeadless<\/span> will choose only ChromeHeadless from the browser list we defined in karma.conf.js.<\/p>\n\n\n\n<h4 id=\"53a7\"><strong>Build Stage<\/strong><\/h4>\n\n\n\n<p id=\"3f4b\">This stage will build the given angular source code for the production and mark the dist folder to capture from the next stage where we create docker images.<\/p>\n\n\n\n<p id=\"aea8\">Copy following into the gitlab-ci.yml,<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>build_image:\r\n  image: node:12-alpine\r\n  stage: build\r\n  script:\r\n    - npm link @angular\/cli@11.2.6\r\n    - npm run build\r\n  artifacts:\r\n    paths:\r\n      - $CI_PROJECT_DIR\/dist\r\n  cache:\r\n    key:\r\n      files:\r\n        - package-lock.json\r\n    paths:\r\n      - node_modules\r\n    policy: pull<\/code><\/pre>\n\n\n\n<ul><li><strong>artifact<\/strong>: This will be gather everything under the dist folder and mark it as artifacts for the project. Additionally, gitlab allows users to download any artifact built inside the gitlab pipeline if there is any requirement.<\/li><\/ul>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-21.png\" alt=\"\" class=\"wp-image-1826\" width=\"679\" height=\"254\" srcset=\"https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-21.png 962w, https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-21-300x112.png 300w, https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-21-768x287.png 768w\" sizes=\"(max-width: 679px) 100vw, 679px\" \/><\/figure><\/div>\n\n\n\n<p>In addition to that, we can directly use this build dist folder content to set up the docker image in the final stage.<\/p>\n\n\n\n<h4 id=\"e6d3\"><strong>Publish Stage<\/strong><\/h4>\n\n\n\n<p id=\"138f\">Now we have all the artifacts for the current code base of the angular application. Hence we can proceed with building the latest docker image for the application.<\/p>\n\n\n\n<p id=\"0aa5\">In this setup this application will finally run using the&nbsp;<strong>Nginx<\/strong>&nbsp;layer, Hence we should set up NGINX using Dockerfile to copy content on the dist folder to the Nginx root path.<\/p>\n\n\n\n<p id=\"5d40\">Just create the Dockerfile which has instructions to set up docker image in the application root.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FROM nginx:1.17.1-alpine\r\nCOPY dist\/angular-keycloak-app \/usr\/share\/nginx\/html\r\nEXPOSE 80<\/code><\/pre>\n\n\n\n<p><strong>The pipeline will identify this dist\/angular-keycloak-app content using the artifacts we created on the build stage<\/strong><\/p>\n\n\n\n<p>Next, Just add the following content to the .gitlab-ci.yml,<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>push-docker-registry:\r\n  image: docker:latest\r\n  stage: publish\r\n  only:\r\n    - master\r\n  script:\r\n    - docker build -t registry.gitlab.com\/&lt;gitlab_username>\/angular-ci-cd .\r\n    - docker login -u &lt;gitlab_username> -p $CI_BUILD_TOKEN registry.gitlab.com\r\n    - docker push registry.gitlab.com\/&lt;gitlab_username>\/angular-ci-cd<\/code><\/pre>\n\n\n\n<p id=\"6100\"><strong>Change this gitlab_username with your gitlab username.<\/strong><\/p>\n\n\n\n<p id=\"3a2a\">Here&nbsp;<strong>we should create $CI_BUILD_TOKEN to use with docker login<\/strong>. You can generate a new token or use any available token which has the following scopes.<\/p>\n\n\n\n<ul><li><strong>read_registry<\/strong>&nbsp;\u2014 Grants read-only access to container registry images on private projects.<\/li><li><strong>write_registry<\/strong>&nbsp;\u2014 Grants write access to container registry images on private projects.<\/li><\/ul>\n\n\n\n<p><em><span class=\"has-inline-color has-vivid-green-cyan-color\"><strong>You can generate a new token using this URL<\/strong><\/span><\/em>\u00a0<a rel=\"noreferrer noopener\" href=\"https:\/\/gitlab.com\/-\/profile\/personal_access_tokens\" target=\"_blank\">https:\/\/gitlab.com\/-\/profile\/personal_access_tokens<\/a>.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-22.png\" alt=\"\" class=\"wp-image-1827\" width=\"518\" height=\"590\" srcset=\"https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-22.png 688w, https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-22-264x300.png 264w\" sizes=\"(max-width: 518px) 100vw, 518px\" \/><\/figure><\/div>\n\n\n\n<p id=\"316b\">Then navigate to project -&gt; Settings -&gt; CI\/CD<\/p>\n\n\n\n<p id=\"dbc1\">and expand Variables, Then create a new variable with Key -: CI_BUILD_TOKEN value:- a newly generated token from personal access token window.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-23.png\" alt=\"\" class=\"wp-image-1828\" width=\"445\" height=\"366\" srcset=\"https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-23.png 668w, https:\/\/nguenkam.com\/blog\/wp-content\/uploads\/2022\/04\/image-23-300x247.png 300w\" sizes=\"(max-width: 445px) 100vw, 445px\" \/><\/figure><\/div>\n\n\n\n<p>In addition to that add the following service to the gitlab-ci file, This docker:dind service will start docker daemon as this pipeline entry point.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>services:\r\n  - docker:dind<\/code><\/pre>\n\n\n\n<p>So our completed gitlab-ci.yml should look like below,<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>services:\n  - docker:dind\n\nstages:\n  - dependencies\n  - test\n  - build\n  - publish\n\ninstall_dependencies:\n  image: node:12-alpine\n  stage: dependencies\n  script:\n    - npm install\n  only:\n    - master\n  cache:\n    key:\n      files:\n        - package-lock.json\n    paths:\n      - node_modules\n\nlint:\n  image: node:12-alpine\n  stage: test\n  script:\n    - npm link @angular\/cli@11.2.6\n    - ng lint\n  cache:\n    key:\n      files:\n        - package-lock.json\n    paths:\n      - node_modules\n    policy: pull\ntest:\n  image: markhobson\/node-chrome:latest\n  stage: test\n  script:\n    - npm link @angular\/cli@11.2.6\n    - npm test -- --browsers=ChromeHeadless --watch=false\n  cache:\n    key:\n      files:\n        - package-lock.json\n    paths:\n      - node_modules\n    policy: pull\n\nbuild_image:\n  image: node:12-alpine\n  stage: build\n  script:\n    - npm link @angular\/cli@11.2.6\n    - npm run build\n  artifacts:\n    paths:\n      - $CI_PROJECT_DIR\/dist\n  cache:\n    key:\n      files:\n        - package-lock.json\n    paths:\n      - node_modules\n    policy: pull\n\n\npush-docker-registry:\n  image: docker:latest\n  stage: publish\n  only:\n    - master\n  script:\n    - docker build -t registry.gitlab.com\/aurelien116\/angular-ci-cd .\n    - docker login -u aurelien116 -p $CI_BUILD_TOKEN registry.gitlab.com\n    - docker push registry.gitlab.com\/aurelien116\/angular-ci-cd<\/code><\/pre>\n\n\n\n<p>All done, Whole Gitlab based continuous integration for angular application setup is done. Just push your code and check CI\/CD -> Pipelines and see how the pipeline running on each stage.<\/p>\n\n\n\n<h5>Reference: <\/h5>\n\n\n\n<p><a href=\"https:\/\/medium.com\/geekculture\">https:\/\/medium.com\/geekculture<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Gitlab, one of the famous Git repository manager which comes with a\u00a0web-based DevOps\u00a0life cycle tool, inbuilt wiki, container registry, issue tracking,\u00a0continuous integration, and deployment pipeline\u00a0features. We can use\u00a0GitLab as a Saas\u00a0or else\u00a0Self-managed installation on our own host\u00a0with Linux for free. Let\u00b4s see \u00a0how we can set up CI\/CD (Continuous Integration\/Deployment) pipeline with GitLab for an [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1829,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[37,60,33,32],"tags":[200,199,214,201],"_links":{"self":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/1821"}],"collection":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=1821"}],"version-history":[{"count":3,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/1821\/revisions"}],"predecessor-version":[{"id":1830,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/1821\/revisions\/1830"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/media\/1829"}],"wp:attachment":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=1821"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=1821"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=1821"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}