GitHub Actions як CI/CD для сайта на статычным генератары і GitHub Pages

GitHub Actions як CI/CD для сайта на статычным генератары і GitHub Pages

Трохі прашарсціў Habr здзівіўся таму, што вельмі мала апублікавана артыкулаў на тэму (beta-)фічы GitHub'а - Actions.

Здавалася б, можна растлумачыць такую ​​недаказанасць тым, што функцыянал яшчэ ў тэсціраванні, няхай і «beta». Але менавіта карысная асаблівасць бэты дазваляе выкарыстоўваць гэтую прыладу ў прыватных рэпазітарах. Менавіта пра працу з дадзенай тэхналогіяй я раскажу ў гэтым артыкуле.

Перадгісторыя

Калі пачынаць па парадку, то варта, мусіць, згадаць той момант, што падчас пошуку хуткага, зручнага, лёгкага і бясплатнага варыянту захоўвання персанальнага сайта «Пра мяне» прыйшлося выдаткаваць некалькі начэй і прошерстить мноства артыкулаў.

Хтосьці на выбірае хостынг, хтосьці хмарны сервер, а тым, каму не хочацца разбірацца ў працы, узаемадзеянні і аплаце ўсяго гэтага - прыходзіцца па душы выгрузка статычных сайтаў у рэпазітар, балазе цяпер гэта можна зрабіць і на GitHub, і на GitLab .

Канешне, гэта асабісты выбар кожнага.

Мой канчатковы выбар быў у карысць GitHub Pages.

Пра Pages

Хто не ў курсе, gh-pages - гэта такі варыянт захоўвання дакументацыі ў выглядзе сайта і прадастаўляецца ён бясплатна, а акрамя дакументацыі прапануецца захоўваць таксама персанальныя сайты. Гэты функцыянал падаецца GitHub'ом усім карыстачам і даступны ў наладах рэпазітара.

Для рэпазітара праекта выкарыстоўваецца галінка. gh-pages, для карыстацкага сайта - асобны рэпазітар з назвай username.github.io з зыходнікамі сайта ў master галінцы.

Падрабязней можна паглядзець у дакументацыі, Але адзначу толькі тое, што GitHub з дзіўнай шчодрасцю дазваляе кожнаму прывязаць уласны дамен да такога сайта, проста дадаўшы файл CNAME c назвай дамена і наладзіўшы DNS свайго дамен-правайдэра на серверы GitHub.

Упэўнены, што артыкулаў аб тым як разгарнуць такі сайт тут знойдзецца мноства, таму далей не пра гэта.

Узнікненне праблемы

Праблема складалася ў тым, што пры выкарыстанні статычнага генератара ёсць неабходнасць складаць дадатковыя мыліцы скрыпты і выкарыстоўваць бібліятэкі для спрашчэння працэсу генерацыі старонак і іх загрузкі ў рэпазітар. Папросту, калі захоўваць зыходнікі ў асобным прыватным рэпазітары, то кожны раз пры любой змене на сайце было неабходна разгортваць лакальнае асяроддзе для наступнай генерацыі статычных старонак і публікацыі ў асноўным рэпазітары сайта.

Існуе багацце статычных генератараў і ўсе яны маюць такую ​​ж праблему. Гэтыя дзеянні займаюць занадта шмат часу і сіл, а па выніку стопорят працу над сайтам, асабліва пасля некалькіх міграцый з АС на АС або інцыдэнтаў са стратай дадзеных на цвёрдых дысках. (так было ў маім выпадку).

Літаральна нядаўна, ці то ва ўсплываючым апавяшчэнні на сайце, ці то ў рассыланні ад GitHub было заўважана новаўбудаваны CI/CD, які дазволіў праводзіць гэтыя дзеянні з мінімальнымі намаганнямі.

Пра генератары статычных старонак

