Это пятая часть серии статей: От фиксации к развертыванию. Часть 1, Часть 2, Часть 3, Часть 4 и 5 вы можете найти здесь.

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

Однако есть тонкая, но существенная проблема. То есть, может ли наша локально запущенная программа нормально функционировать в производственной среде? Распространенная проблема, с которой мы часто сталкиваемся, заключается в том, что в наших тестах все выглядит нормально, ручные проверки также не выявляют проблем, однако проблемы возникают после развертывания системы.

Это связано с потенциальными несоответствиями между нашими локальными конфигурациями и конфигурациями производственной или тестовой среды, от которых зависит наше приложение. Это приводит к проблеме «Это работает на моей машине».

Чтобы решить эту проблему, нам необходимо внедрить практики непрерывной интеграции и непрерывной доставки. Хорошей новостью является то, что реализовать непрерывную интеграцию и непрерывную доставку с помощью наших существующих сценариев сборки и действий GitHub относительно легко.

Непрерывная интеграция

Непрерывная интеграция (CI) — это практика разработки, при которой разработчики часто интегрируют свой код в основную ветку несколько раз в день. Каждая интеграция проверяется автоматической сборкой (включая компиляцию, развертывание и автоматическое тестирование) для обнаружения и исправления ошибок интеграции как можно раньше. Это позволяет командам быстро обнаруживать проблемы и побуждает разработчиков вносить более частые и мелкие изменения, сокращая время на поиск и устранение проблем.

  1. Агент. В системе CI под агентом понимается сервер, выполняющий задачи сборки. Он получает задачи сборки, запускает сценарии сборки и затем возвращает результаты. Агентом может быть физическая машина, виртуальная машина или даже контейнер.
  2. Задача. Задача — это серия определенных операций, которые будут выполняться назначенным агентом. Например, компиляция кода, запуск тестов, упаковка приложений и т. д.
  3. Сценарий сборки: сценарий сборки инструктирует агента, как выполнить задачу сборки. Сценарии сборки обычно хранятся вместе с исходным кодом проекта.
  4. Принцип работы. Когда разработчики отправляют код в систему контроля версий (например, Git), служба CI запускается, а затем запускает задачу сборки на агенте. Агент сначала получает последнюю версию кода из системы контроля версий, а затем выполняет сценарий сборки. Этот сценарий обычно включает в себя такие этапы, как компиляция кода, выполнение теста и упаковка приложения. Если все шаги выполнены успешно, задача сборки завершается успешно. Если какой-либо шаг завершается неудачей, задача сборки завершается неудачно.

Основная цель непрерывной интеграции — обеспечить быструю обратную связь. Если сборка не удалась, разработчики должны быть немедленно уведомлены, чтобы они могли решить проблему как можно скорее. Более того, CI может обеспечить стабильную среду для запуска различных тестов для обеспечения качества кода. Чтобы лучше реализовать непрерывную интеграцию, командам необходимо следовать некоторым передовым практикам, таким как обеспечение быстрой сборки, избежание «сломанных сборок» и частая интеграция кода.

В этой части мы рассмотрим, как использовать Github Actions для реализации непрерывной интеграции и, в конечном итоге, непрерывной доставки.

Введение в действия GitHub

GitHub Actions — это инструмент автоматизации, предоставляемый GitHub, который позволяет вам писать и выполнять рабочие процессы CI/CD (непрерывная интеграция/непрерывная доставка) непосредственно в вашем репозитории GitHub. Это означает, что вы можете автоматизировать любой аспект рабочего процесса разработки программного обеспечения, включая сборку, тестирование и развертывание приложения и многое другое.

Каждый рабочий процесс GitHub Action состоит из одного или нескольких заданий, и каждое задание состоит из ряда шагов. Этими шагами могут быть выполнение команд, запуск сценариев или использование действий, доступных сообществу GitHub. «Бегущий» здесь — это «Агент» на традиционных CI-серверах, используемый для выполнения задач.

Различные события GitHub, такие как push, pull request или Release, могут запускать эти рабочие процессы. Вы также можете запланировать запуск рабочих процессов в определенное время или через определенные промежутки времени, например, заданий cron.

Ниже приведен простой пример рабочего процесса GitHub Actions. Он запускает модульные тесты каждый раз, когда код помещается в основную ветку:

