Jika Anda memasukkan "Jira Badoo" di string pencarian di Habré, hasilnya akan membutuhkan lebih dari satu halaman: kami menyebutkannya hampir di mana-mana, karena itu memainkan peran penting dalam proses kami. Dan kita masing-masing ingin sedikit berbeda darinya.

Pengembang, yang menerima tugas untuk tinjauan, mengharapkan bahwa cabang diindikasikan dalam tugas, ada tautan ke diff dan log perubahan. Pengembang yang menulis kode mengharapkan untuk melihat komentar di Jira setelah ulasan. Penguji, yang menerima tugas setelah mereka, ingin melihat hasil tes dan dapat menjalankan rakitan yang diperlukan tanpa pergi ke antarmuka lain. Manajer produk umumnya ingin membuat sepuluh tugas pengembangan secara bersamaan dengan menekan satu tombol.
Dan semua ini tersedia hari ini dan terjadi secara otomatis. Kami menerapkan sebagian besar keajaiban dalam PHP menggunakan Jira API yang terus berkembang dan menggunakan
webhook -
nya . Dan hari ini kami ingin berbagi dengan komunitas versi klien kami untuk API ini.
Pada awalnya, kami hanya ingin berbicara tentang ide-ide dan pendekatan yang kami gunakan, dan kemudian memutuskan bahwa tidak ada cukup kode untuk artikel seperti itu untuk kejelasan. Jadi ada versi open-source
Klien Badoo Jira PHP . Terima kasih banyak kepada
ShaggyRatte karena membantu deskripsinya. Dan selamat datang di kat!
Apa yang bisa dia lakukan?
Faktanya, Badoo Jira PHP Client adalah sekumpulan kelas wrapper siap pakai untuk respons Jira API, yang sebagian besar dapat berperilaku seperti ActiveRecord: mereka tahu cara mendapatkan data tentang diri mereka sendiri dan cara memperbaruinya di server, mendukung inisialisasi malas dan caching data di tingkat kode. Semua entitas Jira yang harus Anda kerjakan selalu dibungkus:
Masalah, Status, Prioritas, Changelog, Pengguna, Versi, Komponen , dll. (Hampir semua yang Anda lihat di antarmuka).
Selain itu, Badoo Jira PHP Client menyediakan hierarki kelas tunggal untuk semua bidang khusus Jira dan mampu menghasilkan definisi kelas untuk setiap bidang khusus yang Anda butuhkan.
$Issue = new \Badoo\Jira\Issue('SMPL-1'); $Issue->addComment('Sample comment text'); $Issue->attachFile('kitten.jpeg', 'pretty!', 'image/jpeg'); if ($Issue->getStatus()->getName() === 'Open') { $Issue->step('In Progress'); }
$DeveloperField = new \Example\CustomFields\Developer($Issue); $DeveloperField->setValue('username')->save();
$User = \Badoo\Jira\User::get('username'); $User->watchIssue('SMPL-1'); $User->assign('SMPL-2');
Berkat ini, interaksi dengan API dari PHP menjadi lebih mudah dan nyaman, dan dokumentasi untuk Jira Anda langsung berpindah ke kode, yang memungkinkan Anda menggunakan pelengkapan otomatis dalam IDE untuk banyak tindakan standar.
Tetapi hal pertama yang pertama.
Fitur API yang kami temui
Ketika kami mulai aktif menggunakan Jira API, itu hanya tersedia melalui protokol SOAP. Versi REST-nya muncul kemudian, dan kami termasuk pengguna pertama. Pada saat itu, ada sangat sedikit klien REST yang tersedia untuk umum yang ditulis dalam PHP. Bahkan lebih sulit untuk menemukan sesuatu yang dapat dengan mudah diintegrasikan ke dalam basis kode kami, secara bertahap berpindah dari SOAP ke REST. Jadi kami tidak punya pilihan: kami memutuskan untuk terus mengembangkan klien kami sendiri.
Jadi kami hidup dengan menyeret dan menjatuhkan semua jenis retas dan kruk dari klien SOAP dan memperoleh yang baru karena kekhasan REST. Sebagai hasilnya, kami telah mengembangkan beberapa kelas yang sangat berani dengan banyak kode duplikat, dan ada kebutuhan untuk menghapus kekacauan ini.
Bidang kebiasaan selalu menjadi tempat paling menyakitkan bagi kami: kami memiliki lebih dari 300 bidang (saat penulisan artikel ini - 338), dan jumlah ini perlahan-lahan bertambah.
Pesan kesalahan aneh
Selama sejarah panjang berinteraksi dengan API, kami telah melihat banyak hal berbeda. Sebagian besar pesan kesalahan sudah memadai, tetapi ada beberapa yang harus Anda susahkan.
Misalnya, jika Jira tiba-tiba mengenali robot di pengguna Anda, dia akan mulai menunjukkan padanya captcha. Dalam hal ini, saat mengakses API, tanpa malu-malu mengabaikan header
Accept-Encoding: application / json dan memberi Anda HTML. Biasanya, klien yang menunggu JSON mungkin tidak siap untuk "halo" ini.
Dan berikut ini adalah contoh bekerja dengan bidang khusus:

