Автоматизируйте сборку, тестирование и развертывание с помощью GitLab CI / CD на хостинг Firebase.

Недавно я нашел способ настроить непрерывное развертывание вашего репозитория GitLab на хостинге Firebase.

Предварительные требования
1. Учетная запись GitLab
2. Учетная запись Firebase

Обзор
1. Создайте новый проект Angular 7
2. Создайте новый репозиторий GitLab
3. Настройте репозиторий GitLab в нашем проекте
4. Настройте проект Angular 7 для CI / CD (сборка, тестирование, развертывание)
5. Создайте проект Firebase
6. Настройте CI / CD на GitLab

Прежде всего, создайте новый проект angular 7 с помощью angular CLI. Используйте следующую команду CLI для создания нового проекта.

ng new angular_seven_firebase_ci_cd

Затем создайте новый репозиторий GitLab.

Затем запустите следующие команды в окне терминала

cd angular_seven_firbase_ci_cd
git init
git remote add origin https://gitlab.com/##YOUR_USER_NAME##/angular_seven_firebase_ci_cd.git
git add .
git commit -m "Initial commit"
git push -u origin master

Затем настройте проект Angular 7 для сборки, тестирования и развертывания.

Angular 7 поставляется с двумя инструментами тестирования: Karma для модульных тестов и Protractor для end-2-end или интеграционных тестов. У обоих подходов общее то, что они открывают браузер для выполнения тестов.

Во время разработки мы можем запускать тесты на основе Karma с помощью команды ng test, которая открывает браузер (Chrome), выполняет тесты и повторно запускает все тесты при изменении кода. Для выполнения тестов на основе транспортира мы используем команду ng e2e, которая также открывает браузер и запускает тесты.

В нашей среде CI нам нужно только выполнить наши тестовые примеры без использования графического интерфейса браузера и дополнительных затрат памяти. В режиме безголового хромирования это возможно.

Кукловод

Puppeteer - это библиотека Node, которая предоставляет высокоуровневый API для управления Chrome или Chromium по протоколу DevTools. Puppeteer по умолчанию работает без головы, но может быть настроен для запуска полного (без головы) Chrome или Chromium.

Во-первых, нам нужно включить браузер в нашу среду CI. Мы будем использовать библиотеку узлов Puppeteer, которая связывает хром. Благодаря этому мы можем убедиться, что у нас есть правильный браузер, независимо от того, находимся ли мы в разработке или в среде CI.

npm install --save-dev puppeteer   

Карма Конфигурация

откройте файл karma.conf.js из папки src вашего проекта. Мы добавляем настраиваемую программу запуска в наш karma.conf.js, чтобы запускать Chrome в автономном режиме в нашей среде CI. Кроме того, нам нужно использовать параметр - no-sandbox, чтобы он работал, так как мы не выполняли никаких дополнительных пользовательских настроек в нашем образе докера.

Ваш файл karma.conf.js должен быть таким

// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
const puppeteer = require('puppeteer');
process.env.CHROME_BIN = puppeteer.executablePath();

module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, '../coverage'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
customLaunchers: {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
flags: ['--no-sandbox']
}
        },
singleRun: false
});
};

Конфигурация транспортира

создайте новый файл в папке e2e с именем protractor-ci.conf.js

Для тестов e2e мы добавляем в этот файл следующую конфигурацию, чтобы иметь возможность вызывать хром в режиме без заголовка с опцией - no-sandbox.

ваш файл protractor-ci.conf.js будет таким

// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts

const config = require('./protractor.conf').config;
const puppeteer = require('puppeteer');

config.capabilities = {
browserName: 'chrome',
chromeOptions: {
args: ['--headless', '--no-sandbox'],
binary: puppeteer.executablePath()
}
        };

exports.config = config;

Добавить скрипты узла для CI / CD

Для правильной сборки, тестирования и развертывания на CI мы добавляем следующие сценарии в наш package.json файл конфигурации.

ваш package.json like this

{
  "name": "angular_seven_firebase_ci_cd",
    "version": "0.0.0",
    "scripts": {
  "ng": "ng",
      "start": "ng serve",
      "build": "ng build",
      "test": "ng test",
      "lint": "ng lint",
      "e2e": "ng e2e",
      "build-prod": "ng build --prod",
      "test-ci": "ng test --no-watch --no-progress --browsers=ChromeHeadlessNoSandbox",
      "e2e-ci": "ng e2e --protractor-config=e2e/protractor-ci.conf.js",
      "deploy": "firebase deploy --token $FIREBASE_TOKEN --non-interactive"
},
  "private": true,
    "dependencies": {
  "@angular/animations": "~7.1.0",
      "@angular/common": "~7.1.0",
      "@angular/compiler": "~7.1.0",
      "@angular/core": "~7.1.0",
      "@angular/forms": "~7.1.0",
      "@angular/platform-browser": "~7.1.0",
      "@angular/platform-browser-dynamic": "~7.1.0",
      "@angular/router": "~7.1.0",
      "core-js": "^2.5.4",
      "rxjs": "~6.3.3",
      "tslib": "^1.9.0",
      "zone.js": "~0.8.26"
},
  "devDependencies": {
  "@angular-devkit/build-angular": "~0.11.0",
      "@angular/cli": "~7.1.0",
      "@angular/compiler-cli": "~7.1.0",
      "@angular/language-service": "~7.1.0",
      "@types/jasmine": "~2.8.8",
      "@types/jasminewd2": "~2.0.3",
      "@types/node": "~8.9.4",
      "codelyzer": "~4.5.0",
      "firebase-tools": "^6.2.2",
      "jasmine-core": "~2.99.1",
      "jasmine-spec-reporter": "~4.2.1",
      "karma": "~3.1.1",
      "karma-chrome-launcher": "~2.2.0",
      "karma-coverage-istanbul-reporter": "~2.0.1",
      "karma-jasmine": "~1.1.2",
      "karma-jasmine-html-reporter": "^0.2.2",
      "protractor": "~5.4.0",
      "puppeteer": "^1.11.0",
      "ts-node": "~7.0.0",
      "tslint": "~5.11.0",
      "typescript": "~3.1.6"
}
}