name: Run tests
on:
  push:
    branches:
      - master
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - name: Check out repository
      uses: actions/checkout@v2
    - name: Set up Node.js
      uses: actions/setup-node@v1
      with:
        node-version: 14
    - name: Install dependencies
      run: npm ci
    - name: Run tests
      run: npm test

В этом файле конфигурации описывается рабочий процесс задания: сначала проверьте свой код в виртуальной среде Ubuntu, затем настройте среду Node.js, установите зависимости и, наконец, запустите тесты. Давайте объясним это построчно:

  • jobs:: Здесь начинаются задания рабочего процесса. На этом уровне вы можете определить одно или несколько заданий, которые выполняются параллельно, если вы явно не укажете их зависимости.
  • test:: Это название задания, вы можете выбрать любое имя. В данном случае целью задания является запуск тестов, поэтому оно называется «тест».
  • runs-on: ubuntu-latest: Это указывает GitHub Actions выполнить это задание в последней виртуальной среде Ubuntu.
  • steps:: Здесь вы определяете шаги, которые необходимо выполнить в задании.
  • name: Check out repository: Это название шага. Цель этого шага — проверить код репозитория.
  • uses: actions/checkout@v2: это указывает GitHub Actions использовать действие «actions/checkout@v2». Это действие проверяет ваш репозиторий кода на бегуне, позволяя последующим шагам получить к нему доступ.
  • name: Set up Node.js: На этом этапе настраивается среда Node.js.
  • uses: actions/setup-node@v1: Это действие настраивает среду Node.js.
  • with:: используется для передачи параметров действию.
  • node-version: 14: Это сообщает действию setup-node версию Node.js, которую мы хотим настроить.
  • name: Install dependencies: На этом этапе устанавливаются зависимости проекта.
  • run: npm ci: при этом запускается команда npm ci, которая точно установит зависимости проекта в соответствии с файлом package-lock.json.
  • name: Run tests: На этом этапе выполняются тесты.
  • run: npm test: при этом запускается команда npm test, которая выполнит тесты, определенные в файле package.json.

Такой подход определения и запуска рабочих процессов CI/CD непосредственно в репозитории кода облегчает командам разработчиков отслеживание и управление процессом автоматизации и более тесно интегрирует его с кодом.

Создание рабочего процесса

Давайте теперь начнем определять рабочий процесс Github Actions в нашем проекте. Сначала создайте каталог .github/workflows, необходимый для рабочего процесса, а затем создайте файл build.yml:

mkdir -p .github/workflows
touch .github/workflows/build.yml

В .github/workflows/build.yml мы сначала определяем задание с именем build, которое содержит четыре шага: получение кода, настройку среды Node.js, установку зависимостей и запуск npm run build.

name: Build Quote Application
on:
  push:
    branches: [ "main" ]
jobs:
  test:
    name: Test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup node
        uses: actions/setup-node@v3
        with:

          node-version: 18.14.2
          cache: npm
      - name: Install
        run: npm ci
      - name: Test
        run: npm run lint

Мы фиксируем весь каталог .github и затем отправляем его на Github. Это запустит действия Github Actions для выполнения определенного нами рабочего процесса.

Как видно, наш рабочий процесс проходит успешно. Мы можем расширить этот test, добавив больше шагов. Распространенной задачей является упаковка, то есть сжатие окончательных файлов сборки в пакет для развертывания.

Упаковка программного обеспечения

Мы можем внести некоторые незначительные изменения в файл build.yml для запуска npm run build после завершения тестов, который компилирует исходный код и генерирует пакет.

name: Build Quote Application
on:
  push:
    branches: [ "main" ]
jobs:
  build:
    name: Build Frontend Package
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup node
        uses: actions/setup-node@v3
        with:
          node-version: 18.14.2
          cache: npm
      - name: Install
        run: npm ci
      - name: Test
        run: npm run lint
      - name: Build
        run: npm run build
      - name: Packaging
        uses: actions/upload-artifact@v3
        with:
          name: quote-of-the-day
          path: dist/

Мы добавили build и packaging в качестве новых шагов. Эти шаги компилируют исходный код приложения в каталог dist, а затем упаковывают и сжимают результат в цитату дня с помощью upload-artifact.

Большой! Наше программное обеспечение теперь не зависит от локальной среды разработчика. Разработчики могут использовать Mac, Linux или даже Windows. Если среда, используемая на CI-сервере (т. е. ubuntu-latest), соответствует производственной среде, пакет готов к работе.

