Team làm việc trên GitHub dựa vào dữ liệu sự kiện để cộng tác. Dữ liệu ghi nhận qua issue, pull request, và comment trở nên then chốt để hiểu dự án.
Với tính sẵn sàng chung của GitHub Actions, chúng ta có cơ hội truy cập và bảo toàn dữ liệu sự kiện GitHub trong repository. Làm cho dữ liệu thành một phần của chính repository là cách bảo toàn nó bên ngoài GitHub. Nó cũng cho khả năng hiển thị dữ liệu trên website front-facing, như với GitHub Pages.
Và, nếu bạn như tôi, bạn có thể biến comment issue GitHub thành một trang guestbook phong cách năm 90 tuyệt vời.
Không quan trọng use case, nguyên tắc cốt lõi giống nhau. Chúng ta dùng Actions truy cập, bảo toàn, và hiển thị dữ liệu sự kiện GitHub - chỉ với một file workflow. Để minh họa quy trình, tôi sẽ dẫn dắt qua code workflow làm guestbook của tôi phát sáng.
Để nhìn tổng quan GitHub Actions bao gồm trigger workflow, xem A lightweight, tool-agnostic CI/CD flow with GitHub Actions.
Truy cập dữ liệu sự kiện GitHub
Action workflow chạy trong môi trường với biến môi trường mặc định. Nhiều thông tin tiện lợi có sẵn, bao gồm dữ liệu sự kiện. Cách hoàn chỉnh nhất truy cập dữ liệu sự kiện là dùng biến $GITHUB_EVENT_PATH, đường dẫn file chứa full JSON event payload.
Đường dẫn mở rộng trông như /home/runner/work/_temp/_github_workflow/event.json và data tương ứng với webhook event. Tìm tài liệu webhook event data trong GitHub REST API Event Types and Payloads. Để làm JSON data sẵn sàng trong môi trường workflow, dùng tool như jq parse event data và đưa vào biến môi trường.
Dưới đây, tôi lấy comment ID từ issue comment event:
ID="$(jq '.comment.id' $GITHUB_EVENT_PATH)"
Hầu hết event data cũng có sẵn qua biến context github.event không cần parse JSON. Field truy cập bằng dot notation, ví dụ dưới lấy cùng comment ID:
ID=${{ github.event.comment.id }}
Cho guestbook của tôi, tôi muốn hiển thị entry với handle user, ngày và giờ. Tôi capture event data như sau:
AUTHOR=${{ github.event.comment.user.login }}
DATE=${{ github.event.comment.created_at }}
Biến shell tiện cho truy cập data, tuy nhiên chúng ngắn hạn. Môi trường workflow tạo mới mỗi run, và cả biến shell set ở step này không persist sang step khác. Để persist data capture, bạn có hai lựa chọn: dùng artifacts, hoặc commit vào repository.
Bảo toàn dữ liệu sự kiện: dùng artifacts
Dùng artifacts, bạn persist data giữa workflow job không commit vào repository. Tiện khi muốn transform hoặc incorporate data trước khi đặt nơi vĩnh viễn hơn. Cần persist data giữa job vì:
Mỗi job trong workflow chạy trong instance mới của virtual environment. Khi job hoàn tất, runner terminate và xóa instance virtual environment. (Persisting workflow data using artifacts)
Hai action hỗ trợ artifacts: upload-artifact và download-artifact. Dùng action này làm file sẵn cho job khác trong cùng workflow. Xem full example passing data between jobs in a workflow.
File action.yml của upload-artifact chứa giải thích keyword. File upload lưu dạng .zip. Job khác cùng workflow run dùng download-artifact dùng data ở step khác.
Bạn cũng có thể tải thủ công archive trên trang workflow run, dưới tab Actions của repository.
Persist data giữa job không thay đổi file repository, vì artifact chỉ sống trong môi trường workflow.
Cá nhân tôi, thoải mái làm việc shell environment, thấy use case hẹp cho artifacts, dù lười không nhắc. Bên cạnh pass data giữa job, chúng có thể hữu ích tạo archive .zip output test. Trong ví dụ guestbook, tôi chạy tất cả step cần thiết trong một job, triệt tiêu nhu cầu pass data giữa job.
Bảo toàn dữ liệu sự kiện: push file workflow vào repository
Để persist data capture trong workflow trong chính repository, cần add và push data này vào Git repository. Làm được trong workflow bằng cách tạo file mới với data, hoặc append data vào file tồn tại, dùng shell command.
Tạo file trong workflow
Để làm việc với file repository trong workflow, dùng action checkout trước lấy bản copy làm việc:
- uses: actions/checkout@master
with:
fetch-depth: 1
Để thêm comment vào guestbook, tôi biến event data capture trong shell variable thành file proper, dùng substitution trong shell parameter expansion sanitize user input và dịch newline thành paragraph. Tôi viết trước về tại sao user input cần xử lý cẩn thận.
- name: Turn comment into file
run: |
ID=${{ github.event.comment.id }}
AUTHOR=${{ github.event.comment.user.login }}
DATE=${{ github.event.comment.created_at }}
COMMENT=$(echo "${{ github.event.comment.body }}")
NO_TAGS=${COMMENT//[<>]/\`}
FOLDER=comments
printf '%b\n' "<div class=\"comment\"><p>${AUTHOR} says:</p><p>${NO_TAGS//$'\n'/\<\/p\>\<p\>}</p><p>${DATE}</p></div>\r\n" > ${FOLDER}/${ID}.html
Dùng printf và điều hướng output với > đến file mới, event data biến thành file HTML, tên theo comment ID, chứa event data capture. Format trông như:
<div class="comment">
<p>victoriadrake says:</p>
<p>This is a comment!</p>
<p>2019-11-04T00:28:36Z</p>
</div>
Khi làm việc với comment, hiệu ứng đặt tên file dùng comment ID là file mới cùng ID sẽ ghi đè file trước. Tiện cho guestbook, cho phép edit comment thay thế file comment gốc.
Nếu dùng static site generator như Hugo, bạn có thể build file Markdown format, bỏ vào folder content/, và regular site build lo phần còn lại.
Trường hợp guestbook đơn giản của tôi, có step extra gộp file comment riêng lẻ thành trang. Mỗi lần chạy, nó ghi đè index.html hiện có với phần header.html (>), sau đó tìm và append (>>) nội dung tất cả file comment theo thứ tự giảm dần, cuối cùng append phần footer.html kết thúc trang.
- name: Assemble page
run: |
cat header.html > index.html
find comments/ -name "*.html" | sort -r | xargs -I % cat % >> index.html
cat footer.html >> index.html
Commit thay đổi vào repository
Vì action checkout không hoàn toàn giống clone repository, tại thời điểm viết, còn vài issue workaround. Cần thêm step pull, checkout, và push thành công về branch master, nhưng khá đơn giản trong shell.
Dưới đây step add, commit, push thay đổi workflow làm về branch master của repository.
- name: Push changes to repo
run: |
REMOTE=https://${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
git config user.email "${{ github.actor }}@users.noreply.github.com"
git config user.name "${{ github.actor }}"
git pull ${REMOTE}
git checkout master
git add .
git status
git commit -am "Add new comment"
git push ${REMOTE} master
Remote, thực tế repository của chúng ta, chỉ định dùng biến context github.repository. Để workflow được push vào master, dùng biến secrets.GITHUB_TOKEN.
Vì môi trường workflow shiny và mới sinh, cần config Git. Ví dụ trên dùng biến context github.actor nhập username account trigger workflow. Email config tương tự dùng default noreply GitHub email.
Hiển thị dữ liệu sự kiện
Nov 6, 2019 correction: GitHub Actions yêu cầu Personal Access Token trigger Pages site build.
Nếu dùng GitHub Pages với default secrets.GITHUB_TOKEN và không site generator, push thay đổi repository trong workflow chỉ update file repository. GitHub Pages build sẽ fail với lỗi "Your site is having problems building: Page build failed."
Để Actions trigger Pages site build, cần tạo Personal Access Token. Token này lưu as secret trong repository settings và pass vào workflow thay vì default secrets.GITHUB_TOKEN. Tôi viết thêm về Actions environment và variables bài khác.
Với Personal Access Token, push do Actions workflow trigger cũng update Pages site. Bạn tự xem bằng cách để comment trong guestbook của tôi! Sự kiện tạo comment trigger workflow, mất khoảng 30 giây đến 1 phút chạy và update trang guestbook.
Nơi site build cần thiết để publish thay đổi, như dùng Hugo, Action cũng làm được. Tuy nhiên, tránh tạo loop không mong muốn, một Action workflow không trigger Action khác. Thay vào đó, rất tiện xử lý build site với Makefile, workflow nào cũng chạy được. Chỉ thêm chạy Makefile làm step cuối workflow job, với repository token nơi cần:
- name: Run Makefile
env:
TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: make all
Đảm bảo step cuối workflow build và deploy site updated.
Không còn event data horizon
GitHub Actions cung cấp cách gọn gàng capture và sử dụng event data để nó không chỉ có sẵn trong GitHub. Khả năng chỉ giới hạn bởi trí tưởng tượng! Đây vài ý tưởng:
- Public-facing issues board, khách không có GitHub account xem và feedback issue dự án.
- RSS feed tự cập nhật issue mới, comment, PR cho bất kỳ repository.
- Hệ thống comment cho static site, dùng GitHub issue comment làm input method.
- Trang guestbook phong cách năm 90 tuyệt vời.
Đã nói tôi làm trang guestbook năm 90? Inner-Geocities-nerd của tôi hơi excited.