ตอนนี้มีโจทย์ให้คิดครับ เพราะเท่าที่ย้ายมาใช้ Git มาน่าจะ 3 ปี และจะเจอปัญหานึงประจำเลย มี Branch เปิดลอยๆไว้ ไม่เอามา Merge เข้าเส้นหลัก และไม่ได้ Pull Code ให้ Update ล่าสุดด้วย แล้วมันเอาไปทำอะไร ถามแล้วไม่มีใครรับว่าเป็นเจ้าของอีก ได้เป็นโจทย์เล็กๆ สำหรับมาหาว่า Branch อันนี้ใครสร้างคนแรก เพราะที่ส่องจาก GitLab มันจะมี Event Push ขึ้นมา ดังรูป
แต่ก่อนจะใช้งาน API เราต้องเตรียมตัวอะไรบ้างนะ
- Generate Access Token (API KEY)
- เข้าใจการใช้ API ของ GitLab ด้วย มันรองรับแบบ REST API / GraphQL และ OpenAPI โดยการใช้ REST API จะมี Base Path ที่ต่างจากการใช้หน้าเว็บ โดยมีรูปแบบ ดังนี้
- รูปแบบ <<BASE_URL>>/api/<<VERSION>>/<<RESOURCE>>
- ตัวอย่าง http://dev.ds.local/api/v4/projects/ ใช้ API Version 4 สนใจ Resource ข้อมูล Project ครับ
- NOTE: ตอนส่ง Request ต้องแนบ PRIVATE-TOKEN ไปในส่วนของ Header ด้วยครับ แต่มีบาง API ที่ไม่ต้องใช้ ถ้าเปิด Public Project ครับ
Generate Access Token (API KEY)
- เข้ามาที่ User Setting
- เลือก Access Token
- ตั้งชื่อ Token
- กำหนดวันหมดอายุของ Token เช่น ถ้าเราเอาให้คนนอกใช้ ต้องมีการกำหนดส่วนนี้
- กำหนด API ที่ใช้ได้ ว่าจะ Read/Write ส่วนไหน
เมื่อกำหนดขึ้นมาเสร็จ ระบบจะแสดง Key ขึ้นมาเหนือช่อง Token Name ให้ Copy เก็บไว้ ถ้าทำหายก็ Generate ใหม่อย่างเดียวครับ ส่วนถ้าใช้ไปนานๆ แล้ว อยากจะเอาออก (Revoke) สามารถกดที่ Icon ถังขยะได้เลย
Test ด้วย Postman ก่อน ว่ามัน Return อะไรมาบ้าง
ลองยิง Request โดยกำหนด API KEY "PRIVATE-TOKEN" จาก Token ที่ได้สร้างมาก่อนหน้า โดยจะใส่เข้าไปในส่วนของ Header กำหนด Setting ได้ตามรูปเลยครับ
ลองสัก API เช่น GET Project ดึงจาก Project API
http://dev.ds.local/api/v4/projects/
มาลอง API ที่เกี่ยวกับปัญหาของ Blog นี้จริงๆ โดยดึงจาก Event API
http://dev.ds.local/api/v4/projects/:project_id/events?action=pushed
หลังจากลองแล้วจะพบว่า
- API มันจะมี Limit ในการดึงข้อมูล โดย Default 20 Record
- ส่วนของ Response Header จะมี Property ที่น่าสนใจ ดังนี้ ที่จะช่วยให้เราเอา Result ทั้งหมดออกมาได้
- X-Total: บอกว่าจริง แล้ว Request ผลลัพธ์ทั้งหมดเท่าไหร่
- X-Per-Page:จำนวนผลลัพธ์ที่ดึงออกมาได้สุงสุดในแต่ละ Request
- X-Total-Pages:จากผลลัพธ์ทั้งหมด ถ้าต้องการดึงออกมาทั้งหมด ต้องใช้กี่ Request ตอนนี้ X-Total = 3358 / X-Per-Page = 1000 ดังน้้น X-Total-Pages = 34
- X-Request-Id
- X-Page
- X-Prev-Page
- X-Next-Page - จากที่บอกไปตอนต้นว่ามี API Limit 20 Record แต่ถ้าต้องการเพิ่มใส่ได้ per_page เพิ่มเข้าไปได้ แต่มันจะได้สูงสุด 100 และ page บอกหน้าจะดึงตาม X-Prev-Page / X-Next-Page มีคนไปขยายตัว per_page ด้วย
Ref: Make API pagination size configurable (#17329) · Issues · GitLab.org / GitLab · GitLab
ถ้า URL ที่ได้ Pattern ประมาณนี้ครับ
http://<<BASE_URL>>/api/v4/<<RESOURCE>>/:project_id/events?action=pushed&per_page=<<PERPAGE>>&page=<<PAGE>> #ตัวอย่าง http://dev.ds.local/api/v4/projects/95/events?action=pushed&per_page=100&page=4
โจทย์ของเราหา Event ที่บอกว่า Branch ไหนใครสร้าง ถ้าดูจาก Doc แล้ว จาก Event API เพิ่ม action เป็น pushed ไปแล้ว ยังไม่ได้สุด น่าจะต้องใช้ Script มา Filter เพิ่ม ถ้าดูจาก Result ที่ได้ Event แรก Action_Name="pushed new" + push_data.action="created" ที่เป็นการสร้าง Branch ใหม่ ส่วนอีกอันไม่ใช่ครับ
[ { "id": 79664, "project_id": 95, "action_name": "pushed new", "target_id": null, "target_iid": null, "target_type": null, "author_id": 22, "target_title": null, "created_at": "2023-01-28T06:33:32.466Z", "author": { "id": 22, "username": "chatri.ngam", "name": "Bug Buster", "state": "active", "avatar_url": "http://dev.ds.local/uploads/-/system/user/avatar/22/avatar.png", "web_url": "http://dev.ds.local/chatri.ngam" }, "push_data": { "commit_count": 0, "action": "created", "ref_type": "branch", "commit_from": null, "commit_to": "5ef05f52973463b5e5c02a2b57d69c902fbd654d", "ref": "feature/test_gitlabapi", "commit_title": null, "ref_count": null }, "author_username": "chatri.ngam" }, { "id": 79625, "project_id": 95, "action_name": "pushed to", "target_id": null, "target_iid": null, "target_type": null, "author_id": 24, "target_title": null, "created_at": "2023-01-27T10:21:29.436Z", "author": { "id": 24, "username": "aaaa.bbbb", "name": "Bug Lover", "state": "active", "avatar_url": "http://dev.ds.local/uploads/-/system/user/avatar/24/avatar.png", "web_url": "http://dev.ds.local/aaaa.bbbb" }, "push_data": { "commit_count": 1, "action": "pushed", "ref_type": "branch", "commit_from": "ce11eff2c27236a5d12511854951d2a79fcc70a4", "commit_to": "e71094dfe6b2cf3c79b560cc6120c0339cbd5e74", "ref": "develop_EODGW_UI", "commit_title": "แก้ไข DoworkAsync ให้รองรับ GW แบบใหม่ (DSGatewayQueueInfo)", "ref_count": null }, "author_username": "aaaa.bbbb" }, ....
Test เล็กน้อยๆ POC ด้วย PowerShell
สำหรับการเขียน Script ด้วย PowerShell เราจะใช้ Invoke-RestMethod เป็นหลักครับ ตอนมาลอง List Branch ของ Repo ที่สนใจ จาก Branch API ครับ โดยตัว Script ที่ได้ จะมีดังนี้
$APIKEY="<<YOUR-API-KEY>>" #95 = ProjectId $URIBranch="http://dev.ds.local/api/v4/projects/95/repository/branches?per_page=100" [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $BranchList = Invoke-RestMethod -Uri $URIBranch -Headers @{"PRIVATE-TOKEN"=$APIKEY} -ContentType 'application/json' -Method GET
ตอนนี้ผมลอง List Project โดยบอกไปเลย per_page=100 หลังจากลอง Execute Script พอลองจิ้ม Count ดู (หมายเลข 1) ได้มา 36 Records จากนั้นให้มัน Print PSObject ของตัวแปร $BranchList ออกมาดู (หมายเลข 2)
ต่อไปมาลองโจทย์ของ Blog นี้ Branch ไหนใครสร้าง จาก Event API เพิ่ม action เป็น pushed ไปแล้ว ยังไม่ได้สุด มาลองเขียน PowerShell เพื่อ Filter ครับ ได้ Script ประมาณนี้ครับ
$APIKEY="<<YOUR-API-KEY>>" #95 = ProjectId $URI="http://dev.ds.local/api/v4/projects/95/events?action=pushed&per_page=100&after=2022-01-01" $GitPushEvents = Invoke-RestMethod -Uri $URI -Headers @{"PRIVATE-TOKEN"=$APIKEY} -ContentType 'application/json' -Method GET #ตอนเขียน Blog นี้ ผมก็กำลังหาเงื่อนไข Filter เหมือนกัน ถ้า Final แล้ว จะมาเขียนแยกอีก Blog $GitPushEventsNewBranch = $GitPushEvents | where { ($_.push_data.action -eq "created") -and ($_.push_data.commit_count -eq "0") } | select *
ตอนเขียน Blog นี้
- ผมก็กำลังหาเงื่อนไข Filter $GitPushEvents เหมือนกัน ถ้า Final แล้ว จะมาเขียนแยกอีก Blog นึงครับ แต่ Key มี Branch ทั้งหมดของ Repo จาก Branch API มาจับ Event ที่สร้าง Branch นั้นๆขึ้นมาจาก Event API และข้อมูลมายำทำ Report ขึ้นมาครับ
- ที่ลอง Invoke-RestMethod Default มันไม่ Return Response Header มานะครับ ต้องมาปรับ Command เพิ่ม -ResponseHeadersVariable บอกว่าใส่ตัวแปรไหน แต่อันนี้ Required PowerShell6
$GitPushEvents = Invoke-RestMethod -Uri $URI -Headers @{"PRIVATE-TOKEN"=$APIKEY} -ContentType 'application/json' -Method GET -ResponseHeadersVariable GitPushResponseHead
- ตอนนี้ดูๆ ไว้ 2 ทาง PowerShell ต่อไป โดยขยับ Version ที่ Agents จากเดิม 5.xx ขึ้นมา กับลองดูทางเลือกอื่นๆ Client Library ของแต่ละภาษาครับ
มี Library มาช่วยไหม ?
- C#: nmklotas/GitLabApiClient: GitLab API client (github.com)
- JavaScript: gitlab-client - npm (npmjs.com) / gitbeaker: 🤖 GitLab API NodeJS library with full support of all the Gitlab API services.
- Java/Scala: gitlab4j/gitlab4j-api: GitLab4J API (gitlab4j-api) provides a full featured Java client library for working with GitLab repositories via the GitLab REST API
- python: python-gitlab v3.12.0
- RUBY: Class: Gitlab::Client — Documentation for gitlab (4.19.0) (rubydoc.info)
- PHP: GitLabPHP/Client: GitLab API v4 client for PHP (github.com)
มีทางเชื่อมต่อได้เยอะเหมือนกันครับ ต่อไป ถ้าว่างๆ ผมมาเล่นตัว GraphQL API ต่อครับ
Reference
- GitLab APIs | GitLab
- REST API resources | GitLab
- How to find the branch created date? - Tutorials, Tips & Tricks / Tutorials - GitLab Forum
Discover more from naiwaen@DebuggingSoft
Subscribe to get the latest posts sent to your email.