Memanfaatkan API GitHub untuk mengubah pengaturan branch repo


Dalam sebuah proyek di GitHub, ada kalanya kita harus mengubah pengaturan repo di branch tertentu. Kalau hanya satu-dua repo sih mungkin tidak ada masalah, tapi ketika harus mengubah pengaturan ratusan repo, kepala puyeng juga. Untunglah GitHub memiliki API yang cukup lengkap.

Jadi ceritanya, kami kembali mendapatkan tugas untuk mengubah pengaturan branch Tambora di seluruh paket Blankon di GitHub. Total ada 304 repo yang harus diubah pengaturannya, terutama di bagian Branch protection. Sebagai pemalas, tentu saja membuka ratusan repo cukup melelahkan, sehingga harus dicari jalan termudah untuk menyelesaikan task ini. Setelah mengubek dokumentasi API GitHub, ternyata ada cara yang lebih mudah.

Oh iya, spoiler alert, tulisan di blog ini hanya sekadar catatan saja supaya saya tidak lupa, kalau-kalau di kemudian hari harus kembali mengurus ratusan repo GitHub (syukur-syukur API-nya belum berubah). Begini caranya.

Dari hasil ubek-ubek laman dokumentasi API GitHub, untuk mengecek pengaturan proteksi branch ada di bagian ini.

GET /repos/:owner/:repo/branches/:branch/protection

Artinya, untuk melihat pengaturan repo gnome-software di branch Tambora, jadinya seperti ini:

https://api.github.com/repos/blankon-packages/gnome-software/branches/tambora/protection

Tapi sayang beribu sayang, hasilnya tidak memuaskan, karena dari percobaan di Postman, didapat keluaran begini:

{
    "message": "Not Found",
    "documentation_url": "https://developer.github.com/v3/repos/branches/#get-branch-protection"
}

Dari hasil ubek-ubek lagi, ternyata ada masalah di perizinan. Jadi tidak sembarang orang yang dapat mengakses laman tersebut. Hanya orang-orang terpilihlah yang dapat mengakses laman tersebut. Untuk itu diperlukan kode akses agar laman tersebut dapat dibuka. Di sini, kita gunakan token. Karena itu, buat dulu tokennya jika belum ada dengan mengakses laman ini dan buat token baru dengan mengeklik tombol Generate new token.

generate new token
generate new token

Jika sudah, menggunakan Postman, kita coba lagi mengakses laman pengaturan repo gnome-software di atas menggunakan auth tipe Basic (menggunakan username dari akun GitHub kita dan password berupa token yang dikasih GitHub):

akses API lewat postman
akses API lewat postman

Dari gambar di atas bisa dilihat bahwa kita sukses mengakses pengaturan branch protection (ada status code 200 OK). Langkah selanjutnya adalah bagaimana kita mengubah pengaturannya, menggunakan metode PUT. Sesuai contoh di sini, kita tinggal membuat data berbentuk json yang isinya parameter apa saja yang akan diatur. Contohnya seperti di bawah:

{
  "required_status_checks": null,
  "enforce_admins": false,
  "required_pull_request_reviews": {
    "dismissal_restrictions": {
      "users": [
        "namausernya"
      ],
      "teams": []
    },
    "dismiss_stale_reviews": false,
    "require_code_owner_reviews": false
  },
  "restrictions": {
    "users": [
      "namausernya"
    ],
    "teams": []
  }
}

Oh iya, sebelumnya saya membuat skrip python yang menyimpan daftar repo dan disimpan dalam berkas berbentuk csv (tadinya mau diunggah ke Google Drive namun tidak jadi). Data itu saya simpan di berkas hasil.csv dan hasil2.csv. Skripnya kurang lebih seperti ini:

# skrip untuk mendapatkan daftar seluruh repo
def list_repos(page):
    url = "https://api.github.com/orgs/blankon-packages/repos"
    querystring = {"page":"{}".format(page)}
    headers = {
        'cache-control': "no-cache",
        'User-Agent':"Mozilla/5.0"
    }
    response = requests.request("GET", url, headers=headers, params=querystring)
    data = response.json()
    print(len(data))
    output = []
    for i in range(0, len(data)):
        satu = data[i]
        d = "{}, {}, {}/settings/branches/tambora".format(satu['name'], satu['html_url'], satu['html_url'])
        output.append(d)
    writeFile(output, "hasil.csv")