Saat Anda menulis kode dan "tes sekarang" Anda mengujinya, sangat mudah untuk memahami bahwa customfield_12664 adalah
Pengembang . Dan jika kesalahan seperti itu merayap keluar di suatu tempat di produksi (misalnya, karena seseorang mengubah konfigurasi dan mengubah daftar nilai yang dapat diterima untuk bidang Select), seringkali satu-satunya cara untuk mengidentifikasi bidang adalah dengan masuk ke Jira dan mencari tahu nama dari sana. Selain itu, dalam antarmuka, ID tidak ditampilkan - hanya nama.
Ternyata ketika Anda ingin mengetahui nama bidang yang menyebabkan kesalahan dan memperbaiki konfigurasinya, Anda dapat melakukan ini baik melalui permintaan ke API, atau menggunakan beberapa metode tidak jelas lainnya: mengobrak-abrik kode sumber halaman, membuka pengaturan untuk bidang arbitrer dan mengoreksi URL di bilah alamat, dll. Proses ini tidak dapat disebut nyaman, dan setiap kali terlalu banyak waktu untuk tugas yang begitu sederhana.
Tetapi nama-nama bidang yang tidak jelas tidak terbatas pada masalah. Seperti inilah interaksi dengan API jika Anda membuat kesalahan dalam struktur data untuk memperbarui bidang:


Banyak format data yang berbeda
Dan jangan lupa bahwa memperbarui bidang dari berbagai jenis memerlukan struktur data yang berbeda.
$Jira->issue()->edit( 'SMPL-1', [ 'customfield_10200' => ['name' => 'denkoren'], 'customfield_10300' => ['value' => 'PHP'], 'customfield_10400' => [['value' => 'Android'], ['value' => 'iOS']], 'security' => ['id' => 100500], 'description' => 'Just text', ], );
Jawaban API untuk mereka tentu saja juga berbeda.
Adalah mungkin untuk mengingat ini hanya jika Anda terus-menerus bekerja dengan Jira API dan tidak terganggu untuk waktu yang lama dengan memecahkan masalah lain. Jika tidak, fitur-fitur ini akan kehabisan memori dalam beberapa minggu. Selain itu, Anda perlu mengingat jenis bidang yang Anda butuhkan untuk “memberi makan” dengan struktur yang benar. Ketika Anda memiliki ratusan bidang khusus, Anda sering harus mencari kode tempat masih digunakan, atau naik ke panel admin Jira.
Sebelum kami menulis klien kami, Stack Overflow dan Komunitas Atlassian adalah teman terbaik saya tentang memperbarui bidang khusus. Sekarang informasi ini di-google-kan dengan mudah dan cepat, tetapi kami beralih ke REST API ketika masih cukup baru dan dikembangkan secara aktif: butuh sepuluh menit untuk menemukan permintaan CURL yang sesuai di Google, dan kemudian Anda harus mengurai kurung dengan mata Anda dan mengonversi ke dalam struktur yang benar untuk PHP, yang sering tidak berfungsi pada percobaan pertama.
Secara umum, interaksi dengan bidang khusus adalah proses yang reorganisasi diperlukan sejak awal.
Terdiri dari apa klien?
Kelas untuk bekerja dengan bidang khusus
Pertama-tama, kami ingin menyingkirkan mengingat struktur data untuk berinteraksi dengan API dan mendapatkan nama bidang yang dapat dibaca saat terjadi kesalahan.
Akibatnya, kami membuat hierarki kelas tunggal untuk semua bidang khusus. Ternyata tiga lapisan:
- Orang tua abstrak yang umum untuk semua orang: \ Badoo \ Jira \ CustomFields \ CustomField .
- Oleh kelas abstrak untuk setiap jenis bidang: SelectField, UserField, TextField , dll.
- Berdasarkan kelas untuk setiap bidang spesifik: misalnya, Pengembang atau Peninjau .
Kelas-kelas ini dapat ditulis secara independen, atau dapat dibuat secara otomatis menggunakan skrip-generator khusus (kami akan kembali ke sana).