Принять участие в GitLab

Теперь мы можем поделиться нашим локальным кодом с удаленным репозиторием в GitLab. Теперь код должен быть виден в вашем репозитории GitLab.

Создать приложение Firebase

Затем создайте новый проект в пожарной базе.

Установите Firebase Tools в наш проект Angular 7

Поскольку мы хотим развернуть на firebase, нам нужны инструменты firebase. Давайте добавим их в наши dev-зависимости, а также установим их глобально на нашем компьютере:

npm install --save-dev firebase-tools
npm install -g firebase-tools

Теперь файл конфигурации firebase автоматически создается в корневой папке проекта.

Затем мы отправляем все изменения в нашу главную ветку.

Установка и настройка CI / CD в GitLab

GitLab CI / CD настраивается с помощью специального файла с именем .gitlab-ci.yml, который необходимо поместить в корневую папку проекта. GitLab автоматически обнаруживает файл и запускает конвейер в соответствии с конфигурацией. Давайте добавим следующий файл, чтобы начать работу с простым трехэтапным конвейером, который включает сборку, тестирование и развертывание в производственной среде с кэшированием и хранением артефактов сборки.

Ваш файл .gitlab-ci.yml выглядит следующим образом

image: node:latest

build:
    stage: build
cache:
    paths:
        - node_modules/
        script:
- npm install --quiet
- npm run build-prod
artifacts:
    paths:
        - dist/

        test:
stage: test
cache:
    policy: pull
paths:
    - node_modules/
    script:
# install dependencies to use chrome w/ puppeteer
- apt update && apt install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
- npm run test-ci
- npm run e2e-ci

deploy_prod:
    stage: deploy
environment:
    name: production
url: $FIREBASE_URL
only:
    - master
dependencies:
    - build
cache:
    policy: pull
paths:
    - node_modules/
    script:
- npm run deploy

Объяснение настроенного конвейера

С помощью image: node:latest мы сообщаем нашему конвейеру, какой контейнер докеров следует использовать для сборки. Для Angular 7 нам нужна последняя версия Node.

Мы разделили конвейер на 3 задания: build, test и deploy_prod. Каждый шаг выполняется независимо от изображения, которое мы определили, один за другим. Конвейер останавливается при возникновении ошибки. Пример: если build не удается, testи deploy_prod не будут выполнены.

С caches: path: node_modules/ мы кэшируем все node_modules, которые загружаются во время установки зависимостей. Это ускорит последующие задания конвейера, поскольку все они выполняются на пустом изображении. Политика кеширования по умолчанию - pull-push. Это означает, что файлы, которые определены для кэширования, извлекаются из репозитория кеша до того, как в рамках задания будет запущен какой-либо сценарий. После запуска всех сценариев файлы возвращаются в репозиторий кеша.

Для задания test и deploy_prod мы определяем одну и ту же папку для кэширования, но с политикой кеширования pull, потому что нам не нужно записывать кэш обратно. Это ускоряет процесс.

С помощью команды only: master мы говорим deploy_prod задание запускаться только в том случае, если происходят изменения в главной ветви. Таким образом, мы гарантируем, что не каждое изменение функции или других веток будет внедрено в производственную среду.

С помощью команды dependencies: build мы говорим deploy_prod заданию получить те артефакты, которые мы определили в задании сборки. Таким образом, нам не нужно собирать его снова и следить за тем, чтобы мы не развертывали что-то еще.

Для отслеживания развертываний в среде prod мы используем команду environment, которая указывает GitLab рассматривать это задание как производственное развертывание. Более подробную информацию можно найти здесь, в Средах GitLab.

Основная часть каждого задания - это раздел script:, в котором есть следующие задачи:

  1. Сборка: установите все необходимые модули, описанные в package.json, и создайте артефакты, которые мы хотим развернуть.
  2. Тест: установите необходимые библиотеки для запуска Chrome в образе докера, как описано в документации по устранению неполадок кукловода. Затем выполните тесты Кармы и Транспортира.
  3. Развернуть: развертывание артефактов в Firebase.

Если какая-либо команда терпит неудачу, отказывает весь конвейер. Это означает, что неудачный тест предотвратит развертывание на сервере (что хорошо, поскольку мы не хотим прерывать производство).

Установить переменные среды в GitLab

Зайдите в настройки вашего проекта на GitLab. Выберите подменю CI / CD. Разверните раздел переменных и добавьте следующие две переменные.

  1. FIREBASE_TOKEN, который используется для аутентификации GitLab против Firebase и
  2. FIREBASE_URL, который является URL-адресом нашего проекта и используется только в качестве метаинформации для конфигурации нашей среды в GitLab.

Используйте следующую команду, чтобы получить токен Firebase из окна терминала.

firebase login:ci

Откроется окно входа в систему. Вы успешно вошли в свою учетную запись firebase и получаете токен. скопируйте этот токен из окна терминала и вставьте его сюда.

URL-адрес Firebase - это URL-адрес домена приложения Firebase. вы можете найти это на своей консоли firebase.

Теперь зафиксируйте любое изменение в мастере или слияние в мастере, и вы увидите развертывание в Firebase. Если вы выполните фиксацию в любой другой ветке, будут выполняться только задания сборки и тестирования.

Вы можете найти свое приложение, используя URL-адрес своего домена firebase