# buat file baru yang isinya cuma menyisipkan kolom alamat restriction (harusnya di fungsi atas juga bisa)
def getRestriction():

    namafile = "output/hasil.csv"
    frmt = "https://api.github.com/repos/blankon-packages/"
    brnch = "/branches/tambora/protection"

    with open(namafile) as f:
        out = csv.reader(f, delimiter=",")
        hasil = []
        for row in out:
            pr = "{}{}{}".format(frmt, row[0], brnch)
            o = "'{}','{}','{}','{}'".format(row[0], row[1].strip(), row[2].strip(), pr)
            hasil.append(o)
            print(o)
        writeFile(hasil, "hasil2.sv")

# simpan file csv
def writeFile(data, nama):
    jml = len(data)
    namafile = "output/{}".format(nama)

    with open(namafile, "a") as f:
        for i in range(0, jml):
            f.write("{}\n".format(data[i]))

Dari berkas hasil2.csv kita olah lagi dengan mengakses kolom terakhir untuk mendapatkan url API restriction. Di sini kita gunakan token yang didapat dari GitHub tadi, dan diolah untuk kemudian disisipkan di bagian header. Karena GitHub menggunakan sistem auth basic, maka username GitHub dan token itu diubah bentuknya menjadi format Authorization Basic tokenHasilolahandariTokenGitHub. Cara encode tokennya bisa dibaca di sini. Tapi saya sih tak mau repot, jadi cukup contek hasil encode dari postman :D. Nanti headernya jadi begini:

h = {
        'content-type': "application/json",
        'authorization': "Basic tokenHasilolahandariTokenGitHub",
        'cache-control': "no-cache"
    }

Lalu di mana si data parameter disimpan? Kita buat variabel baru bernama payload, bentuknya kira-kira begini (lagi-lagi ini hasil contekan dari postman. terpujilah wahai pembuat postman):

payload = "{\n  \"required_status_checks\": null,\n  \"enforce_admins\": false,\n  \"required_pull_request_reviews\": {\n    \"dismissal_restrictions\": {\n      \"users\": [\n        \"namausernya\"\n      ],\n      \"teams\": []\n    },\n    \"dismiss_stale_reviews\": false,\n    \"require_code_owner_reviews\": false\n  },\n  \"restrictions\":{\n      \"users\": [\n        \"namausernya\"\n      ],\n      \"teams\": []\n    }\n}"

Skrip lengkapnya kira-kira begini:

def cekProtection():
    namafile = "output/hasil2.csv"
    with open(namafile) as f:
        out = csv.reader(f, delimiter=",", quotechar="'")
        headers = {
            'authorization': "Basic tokenHasilolahandariTokenGitHub",
            'cache-control': "no-cache"
        }

        i = 0
        for row in out:
            i+= 1
            print("{} {}\n".format(i, row[3]))
            r = requests.get(row[3], headers=headers)
            status = r.status_code
            print(status)
            stat_output = False
            if status == 404:
                print('belum diprotek')
                stat_output = updateBranch(row[3])
                file_log = "output/log2.txt"
                writeHasil(file_log, row, stat_output)
            else:
                print("sudah diprotek")

def updateBranch(url):
    h = {
        'content-type': "application/json",
        'authorization': "Basic tokenHasilolahandariTokenGitHub",
        'cache-control': "no-cache"
    }
    payload = "{\n  \"required_status_checks\": null,\n  \"enforce_admins\": false,\n  \"required_pull_request_reviews\": {\n    \"dismissal_restrictions\": {\n      \"users\": [\n        \"namausernya\"\n      ],\n      \"teams\": []\n    },\n    \"dismiss_stale_reviews\": false,\n    \"require_code_owner_reviews\": false\n  },\n  \"restrictions\":{\n      \"users\": [\n        \"namausernya\"\n      ],\n      \"teams\": []\n    }\n}"
    r = requests.put(url, data=payload, headers=h)
    status = r.status_code
    if status == 200:
        print("Berhasil\n")
        return True
    else:
        print("gagal\n")
        return False
    return False

def writeHasil(namafile, data, isHasil):
    with open(namafile, "a") as f:
        f.write("{}, {}\n".format(data[0], isHasil))

if __name__ == '__main__':
    cekProtection()

Simpanlah 3 fungsi terakhir, misalnya di berkas app.py, lalu jalankan di terminal:

$ python app.py

Tunggulah sebentar atau dua bentar (tergantung koneksi internet), lalu sambil ngopi kita bisa melihat API bekerja*)

*) mencontek mentah-mentah dari judul buku Aan Mansyur berjudul Melihat Api Bekerja


Ada komentar?

This site uses Akismet to reduce spam. Learn how your comment data is processed.