Не буду завастраць на гэтым падпункце асаблівую ўвагу, але падзялюся парай тэзісаў да якіх прыйшоў за час выбару і выкарыстання такіх:

1) выбіраць генератар стаіць пад сваю мову праграмавання, ці такі які быў максімальна зразумелы. Да гэтай ідэі я прыйшоў у той момант, калі самому прыйшлося дапісваць некаторы функцыянал для працы сайта, прастаўляць мыліцы для яго большай устойлівасці і аўтаматызацыі. Акрамя таго, гэта добрая нагода самому напісаць дадатковы функцыянал у выглядзе плагінаў;

2) на якім менавіта генератары спыняцца гэта асабісты выбар, але варта ўлічваць, што для пачатковага апускання ў працу функцыяналу GitHub Pages неабходна спачатку паставіць сабе Джэкіл. Балазе, ён дазваляе генераваць сайт з зыходнікаў прама ў рэпазітары (гэта я і паўтару са сваім выбарам).

Мой выбар генератара засноўваецца на першым пункце. пелікан які напісаны на Python з лёгкасцю замяніў чужы для мяне Jekyll (карыстаўся амаль год). У выніку нават стварэнне і рэдагаванне артыкулаў, робата над сайтам дае дадатковы досвед у цікавай для мяне мове.

__

Пастаноўка задачы

Галоўная задача будзе - напісаць такі скрыпт (на самай справе файл канфігурацыі), які дазволіў бы аўтаматычна генераваць статычныя старонкі з прыватнага рэпазітара. У рашэнні будзе задзейнічаны функцыянал віртуальнага асяроддзя. Скрыпт сам будзе дадаваць гатовыя старонкі ў публічны рэпазітар.

Інструменты для вырашэння

Інструменты, якія будзем выкарыстоўваць для вырашэння задачы:

  • GitHub Actions;
  • Python 3.7;
  • пелікан;
  • Git;
  • GitHub Pages.

Рашэнне праблемы

Разам, пазнаёміўшыся крыху з дакументацыяй і разабраўшыся як пішуцца скрыпты для Actions стала зразумела што гэты механізм цалкам вырашыць узніклую праблему. На момант напісання артыкула для выкарыстання дадзенага функцыяналу неабходна падпісацца на бэта-тэставанне!

GitHub Actions як CI/CD для сайта на статычным генератары і GitHub Pages
Апісанне новага функцыяналу самім Github

Пачынаецца напісанне Actions-скрыпту са стварэння найменнага файла ў тэчцы .github і яе падтэчку workflows. Зрабіць гэта можна як уручную, так і з рэдактара ва ўкладцы Actions на старонцы рэпазітара.

GitHub Actions як CI/CD для сайта на статычным генератары і GitHub Pages
Прыклад пустога бланка скрыпту

Коратка адкаментую бланк

name: CI    # название скрипта: будет отображаться во вкладке Actions

on: [push]  # действие, по которому запускается данный скрипт

jobs:       # роботы, которые будут выполняться
  build:    # сборка, которая..

    runs-on: ubuntu-latest      # ..будет запущена на основе этого образа

    steps:              # шаги которые будут проделаны после запуска образа
    - uses: actions/checkout@v1     # переход в самую актуальную ветку
    - name: Run a one-line script   # имя работы номер 1
      run: echo Hello, world!       # суть работы номер 1 (bash-команда записана в одну строку)
    - name: Run a multi-line script   # имя работы номер 2
      run: |                    # суть работы номер 2 (многострочная)
        echo Add other actions to build,
        echo test, and deploy your project.

Напішам свой на аснове шаблону:

0) Імя можна пакінуць і "CI". Тут справа густаўшчыны.

1) Далей неабходна абраць тое дзеянне/трыгер, якое прывядзе да запуску скрыпту, у нашым выпадку гэта звычайны пуш новага комміта ў рэпазітар.

on:
  push