Проведение приемочного тестирования

Кроме того, мы хотим выполнить автоматические приемочные тесты в среде CI. Это позволяет нам немедленно узнать и исправить, если какая-либо функциональность нарушена. Эти задачи необходимо выполнить после завершения упаковки. Если статические проверки не пройдены или компиляция не удалась, нам не нужно выполнять приемочные тесты. То есть шаг проведения приемочных тестов зависит от статических проверок и процесса компиляции.

Проведение приемочных тестов, как правило, сложно. Нам нужно запустить http-сервер в нужный момент, запустить тесты, а затем закрыть http-сервер после завершения тестов. Однако cypress предоставляет упакованные действия Github, которые мы можем просто вызвать.

Нам нужно добавить новое задание в файл build.yml:

cypress:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Cypress run
        uses: cypress-io/github-action@v5
        with:
          build: npm run build
          start: npm start
          command: npm run e2e

Мы определили новое задание GitHub Actions с именем cypress, которое отвечает за выполнение сквозных тестов в процессе непрерывной интеграции. Здесь следует отметить некоторые моменты:

  • needs: build: Это означает, что это задание зависит от другого задания с именем «сборка». Задание «кипарис» начнет выполняться только после успешного завершения задания «сборка».
  • uses: cypress-io/github-action@v5: используется официальный экшен Cypress GitHub. Это действие устанавливает и запускает тесты Cypress.
  • build: npm run build: Перед запуском тестов этот параметр указывает действию Cypress выполнить команду npm run build для сборки проекта.
  • start: npm start: Этот параметр указывает действию Cypress запускать приложение перед запуском тестов, что достигается выполнением команды npm start.
  • command: npm run e2e: Этот параметр определяет фактическую команду, которую необходимо выполнить, т. е. «npm run e2e», которая запускает Cypress и запускает тесты, определенные в

Создание пакета программного обеспечения

Мы можем внести несколько простых изменений в наш build.yml, чтобы после завершения тестов npm run build выполнялся для компиляции исходного кода и создания пакета.

name: Build Quote Application
on:
  push:
    branches: [ "main" ]
jobs:
  build:
    name: Build Frontend Package
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup node
        uses: actions/setup-node@v3
        with:
          node-version: 18.14.2
          cache: npm
      - name: Install
        run: npm ci
      - name: Test
        run: npm run lint
      - name: Build
        run: npm run build
      - name: Packaging
        uses: actions/upload-artifact@v3
        with:
          name: quote-of-the-day
          path: dist/

Мы добавили два новых шага, build и packaging, на которых исходный код приложения сначала компилируется в каталог distdirectory. После этого upload-artifact используется для упаковки и сжатия результатов в quote-of-the-day.

Большой! Благодаря этому наше программное обеспечение больше не зависит от локальной среды разработчика. Не имеет значения, использует ли разработчик Mac, Linux или Windows. Если среда, используемая на CI-сервере (в данном случае ubuntu-latest), соответствует производственной среде, пакет готов к работе.

Проведение приемочного тестирования

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

Обычно запуск приемочных тестов — сложный процесс: нам нужно запустить http-сервер в нужное время, запустить тесты, а затем закрыть http-сервер после завершения тестов. Однако cypress предоставляет предварительно упакованные действия Github, которые мы можем вызывать напрямую.

Нам нужно добавить новую задачу в build.yml:

cypress:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Cypress run
        uses: cypress-io/github-action@v5
        with:
          build: npm run build
          start: npm start
          command: npm run e2e

Здесь мы определили новую задачу GitHub Actions с именем cypress, которая отвечает за выполнение сквозных тестов в процессе непрерывной интеграции. Следует отметить несколько моментов:

  • needs: build: Это указывает на то, что задание зависит от другого задания с именем «сборка». Задание «кипарис» начнет выполняться только после успешного завершения задания «сборка».
  • uses: cypress-io/github-action@v5: используется официальное действие GitHub, предоставленное Cypress. Это действие устанавливает и запускает тесты Cypress.
  • build: npm run build: Этот параметр указывает действию Cypress выполнить команду «npm run build» для сборки проекта перед запуском тестов.
  • start: npm start: Этот параметр указывает действию Cypress запустить приложение перед запуском тестов, что выполняется путем выполнения команды npm start.
  • command: npm run e2e: Этот параметр указывает действию Cypress выполнить фактическую команду сквозного тестирования.

