CircleCI - одно из самых популярных и удобных решений для непрерывной интеграции. Он поддерживает множество языков программирования и инструментов, включая Elixir и Erlang / OTP.

CircleCI полностью бесплатен, когда речь идет о репозиториях GitHub с открытым исходным кодом, но он также предоставляет бесплатные 1500 минут в месяц для любых частных репозиториев.

Начиная с версии 2.0 CircleCI может создавать задания на основе любых образов из DockerHub. Эта функция позволяет создавать любой язык программирования или платформу, которые можно разместить в образе Docker.

Представьте, что у вас есть стандартное приложение Elixir Phoenix / Ecto. Вам нужно запустить его на последних версиях Elixir и Erlang / OTP и запустить тесты в базе данных PostgreSQL.

Начнем с создания файла конфигурации CircleCI в .circleci/config.yml:

version: 2  # use CircleCI 2.0 instead of CircleCI Classic
jobs:  # basic units of work in a run
  build:  # runs not using Workflows must have a `build` job as entry point
    parallelism: 1  # run only one instance of this job in parallel
    docker:  # run the steps with Docker
      - image: circleci/elixir:1.6 # ...with this image as the primary container; this is where all `steps` will run
        environment:  # environment variables for primary container
          MIX_ENV: test
          SHELL: /bin/bash
      - image: mdillon/postgis:9.6-alpine  # database image
        environment:  # environment variables for database
          POSTGRES_DB: app_test

    steps:  # commands that comprise the `build` job
      - checkout  # check out source code to working directory

      - run: mix local.hex --force  # install Hex locally (without prompt)
      - run: mix local.rebar --force  # fetch a copy of rebar (without prompt)

Как видите, мы объявляем build задание на непрерывную интеграцию. В основном мы будем использовать Elixir 1.6 с PostgreSQL 9.6 для запуска тестов в базе данных app_test. После этого мы проверим базу исходного кода, чтобы внести наши последние изменения в сборку. mix local задач также необходимы, чтобы использовать любую из задач Смешать позже.

Запуск тестов и качество кода

Все мы хотим выполнить все стандартные этапы непрерывной интеграции, такие как:

  • Получить зависимости и скомпилировать приложение
  • Запустить инструменты и проверки качества кода (подробнее об этом можно прочитать здесь)
  • Выполните все тесты, чтобы убедиться, что наша сборка успешна и безошибочна.
  • Запускайте тяжелые и громоздкие инструменты статического анализа

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

- restore_cache:  # restores saved mix cache
          keys:  # list of cache keys, in decreasing specificity
            - v1-mix-cache-{{ .Branch }}-{{ checksum "mix.lock" }}
            - v1-mix-cache-{{ .Branch }}
            - v1-mix-cache
      - restore_cache:  # restores saved build cache
          keys:
            - v1-build-cache-{{ .Branch }}
            - v1-build-cache
      - restore_cache:  # restores saved plt cache
          keys:
            - dialyzer-cache

      - run: mix do deps.get, compile # get updated dependencies & compile them

      - save_cache:  # generate and store cache so `restore_cache` works
          key: v1-mix-cache-{{ .Branch }}-{{ checksum "mix.lock" }}
          paths: "deps"
      - save_cache:  # make another less specific cache
          key: v1-mix-cache-{{ .Branch }}
          paths: "deps"
      - save_cache:  # you should really save one more cache just in case
          key: v1-mix-cache
          paths: "deps"
      - save_cache: # don't forget to save a *build* cache, too
          key: v1-build-cache-{{ .Branch }}
          paths: "_build"
      - save_cache: # and one more build cache for good measure
          key: v1-build-cache
          paths: "_build"

      - run: mix do format --check-formatted, credo --strict, security
      - run: mix do xref deprecated --include-siblings, xref unreachable --include-siblings, xref graph --format stats

      - run:  # special utility that stalls main process until DB is ready
          name: Wait for DB
          command: dockerize -wait tcp://localhost:5432 -timeout 1m

      - run: mix do ecto.migrations, ecto.load
      - run: mix test  # run all tests in project

      - run: mix dialyzer --halt-exit-status
      - save_cache:
          key: dialyzer-cache
          paths: "_build/test/dialyxir*.plt"

      - store_test_results:  # upload test results for display in Test Summary
          path: _build/test/lib/app/results.xml

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

Развертывание

Однако наличия только одного задания на сборку недостаточно даже для простейшего процесса CI. Чаще всего нам нужно сделать выпуск постановки / производства на Ликеро-водочном заводе.

Давайте продолжим заполнение нашего файла конфигурации, добавив новое deploy задание:

deploy:
    docker:
      - image: circleci/elixir:1.6
        environment:  # environment variables for primary container
          SHELL: /bin/bash
          MIX_ENV: staging
    steps:
      - checkout  # check out source code to working directory

      - run: mix local.hex --force  # install Hex locally (without prompt)
      - run: mix local.rebar --force  # fetch a copy of rebar (without prompt)

      - run: mix do deps.get, compile # get updated dependencies & compile them

      # set MIX_ENV to prod or staging value according to the source branch
      - run:
          name: Update MIX_ENV environment variable
          command: |
            echo "export MIX_ENV=$(if [ '$CIRCLE_BRANCH' '==' 'master' ]; then echo 'prod'; else echo 'staging'; fi)" >> $BASH_ENV
            source $BASH_ENV

      - run: cd deps/argon2_elixir && make clean && make && cd -
      - run: MIX_ENV=staging mix release --env $MIX_ENV

      - run: tar -zcvf $CIRCLE_SHA1.tar.gz bin appspec.yml VERSION _build/$MIX_ENV/rel/app/releases/$(cat VERSION)/app.tar.gz

Этого будет достаточно, чтобы создать отдельное задание развертывания, которое будет запускаться в отдельном образе Docker. Однако нам нужно будет запускать его только в ветвях разработки и master, чтобы соответственно загружать промежуточные / производственные выпуски. Мы можем добиться этого, используя рабочий процесс CircleCI и предоставляя простую конфигурацию внизу нашего файла конфигурации:

workflows:
  version: 2
  build-and-deploy:
    jobs:
      - build
      - deploy:
          requires:
            - build
          filters:
            branches:
              only:
                - develop
                - master

После этого вы можете загрузить собранный релиз на любой сервер или любую платформу, какую захотите. Вы можете использовать Edeliver, Ansible, Chef, Docker - выбор за вами.

Вывод

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

Если вы хотите узнать больше по теме, то давайте прочитаем Документацию CircleCI 2.0 и Руководство по языку Elixir.

Всем удачного взлома!

Эта статья изначально была размещена на моем собственном сайте.