2) Выява на аснове якога будзе запускацца скрыпт таксама пакінем з прыкладу, бо Ubuntu суцэль уладкоўвае па неабходным функцыянале. Гледзячы на даступныя інструменты становіцца зразумела, што гэта можа быць любы неабходны ці проста зручны вобраз (або докер кантэйнер на яго аснове).

  build:
    runs-on: ubuntu-latest

3) У кроках спачатку наладзім асяроддзе для падрыхтоўкі да асноўнай працы.

3.1) пераходзім у неабходную нам галінку (стандартны крок checkout):

- uses: actions/checkout@v1

3.2) усталёўваны Python:

    - name: Set up Python
      uses: actions/setup-python@v1
      with:
        python-version: 3.7

3.3) усталёўваны залежнасці нашага генератара:

    - name: Install dependencies
      run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt

3.4) ствараем дырэкторыю, у якую будуць генеравацца старонкі сайта:

   - name: Make output folder
      run: mkdir output

4) Для таго, каб праца над сайтам была паслядоўная, а менавіта не выдаляла папярэднія змены і можна было без канфліктаў дадаваць змены ў рэпазітар сайта, наступным крокам будзем кожны раз кланаваць рэпазітар сайта:

   - name: Clone master branch
      run: git clone "https://${{ secrets.ACCESS_TOKEN }}@github.com/${GITHUB_ACTOR}/${GITHUB_ACTOR}.github.io.git" --branch master --single-branch ./output

Гэты крок выклікае сістэмныя зменныя:

  • зменную GITHUB_ACTOR GitHub усталёўвае сам, і гэтае імя карыстальніка, па віне якога запусціўся дадзены скрыпт;
  • пераменная secrets.ACCESS_TOKEN гэта згенераваны токен для кіравання Github'ом, яго ў выглядзе зменнай асяроддзя мы можам перадаць усталяваўшы ва ўкладцы Secrets налад нашага рэпазітара. Прашу заўважыць, пры генерацыі токен падасца нам аднойчы, больш доступу да яго не будзе. Таксама як і значэння пунктаў Secrets.

5) Пераходзім да генерацыі нашых старонак:

   - name: Generate static pages
      run: pelican content -o output -s publishconf.py

Параметры, перададзеныя генератару, адказваюць за дырэкторыю, куды будзе адпраўлены згенераваныя файлы (-o output) і канфігурацыйны файл, які выкарыстоўваем для генерацыі (-s publishconf.py; пра падыход да падзелу лакальнага канфіга і канфіга для публікацыі можна пачытаць у дакументацыі Pelican).

Нагадаю, што ў нас у тэчку output ужо схіляецца рэпазітар сайта.

6) Наладзім git і праіндэксуем нашы змененыя файлы:

    - name: Set git config and add changes
      run: |
          git config --global user.email "${GITHUB_ACTOR}@https://users.noreply.github.com/"
          git config --global user.name "${GITHUB_ACTOR}"
          git add --all
      working-directory: ./output

У гэтым пункце выкарыстоўваецца ўжо вядомая пераменная, і ўказваецца рабочая дырэкторыя, у якой будзе адбывацца запуск каманд з гэтага кроку. Каманда пераходу ў працоўную дырэкторыю інакш выглядала б як. cd output.

7) Згенеруем паведамленне комміта, закамміцім змены і запушым іх у рэпазітар. Каб коміт не быў марна, і адпаведна не выдаў памылку ў bash (вынік на выхадзе не 0) - спачатку праверым ці неабходна наогул нешта каміціць і пушыць. Для гэтага выкарыстоўваем каманду git diff-index --quiet --cached HEAD -- якая на выхадзе ў тэрмінал выдасць 0 калі няма зменаў адносна папярэдняй версіі сайта, і 1 такія змены ёсць. Пасля чаго апрацоўваем вынік гэтай каманды. Такім чынам, мы ў інфармацыі аб выкананні скрыпту запішам карысную інфармацыю аб стане сайта на гэтым этапе, замест аўтаматычнага падзення і адпраўкі нам справаздачы аб падзенні скрыпту.