Отличный! Благодаря поддержке этих автоматизированных сценариев сборки и рабочих процессов каждое нажатие запускает этот рабочий процесс, в котором будут выполняться статические проверки и автоматические тесты. Это гарантирует, что каждая модификация кода может создать развертываемое готовое к выпуску программное обеспечение.

Можем ли мы сделать еще один шаг вперед? Если все тесты каждый раз пройдены, а приемочное тестирование также пройдено, мы можем развернуть приложение в производственной среде. Таким образом, наши новые функции смогут использовать реальные пользователи!

Непрерывная доставка

Непрерывная доставка (CD) — это стратегия разработки программного обеспечения, которая подчеркивает, что каждое изменение должно быть частым, надежным и легко развертываемым в производственной среде, когда это необходимо. На компакт-диске программное обеспечение можно развертывать на протяжении всего его жизненного цикла. Разработчики постоянно отправляют изменения кода в систему контроля версий и проверяют эти изменения посредством автоматизированных процессов сборки и тестирования. Эти изменения затем развертываются для более глубокого тестирования в производственной среде. Если все пойдет хорошо, эти изменения можно будет развернуть в производственной среде. Таким образом, компакт-диск сохраняет программное обеспечение в постоянно доступном для выпуска состоянии.

Преимущества непрерывной доставки:

  1. Снижает риск: компакт-диск гарантирует, что изменения, вносимые при каждом развертывании, будут небольшими, что снижает вероятность возникновения проблем и упрощает поиск и устранение неполадок.
  2. Улучшает качество. Благодаря автоматическому тестированию и развертыванию компакт-диск помогает уменьшить количество человеческих ошибок, повышая качество программного обеспечения.
  3. Ускоренный выход на рынок: компакт-диск позволяет выпускать новые функции и улучшения быстрее и чаще, тем самым быстрее удовлетворяя потребности пользователей и повышая их удовлетворенность.

С помощью Github Actions мы можем легко добиться непрерывной доставки. Будь то внешнее или серверное приложение, мы можем легко развернуть готовое к выпуску программное обеспечение в соответствующей среде, используя пакетные действия, предоставляемые Github Actions и другими сторонними платформами.

Поскольку наше приложение представляет собой чисто интерфейсную программу, ему не требуется развертывать собственную серверную службу, поэтому мы можем развернуть его на страницах Github. GitHub Pages — это служба хостинга статических веб-сайтов, предоставляемая GitHub. Он может напрямую получать файлы HTML, CSS и JavaScript из репозиториев GitHub, а затем создавать общедоступный веб-сайт. Это позволяет пользователям легко создавать и поддерживать личные веб-сайты, веб-сайты проектов или даже библиотеки документации.

Мы надеемся завершить выпуск после прохождения приемочных испытаний. Нам нужно определить новую задачу развертывания следующим образом:

deploy:
    name: Deploy Application
    runs-on: ubuntu-latest
    needs: cypress

    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}

    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v2

Эта конфигурация определяет задачу рабочего процесса с именем «развертывание», целью которой является развертывание приложения. Он должен работать в среде «ubuntu-latest» и зависит от ранее определенной задачи «cypress». Если задача «кипарис» успешно выполнена, начнет выполняться задача «развертывание».

Поле environment определяет имя среды и URL-адрес, в котором выполняется задача. Здесь среда называется «github-pages», а URL-адрес определяется выходным параметром «page_url» этапа развертывания.

В разделе шагов определен шаг под названием «Развертывание на страницах GitHub» с использованием действия Github «actions/deploy-pages@v2». Это действие развернет ваше приложение на страницах GitHub.

id: deployment присваивает этому шагу уникальный идентификатор. Последующие шаги или задачи могут получить выходное содержимое этого шага через этот идентификатор. Например, ${{ steps.deployment.outputs.page_url }} здесь получает выходные данные «page_url» этого шага.

Также на шаге build, помимо использования actions/upload-artifact@v3, нам необходимо использовать специальный

действие для упаковки для страниц Github:

- name: Upload pages artifact
  uses: actions/upload-pages-artifact@v1
  with:
    name: github-pages
    path: dist/

Обратите внимание, что здесь вам необходимо определить окончательное имя файла как github-pages, чтобы Github Pages мог правильно его распознать. Если вы зафиксируете и отправите код на этом этапе, вы увидите ошибку на вкладке «Действия» Github:

