Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

Често ми се налага да построявам пайплайн за компилиране на проекти на Java. Понякога това е с отворен код, понякога не е. Напоследък реших да опитам да пренеса част от репозиторите си от Travis-CI и TeamCity на GitHub Actions и ето какво се получи.

Какво ще автоматизираме

Започваме с проект, който ще автоматизираме. Нека направим малко приложение на Spring Boot / Java 11 / Maven. В рамките на тази статия логиката на приложението няма да ни интересува, важно е за нас само инфраструктурата около приложението, така че ще ни е достатъчен прост REST API контролер.

Може да видите изходния код тук: github.com/antkorwin/github-actions всички етапи на построяването на конвейера са отразени в пулл-реквестите на този проект.

JIRA и планиране

Трябва да спомена, че обикновено използваме JIRA като трекер на задачи, така че нека създадем отделен борд за този проект и да добавим първите задачи:

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

По-късно отново ще се върнем на това, какво интересно може да предложат JIRA и GitHub в комбинация.

Автоматизиране на компилацията на проекта

Нашият тестов проект се компилира чрез Maven, така че компилацията му е доста проста, всичко, от което се нуждаем, е mvn clean package.

За да направим това с помощта на GitHub Actions, ще трябва да създадем файл в репозитория с описанието на нашия workflow. Това може да стане с обикновен yml файл, не мога да кажа, че ми харесва 'програмирането на yml', но какво да се направи — създаваме файл build.yml в директорията .github/workflow/, в който ще опишем действията по компилация на главната клонка:

name: Build

on:
  pull_request:
    branches:
      - '*'
  push:
    branches:
      - 'master'

jobs:
  build:
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/checkout@v1
      - name: set up JDK 11
        uses: actions/setup-java@v1
        with:
          java-version: 1.11
      - name: Maven Package
        run: mvn -B clean package -DskipTests

включено — това е описание на събитието, при което ще се стартира нашият скрипт.

on: pull_request / push — указва, че този workflow трябва да се стартира при всяко пушване в главната и при създаване на пулл-реквести.

Следва описанието на задачите (jobs) и стъпките за изпълнение (steps) за всяка задача.

runs-on — тук можем да изберем целевата ОС. Учудващо е, че можем да изберем дори Mac OS, но на частни репозитории това е доста скъпо удоволствие (в сравнение с Linux).

uses позволява да използваме отново други action-и. Например, с помощта на action-а actions/setup-java инсталираме среда за Java 11.

С помощью with Можем да зададем параметри, с които стартираме действието, по същността си това са аргументите, които ще бъдат предавани на екшъна.

Остава само да стартираме build на проекта с Maven: run: mvn -B clean package флаг -B казва, че имаме нужда от non-interactive mode, за да не попита Maven нещо.

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

Отлично! Сега при всеки commit в master стартира build на проекта.

Автоматизираме стартирането на тестовете.

Сборката е добре, но в реалността проектът може да се компилира успешно, но да не работи. Следователно, следващата стъпка е автоматизация на изпълнението на тестовете. Освен това, е много удобно да се гледат резултатите от тестовете по време на рецензия на PR — точно знаеш, че тестовете минават и никой не е забравил да тества своя клон преди сливането.

Правим стартиране на тестовете при създаване на pull request и merge в master, а заедно с това добавяме генерирането на отчет за code-coverage.

name: Build

on:
  pull_request:
    branches:
      - '*'
  push:
    branches:
      - 'master'

jobs:
  build:
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/checkout@v1
      - name: set up JDK 11
        uses: actions/setup-java@v1
        with:
          java-version: 1.11
      - name: Maven Verify
        run: mvn -B clean verify
      - name: Test Coverage
        uses: codecov/codecov-action@v1
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

За покритие на тестовете използвам codecov в комбинация с jacoco плъгин. Codecov има собствен екшън, но за работа с нашия pull request му е нужен токен:

${{ secrets.CODECOV_TOKEN }} — такава конструкция ще срещнем още не един път, secrets е механизъм за съхранение на тайни в GitHub, можем да записваме пароли/токени/хостове/URL и други данни, които не трябва да се разкриват в кода.

