GitLab-CE: มาลองปรับ Merge Request Approval ให้มีประสิทธิภาพมากขึ้น

เกริ่นนำก่อนครับ Gitlab มี Feature Merge Request Approval โดย

  • Tier ฟรี (Community) มันจะเปิดให้ แต่เป็น Optional ไม่บังคับครับ
  • Tier เสียเงิน จะมี Feature เสริมเข้ามา เช่น ถ้าต้องการบังคับ หรือ กำหนดกฏเพิ่มเข้ามา แบบว่าถ้ายังไม่ Approve จะไม่ให้ Merge ซึ่งของใน Feature เสียเงิน มันช่วยได้หลายอย่าง
    - กันลั่น
    - เลือกคน Review ที่เหมาะสม ตาม Scope ได้ แต่ส่วน Microservice A ของทีม A / ส่วนของ Docker / Deployment File ให้ DevOps เป็นต้น

ส่วนที่ทำไมต้องทำ มันลั่นบ่อย / ไม่ได้ Review กันจริงจัง บางทีส่งมา หลายร้อยไฟล์ ก็มากดๆให้เป็นพิธี ระบบไม่บังคับก็ไม่กดรับทราบกัน พอเกิดปัญหาไม่มีหลักฐานการ Review อีก หรือ พอเป็นคนละหน่วย ไม่อยากคุยกันอะไรประมาณนี้ ลูกค้าด่าที ค่อยหาคนมาหยุม 5555

เลยเป็นที่มาของการมาหาวิธีทำ Merge Request Approval แบบ Require + กฏนิดหน่อย ภายใน GitLab-CE ครับ

GitLab CE: Merge Request Approve

สำหรับผม การใช้ GitLab Pipeline + GitLab API ไว้แล้ว (Blog: ลองใช้ GitLab REST API) จากนั้นเราจะลองมาไล่กันดู มี API Get พวก Merge Request Approval โดยขั้นตอนลองประมาณนี้ครับ

- POC ด้วย Postman

มันมี API จาก GitLab ที่ช่วยดึงนะ

  • Merge requests API | GitLab - เอาดูข้อมูล Merge Request เช่น จำนวนไฟล์ที่ Change ใครส่ง Merge / ข้อมูล Merge
$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID
$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/approvals

ก่อนทดสอบต้องลอง Generate Access Token จากหน้า User ใน GitLab จะประมาณนี้

และแปะใน postman ถ้าอยากรู้เรื่อง GitLab RestAPI อ่าน Blog นี้ได้ครับ ลองใช้ GitLab REST API

- Design Pipeline

ผมจะลองกำหนดกฏไว้ประมาณนี้ก่อน

การ Merge Code เข้า master/develop มีเงื่อนไขการตรวจสอบ และ Approve ดังนี้

  • กรณี Merge นั้นมีขนาดเล็ก แก้ไข < 10 ไฟล์ ให้มี Dev เข้ามา กด Approve ใน Merge Request 1 ท่าน
  • กรณี Merge นั้นมีขนาดใหญ่ แก้ไข >= 10 ไฟล์ขึ้นไป ให้มี Dev เข้ามา กด Approve ใน Merge Request 3 ท่านขึ้นไป
- Implement Pipeline

หลังจากออกแบบ Flow แล้ว สามารถเขียน Script ใน Pipeline .gitlab-ci.yml ได้ประมาณนี้ครับ

code_approved:
  rules:
    - if: $CI_MERGE_REQUEST_ID
    - if: $CI_MERGE_REQUEST_APPROVED    #Only Inject Variable Your Pay a money
    #- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
    #- if: $CI_MERGE_REQUEST_ID && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH
  script:
    - apk update
    - apk add curl
    - apk add jq
    - echo $CI_MERGE_REQUEST_ID
    - echo $CI_MERGE_REQUEST_APPROVED
    - echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
    - echo $CI_DEFAULT_BRANCH
    - > 
      if [ $CI_MERGE_REQUEST_TARGET_BRANCH_NAME != $CI_DEFAULT_BRANCH ] && [ "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" != "master" ] && [ "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" != "develop" ]; then
        echo "Not Default Repo Branch (master/develop or $CI_DEFAULT_BRANCH)"
        exit 0
      fi
    - >
      NUM_MR_FILE=$(curl --location "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID" --header "PRIVATE-TOKEN: $SECRET_GITLABINFO" | jq '.changes_count | tonumber ')
    - echo $NUM_MR_FILE
    - >
      NUM_APPROVE=$(curl --location "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/approvals" --header "PRIVATE-TOKEN: $SECRET_GITLABINFO" | jq '.approved_by | length')
    - echo $NUM_APPROVE
    - > 
      if [ $NUM_MR_FILE -le 9 ]; then
        if [ $NUM_APPROVE -ge 1 ]; then
          echo "Approve Min Merge"
          exit 0
        else
          echo "Not Approve Min Merge"
          exit 1
        fi
      else
        if [ $NUM_APPROVE -ge 3 ]; then
          echo "Approve Larger Merge"
          exit 0
        else
          echo "Not Approve Larger Merge"
          exit 1
        fi
      fi