Проверяя журнал, мы видим, что Github не включил функцию «Развертывание с помощью действий» по умолчанию, поэтому нам необходимо включить эту функцию в настройках проекта.

Error: Error: Failed to create deployment (status: 404) with build version 1da0b6ac55db2504119ce931701b4b667bd34efe. 
Ensure GitHub Pages has been enabled: https://github.com/icodeit-juntao/quote-of-the-day/settings/pages

Итак, нам нужно включить опцию beta для действий Github:

Кроме того, поскольку при развертывании необходимо изменить наш репозиторий кода, нам необходимо указать права записи для build.yml.

permissions:
  contents: read
  pages: write
  id-token: write

Благодаря этому наше приложение наконец может быть успешно развернуто. Обратите внимание на зависимости здесь. Задача развертывания зависит от приемочного тестирования, которое зависит от сборки. Таким образом, если наши тесты достаточно тщательны, приложение, развернутое в производственной среде, гарантированно будет работать.

И окончательная конфигурация build.yml:

name: Build Quote Application

on:
  push:
    branches: [ "main" ]

permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  build:
    name: Build Frontend Package
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup node
        uses: actions/setup-node@v3
        with:
          node-version: 18.14.2
          cache: npm
      - name: Install
        run: npm ci
      - name: Test
        run: npm run lint
      - name: Build
        run: npm run build
      - name: Upload pages artifact
        uses: actions/upload-pages-artifact@v1
        with:
          name: github-pages
          path: dist/
      - name: Packaging
        uses: actions/upload-artifact@v3
        with:
          name: quote-of-the-day
          path: dist/
  
  cypress:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Cypress run
        uses: cypress-io/github-action@v5
        with:
          build: npm run build
          start: npm start
          command: npm run e2e

  deploy:
    name: Deploy Application
    runs-on: ubuntu-latest
    needs: cypress
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v2

В нашем рабочем процессе непрерывного развертывания мы определили автоматизацию процессов сборки, тестирования и развертывания нашего проекта. Он запускается всякий раз, когда в основной ветке появляется новый коммит, выполняя три задачи, определенные ниже:

  1. Задача сборки: эта задача выполняется в последней версии Ubuntu. Он выполняет проверку кода, настраивает среду Node, устанавливает зависимости, выполняет тестирование (линтинг) и собирает приложение. После завершения сборки продукт сборки (папка dist) загружается как артефакт.
  2. Задача Cypress. Эта задача зависит от успешного завершения задачи сборки. Это означает, что задача Cypress выполняется только после успешного завершения задачи сборки. Он также работает в последней версии Ubuntu, проверяя код, а затем запуская Cypress для проведения сквозных тестов.
  3. Задача развертывания. Эта задача зависит от задачи Cypress. Это означает, что задача развертывания будет выполняться только после успешного завершения задачи Cypress. Эта задача отвечает за развертывание созданного продукта на страницах GitHub. В случае успеха задачи будет выведен URL-адрес развернутой страницы.

Краткое содержание

В этой заключительной части мы обсудили автоматизацию процесса разработки с помощью GitHub Actions, обеспечение непрерывной интеграции и доставки (CI/CD). Впервые мы представили GitHub Actions — инструмент, который позволяет выполнять рабочие процессы программного обеспечения непосредственно в репозиториях GitHub.

В нашем рабочем процессе мы поставили три основные задачи: создание пакета внешнего интерфейса, выполнение комплексных тестов и развертывание приложения на страницах GitHub. В задаче сборки мы использовали GitHub Actions для выполнения таких операций, как установка зависимостей, запуск проверок и компиляция приложения. После этого мы создали задачу сквозного тестирования, зависящую от задачи сборки, для автоматического запуска тестов Cypress после сборки.

Наконец, мы настроили задачу развертывания, которая зависит от задачи тестирования Cypress и выполняется только при прохождении всех тестов. Мы использовали функцию страницы развертывания GitHub Actions в задаче развертывания, развернув скомпилированное приложение на страницах GitHub.

С помощью этого метода мы достигли полной автоматизации от отправки кода до развертывания приложения. Это повысило эффективность разработки и обеспечило качество кода и стабильность приложения.

Если вам понравилось чтение, пожалуйста, Подпишитесь на мою рассылку. Я делюсь методами чистого кода и рефакторинга еженедельно в блогах, книгах и видео.