Berkat struktur ini, untuk mengajarkan kode untuk memperbarui nilai bidang kustom Anda dari tipe
Select List (pilihan ganda) , cukup membuat kelas PHP yang diwarisi dari
SelectField . Bahkan, setiap bidang Jira kustom berubah menjadi ActiveRecord biasa dalam kode PHP.
namespace \Example\CustomFields; class Developer extends \Badoo\Jira\CustomFields\SingleUserField { const ID = 'customfield_10200'; const NAME = 'Developer'; }
Di kelas yang sama, kami menyimpan informasi tentang bidang: secara default, ini adalah ID, nama bidang, dan daftar nilai yang tersedia, jika terbatas (misalnya, untuk
Kotak Centang dan
Pilih ).
Contoh bidang di antarmuka Jira dan kelas yang terkait
class IssueFor extends \Badoo\Jira\CustomFields\SingleSelectField { const ID = 'customfield_10662'; const NAME = 'Issue for'; const VALUE_BI = 'BI'; const VALUE_C_C = 'C\C++'; const VALUE_HTML_CSS = 'HTML\CSS'; const VALUE_JS = 'JS'; const VALUE_OTHER = 'Other'; const VALUE_PHP = 'PHP'; const VALUE_TRANSLATION = 'Translation'; const VALUES = [ self::VALUE_BI, self::VALUE_C_C, self::VALUE_HTML_CSS, self::VALUE_JS, self::VALUE_OTHER, self::VALUE_PHP, self::VALUE_TRANSLATION, ]; public function getItemsList() : array { return static::VALUES; } }
Ternyata jenis dokumentasi itu untuk Jira Anda, yang terletak langsung di kode PHP. Ketika sangat dekat, sangat nyaman dan secara signifikan mempercepat pengembangan, sekaligus mengurangi jumlah kesalahan.
Selain itu, pesan kesalahan menjadi lebih jelas: alih-alih tidak mengatakan apa pun,
'customfield_12664' macet, misalnya, sesuatu seperti ini:
Uncaught Badoo\Jira\Exception\CustomField: User 'asdkljfh' not found in Jira. Can't change 'Developer' field value.
Kelas untuk bekerja dengan objek sistem
Jira memiliki banyak data dengan struktur yang kompleks: misalnya, bidang
Status dan Sistem
Keamanan , tautan antara tugas, pengguna, versi, lampiran (file).
Kami juga membungkus mereka dalam kelas:
Pembungkus seperti itu memberi IDE Anda kemampuan untuk mengetahui data mana yang tersedia dan memungkinkan Anda untuk memformalkan antarmuka fungsi dalam kode Anda secara ketat. Kami secara aktif menggunakan deklarasi tipe, hampir selalu memungkinkan kami melihat kesalahan bahkan ketika menulis kode berkat penyorotan IDE. Dan jika Anda masih melewatkan kesalahan, itu akan keluar tepat di tempat pertama kali muncul, dan bukan di mana Anda akhirnya menjatuhkan kode Anda.
Masih ada metode statis yang memungkinkan Anda mendapatkan objek dengan cepat dengan beberapa kriteria:
$users = \Badoo\Jira\User::search('<pattern>');
Metode ini mematuhi aturan umum sehingga mudah ditemukan:
- :: search () , jika Anda perlu menemukan objek berdasarkan beberapa bidang: \ Badoo \ Jira \ Issue :: search () mencari tugas menggunakan JQL, di mana Anda dapat menentukan banyak kriteria pencarian, dan \ Badoo \ Jira \ User :: search () mencari pengguna secara bersamaan dengan 'name' (login), 'email' dan 'displayName' (nama yang dirender di web);
- :: by * () , jika Anda perlu mendapatkan objek bukan dengan ID, tetapi dengan kriteria lain: \ Badoo \ Jira \ User :: byEmail () mencari pengguna dengan alamat emailnya;
- :: for * () mencari semua objek yang terkait dengan sesuatu: \ Badoo \ Jira \ Version :: forProject
memberikan semua versi dari proyek tertentu; - :: fromStdClass () akan membuat objek dari data mentah yang memiliki struktur yang sesuai, tetapi tidak diterima dari API, tetapi, misalnya, dari webhook : di badan permintaan POST, Jira mengirim JSON dengan informasi berbeda tentang acara tersebut, termasuk badan tugas termasuk semua bidang. Berdasarkan data ini, Anda dapat membuat objek \ Badoo \ Jira \ Issue dan menggunakannya seperti biasa.
Masalah Kelas \ Badoo \ Jira \
Menurut saya, tangkapan layar PhpStorm berikut ini cukup fasih:

