Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Dalam penganalisis PVS-Studio untuk bahasa C dan C++ di Linux dan macOS, mulai dari versi 7.04, opsi pengujian telah muncul untuk memeriksa daftar file yang ditentukan. Dengan menggunakan mode baru, Anda dapat mengonfigurasi penganalisis untuk memeriksa penerapan dan menarik permintaan. Artikel ini akan memberi tahu Anda cara mengatur pemeriksaan daftar file yang diubah dari proyek GitHub dalam sistem CI (Continuous Integration) yang populer seperti Travis CI, Buddy, dan AppVeyor.

Mode pemeriksaan daftar file

PVS-Studio adalah alat untuk mengidentifikasi kesalahan dan potensi kerentanan dalam kode sumber program yang ditulis dalam C, C++, C# dan Java. Bekerja pada sistem 64-bit di Windows, Linux dan macOS.

Di versi PVS-Studio 7.04 untuk Linux dan macOS, mode untuk memeriksa daftar file sumber telah muncul. Ini berfungsi untuk proyek yang sistem pembangunannya memungkinkan Anda membuat file kompilasi_perintah.json. Penganalisis diperlukan untuk mengekstrak informasi tentang kompilasi file yang ditentukan. Jika sistem build Anda tidak mendukung pembuatan file kompilasi_commands.json, Anda dapat mencoba membuat file tersebut menggunakan utilitas Beruang.

Selain itu, mode pemeriksaan daftar file dapat digunakan bersama dengan log jejak strace dari peluncuran kompiler (pelacakan pvs-studio-analyzer). Untuk melakukan ini, Anda harus terlebih dahulu melakukan pembangunan proyek secara penuh dan melacaknya sehingga penganalisis mengumpulkan informasi lengkap tentang parameter kompilasi dari semua file yang diperiksa.