Добавянето на променлива в secrets може да стане в настройките на репозитория в GitHub:

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

Можете да получите токен на codecov.io след авторизация чрез GitHub, за добавяне на публичен проект просто преминете по линка от вида: Потребителско име в GitHub/[repo name]. Приватный репозиторий тоже можно добавить, для этого надо дать права codecov приложению в гитхабе.

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

Добавяме jacoco плъгина в POM файла:

org.jacoco
	jacoco-maven-plugin
	0.8.4
	
		
			
				prepare-agent
			
		
		
		
			report
			test
			
				report
			
		
	


	org.apache.maven.plugins
	maven-surefire-plugin
	2.22.2
	
		plain
		
			**/*Test*.java
			**/*IT*.java

Сега всеки наш пулл-реквест ще достига до бота codecov и ще добавя график на промените в покритията:

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

Да добавим статичен анализатор

В повечето от моите open-source проекти използвам SonarCloud за статичен анализ на кода, което е доста лесно да се свърже с Travis CI. Така че това е логична стъпка при миграцията към GitHub Actions - да направим същото. Marketplace на Actions е страхотно нещо, но този път той ме разочарова малко, защото по навик намерих необходимият екшън и го добавих в workflow. Оказа се, че Sonar не поддържа работа чрез действие за анализ на проекти на Maven или Gradle. Разбира се, това е написано в документацията, но кой чете?!

Не може през действие, така че ще го направим през Maven плъгин:

name: SonarCloud

on:
  push:
    branches:
      - master
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  sonarcloud:
    runs-on: ubuntu-16.04
    steps:
      - uses: actions/checkout@v1
      - name: Set up JDK
        uses: actions/setup-java@v1
        with:
          java-version: 1.11
      - name: Analyze with SonarCloud
#       set environment variables:
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
#       run sonar maven plugin:
        run: mvn -B verify sonar:sonar -Dsonar.projectKey=antkorwin_github-actions -Dsonar.organization=antkorwin-github -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=$SONAR_TOKEN -Dsonar.coverage.jacoco.xmlReportPaths=./target/site/jacoco/jacoco.xml

SONAR_TOKEN — може да бъде получен в sonarcloud.io и трябва да бъде записан в secrets. GITHUB_TOKEN — това е вграден токен, който генерира GitHub, чрез него SonarCloud[bot] ще може да се авторизира в Git, за да оставя съобщения в пулл-реквестите.

Dsonar.projectKey — името на проекта в Sonar, може да се види в настройките на проекта.

Dsonar.organization — името на организацията от GitHub.

Правим пулл-реквест и чакаме, когато SonarCloud[bot] дойде в коментарите:

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

Управление на релизи

Билдът е настроен, тестовете са проведени, време е и за релиз. Да видим как GitHub Actions помага значително при опростяването на управлението на релизите.

На работата ми имам проекти, кодовата база на които е в Bitbucket (всичко като в онази история „денем пиша в Bitbucket, нощем комитирам в GitHub“). За съжаление, в Bitbucket няма вградени средства за управление на версии. Това е проблем, защото за всяка версия трябва ръчно да създам страница в Confluence и да добавя всичките характеристики, включени във версията, да прегледам тънките места на разума, задачите в Jira и комитите в репозитория. Шансовете за грешки са много, може нещо да бъде забравено или да запиша неща, които вече сме издали в миналото, понякога просто не е ясно как да се отнесе определен pull request — това е нова функционалност или поправка на бъгове, или корекция на тестове, или нещо инфраструктурно.

Как GitHub Actions може да ни помогне? Има отличен екшън — Release Drafter, който позволява да зададете шаблон за файла с бележки за версията, за да настроите категориите на pull request-ите и автоматично да ги групирате в файла с бележки за версията:

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

Пример за шаблон за настройка на доклад (.github/release-drafter.yml):

name-template: 'v$NEXT_PATCH_VERSION'
tag-template: 'v$NEXT_PATCH_VERSION'
categories:
  - title: ' Нови Функции'
    labels:
      - 'type:features'