Pada dasarnya, objek
\ Badoo \ Jira \ Issue mengikat semua yang dijelaskan di atas ke dalam satu sistem. Ia menyimpan semua informasi tentang tugas itu, ia memiliki metode untuk akses cepat ke data yang paling sering digunakan, tugas transfer antar status, dll.
Untuk membuat objek dalam kasus yang paling sederhana, cukup mengetahui kunci tugas saja.
Buat objek hanya dengan kunci tugas di saku Anda $Issue = new \Badoo\Jira\Issue('SMPL-1');
Anda juga dapat menggunakan dataset yang terfragmentasi. Misalnya, informasi tautan antara tugas-tugas yang tiba dari API hanya berisi beberapa bidang: id, ringkasan, status, prioritas, dan issuetype.
\ Badoo \ Jira \ Issue memungkinkan Anda mengumpulkan objek dari data ini sehingga dapat segera dikembalikan, dan sisanya, mengakses API.
Buat objek, nilai caching untuk beberapa bidang $IssueFromLink = \Badoo\Jira\Issue::fromStdClass( $LinkInfo, [ 'id', 'key', 'summary', 'status', 'priority', 'issuetype', ] );
Ini dicapai melalui inisialisasi malas dan caching data dalam kode. Pendekatan ini sangat nyaman karena Anda hanya dapat menukar objek
\ Badoo \ Jira \ Issue dalam kode Anda, terlepas dari kumpulan bidang mana mereka dibuat.
Dapatkan data tugas yang hilang $IssueFromLink->getSummary();
Bagaimana kita menuju ke APIDi Jira API, dimungkinkan untuk mendapatkan tidak semua bidang untuk tugas, tetapi hanya bidang yang saat ini diperlukan: misalnya, hanya kunci dan ringkasan. Namun, kami sengaja tidak pergi ke Jira hanya untuk satu bidang di pengambil. Pada contoh di atas, getDescription () akan memperbarui informasi tentang semua bidang sekaligus. Karena
\ Badoo \ Jira \ Issue tidak memiliki gagasan sedikit pun tentang apa lagi yang Anda butuhkan selanjutnya, lebih menguntungkan untuk mendapatkan semuanya dari API segera, karena kami tetap pergi ke sana. Ya, kueri "dapatkan hanya deskripsi" dan kueri "dapatkan semua bidang secara default" untuk beberapa ratus tiket membutuhkan waktu yang berbeda, tetapi untuk satu perbedaan ini tidak begitu terlihat.
//Time for single field: 0.40271635055542 (second) //Time for all default fields: 0.84159119129181 (second)
Dari angka-angka itu jelas bahwa ketika menerima hanya tiga bidang (satu dalam permintaan), lebih menguntungkan untuk mendapatkan semuanya sekaligus, daripada pergi ke API untuk masing-masing. Hasil pengukuran ini, pada kenyataannya, tergantung pada konfigurasi Jira dan server yang digunakannya. Dari tugas ke tugas dan dari pengukuran ke pengukuran, angka-angka berubah dan
Waktu untuk semua bidang standar ternyata secara stabil kurang dari tiga
Waktu untuk bidang tunggal , dan seringkali bahkan kurang dari dua.
Namun, ketika bekerja dengan sejumlah besar tugas, perbedaannya dapat diukur dalam hitungan detik. Karenanya, ketika Anda tahu bahwa Anda hanya perlu kunci dan deskripsi untuk 500 tiket, kemampuan untuk mendapatkannya dengan satu permintaan efektif tetap ada di metode
\ Badoo \ Jira \ Issue :: search () dan
\ Badoo \ Jira \ Issue :: byKeys () .
\ Badoo \ Jira \ Issue - umumnya tentang tugas di beberapa Jira abstrak. Tetapi Jira Anda (seperti milik kami) tidak abstrak - ia memiliki serangkaian bidang khusus yang sangat spesifik dan alur kerjanya sendiri. Anda sering menggunakan beberapa bidang dan transisi, jadi tidak nyaman untuk mengikutinya dari jauh. Oleh karena itu,
\ Badoo \ Jira \ Issue dapat dengan mudah diperluas dengan metode sendiri khusus untuk konfigurasi Jira tertentu.
Contoh ekstensi kelas dengan metode untuk mendapatkan bidang kustom dengan cepat namespace \Deploy; class Issue extends \Badoo\Jira\Issue {
Masalah buat permintaan
Membuat tugas di Jira adalah prosedur yang agak rumit. Ketika Anda melakukan ini melalui antarmuka web, Anda akan diperlihatkan layar khusus (Buat Layar) dengan seperangkat bidang. Beberapa dari mereka dapat Anda isi hanya karena Anda inginkan, dan beberapa ditandai sebagai wajib. Pada saat yang sama, Buat Layar dapat menjadi unik untuk setiap proyek dan bahkan untuk berbagai jenis tugas dalam satu proyek. Jadi ada semua jenis pembatasan pada nilai-nilai bidang dan pada sangat mungkin untuk menetapkan nilai bidang dalam proses pembuatan tugas.
Hal yang paling tidak menyenangkan bagi pengembang dalam situasi ini adalah pembatasan ini berlaku untuk API. Yang terakhir memiliki permintaan khusus (
create-meta telah tersedia di REST API sejak versi 5.0), yang dengannya Anda bisa mendapatkan daftar pengaturan bidang yang tersedia saat membuat tugas. Namun, pengembang yang perlu "hanya melakukan hal sederhana sekarang" kemungkinan besar tidak akan repot dengan ini.
Akibatnya, itu terjadi seperti ini: karena permintaan untuk membuat tugas bisa sangat besar, kami sering menambahkan data secara bertahap, dan kami menerima kesalahan ketika kami mencoba mengirim semuanya ke Jira. Setelah itu, saya harus melihat kode untuk semua tempat di mana ada sesuatu yang berubah dalam permintaan, dan untuk upaya yang panjang dan membosankan untuk memahami apa yang sebenarnya salah.
Karenanya, kami melakukan
\ Badoo \ Jira \ Issue \ CreateRequest . Ini memungkinkan Anda untuk melihat kesalahan sebelumnya, tepat di tempat Anda mencoba melakukan sesuatu yang salah: berikan bidang semacam nilai melengkung atau ubah bidang yang tidak tersedia. Misalnya, jika Anda mencoba memberi tahu tugas komponen yang tidak ada dalam proyek, pengecualian akan macet di tempat Anda melakukannya, dan bukan di mana Anda akhirnya mengirim permintaan ke API.
Alur kerja dengan CreateRequest terlihat seperti ini $Request = new \Badoo\Jira\Issue\CreateRequest('DD', 'Task', $Client); $Request ->setSummary('summary') ->setDescription('description') ->setFieldValue('For QA', 'custom field with some comments for QA who will check the issue'); $Request->send();
Bekerja dengan API secara langsung
Set kelas yang dijelaskan di atas mencakup sebagian besar kebutuhan. Namun, kami sangat sadar bahwa mayoritas jauh dari segalanya. Oleh karena itu, kami juga memiliki klien kecil untuk bekerja dengan API secara langsung -
\ Badoo \ Jira \ REST \ Client .
Wadah Penggunaan Pelanggan $Jira = \Badoo\Jira\REST\Client::instance(); $Jira->setJiraUrl('https://jira.example.com/'); $Jira->setAuth('user', 'password') $IssueInfo = $Jira->issue()->get('SMPL-1');
Generator kelas untuk bidang khusus
Agar nyaman dengan bidang kustom, setiap bidang harus memiliki kelasnya sendiri dalam kode. Kami membuat sendiri secara manual sesuai kebutuhan, tetapi sebelum mempublikasikan klien kami memutuskan bahwa pendekatan ini mungkin tidak nyaman bagi pengguna baru. Oleh karena itu, kami membuat generator khusus yang bisa pergi ke Jira API untuk daftar bidang khusus dan membuat kelas templat untuk jenis bidang yang dikenal.
Kami percaya bahwa untuk sebagian besar tugas, cukup menggunakan
bin / menghasilkan skrip CLI dari repositori kami. Anda dapat memintanya untuk menceritakan tentang dirinya sendiri melalui opsi
--help / -h :
./bin/generate --help
Dalam kasus yang paling sederhana, untuk generasi sudah cukup untuk menentukan URL Jira Anda, pengguna, kata sandinya, namespace untuk kelas-kelas dan direktori tempat meletakkan kode:
./bin/generate -u user -p password --jira-url https://jira.mlan --target-dir custom-fields --namespace CustomFields
Kami juga menerapkan kemampuan untuk menambahkan templat kami sendiri dan menghasilkan kelas untuk masing-masing bidang. Ini dapat ditemukan dalam
dokumentasi .
Kesimpulan
Kami menyukai apa yang kami dapatkan. Dengan konsep ini - kelas kami sendiri untuk bidang khusus, pembungkus untuk status, versi, pengguna, dll. - kami telah hidup selama lebih dari setahun dan merasa luar biasa. Sebelum menerbitkan kode, kami bahkan memperluas fungsionalitas dan menambahkan hal-hal luar biasa yang tidak sampai ke tangan Anda dalam waktu lama untuk menggunakan klien bahkan lebih nyaman: misalnya, kami menambahkan kemampuan untuk memperbarui beberapa bidang dalam Masalah dalam satu permintaan dan menulis generator kelas untuk bidang khusus.
Menurut pendapat kami, itu ternyata menjadi hal yang baik, yang pasti harus dirasakan untuk memahami apakah itu sesuai dengan tugas dan persyaratan Anda. Di bawah kita - pas.
Tautkan lagi:
github.com/badoo/jira-client .
Terima kasih sudah membaca sampai akhir. Kami berharap kode ini sekarang akan bermanfaat dan menghemat waktu tidak hanya untuk kami.