Namun, opsi ini memiliki kelemahan yang signifikan - Anda harus melakukan jejak build lengkap dari keseluruhan proyek setiap kali Anda menjalankannya, yang dengan sendirinya bertentangan dengan gagasan untuk memeriksa penerapan dengan cepat. Atau, jika Anda menyimpan hasil pelacakan itu sendiri dalam cache, proses penganalisa selanjutnya mungkin tidak lengkap jika struktur ketergantungan file sumber berubah setelah pelacakan (misalnya, #include baru ditambahkan ke salah satu file sumber).

Oleh karena itu, kami tidak menyarankan penggunaan mode pemeriksaan daftar file dengan log jejak untuk memeriksa penerapan atau permintaan penarikan. Jika Anda dapat melakukan build tambahan saat memeriksa penerapan, pertimbangkan untuk menggunakan mode ini analisis tambahan.

Daftar file sumber untuk analisis disimpan dalam file teks dan diteruskan ke penganalisis menggunakan parameter -S:

pvs-studio-analyzer analyze ... -f build/compile_commands.json -S check-list.txt

File ini menentukan jalur relatif atau absolut ke file, dan setiap file baru harus berada di baris baru. Dapat diterima untuk menentukan tidak hanya nama file untuk analisis, tetapi juga berbagai teks. Penganalisis akan melihat bahwa ini bukan file dan akan mengabaikan baris tersebut. Ini berguna untuk memberi komentar jika file ditentukan secara manual. Namun, sering kali daftar file akan dihasilkan selama analisis di CI, misalnya, ini bisa berupa file dari permintaan penerapan atau penarikan.

Sekarang, dengan menggunakan mode ini, Anda dapat dengan cepat memeriksa kode baru sebelum masuk ke cabang pengembangan utama. Untuk memastikan bahwa sistem pemindaian merespons peringatan penganalisis, utilitas konverter plog bendera ditambahkan --indikasi-peringatan:

plog-converter ... --indicate-warnings ... -o /path/to/report.tasks ...

Dengan tanda ini, konverter akan mengembalikan kode bukan nol jika ada peringatan di laporan penganalisis. Dengan menggunakan kode pengembalian, Anda dapat memblokir permintaan hook, commit, atau pull yang telah dilakukan sebelumnya, dan laporan penganalisis yang dihasilkan dapat ditampilkan, dibagikan, atau dikirim melalui email.

Catatan. Saat Anda pertama kali mulai menganalisis daftar file, keseluruhan proyek akan dianalisis, karena penganalisis perlu membuat file ketergantungan file sumber proyek pada file header. Ini adalah fitur menganalisis file C dan C++. Di masa depan, file ketergantungan dapat di-cache dan akan diperbarui secara otomatis oleh penganalisis. Keuntungan memeriksa komit saat menggunakan mode pemeriksaan daftar file dibandingkan menggunakan mode analisis tambahan adalah Anda hanya perlu menyimpan file tersebut dalam cache dan bukan file objek.

Prinsip umum analisis permintaan tarik

Menganalisis keseluruhan proyek membutuhkan banyak waktu, jadi masuk akal untuk memeriksa hanya bagian tertentu saja. Masalahnya adalah Anda perlu memisahkan file baru dari file proyek lainnya.

Mari kita lihat contoh pohon komit dengan dua cabang:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio

Mari kita bayangkan komitmen itu A1 berisi sejumlah besar kode yang telah diuji. Beberapa saat sebelumnya kami membuat cabang dari komit A1 dan mengubah beberapa file.

Anda, tentu saja, memperhatikan hal itu setelahnya A1 terjadi dua komitmen lagi, tapi ini juga merupakan penggabungan cabang lain, karena kami tidak berkomitmen menguasai. Dan sekarang waktunya telah tiba perbaikan terbaru siap. Karena itulah muncul pull request merger B3 ΠΈ A3.

Tentu saja, dimungkinkan untuk memeriksa seluruh hasil penggabungannya, tetapi ini akan memakan waktu terlalu lama dan tidak dapat dibenarkan, karena hanya sedikit file yang diubah. Oleh karena itu, akan lebih efisien jika hanya menganalisis perubahan saja.

Untuk melakukan ini, kita mendapatkan perbedaan antar cabang, berada di HEAD cabang tempat kita ingin menggabungkannya menjadi master:

git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list

$MERGE_BASE kita akan melihatnya secara detail nanti. Faktanya adalah tidak semua layanan CI menyediakan informasi yang diperlukan tentang database untuk digabungkan, jadi setiap kali Anda harus menemukan cara baru untuk mendapatkan data ini. Ini akan dijelaskan secara rinci di bawah ini di setiap layanan web yang dijelaskan.

Jadi, kami mendapatkan perbedaan antar cabang, atau lebih tepatnya, daftar nama file yang diubah. Sekarang kita perlu memberikan filenya .pvs-pr.list (kami mengarahkan output di atas ke sana) ke penganalisis:

pvs-studio-analyzer analyze -j8 
                            -o PVS-Studio.log 
                            -S .pvs-pr.list

Setelah analisis, kita perlu mengonversi file log (PVS-Studio.log) ke dalam format yang mudah dibaca:

plog-converter -t errorfile PVS-Studio.log --cerr -w

Perintah ini akan mencantumkan kesalahan di stderr (keluaran pesan kesalahan standar).

Hanya sekarang kami tidak hanya perlu menampilkan kesalahan, tetapi juga memberi tahu layanan perakitan dan pengujian kami tentang adanya masalah. Untuk tujuan ini, sebuah bendera telah ditambahkan ke konverter -W (--indikasi-peringatan). Jika ada setidaknya satu peringatan penganalisis, kode pengembalian utilitas konverter plog akan berubah menjadi 2, yang pada gilirannya akan menginformasikan layanan CI tentang adanya potensi kesalahan dalam file permintaan tarik.

Travis CI

Konfigurasi dibuat sebagai file .travis.yml. Untuk kenyamanan, saya menyarankan Anda untuk memasukkan semuanya ke dalam skrip bash terpisah dengan fungsi yang akan dipanggil dari file .travis.yml (bash skrip_nama.sh nama_fungsi).

Kami akan menambahkan kode yang diperlukan ke skrip di menampar, dengan cara ini kita akan mendapatkan lebih banyak fungsi. Di bagian install mari kita tulis yang berikut ini:

install:
  - bash .travis.sh travis_install

Jika Anda memiliki instruksi apa pun, Anda dapat mentransfernya ke dalam skrip, menghapus tanda hubung.

Mari kita buka filenya .travis.sh dan tambahkan pengaturan penganalisis ke fungsinya travis_install():

travis_install() {
  wget -q -O - https://files.viva64.com/etc/pubkey.txt 
    | sudo apt-key add -
  sudo wget -O /etc/apt/sources.list.d/viva64.list 
    https://files.viva64.com/etc/viva64.list
  
  sudo apt-get update -qq
  sudo apt-get install -qq pvs-studio 
}

Sekarang mari kita tambahkan ke bagian tersebut naskah jalankan analisis:

script:
  - bash .travis.sh travis_script

Dan dalam skrip bash:

travis_script() {
  pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY
  
  if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
    git diff --name-only origin/HEAD > .pvs-pr.list
    pvs-studio-analyzer analyze -j8 
                                -o PVS-Studio.log 
                                -S .pvs-pr.list 
                                --disableLicenseExpirationCheck
  else
    pvs-studio-analyzer analyze -j8 
                                -o PVS-Studio.log 
                                --disableLicenseExpirationCheck
  fi
  
  plog-converter -t errorfile PVS-Studio.log --cerr -w
}

Kode ini perlu dijalankan setelah membangun proyek, misalnya, jika Anda membangun CMake:

travis_script() {
  CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  cmake $CMAKE_ARGS CMakeLists.txt
  make -j8
}

Ini akan menjadi seperti ini:

travis_script() {
  CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  cmake $CMAKE_ARGS CMakeLists.txt
  make -j8
  
  pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY
  
  if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
    git diff --name-only origin/HEAD > .pvs-pr.list
    pvs-studio-analyzer analyze -j8 
                                -o PVS-Studio.log 
                                -S .pvs-pr.list 
                                --disableLicenseExpirationCheck
  else
    pvs-studio-analyzer analyze -j8 
                                -o PVS-Studio.log 
                                --disableLicenseExpirationCheck
  fi
  
  plog-converter -t errorfile PVS-Studio.log --cerr -w
}

Anda mungkin sudah memperhatikan variabel lingkungan ini $TRAVIS_PULL_REQUEST ΠΈ $TRAVIS_BRANCH. Travis CI mendeklarasikannya secara independen:

  • $TRAVIS_PULL_REQUEST menyimpan nomor permintaan tarik atau palsu, jika ini adalah cabang biasa;
  • $TRAVIS_REPO_SLUG menyimpan nama repositori proyek.

Algoritma untuk fungsi ini:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Travis CI merespons kode yang dikembalikan, sehingga adanya peringatan akan memberitahu layanan untuk menandai penerapan sebagai mengandung kesalahan.

Sekarang mari kita lihat lebih dekat baris kode ini:

git diff --name-only origin/HEAD > .pvs-pr.list

Faktanya adalah Travis CI secara otomatis menggabungkan cabang saat menganalisis permintaan tarik:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Oleh karena itu kami menganalisis A4Dan tidak B3->A3. Karena fitur ini, kita perlu menghitung selisihnya dengan A3, yang tepatnya merupakan bagian atas cabang asal.

Ada satu detail penting yang tersisa - menyimpan cache dependensi file header pada unit terjemahan yang dikompilasi (*.c, *.cc, *.cpp, dll.). Penganalisis menghitung dependensi ini saat pertama kali diluncurkan dalam mode pemeriksaan daftar file dan kemudian menyimpannya di direktori .PVS-Studio. Travis CI memungkinkan Anda melakukan cache folder, jadi kami akan menyimpan data direktori .PVS-Studio/:

cache:
  directories:
    - .PVS-Studio/

Kode ini perlu ditambahkan ke file .travis.yml. Direktori ini menyimpan berbagai data yang dikumpulkan setelah analisis, yang secara signifikan akan mempercepat proses analisis daftar file atau analisis tambahan berikutnya. Jika hal ini tidak dilakukan, maka penganalisa akan menganalisis semua file setiap saat.

Buddy

Seperti Travis CI, Buddy memberikan kemampuan untuk secara otomatis membangun dan menguji proyek yang disimpan di GitHub. Tidak seperti Travis CI, ini dikonfigurasi di antarmuka web (tersedia dukungan bash), sehingga tidak perlu menyimpan file konfigurasi di proyek.

Pertama-tama, kita perlu menambahkan tindakan baru ke jalur perakitan:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Mari tunjukkan kompiler yang digunakan untuk membangun proyek. Perhatikan kontainer buruh pelabuhan yang diinstal dalam tindakan ini. Misalnya, ada wadah khusus untuk GCC:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Sekarang mari kita instal PVS-Studio dan utilitas yang diperlukan:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Mari tambahkan baris berikut ke editor:

apt-get update && apt-get -y install wget gnupg jq

wget -q -O - https://files.viva64.com/etc/pubkey.txt | apt-key add -
wget -O /etc/apt/sources.list.d/viva64.list 
  https://files.viva64.com/etc/viva64.list

apt-get update && apt-get -y install pvs-studio

Sekarang mari kita pergi ke tab Run (ikon pertama) dan tambahkan kode berikut ke kolom editor yang sesuai:

pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY

if [ "$BUDDY_EXECUTION_PULL_REQUEST_NO" != '' ]; then
  PULL_REQUEST_ID="pulls/$BUDDY_EXECUTION_PULL_REQUEST_NO"
  MERGE_BASE=`wget -qO - 
    https://api.github.com/repos/${BUDDY_REPO_SLUG}/${PULL_REQUEST_ID} 
    | jq -r ".base.ref"`

  git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
  pvs-studio-analyzer analyze -j8 
                              -o PVS-Studio.log 
                              --disableLicenseExpirationCheck 
                              -S .pvs-pr.list
else
  pvs-studio-analyzer analyze -j8 
                              -o PVS-Studio.log 
                              --disableLicenseExpirationCheck
fi

plog-converter -t errorfile PVS-Studio.log --cerr -w

Jika Anda membaca bagian Travs-CI, maka kode ini sudah tidak asing lagi bagi Anda, namun sekarang ada tahap baru:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Faktanya adalah sekarang kita menganalisis bukan hasil penggabungan, tetapi KEPALA cabang tempat permintaan penarikan dibuat:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Jadi kita berada dalam komitmen bersyarat B3 dan kita perlu mendapatkan perbedaannya A3:

PULL_REQUEST_ID="pulls/$BUDDY_EXECUTION_PULL_REQUEST_NO"
  MERGE_BASE=`wget -qO - 
    https://api.github.com/repos/${BUDDY_REPO_SLUG}/${PULL_REQUEST_ID} 
    | jq -r ".base.ref"`
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list

Untuk menentukan A3 Mari gunakan API GitHub:

https://api.github.com/repos/${USERNAME}/${REPO}/pulls/${PULL_REQUEST_ID}

Kami menggunakan variabel berikut yang Sobat sediakan:

  • $BUDDY_EXECUTION_PULL_REQEUST_NO β€” nomor permintaan tarik;
  • $BUDDY_REPO_SLUG β€” kombinasi nama pengguna dan repositori (misalnya max/test).

Sekarang mari simpan perubahan menggunakan tombol di bawah dan aktifkan analisis permintaan tarik:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Berbeda dengan Travis CI, kami tidak perlu menentukannya .pvs-studio untuk caching, karena Sobat secara otomatis menyimpan semua file dalam cache untuk peluncuran selanjutnya. Oleh karena itu, hal terakhir yang tersisa adalah menyimpan login dan password PVS-Studio di Buddy. Setelah menyimpan perubahan, kita akan dibawa kembali ke Pipeline. Kita perlu melanjutkan ke pengaturan variabel dan menambahkan login dan kunci untuk PVS-Studio:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Setelah ini, kemunculan pull request atau commit baru akan memicu peninjauan. Jika komit mengandung kesalahan, Sobat akan menunjukkannya di halaman permintaan penarikan.

AplikasiVeyor

Menyiapkan AppVeyor mirip dengan Buddy, karena semuanya terjadi di antarmuka web dan tidak perlu menambahkan file *.yml ke repositori proyek.

Mari buka tab Pengaturan di ikhtisar proyek:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Mari gulir ke bawah halaman ini dan aktifkan penyimpanan cache untuk mengumpulkan permintaan tarik:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Sekarang mari kita pergi ke tab Lingkungan, tempat kita menentukan gambar untuk perakitan dan variabel lingkungan yang diperlukan:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Jika Anda telah membaca bagian sebelumnya, Anda sangat familiar dengan kedua variabel ini - PVS_KEY ΠΈ PVS_USERNAME. Jika tidak, izinkan saya mengingatkan Anda bahwa hal itu diperlukan untuk memverifikasi lisensi penganalisis PVS-Studio. Kita akan melihatnya lagi di skrip Bash di masa mendatang.

Pada halaman yang sama di bawah ini kami menunjukkan folder untuk caching:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Jika kami tidak melakukan ini, kami akan menganalisis keseluruhan proyek, bukan beberapa file, tetapi kami akan mendapatkan output dari file yang ditentukan. Oleh karena itu, penting untuk memasukkan nama direktori yang benar.

Sekarang saatnya skrip diuji. Buka tab Tes dan pilih Skrip:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Anda perlu menempelkan kode berikut ke formulir ini:

sudo apt-get update && sudo apt-get -y install jq

wget -q -O - https://files.viva64.com/etc/pubkey.txt 
  | sudo apt-key add -
sudo wget -O /etc/apt/sources.list.d/viva64.list 
  https://files.viva64.com/etc/viva64.list

sudo apt-get update && sudo apt-get -y install pvs-studio

pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY

PWD=$(pwd -L)
if [ "$APPVEYOR_PULL_REQUEST_NUMBER" != '' ]; then
  PULL_REQUEST_ID="pulls/$APPVEYOR_PULL_REQUEST_NUMBER"
  MERGE_BASE=`wget -qO - 
    https://api.github.com/repos/${APPVEYOR_REPO_NAME}/${PULL_REQUEST_ID} 
    | jq -r ".base.ref"`

  git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
  pvs-studio-analyzer analyze -j8 
                              -o PVS-Studio.log 
                              --disableLicenseExpirationCheck 
                              --dump-files --dump-log pvs-dump.log 
                              -S .pvs-pr.list
else
  pvs-studio-analyzer analyze -j8 
                              -o PVS-Studio.log 
                              --disableLicenseExpirationCheck
fi

plog-converter -t errorfile PVS-Studio.log --cerr -w

Mari kita perhatikan bagian kode berikut ini:

PWD=$(pwd -L)
if [ "$APPVEYOR_PULL_REQUEST_NUMBER" != '' ]; then
  PULL_REQUEST_ID="pulls/$APPVEYOR_PULL_REQUEST_NUMBER"
  MERGE_BASE=`wget -qO - 
   https://api.github.com/repos/${APPVEYOR_REPO_NAME}/${PULL_REQUEST_ID} 
   | jq -r ".base.ref"`

  git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
  pvs-studio-analyzer analyze -j8 
                              -o PVS-Studio.log 
                              --disableLicenseExpirationCheck 
                              --dump-files --dump-log pvs-dump.log 
                              -S .pvs-pr.list
else
  pvs-studio-analyzer analyze -j8 
                              -o PVS-Studio.log 
                              --disableLicenseExpirationCheck
fi

Penetapan nilai perintah pwd yang agak spesifik ke variabel yang seharusnya menyimpan nilai default ini tampak aneh pada pandangan pertama, namun, saya akan menjelaskan semuanya sekarang.

Saat menyiapkan penganalisis di AppVeyor, saya menemukan perilaku penganalisis yang sangat aneh. Di satu sisi, semuanya bekerja dengan benar, tetapi analisis tidak dimulai. Saya menghabiskan banyak waktu memperhatikan bahwa kita berada di direktori /home/appveyor/projects/testcalc/, dan penganalisis yakin bahwa kita berada di /opt/appveyor/build-agent/. Kemudian saya menyadari bahwa variabel $PWD sedikit berbohong. Karena alasan ini, saya memperbarui nilainya secara manual sebelum memulai analisis.

Dan kemudian semuanya seperti sebelumnya:

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio
Sekarang perhatikan cuplikan berikut:

PULL_REQUEST_ID="pulls/$APPVEYOR_PULL_REQUEST_NUMBER"
MERGE_BASE=`wget -qO - 
  https://api.github.com/repos/${APPVEYOR_REPO_NAME}/${PULL_REQUEST_ID} 
  | jq -r ".base.ref"`

Di dalamnya kita mendapatkan perbedaan antara cabang tempat permintaan penarikan dideklarasikan. Untuk melakukan ini kita memerlukan variabel lingkungan berikut:

  • $APPVEYOR_PULL_REQUEST_NUMBER β€” nomor permintaan penarikan;
  • $APPVEYOR_REPO_NAME - nama pengguna dan repositori proyek.

Kesimpulan

Tentu saja, kami belum mempertimbangkan semua kemungkinan layanan integrasi berkelanjutan, namun semuanya memiliki spesifikasi pengoperasian yang sangat mirip satu sama lain. Kecuali caching, setiap layanan membuat β€œsepeda” sendiri, jadi semuanya selalu berbeda.

Di suatu tempat, seperti di Travis-CI, beberapa baris kode dan caching berfungsi dengan sempurna; di suatu tempat, seperti di AppVeyor, Anda hanya perlu menentukan folder di pengaturan; tetapi di suatu tempat Anda perlu membuat kunci unik dan mencoba meyakinkan sistem untuk memberi Anda kesempatan untuk menimpa fragmen yang di-cache. Oleh karena itu, jika Anda ingin mengatur analisis permintaan tarik pada layanan integrasi berkelanjutan yang tidak dibahas di atas, pastikan terlebih dahulu bahwa Anda tidak akan mengalami masalah dengan caching.

Terima kasih atas perhatian Anda. Jika ada yang tidak berhasil, jangan ragu untuk menulis kepada kami di mendukung. Kami akan memberi saran dan membantu.

Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio

Jika Anda ingin membagikan artikel ini kepada audiens berbahasa Inggris, silakan gunakan tautan terjemahan: Maxim Zvyagintsev. Analisis komit dan permintaan tarik di Travis CI, Buddy dan AppVeyor menggunakan PVS-Studio.

Sumber: www.habr.com

Tambah komentar