Гэтыя дзеянні таксама праводзім у нашай дырэкторыі з гатовымі старонкамі.

   - name: Push and send notification
      run: |
          COMMIT_MESSAGE="Update pages on $(date +'%Y-%m-%d %H:%M:%S')"
          git diff-index --quiet --cached HEAD -- && echo "No changes!" && exit 0 || echo $COMMIT_MESSAGE
          # Only if repo have changes
          git commit -m "${COMMIT_MESSAGE}"
          git push https://${{ secrets.ACCESS_TOKEN }}@github.com/${GITHUB_ACTOR}/${GITHUB_ACTOR}.github.io.git master
      working-directory: ./output

Вынік

У выніку такі скрыпт дазваляе не думаць аб стварэнні статычных старонак. Дадаючы змены напроста ў прыватны рэпазітар, няхай гэта будзе працай з git з-пад любой сістэмы ці стварэннем файла праз web-інтэрфейс GitHub'а, Actions зробяць усё самі. У выпадку нечаканага падзення скрыпту на пошту прыйдзе апавяшчэнне.

Поўны код

Пакіну свой працоўны варыянт, у ім у апошні крок дададзена адпраўка апавяшчэння аб тым, што коміт быў запушаны ў асноўны рэпазітар.

Выкарыстоўваюцца вышэйапісаныя Secrets куды дададзены токен бота і ідэнтыфікатар карыстальніка якому трэба адправіць паведамленне.

name: Push content to the user's GitHub pages repository

on:
  push

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1
    - name: Set up Python
      uses: actions/setup-python@v1
      with:
        python-version: 3.7
    - name: Install dependencies
      run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
    - name: Make output folder
      run: mkdir output
    - name: Clone master branch
      run: git clone "https://${{ secrets.ACCESS_TOKEN }}@github.com/${GITHUB_ACTOR}/${GITHUB_ACTOR}.github.io.git" --branch master --single-branch ./output
    - name: Generate static pages
      run: pelican content -o output -s publishconf.py
    - name: Set git config and add changes
      run: |
          git config --global user.email "${GITHUB_ACTOR}@https://users.noreply.github.com/"
          git config --global user.name "${GITHUB_ACTOR}"
          git add --all
      working-directory: ./output
    - name: Push and send notification
      run: |
          COMMIT_MESSAGE="Update pages on $(date +'%Y-%m-%d %H:%M:%S')"
          git diff-index --quiet --cached HEAD -- && echo "No changes!" && exit 0 || echo $COMMIT_MESSAGE
          git commit -m "${COMMIT_MESSAGE}"
          git push https://${{ secrets.ACCESS_TOKEN }}@github.com/${GITHUB_ACTOR}/${GITHUB_ACTOR}.github.io.git master
          curl "https://api.telegram.org/bot${{ secrets.BOT_TOKEN }}/sendMessage?text=$COMMIT_MESSAGE %0ALook at ${GITHUB_ACTOR}.github.io %0ARepository%3A github.com/${GITHUB_ACTOR}/${GITHUB_ACTOR}.github.io&chat_id=${{ secrets.ADMIN_ID }}"
      working-directory: ./output

Скрыншоты

GitHub Actions як CI/CD для сайта на статычным генератары і GitHub Pages
Вынік аднаго з запускаў адлюстраваны ва ўкладцы Actions рэпазітара з зыходнікамі

GitHub Actions як CI/CD для сайта на статычным генератары і GitHub Pages
Паведамленне ад бота аб завяршэнні працы скрыпту

Карысныя спасылкі

Агульныя звесткі пра Actions
Сінтаксіс Actions
Спіс трыгераў
Варыянты віртуальных акружэнняў
Старонкі Github
Static Generator list

Крыніца: habr.com

Дадаць каментар