# в тази категория събираме всички PR с етикет type:features

  - title: ' Поправки на Бъгове'
    labels:
      - 'type:fix'
# аналогично за етикет type:fix и т.н.

  - title: ' Документация'
    labels:
      - 'type:documentation'

  - title: ' Конфигурация'
    labels:
      - 'type:config'

change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
template: |
  ## Промени
  $CHANGES

Добавяме скрипт за генериране на черновата за версията (.github/workflows/release-draft.yml):

name: "Създаване на чернова за версия"

on:
  push:
    branches:
      - master

jobs:
  update_draft_release:
    runs-on: ubuntu-18.04
    steps:
      - uses: release-drafter/release-drafter@v5
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Всички pull request-и от този момент ще се събират автоматично в бележките за версията — магия!

Тук може да възникне въпрос: а какво, ако разработчиците забравят да зададат етикети на PR? Тогава не е ясно в коя категория да го отнесем и отново ще трябва да се занимаваме ръчно с всеки PR поотделно. За да решим този проблем, можем да използваме още един екшън — Label Verifier — той проверява наличието на етикети на pull request-ите. Ако няма нито един задължителен етикет, проверката ще бъде неуспешна и съобщение за това ще видим в нашия pull request.

name: "Проверка на етикетите по тип"

on:
  pull_request:
    types: [opened, labeled, unlabeled, synchronize]

jobs:
  triage:
    runs-on: ubuntu-18.04
    steps:
      - uses: zwaldowski/match-label-action@v2
        with:
          allowed: 'type:fix, type:features, type:documentation, type:tests, type:config'

Сега всеки pull request трябва да бъде обозначен с един от следните етикети: type:fix, type:features, type:documentation, type:tests, type:config.

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

Авто-аннотирование пулл-реквестов

Раз уж ние кам ни все названо "effective работа с пулл-реквестами", то стоит сказать еще о таком экшене, как labeler, который присваивает метки в PR на основании того, какие файлы были изменены. Например, можем пометить как [build] любой пул-реквест, в котором есть изменения в каталоге .github/workflow.

Подключить его довольно просто:

name: "Auto-assign themes to PR"

on:
  - pull_request

jobs:
  triage:
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/labeler@v2
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}

Еще нам понадобится файл с описанием соответствия каталогов проекта с тематиками пулл-реквестов:

theme:build:
  - ".github/**"
  - "pom.xml"
  - ".travis.yml"
  - ".gitignore"
  - "Dockerfile"

theme:code:
  - "src/main/*"

theme:tests:
  - "src/test/*"

theme:documentation:
  - "docs/**"

theme:TRASH:
  - ".idea/**"
  - "target/**"

Подружить действие, которое автоматически проставляет метки в пулл-реквесты, и действие, проверяющее наличие обязательных меток, у меня не вышло; match-label наотрез не хочет видеть проставленные ботом метки. Похоже, проще написать свое действие, совмещающее оба этапа. Но даже в таком виде пользоваться довольно удобно, нужно выбрать метку из списка при создании пулл-реквеста.

Пора деплоить

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

Я попробовал несколько вариантов деплоя через GitHub Actions (через ssh, через scp, и при помощи docker-hub), и могу сказать, что, скорее всего, вы найдете способ залить бинарный файл на сервер, каким бы не был ваш pipeline.

Мне понравился вариант держать всю инфраструктуру в одном месте, поэтому рассмотрим, как сделать деплой в GitHub Packages (это репозиторий для бинарного контента, npm, jar, docker).

Скрипт сборки docker образа и публикации его в GitHub Packages:

име: Разгънете docker изображение

при:
  натискане:
    клонове:
      - 'master'

работи:

  изграждане_docker_изображение:
    работа на: ubuntu-18.04
    стъпки:

#     Изграждане на JAR:
      - използва: actions/checkout@v1
      - име: настройка на JDK 11
        използва: actions/setup-java@v1
        с:
          java-version: 1.11
      - име: Maven Пакет
        стартиране: mvn -B clean compile package -DskipTests

