ลองใช้ GitLab REST API

ตอนนี้มีโจทย์ให้คิดครับ เพราะเท่าที่ย้ายมาใช้ 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)

  1. เข้ามาที่ User Setting
  2. เลือก Access Token
  3. ตั้งชื่อ Token
  4. กำหนดวันหมดอายุของ Token เช่น ถ้าเราเอาให้คนนอกใช้ ต้องมีการกำหนดส่วนนี้
  5. กำหนด 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 มาช่วยไหม ?

มีทางเชื่อมต่อได้เยอะเหมือนกันครับ ต่อไป ถ้าว่างๆ ผมมาเล่นตัว GraphQL API ต่อครับ

Reference


Discover more from naiwaen@DebuggingSoft

Subscribe to get the latest posts to your email.