จาก pipeline จะเห็นตรง curl ผมไม่สามารถใช้ "JOB-TOKEN: $CI_JOB_TOKEN"

curl --location "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/approvals" --header "JOB-TOKEN: $CI_JOB_TOKEN"  ...

ลองจากเว็บ GitLab เอง ใช้งานได้ (ลอง Test 2024-FEB) แต่พอลองไปใช้กับ GitLab (Self-Host) ที่ลองมา 15.2.1 / 16.7.3 ใช้ไม่ได้ เลยต้องไปใช้ท่า "PRIVATE-TOKEN: $SECRET_GITLABINFO" โดยที่

  • PRIVATE-TOKEN ต้องไป Generate Access Token จากหน้า User ถ้าจำไม่ผิด รอบแรก api, read_api, read_user, read_repository แต่ลองแก้ตามรูปก็ได้ครับ
  • อ๋อ แล้วพวก GitLab 16.7.3 ที่ผมลอง มันไม่ยอมให้สร้าง Token ระยะยาวแล้วนะ ยอมได้ 1 ปี แสดงว่าเดี๋ยวต้องมีรอบการ Main Update Secret
  • พอได้ Token แล้ว เอาไปใช้ใน SECRET ส่วน CI/CD ของ REPO
  • และกำหนด Merge Request ให้ Pipeline สำเร็จก่อน ถึงยอมให้ Merge
  • ส่วนตัว Git ต้องทำ prehook กัน Push ตรง Branch สำคัญ เช่น Develop / Master
  • จากนั้นอย่างลืม Add Gen Token สำหรับ Git Runner ตัว Runner ผมใช้ของ GitLab เลย ขึ้น Container ใส่ Token Add เรียบร้อยพร้อมใช้งานครับ

คำสั่งของ Docker ประมาณนี้ที่เหลือตามดูในรูปได้เลย

#1 Generate Token
#2 Add Runner 
docker run -d --name gitlab-runner --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest
#3 Register Toker from #1
docker exec -it <container_id / name> gitlab-runner register
#4 Verify 
docker exec -it <container_id / name> gitlab-runner verify
- ตัวอย่าง Flow ตอนทำงาน ประมาณนี้เลยครับ
  • เมื่อมี merge จะูกบังคับให้ Run Pipeline ครับ
  • จากนั้นรอคน Approve อาจจะ manual run pipeline เพื่อดูผล ในรูปจะใส่เคส Success / Fail
- ข้อดี / ข้อเสียของการ Workaround โดยใช้ Pipeline
  • ข้อเสีย มันยังกันไม่ครบ แม้ว่าเราจะใช้ Pipeline มาทำเรือ่ง Check ก่อน Merge แล้ว แต่ทว่า ถ้ามีคนหัวใส
    - ลบ Pipeline ทิ้ง
    - แก้ Config ให่ไม่ต้องสนใจ Result จาก Pipeline
    - หรือ ใจหยาบหน่อย ตรวจตรง Develop / Master เฉพาะ Merge Request ด้วย งั้น push ตรงเลย
    - งานยัง Manual อยู่ Approve ต้องมากดรัน Pipeline นอกจากไป Commit หลอกๆใน Readme
    - เนื่องจากไม่ใช้ Solution จาก Official ตอนนี้ GitLab version นี้ + API v4 อาจจะทำงานได้ แต่ตอน Update ต้องมาตรวจด้วย
  • ข้อดี ฟรี แต่ต้องหา Solution อื่นมาด้วย อาทิ เช่น
    - ป้องกันไม่ให้ Push ตรงได้ ในเมือตัว GitLab ฟรี มันไม่กัน เราต้องไปใช้พวก Git Pre-Commit Hook มาดักแทน
    - ป้องกันใครมือบอนไปโม Pipeline
    - หรือ Improve เพิ่ม เช่น ไปดู API Group / User เพื่อมาจัดหาทีมงาน Approve ให้เหมาะสม

จากที่ทำมา อาจจะไม่ได้ช่วยทั้งหมด แต่เรียกว่าช่วยถ่วงเวลา ให้เรามืสติให้ได้มากที่สุดครับ หันมาคุยกันบ้าง Blog นี้เขียนดองไว้มาปีนึง ลองแล้ว Re-write ใหม่อีกทีครับ ลอง Solution ของ Blog นี้ไปสักพักก่อน แต่ถ้าไม่เหลือบ่ากว่าแรง ลงทุนเสียเงินเถอะครับ จะได้เอาเวลามาแก้ปัญหาจุจิกไป Focus กับ Product ได้

นอกจากแนวทางนี้แล้ว ใครที่คิดแบบอื่นมาบ้าง เท่าที่ลอง Research มามี


Discover more from naiwaen@DebuggingSoft

Subscribe to get the latest posts sent to your email.