#     Задайте глобални променливи на средата:
      - име: задайте глобална среда
        идентификатор: global_env
        стартиране: |
          echo "::set-output name=IMAGE_NAME::${GITHUB_REPOSITORY#*\/}"
          echo "::set-output name=DOCKERHUB_IMAGE_NAME::docker.pkg.github.com/${GITHUB_REPOSITORY}/${GITHUB_REPOSITORY#*\/}"

#     Изграждане на Docker изображение:
      - име: Изграждане и етикетиране на изображение
        стартиране: |
          docker build -t "${{ steps.global_env.outputs.DOCKERHUB_IMAGE_NAME }}:latest" -t "${{ steps.global_env.outputs.DOCKERHUB_IMAGE_NAME }}:${GITHUB_SHA::8}" .

      - име: Docker вход
        стартиране: docker login docker.pkg.github.com -u $GITHUB_ACTOR -p ${{secrets.GITHUB_TOKEN}}

#     Публикувайте изображението в хранилището на пакети на GitHub:
      - име: Публикуване на изображение
        среда:
          IMAGE_NAME: $GITHUB_REPOSITORY
        стартиране: docker push "docker.pkg.github.com/$GITHUB_REPOSITORY/${{ steps.global_env.outputs.IMAGE_NAME }}"

Първо трябва да съберем JAR файла на нашето приложение, след което изчисляваме пътя до GitHub docker регистъра и името на нашето изображение. Има няколко трика, с които още не сме се сблъсквали:

  • конструкция вида: echo «::set-output name=NAME::VALUE» позволява да зададете стойност на променливата в текущата стъпка, така че след това тя да може да бъде прочетена в останалите стъпки.
  • може да получите стойността на променливата, зададена на предишната стъпка, чрез идентификатора на тази стъпка: ${{ steps.global_env.outputs.DOCKERHUB_IMAGE_NAME }}
  • стандартната променлива GITHUB_REPOSITORY съдържа името на репозитория и неговия собственик («owner/repo-name»). За да изрежете от тази строка всичко освен името на репозитория, ще използваме bash синтаксис: ${GITHUB_REPOSITORY#*\/}

След това трябва да изградим docker изображението:

docker build -t "docker.pkg.github.com/antkorwin/github-actions/github-actions:latest"

Авторизирайте се в регистъра:

docker login docker.pkg.github.com -u $GITHUB_ACTOR -p ${{secrets.GITHUB_TOKEN}}

И публикувайте изображението в GitHub Packages Repository:

docker push "docker.pkg.github.com/antkorwin/github-actions/github-actions"

За да зададем версията на изображението, използваме първите цифри от SHA хеш кода на commit — GITHUB_SHA тук също има нюанси, ако ще правите такива сборки не само при merge в master, а и по събитие за създаване на pull request, SHA може да не съвпада с хеша, който виждаме в историята на git, защото действието actions/checkout прави свой уникален хеш, за да избегне взаимни блокировки на действията в PR.

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

Ако всичко е минало успешно, отваряйки раздела с пакети (https://github.com/antkorwin/github-actions/packages) в репозитория, ще видите нов docker образ:

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

Тук можете да видите списък с версиите на Docker образа.

Остава само да конфигурираме нашия сървър да работи с този регистър и да рестартираме услугата. Как да го направим чрез systemd, ще разкажа друг път.

Мониторинг

Нека разгледаме прост вариант за здравна проверка на нашето приложение с помощта на GitHub Actions. В нашето бутово приложение има actuator, така че не е нужно да пишем API за проверка на състоянието, всичко е вече направено. Трябва само да извикаме хоста: SERVER-URL:PORT/actuator/health

$ curl -v 127.0.0.1:8080/actuator/health

> GET /actuator/health HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.61.1
> Accept: */*

< HTTP/1.1 200
< Content-Type: application/vnd.spring-boot.actuator.v3+json
< Transfer-Encoding: chunked
< Date: Thu, 04 Jun 2020 12:33:37 GMT

{"status":"UP"}

Всичко, което ни е нужно, е да напишем задача за проверка на сървъра по крон, а ако той не отговори, ще изпратим известие в Telegram.

Първо, да разберем как да стартираме workflow по крон:

on:
  schedule:
    - cron:  ' */5 * * * *'

Всичко е просто, не мога да повярвам, че в GitHub могат да се правят такива събития, които не се получават с webhook. Подробности в документацията: help.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule

Ще проверим статуса на сървъра ръчно чрез curl:

jobs:
  ping:
    runs-on: ubuntu-18.04
    steps:

      - name: curl actuator
        id: ping
        run: |
          echo "::set-output name=status::$(curl ${{secrets.SERVER_HOST}}/api/actuator/health)"

      - name: health check
        run: |
          if [[ ${{ steps.ping.outputs.status }} != *"UP"* ]]; then
            echo "health check is failed"
            exit 1
          fi
          echo "It's OK"

Първо запазваме в променлива отговора, който сървърът ни е дал на запитването, на следващата стъпка проверяваме status UP и, ако не е така, излизаме с грешка. Ако е нужно ръчно да 'провалим' действието, то exit 1 — подходящото оръжие.

  - name: send alert in telegram
    if: ${{ failure() }}
    uses: appleboy/telegram-action@master
    with:
      to: ${{ secrets.TELEGRAM_TO }}
      token: ${{ secrets.TELEGRAM_TOKEN }}
      message: |
        Health check of the:
        ${{secrets.SERVER_HOST}}/api/actuator/health
        failed with the result:
        ${{ steps.ping.outputs.status }}

Изпращането в Telegram го правим само ако действието е неуспешно на предишната стъпка. За изпращане на съобщение използваме appleboy/telegram-action, а как да получим токен на бота и ID на чата можете да прочетете в документацията: github.com/appleboy/telegram-action

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

Не забравяйте да запишете в секретите на GitHub: URL за сървъра и токените за Telegram бота.

Бонус трак — JIRA за мързеливите

Обещах, че ще се върнем към JIRA, и ето ни отново. Стотици пъти съм наблюдавал на стендапове как разработчиците правят функция, сливат клон, но забравят да преместят задачата в JIRA. Разбира се, ако всичко това се правеше на едно място, щеше да е по-лесно, но всъщност пишем код в IDE, сливаме клонове в Bitbucket или GitHub, а задачите след това прехвърляме в JIRA, за целта трябва да отворим нови прозорци, понякога да се логваме отново и т.н. Когато напълно си спомняш какво трябва да направиш следващо, няма смисъл да отваряш таблото за задачите пореден път. В резултат, сутрин на стендапа трябва да се отдели време за актуализиране на дъската със задачи.

GitHub ще ни помогне и в това рутинно занимание, за начало можем да преместим задачите автоматично в колоната code_review, когато сме изпратили пулл-реквест. Всичко, което трябва — е да се придържаме към съгласията за именуване на клоновете:

[име на проекта]-[номер на задачата]-име

например, ако ключът на проекта „GitHub Actions“ е GA, то GA-8-jira-bot може да е клон за реализиране на задачата GA-8.

Интеграцията с JIRA работи чрез действия от Atlassian, не са идеални, трябва да спомена, че някои от тях изобщо не заработиха за мен. Но ще обсъдим само онези, които определено работят и се използват активно.

За начало трябва да преминем авторизация в JIRA с помощта на действието: atlassian/gajira-login

jobs:
  build:
    runs-on: ubuntu-latest
    name: Jira Workflow
    steps:
      - name: Вход
        uses: atlassian/gajira-login@master
        env:
          JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
          JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
          JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}

За това трябва да получим токен в JIRA, как точно да го направим е описано тук: confluence.atlassian.com/cloud/api-tokens-938839638.html

Извличаме идентификатора на задачата от името на клона:

  - name: Намиране на задача
    id: find_issue
    shell: bash
    run: |
      echo "::set-output name=ISSUE_ID::$(echo ${GITHUB_HEAD_REF} | egrep -o 'GA-[0-9]{1,4}')"
      echo име на клон: $GITHUB_HEAD_REF
      echo извлечена задача: ${GITHUB_HEAD_REF} | egrep -o 'GA-[0-9]{1,4}'

  - name: Проверка на задача
    shell: bash
    run: |
      if [[ "${{steps.find_issue.outputs.ISSUE_ID}}" == "" ]]; then
        echo "Моля, именувайте клона си в съответствие със задачата в JIRA: [project_key]-[task_number]-branch_name"
        exit 1
      fi
      echo успешно намерена задача JIRA: ${{steps.find_issue.outputs.ISSUE_ID}}

Ако потърсите в GitHub marketplace, можете да намерите действие за тази задача, но ми се наложи да напиша същото чрез grep по името на клона, защото това действие от Atlassian изобщо не искаше да работи по моя проект, а да се занимавам да разбера какво не е наред — отнема повече време, отколкото да направя същото ръчно.

Остава само да преместите задачата в колоната „Code review“ при създаването на пулл-реквеста:

  - name: Transition issue
    if: ${{ success() }}
    uses: atlassian/gajira-transition@master
    with:
      issue: ${{ steps.find_issue.outputs.ISSUE_ID }}
      transition: "Code review"

За това има специално действие в GitHub, всичко, от което се нуждае, е идентификаторът на задачата, получен на предишната стъпка, и авторизация в JIRA, която направихме по-горе.

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

По същия начин можете да прехвърляте задачи при merge в master и при други събития от GitHub workflow. Всичко зависи от вашето въображение и желание да автоматизирате рутинни процеси.

Изводи

Ако погледнем на класическата диаграма DEVOPS, покрихме всичките етапи, освен operate, мисля, че ако се постараем, можем да намерим някакво действие на пазара за интеграция с help-desk система, така че да считаме, че pipeline-ът е солиден и на базата на неговото използване може да се направят заключения.

Кръговете на ада с GitHub Actions (строим CI/CD веригата за Java проект)

Плюсове:

  • Marketplace с готови действия за всички случаи на живота, това е наистина страхотно. В повечето от тях може също така да видите изходния код, за да разберете как да решите подобна задача или да публикувате feature request към автора директно в GitHub репозитория.
  • Изборът на целева платформа за изграждане: Linux, macOS, Windows е доста интересна функция.
  • GitHub Packages е отлична работа, да държите цялата инфраструктура на едно място е удобно, не е нужно да прелиствате различни прозорци, всичко е на един-два клика разстояние и е прекрасно интегрирано с GitHub Actions. Поддръжката на Docker registry в безплатната версия също е добро предимство.
  • GitHub крие тайните в логовете на сборката, затова да го ползвате за съхранение на пароли и токени не е толкова страшно. През всичкото време на експерименти не успях да видя тайна в чист вид в конзолата.
  • Безплатен за Open Source проекти

Недостатъци:

  • YML, не го харесвам. При работа с такъв флоу, най-честото ми commit съобщение е „fix yml format“, понякога забравям да сложа таб, друг път пък пиша на грешния ред. Общо взето, да седите пред екрана с транспортир и линия не е най-приятното занимание.
  • DEBUG, отстраняването на флоу с комити, стартиране на повторно изграждане и извеждане в конзолата не винаги е удобно, но това е повече от рода на „вие сте взискателни“, свикнали сте да работите с удобни IDEA, когато може да се отстраняват всичко, което е нужно.
  • Вашият екшън може да бъде написан на какъвто и да е език, ако го опаковате в Docker, но единствено JavaScript се поддържа нативно. Разбира се, това е въпрос на вкус, но аз бих предпочел нещо друго вместо JavaScript.

Напомням, че репозиториумът с всички скриптове е тук: github.com/antkorwin/github-actions

Следващата седмица ще говоря на с доклад конференцията Heisenbug 2020 Piter. Ще споделя не само как да избегнете грешки при подготовката на тестови данни, но и моите тайни за работа с набори от данни в Java приложения!

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster