Integrasi python dari Gitlab, Jira dan Confluence untuk mengotomatiskan rilis build

Baru-baru ini, di stand-up, seorang kolega membuat proposal yang rasional : untuk mengotomatiskan build rilis, mengambil sebagai dasar perkembangan interaksi dengan Jira yang ditulis dalam Python.

Proses penyebaran adalah sebagai berikut: ketika sejumlah tugas yang telah diuji menumpuk, mereka melepaskan kandidat kandidat (RC) di setiap proyek yang dipengaruhi oleh tugas-tugas tersebut, maka tugas-tugas tersebut diuji sebagai bagian dari RC. Setelah itu, RC dituangkan ke server pementasan, di mana, di dekat lingkungan tempur, masih diuji dan regresi penuh dilakukan. Dan kemudian, setelah tindakan penyebaran yang diperlukan, rilis baru dituangkan ke master.

Sampai saat ini, seluruh proses perakitan dilakukan secara manual oleh salah satu pengembang. Yang memakan waktu satu jam, dua atau lebih waktu dan, menurut saya, bukan pekerjaan yang sangat menarik. Sekarang, ketika hampir semuanya sudah siap, pelepasan 20 tugas, mempengaruhi 5 proyek, akan kurang dari satu menit. Masih ada, tentu saja, resolusi konflik, menjalankan tes yang terlewatkan, dan banyak lagi, tetapi bahkan dengan mempertimbangkan ini, waktu pengembang dan penguji, yang harus menunggu sampai seseorang yang pertama membebaskan diri mereka dan membuat RC, diselamatkan banyak.

Secara umum, saya mulai mengerjakan tugas, dan ternyata sangat menarik dan mempesona. Dan apa lagi yang diperlukan untuk kesenangan bekerja, jika bukan proyek yang mengasyikkan?

Saya mempelajari warisan: ternyata menggunakan API Jira secara langsung, dan itu ditulis, menurut saya, tidak optimal. Sebagai contoh, daftar tugas rilis diperoleh sebagai berikut: semua rilis yang ada diunduh dari Jira, dan kemudian masing-masing dengan nama dibandingkan dengan nama rilis kami sampai yang diinginkan ditemukan:

