Tản mạn về Github Actions

Github Actions là gì

  • Github action là 1 chức năng được Github công bố và giới thiệu vào năm 2018 tại hội nghị Universe, chức năng này giúp chúng ta đẩy mạnh quy trình phát triển phần mềm ngay trong repositories của mình ( Tương tự CI/CD , chỉ khác cái là khi ta dùng các service CI/CD khác thì mình sẽ phải ủy quyền cho App của bên họ vào repositories của mình ) .
  • Ta có thể viết các tác vụ xung quanh liên quan tới quy trình phát triển phần mềm không chỉ có tích hợp CI/CD không thôi , ví dụ như việc review , assign hay set các label commit, hoặc làm bất kể 1 cái gì đó nếu có event xảy ra ( pull , push , issue , v...v các event xung quanh github khá là đa dạng có thể tham khảo thêm tại đây https://help.github.com/en/actions/automating-your-workflow-with-github-actions/events-that-trigger-workflows )
Chi Phí
  • Đối với các service CI/CD Bên ngoài thì thường là trong 1 khoảng thời gian nào đó mình sẽ được miễn phí khi build, đến giới hạn rồi thì sẽ phải bỏ tiền ra để nâng cấp dịch vụ
  • Đối với github action



Thành phần của Action
  • Để bắt đầu với github actions ta cần tạo 1 thư mục .github/workflows tất cả các file dạng workflow.yml sẽ được đặt trong này và được coi là 1 Action
  • Workflows được chia thành các bậc (Workflows > Jobs > Steps)
  • Tính tới thời điểm hiện tại Github action cũng ra mắt được hơn 1 năm , lượng người chia sẻ các action rất nhiều và đông đảo chúng ta tưởng tượng nó giống như NPM vậy.
  • Và trong 1 workflow chúng ta có thể config cho nó build trên nhiều môi trường , hệ điều hành, phiên bản ngôn ngữ lập trình khác nhau. Ví dụ:
Events that triger
  • Như nói ở trên tại github action ta có thể điều chỉnh việc chạy các workflow theo 1 cái event (sự kiện) nào đó xảy ra . Ví dụ về sự kiện đơn
# Trigger on push
on: push
Ví dụ về nhiều sự kiện

# Trigger the workflow on push or pull request
on: [push, pull_request]
Ví dụ về sử dụng nhiều sự kiện và option đi theo sự kiện đó

on:
  # Trigger the workflow on push or pull request,
  # but only for the master branch
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  # Also trigger on page_build, as well as release created events
  page_build:
  release:
    types: # This configuration does not affect the page_build event above
      - created
Contexts and expression syntax for GitHub Actions
  • Nôm na giống như cách chúng ta truy cập vào các biến hay các command kiểm tra điều kiện if, ví dụ kiểu ta sẽ thực hiện 1 steps này khi steps kia có đầu ra == ABCXYZ , thì cách viết biểu thức truy cập vào các biến Ví dụ thiết lập một biến môi trường
env:
  my_env_var: ${{ <expression> }}
NHƯNG đối với biểu thức if thì khác nhé

steps:
  - uses: actions/hello-world-javascript-action@master
    if: <expression>
Tên contextData typeMô tảgithub | object | Thông tin tổng quát về quy trình làm việc, về pull request , về repository v...v Chi tiết
env | string | Các biến môi trường trong 1 workflow
job | object | Thông tin về job đang chạy vd như status, container id Chi tiết
steps | object | Thông tin về các steps đã được chạy trong job này. Chi tiết
secrets | object | Cho phép truy cập vào các secrets variable được thiết lập trong một repository. Cách tạo và sử dụng secrets key

  • Cách truy cập vào các context
    • Dưới dạng mảng : github['sha']
    • Dưới dạng object: github.sha
  • Chúng ta hãy cùng thử dump dữ liệu của các context ra xem thế nào nhé , tạo 1 workflow tại .github/workflows/main.yml
on: push

jobs:
  one:
    runs-on: ubuntu-16.04
    steps:
      - name: Dump GitHub context
        env:
          GITHUB_CONTEXT: ${{ toJson(github) }}
        run: echo "$GITHUB_CONTEXT"
      - name: Dump job context
        env:
          JOB_CONTEXT: ${{ toJson(job) }}
        run: echo "$JOB_CONTEXT"
      - name: Dump steps context
        env:
          STEPS_CONTEXT: ${{ toJson(steps) }}
        run: echo "$STEPS_CONTEXT"
      - name: Dump runner context
        env:
          RUNNER_CONTEXT: ${{ toJson(runner) }}
        run: echo "$RUNNER_CONTEXT"
      - name: Dump strategy context
        env:
          STRATEGY_CONTEXT: ${{ toJson(strategy) }}
        run: echo "$STRATEGY_CONTEXT"
      - name: Dump matrix context
        env:
          MATRIX_CONTEXT: ${{ toJson(matrix) }}
        run: echo "$MATRIX_CONTEXT"
  • OK Giờ chúng ta push lên và kiểm tra trong action của repository thôi.
Quickstart trên repositories
  • Ngoài cách tạo folder .github/workflows mình nói trên thì còn cách khác đó là ta lên thẳng github để khởi tạo action.
  • Từ repository của mình ta chọn Actions
  • Tại repository của mình đã có các workflow, nên khi vào mình sẽ thấy dashboard lịch sử các lần chạy workflow, trong trường hợp chúng ta khởi tạo hãy chọn New workflow
  • Github sẽ suggest cho mình một số action ví dụ trong việc build hoặc test code hay thậm chí cả deploy
  • Ở đây mình sử dụng Laravel nên sẽ install Workflow của Laravel mà github đã suggest, chọn Set up this workflow và sau đó nó sẽ tạo ra cho chúng ta 1 commit ( đơn giản là nó tạo .github folder rồi workflow thôi ấy mà ) Nội dung file đó như sau

  • Như mình giới thiệu ở trên đây là 1 file workflow, nó có 1 jobs tên là laravel-tests , runs-on chính là cái môi trường để build các step dưới. Và cái sự kiện để kích hoat workflow này đấ là push , chúng ta có thể cấu hình nó theo branch , tags , hoặc branches-ignore , issue v...v tham khảo tại Workflow Syntax


  • Các steps bên trong workflow này có :

    • Uses ( Đây là khai báo 1 action được chia sẻ từ người dùng khác kiểu như là 1 package trên NPM ý :v )
    • name : Copy . env ( step này copy .env tương ứng với câu lệnh dòng run ở dưới )`
    • tương tự Install Dependencies, Generate Key, Create Database các step rất quen thuốc đối với các bạn sử dụng Laravel Framework

  • Tiếp theo là việc run workflow , như ở trên khi mình push code nó sẽ chạy workflow này bất kể branches nào, ta có thể quan sát việc nó run qua chức năng Action trên repostiroy



  • Cá nhân mình thấy tại màn hình logs này của Github Action thì rất là tiện và hay, nó cho ta xem theo thời gian thực và có các thanh cuộn khá hợp lý

Cộng đồng
  • Nói về cộng đồng thì github chắc hẳn là lớn rồi , vì thế khi làm việc với github action ta sẽ có 1 kho tài nguyên khổng lồ , giúp cho việc start action dễ dàng hơn bất cứ service CI/CD nào khác tham khảo các action được chia sẻ tại đây https://github.com/marketplace?type=actions
  • Như mình có sử dụng 1 action giúp cho việc filter các commit trên github thuận tiện hơn đó là Labeler , nó cho phép gán label tự động khi có thay đổi từ 1 file nào đó, ví dụ trong commit của mình thay đổi file readme.md thì tự động nó sẽ gán label là Document (mình tự định nghĩa) Khá là hay ho :D Link của action https://github.com/actions/labeler
  • Cấu trúc folder như sau
  • Nội dung workflow label.yml
Vẫn là 1 jobs tên là label, chạy trên môi trường ubuntu, có 1 step được sử dụng tới packge action/labeler@v2 cùng với 1 cấu hình repo-token ( tại vì việc gán label sẽ do 1 app của github nên mình sẽ phải cấp token cho package này sử dụng cái app đó gán cho mình ) và workflow này nó sẽ được chạy khi phát sinh 1 pull_request

Và quan trọng nhất việc cấu hình các label mình để tại 1 file labeler.yml nội dung

Và đây là kết quả khi mình tạo pull request:


Nhìn xanh lè thế kia là biết pull hịn hò rồi =)) Merge thôi Các tài liệu liên quan tới action có thể truy cập vào đây https://help.github.com/en/actions/

CI (continuous integration)
  • Tại nội bộ công ty Sun Asterisk mọi người hay sử dụng image framgiaciteam/php:7.3 để check convetion ( đối với PHP ) và chúng ta có 1 chuẩn riêng để check phpcs đó là chuẩn Framgia
phpcs --standard=Framgia app
  • Để chúng ta sử dụng được phpcs thì trên github action marketplace cũng đã có một vài action hỗ trợ rồi ( VD : https://github.com/marketplace/actions/phpcodesniffer) tuy nhiên hiện tại cũng chỉ có 1 vài các Standard rule cơ bản của phpcs mà thôi, mình xem qua thì khi người dùng muốn dùng 1 bộ rule riêng ( chuẩn Framgia ) thì chúng ta cần định nghĩa các rule đó thành các file ở source code rồi config trong action trên , mình thấy khá bất tiện :d
  • Vậy liệu chúng ta ánh xạ image từ docker vào github action có được không ? Theo mình tìm hiểu được thì không , nó cũng không hoàn toàn là không thể, github ánh xạ được docker tuy nhiên để sử dụng trơn tru thì trên image docker đó cần có vài config liên quan tới github action và còn cách thứ 2 nữa đó là chúng ta sẽ make ra một action và action sẽ chèn image docker cần sử dụng và nó được gọi là Docker Container Action
  • Cách tạo Docker Container Action có thể tham khảo tại đây ( https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-a-docker-container-action )
Solutions cho PHP CS Standard Framgia
  • Tất cả những gì mình nói ở trên chúng ta có thể đúc kết có 2 cách đơn giản nhất để require standard framgia vào phpcs
    • 1 . Là chúng ta sẽ dùng 1 action môi trường cài phpcs rồi , và chúng ta cần có vài dòng lệnh nôm na là để cài đặt PHPCS Framgia như
    •  cd ~/.composer/vendor/squizlabs/php_codesniffer/src/Standards
       git clone git@github.com:wataridori/framgia-php-codesniffer.git Framgia
    • Tức là chúng ta sẽ tiến hành cài và chạy bằng lệnh khi action chạy
    • 2 . Cách thứ 2 là tạo một Docker Container Action được khởi tạo từ image framgiaciteam/php, rồi ta sử dụng action này vào workflow thôi, tại thời điểm viết bài này mình cũng đã tạo ra một action để chạy phpcs chuẩn framgia như vậy rồi mọi người có thể tham khảo hoặc sử dụng tại đây (https://github.com/marketplace/actions/sun-ci) trong link cũng có sẵn example rồi chúng ta chỉ việc ném vào test trên repository của mình thôi
Đối với CD

  • Đối với việc deploy ở đây mình sử dụng deployer, hiện tại trên github cũng có action này rồi đó là musps/action-deployer-php https://github.com/musps/action-deployer-php


  • Đầu tiên ta tạo 1 file deploy.yml nội dung như sau



  • Workflow này sẽ được chạy khi có sự kiện push ở branch develop ta chú ý khi sử dụng action musps/action-deployer-php sẽ có 1 tham số args là câu lệnh để chạy deploy


  • Tham số thứ là env SSH_PRIVATE_KEY ta sẽ nhét private vào phần secret của repository

Và cuối cùng để cho github action chạy thôi :D


Workflow : Thông báo về chatwork khi chạy xong các workflow
  • Dựa vào các phần mình nói ở trên mình có làm demo 1 workflow chức năng của nó sẽ thông báo về chatwork cho chúng ta là build các job thành công hay thất bại, bắt đầu nhé, Ý tưởng như sau
    • Chúng ta sẽ có 1 step để gọi API Post message về chatwork ( mình sử dụng curl để làm việc này ) và nó sẽ được thực hiện cuối cùng tất cả các workflow.
    • Chúng ta cần có CHATWORK_TOKEN và CHATWORK_ROOM để thực hiện việc trên
    • Chúng ta cần sử dụng các Context để lấy 1 vài thông tin cơ bản về phiên action đó để ném vào message
Đầu tiên mình sẽ tạo các secrets key (CHATWORK_TOKEN và CHATWORK_ROOM ) Ở trên repository, ta vào {Repo} > Settings > Secrets Và lần lượt add các key đó vào .


  • Tiếp theo ta cùng suy nghĩ nhé, như đã nói ở trên cái job post message này nó sẽ phải chạy sau cùng, theo mặc định các jobs nó chạy song song tuy nhiên có 1 thuộc tính giúp ta điều khiển cái quy trình chạy của nó là needs ví dụ
jobs:
  job1:
  job2:
    needs: job1
  job3:
    needs: [job1, job2]
Ở đây nôm na là job1 chạy thành công xong thì job2 mới chạy, và job3 sẽ đợi job1 job2 chạy xong mới chạy. Trông rất hợp lý nhưng có 2 nhược điểm ở đây

  • Job2 chỉ biết job1 chạy xong rồi tuy nhiên không hề biết job1 đã pass hết các step hay chưa ? ( Để mình send message sao cho hợp lý )
  • Trong trường hợp list checks của repository của mình không chỉ có action mà còn có cả các service khác như CircleCI , FramgiaCI thì sao ?? nó đâu phải job để biết đã pass hay chưa Từ hai nhược điểm nêu trên, đó mới là vấn đề thực sự trong bài toán này, loanh quanh trên mạng một hồi thì mình có tìm thấy 1 cái action khá hay để sử dụng đó là github-action-wait-for-status , về cơ bản action này sẽ dùng interval để check status pass checks của pull và sẽ cho ra 1 cái outputs ( outputs của action đó nhé ) là success hoặc failure
  • OK Xong chỉ cần có thế, vấn đề đã được giải quyết xem thử workflow sẽ ra sao khi ta cài đặt như trên nhé
name: Notification
on: [pull_request]

jobs:
  Notification:
    runs-on: ubuntu-latest
    steps:
    - name: Wait for status checks
      id: waitforstatuschecks
      uses: WyriHaximus/github-action-wait-for-status@master
      with:
        ignoreActions: Notification
        checkInterval: 13
      env:
        GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
    - name: State Pull Request
      if: steps.waitforstatuschecks.outputs.status == 'success' || steps.waitforstatuschecks.outputs.status == 'failure'
      run: |
        if [[ true ]];  then
          curl -X POST -H "X-ChatWorkToken: ${{ secrets.CW_TOKEN }}" -d \
            "body=
            [toall][info][title] Build ${{ github.run_number }}| Status : ${{ steps.waitforstatuschecks.outputs.status }} [/title]- Action Pull Request: https://github.com/${{ github.repository }}/actions
        - Author: ${{ github.actor }}
        - Branch Pull From: ${{ github.head_ref }}
        - Branch Pull To: ${{ github.base_ref }}
        - Changes File : ${{ github.event.pull_request.changed_files }}
        - Comments: ${{ github.event.pull_request.comments }}
        - Commits: ${{ github.event.pull_request.commits }}
        - Review Comments: ${{ github.event.pull_request.review_comments }}[/info]
            " \
            "https://api.chatwork.com/v2/rooms/${{ secrets.CW_ROOM }}/messages"
        fi
  • Ở trên là workflow của mình , có 2 steps 1 là check status và 2 là send message, ở step send message mình có 1 điều kiện if đó là steps.waitforstatuschecks.outputs.status == success hoặc failure thì mới chạy step send message, để ý kỹ nó sẽ có dạng <context>.<id>.outputs.<property> Trong đó context thì như mình đã nói ở trên, id để xác định của steps nào và property là các thuộc tính đầu ra ( cái này thì tùy vào actions của người phát triển ra action đó thôi nhé ) Và đây là kết quả :
Workflow : Thông báo về chatwork khi có người comments , approved pull request
  • Mình không biết các dự án khác thế nào nhưng dự án mình làm hiện tại khi mỗi khi mình approved hay comments pull của người nào đó mình lại phải confirm với họ qua chatwork mình thấy hơi mất thời gian nhất là trong những lúc tập trung review code khiến mình quên mất,
  • Thì về workflow này ý tưởng không có gì cả chỉ là Call API Message KHI có một pull_request_review type là submitted đây chính là 1 loại Event trigger như mình đã đề cập ở trên, và loại này có các type
- submitted
- edited
- dismissed
Ở đây mình cần cái submitted, nội dung workflow của mình sẽ như sau

name: Pull_Comment
on:
  pull_request_review:
    types: [submitted]

jobs:
  deploys:
    runs-on: ubuntu-latest
    steps:
      - name: Pull Comment
        env:
          GITHUB_CONTEXT: ${{ toJson(github) }}
        run: |
          if [[ true ]];  then
            curl -X POST -H "X-ChatWorkToken: ${{ secrets.CW_TOKEN }}" -d \
              "body=
              [toall][info][title] New Request Submitted [/title]- New submitted URL: ${{ github.event.review.html_url }}
          - Author: ${{ github.event.review.user.login }} ( ${{ github.event.review.user.html_url }} )
          - Submitted at: ${{ github.event.review.submitted_at }}
          - Type: ${{ github.event.review.state }}[/info]
              " \
              "https://api.chatwork.com/v2/rooms/${{ secrets.CW_ROOM }}/messages"
          fi
Đơn giản vậy thôi đúng không, và đây là kết quả

NOTE : Đưa 1 action lên Github Marketplace
  • Thực ra khi tạo xong 1 action theo hướng dẫn ở đây là mình đã có thể đưa action đó vào sử dụng theo dạng
uses: {author}/{repo_name}@{branch}
# uses: hieudt/sun-phpcs@master
Tuy nhiên chúng ta nên release lên Github Marketplace để mọi người dễ tìm kiếm, và bản thân mình cũng hay lên trên này để tìm kiếm các actions ngon lành để sử dụng vào dự án của mình. Các bước đưa lên Github marketplace ( sau khi đã xong hết phần logic code rồi )

  • B1. Ta vào repo của action, chọn Releases
  • B2. Tạo ra 1 bản Realease bằng cách bấm vào Draft a new release
  • B3. Nhập Version, chọn branch cần release, title và description của release
  • B4. Tại phần Release Action , nếu muốn đưa lên Github Marketplace hãy tích vào Marketplace Developer Agreement và Đồng ý với điều khoản đưa ra nhé
    Sau khi submit xong, action của bạn đã lên Marketplace một cách nhanh chóng, chia sẻ cho mọi người thôi :D

Leave a reply

Success Comment, please wait admin approved

Your email address will not be published !

EST. READING TIME less than a minute
Category
STAT 539 Views
Shared Facebook Twitter Reddit