เกริ่นนำก่อนครับ 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
- Merge request approvals API | GitLab - ดูข้อมูลการ Approve จากส่วน "approved_by"
$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 ดังนี้
- 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 มามี
- ApproveGuard: ApproveGuard: A CLI tool for enforcing upvote thresholds on GitLab Community Edition merge requests, designed to integrate seamlessly into Atlantis workflows - อันนี้จะไปจับ API ของ UpVote / DownVote แทน และใช้ตัว Workflow อย่าง Atlantis มาช่วย ใช้ go เขียนด้วยนะ
Discover more from naiwaen@DebuggingSoft
Subscribe to get the latest posts sent to your email.