def get_release_info(config):

   try:

       release_input = sys.argv[1]

   except IndexError:

       raise Exception('Enter release name')

   releases_json = requests.get(url=RELEASES_LIST_URL, auth=(login, jira_password).json()

   for release in releases_json:

       if release['name'] == release_input:

                ...


Secara umum, interaksi langsung dengan API menyebabkan kode tidak terlalu mudah dibaca. Dan saya tidak ingin menciptakan sepeda. Pencarian pertama saya di Github membawa saya ke Perpustakaan Python JIRA, sebuah perpustakaan yang cukup sederhana dan kuat. Awalnya saya berencana untuk membuat Marge Requests menggunakan perpustakaan GitPython, juga ditemukan di Github. Tetapi studi lebih lanjut tentang masalah ini langsung mengarah pada gagasan untuk menemukan sesuatu yang terkait bukan dengan git, melainkan langsung ke Gitlab. Akibatnya, saya memilih solusi yang paling terkenal: Python GitLab.

Saya mulai dengan mendapatkan daftar tugas dalam status yang sesuai untuk rilis . Saya memutuskan untuk tidak mengubah solusi sebelumnya, tetapi untuk membuatnya lebih efektif dengan segera meminta API tugas rilis yang diinginkan:

fix_issues = jira.search_issues(f'fixVersion={release_input}')

fix_id = jira.issue(fix_issues.iterable[0]).fields.fixVersions[0].id

Meskipun kemungkinan besar hal yang sama terjadi di bawah tenda, namun ternyata lebih indah dan optimal, tetapi masih belum terlalu mudah dibaca. Selanjutnya, dari tugas yang diterima, perlu untuk mengumpulkan tautan untuk menggabungkan permintaan. Saya memutuskan untuk menyimpan permintaan gabungan yang ditemukan di namedtuple, mereka sangat bagus untuk ini:

Merge_request = namedtuple('Merge_request', ['url', 'iid', 'project', 'issue'])

Permintaan gabungan juga diterima menggunakan Jira API:

projects = set()

links_json = requests.get(url=REMOTE_LINK.format(issue_number),

                            auth=login,jira_password).json()

for link in links_json:

   url_parts = link['object']['url'].split('/')

   project = f'{url_parts[4]}'

   iid = url_parts[6]

   projects.add(project)   

Setelah itu, saya memutuskan di mana saya bisa menggunakan perpustakaan yang ditemukan . Maka, mungkin, saya akan memperbaiki potongan-potongan ini.

Selanjutnya, Anda perlu memeriksa, tiba-tiba cabang RC yang tepat sudah ada, jika sudah ada upaya untuk membangun, maka mereka perlu dihapus dan yang baru dibuat. Saya sudah melakukan ini menggunakan perpustakaan Python GitLab:

gl = gitlab.Gitlab('https://gitlab...ru/', private_token=GITLAB_PRIVATE_TOKEN)

pr = gl.projects.get(project)

try:

   rc = pr.branches.get(f'{RC_name}')

   rc.delete()

   pr.branches.create({'branch': f'{RC_name}', 'ref': 'master'})

except gitlab.GitlabError:

   pr.branches.create({'branch': f'{RC_name}', 'ref': 'master'})

Setelah itu, Anda bisa mulai mengisi tabel dalam tugas perakitan Jira . Informasi dalam tabel terdapat dalam kolom berikut: Tidak., Tugas, Prioritas, Permintaan gabungan dari tugas di RC, Status permintaan gabungan (apakah tes lulus dalam Gitlab, apakah ada konflik atau tidak, dituangkan / tidak dituangkan).

Pada langkah ini, saya menemukan cacat Gitlab yang tidak menyenangkan: jika perubahan sebelumnya dibekukan di cabang tujuan permintaan penggabungan, maka API Gitlab, ketika meminta status permintaan penggabungan, memberikan jawaban tentang keberadaan konflik. Pada prinsipnya, ini dapat dipahami: jika tidak ada yang menuangkan, maka itu tidak akan berhasil, tetapi mengapa mengatakan bahwa ada konflik di tempat ini? Forum Gitlab telah meminta orang selama beberapa tahun, tetapi belum ada jawaban.

Dalam kasus saya, ini mengarah ke status konflik palsu dan secara manual memeriksa permintaan penggabungan. Saya belum menemukan apa pun.

Logika saat membuat permintaan menggabungkan adalah sebagai berikut: jika tes tidak lulus, atau ada konflik, permintaan menggabungkan dibuat, tetapi mereka tidak mengalir ke RC, status yang sesuai dimasukkan ke dalam tabel.

Untuk memeriksa pelaksanaan tes, kami mencari daftar pipa yang sesuai. Gitlab memancarkannya diurutkan berdasarkan tanggal dalam urutan menurun, seperti yang kita butuhkan. Kami mengambil yang pertama - itu akan menjadi yang dibutuhkan:

pipelines = project.pipelines.list(ref=f'{issue}')

if pipelines:

   pipelines = pipelines[0]

   if pipelines.attributes['status'] != 'success':

       status = '(x)   !, '

Kemudian buat permintaan gabungan sendiri . Kami memeriksa yang terbuka, kalau-kalau ini bukan upaya pertama untuk membangun. Dengan tidak adanya permintaan gabungan yang diperlukan, buat ini:

mr = project.mergerequests.list(

 state='opened',

source_branch=source_branch,         target_branch=target_branch)

if mr:

   mr = mr[0]

else:

   mr = project.mergerequests.create(

{'source_branch': source_branch,

           'target_branch': target_branch,

           'title': f"{(MR.issue).replace('-', '_')} -> {RC_name}",

           'target_project_id': PROJECTS_NAMES[MR.project],})

status = mr.attributes['merge_status']

url = mr.attributes['web_url']

return status, url, mr

MR.issue.replace ('-', '_') - ubah nama tugas untuk menghilangkan komentar tidak informatif Gitlaba tentang tugas di Jira.

Selanjutnya, kami melihat status permintaan gabungan yang diterima : jika tidak ada konflik, kami tuangkan ke dalam RC. Jika ada konflik, letakkan status yang sesuai dan biarkan untuk verifikasi manual.

Selanjutnya, dengan analogi, kami membuat permintaan gabungan dari RC ke Staging dan dari Staging ke Master untuk semua proyek. Mereka akan dituangkan setelah memeriksa seluruh rilis rilis di cabang RC.

Dua bidang ditambahkan ke templat tugas Jira: untuk tindakan pra-pra-pasca dan pasca-pasca. Untuk semua tugas yang terlibat, algoritme mengumpulkan daftar tindakan tersebut dan memasuki tugas perakitan agar tidak melupakan apa pun.

Dan akhirnya, hasil dalam Jira adalah penciptaan tugas perakitan :

existing_issue = jira.search_issues(

f'project=PROJ AND summary ~ " {release_name}"')

if existing_issue:

   existing_issue = existing_issue[0]

   existing_issue.update(fields={

       'description': message,

       'customfield_xxx': message_before_deploy,

       'customfield_yyy': message_post_deploy,})

else:

   issue_dict = {

       "fixVersions": [{"name": release_name,}],

       'project': {'key': 'PROJ'},

       'summary': f" {release_name}",

       'description': message,

       'issuetype': {'name': 'RC'},  #      

       'customfield_xxx': message_before_deploy,

       'customfield_yyy': message_post_deploy,}

   new_issue = jira.create_issue(fields=issue_dict)

Pikiran lebih lanjut adalah sebagai berikut : menjalankan skrip di Gitlab dengan kait web dari Jira. Misalnya, Anda bisa membuat webhook untuk membuat tugas perakitan (membuat jenis tugas khusus untuk itu), atau membuat tugas dengan kata "Majelis" dalam judul. Dan Gitlab untuk hook ini akan menjalankan skrip bash yang memulai seluruh proses, atau menaikkan gambar Docker dengan Python dan menjalankan skrip di atasnya. Meskipun opsi kedua sudah terlalu rumit. Ya, dan perlu akun teknis di Jira dan Gitlab. Secara umum, belum ada keputusan akhir.

Setelah membuat cabang RC, Anda juga dapat menggunakan bangku tes di cabang yang diperlukan dan menjalankan tes regresi. Jenkins dapat menangani ini. Tetapi ini juga dalam rencana untuk saat ini.

Ini semua demi mempercepat pekerjaan penguji dan membebaskan pengembang dari pekerjaan rutin. Namun, pengertian ekonomi di sini juga cukup spesifik: ambil pengembang rata-rata (dalam ruang hampa) dengan gaji hipotetis 150.000 rubel selama 8 jam waktu kerja per hari. Selama dua tahun, kami memiliki sekitar 700 rilis - ini adalah tentang rilis per hari. Beberapa lebih, beberapa kurang, tetapi rata-rata, saya pikir, setidaknya satu jam waktu pengembang untuk membangun rilis sudah hilang. Artinya, otomatisasi proses ini menghemat perusahaan minimal 150.000 / 8 = 18.750 rubel per bulan.

Sepanjang jalan, saya membuat skrip terpisah untuk diri saya sendiri, menunjukkan statistik pada rilis mendatang: berapa banyak tugas, proyek apa yang terpengaruh, dll. Karena jika saya tidak memiliki status Pengembang di salah satu proyek di Gitlab, akan ada penolakan akses ketika membuat permintaan penggabungan. Juga, lebih mudah untuk mengetahui terlebih dahulu tentang tindakan penyebaran atau untuk menangkap tugas yang masuk ke dalam rilis ini karena kesalahan. Distribusi pemberitahuan rilis diselesaikan menggunakan modul SMTP dan email.

Saya senang dengan solusi untuk masalah ini: selalu menarik untuk mempelajari sesuatu yang baru dan mempraktikkannya. Akan menyenangkan jika pengalaman ini bermanfaat bagi seseorang.

All Articles