Repo ini memberikan contoh sederhana tentang cara menyiapkan berbagai layanan CI serta mengintegrasikan alat analisis ke dalam layanan ini. Alat-alat ini harus digunakan sebagai bagian dari Proses Pengembangan Perangkat Lunak (SDP) yang komprehensif dan juga dapat digunakan sebagai templat awal untuk aplikasi C atau C++ apa pun. Alat CI berikut digunakan, memberikan dukungan pengujian untuk Windows, Cygwin, Linux dan macOS
Pemeriksaan berikut dilakukan:
Proyek dunia nyata berikut menggunakan berbagai teknik ini sebagai bagian dari SDP mereka:
Meskipun repo ini dapat dijalankan pada sebagian besar sistem, berikut adalah platform yang didukung dan dependensinya:
sudo apt-get install git build-essential cmake
setup-x86_64.exe -q -P git,make,gcc-core,gcc-g++,cmake
Instal paket berikut:
Untuk mengkompilasi dan menginstal contoh ini, gunakan instruksi berikut:
git clone https://github.com/ainfosec/ci_helloworld.git
mkdir ci_helloworld/build
cd ci_helloworld/build
cmake ..
make
make test
git clone https://github.com/ainfosec/ci_helloworld.git
mkdir ci_helloworld/build
cd ci_helloworld/build
cmake -G "NMake Makefiles" ..
nmake
nmake test
git clone https://github.com/ainfosec/ci_helloworld.git
mkdir ci_helloworld/build
cd ci_helloworld/build
cmake -G "Visual Studio 15 2017 Win64" ..
msbuild ci_helloworld.sln
ctest
git clone https://github.com/ainfosec/ci_helloworld.git
mkdir ci_helloworld/build
cd ci_helloworld/build
cmake ..
make
make test
Berikut ini penjelasan seluruh alat analisis yang telah diintegrasikan ke dalam layanan CI yang digunakan oleh proyek ini termasuk penjelasan cara kerjanya.
CI disiapkan untuk memeriksa dokumentasi yang hilang menggunakan doxygen. Tidak seperti kebanyakan alat analisis yang digunakan dalam proyek ini, tidak ada target make untuk doxygen, melainkan dijalankan menggunakan doxygen secara manual dengan skrip berikut:
- doxygen .doxygen.txt
- |
if [[ -s doxygen_warnings.txt ]]; then
echo "You must fix doxygen before submitting a pull request"
echo ""
cat doxygen_warnings.txt
exit -1
fi
Skrip ini menjalankan doxygen terhadap kode sumber dan peringatan apa pun ditempatkan ke dalam file bernama doxygen_warnings.txt
. Jika file ini kosong, berarti analisis doxygen berhasil, dan semua kode didokumentasikan berdasarkan pengaturan di file konfigurasi .doxygen.txt
. Jika file ini tidak kosong, pengujian gagal, dan mencetak peringatan yang dihasilkan oleh doxygen.
git diff --check
menyediakan cara sederhana untuk mendeteksi kapan kesalahan spasi putih telah diperiksa ke dalam repo, serta memeriksa kapan baris baru di akhir file hilang, atau berisi terlalu banyak. Informasi lebih lanjut tentang pemeriksaan ini dapat ditemukan di sini. Pemeriksaan ini sangat berguna bagi pengembang ketika PR berisi modifikasi yang tidak terkait dengan perubahan spesifiknya.
- |
if [[ -n $(git diff --check HEAD^) ]]; then
echo "You must remove whitespace before submitting a pull request"
echo ""
git diff --check HEAD^
exit -1
fi
Pemeriksaan ini hanya menjalankan git diff --check
, yang kembali dengan kesalahan jika pemeriksaan gagal. Jika ini terjadi, perbedaannya akan ditampilkan untuk dilihat pengguna.
Pemformatan kode sumber adalah cara terbaik untuk menjaga konsistensi tampilan dan nuansa dengan kode. Masalah dengan pemformatan sumber adalah, kecuali semua orang menggunakannya, PR pengembang akan berisi modifikasi yang tidak terkait dengan perubahan spesifik mereka, atau lebih buruk lagi, upaya untuk memperbaiki pemformatan sumber secara berkala akan menghancurkan riwayat git repo Anda setiap kali Anda memformat sumber. Oleh karena itu, jika pemformatan sumber akan digunakan, maka harus diperiksa pada setiap perbedaan kode untuk memastikan pemformatan sudah benar.
Untuk contoh ini, kami menggunakan Astyle, tetapi Format Dentang juga bisa digunakan. Untuk mendukung Astyle dengan cara yang sederhana, kami menyediakan target make yang memungkinkan pengembang memformat kode sumbernya hanya dengan menjalankan make format
. Untuk melakukan ini, pertama-tama kita harus mendapatkan Astyle:
list ( APPEND ASTYLE_CMAKE_ARGS
"-DCMAKE_INSTALL_PREFIX= ${CMAKE_BINARY_DIR} "
)
ExternalProject_Add(
astyle
GIT_REPOSITORY https://github.com/Bareflank/astyle.git
GIT_TAG v1.2
GIT_SHALLOW 1
CMAKE_ARGS ${ASTYLE_CMAKE_ARGS}
PREFIX ${CMAKE_BINARY_DIR} /astyle/ prefix
TMP_DIR ${CMAKE_BINARY_DIR} /astyle/tmp
STAMP_DIR ${CMAKE_BINARY_DIR} /astyle/stamp
DOWNLOAD_DIR ${CMAKE_BINARY_DIR} /astyle/download
SOURCE_DIR ${CMAKE_BINARY_DIR} /astyle/src
BINARY_DIR ${CMAKE_BINARY_DIR} /astyle/ build
)
Logika cmake ini menggunakan ExternalProject_Add untuk mengunduh Astyle secara otomatis, mengkompilasinya untuk platform Anda, dan menginstalnya ke direktori build Anda sehingga dapat digunakan oleh target make kustom kami. Perhatikan bahwa kami menggunakan versi Astyle kami yang telah dipatch dan mengubah sistem build dari kumpulan Makefile khusus Astyle menjadi sistem build CMake untuk kesederhanaan.
list ( APPEND ASTYLE_ARGS
--style=1tbs
--lineend=linux
-- suffix =none
--pad-oper
--unpad-paren
--break-closing-brackets
--align-pointer= name
--align-reference= name
--indent-preproc-define
--indent-switches
--indent-col1-comments
--keep-one-line-statements
--keep-one-line-blocks
--pad-header
--convert-tabs
--min-conditional-indent=0
--indent=spaces=4
--close-templates
--add-brackets
--break-after-logical
${CMAKE_SOURCE_DIR} / include /*.h
${CMAKE_SOURCE_DIR} /src/*.cpp
${CMAKE_SOURCE_DIR} / test /*.cpp
)
if ( NOT WIN32 STREQUAL "1" )
add_custom_target (
format
COMMAND ${CMAKE_SOURCE_DIR} /bin/astyle ${ASTYLE_ARGS}
COMMENT "running astyle"
)
else ()
add_custom_target (
format
COMMAND ${CMAKE_SOURCE_DIR} /bin/astyle.exe ${ASTYLE_ARGS}
COMMENT "running astyle"
)
endif ()
Untuk membuat target pembuatan astyle khusus, kami menggunakan kode CMake di atas. Hal ini mengarahkan CMake ke biner astyle yang dihasilkan bergantung pada platformnya, dan memberikan astyle opsi pemformatan dan file sumber khusus untuk proyek ini.
- cmake -DENABLE_ASTYLE=ON -DCMAKE_CXX_COMPILER="g++-6" ..
- make
- make format
- |
if [[ -n $(git diff) ]]; then
echo "You must run make format before submitting a pull request"
echo ""
git diff
exit -1
fi
Terakhir, untuk memverifikasi pada setiap PR bahwa perubahan kode mematuhi konfigurasi Astyle kami, kami menambahkan kode di atas ke skrip Travis CI kami. Ini menciptakan target make format
kami dan mengeksekusinya untuk memformat kode. Jika make format
kode, sebuah diff akan dibuat yang dapat dideteksi oleh git diff
. Jika tidak ada diff yang dibuat, berarti semua sumber mematuhi konfigurasi Astyle kami, dan pengujian berhasil.
Clang Tidy menyediakan analisis statis. Dukungan untuk alat ini dimulai dengan menambahkan yang berikut ke CMakeLists.txt:
set (CMAKE_EXPORT_COMPILE_COMMANDS ON )
Ini memberitahu CMake untuk mencatat semua instruksi kompilasi yang digunakan untuk mengkompilasi proyek Anda termasuk tanda dan definisi. Clang Tidy akan menggunakan informasi ini untuk menganalisis proyek Anda secara statis dengan cara yang sama seperti saat kompilasi. Keuntungan dari pendekatan ini adalah peningkatan akurasi yang signifikan. Kerugian utama dari pendekatan ini adalah Clang Tidy tidak pandai menganalisis secara statis file yang tidak muncul dalam database kompilasi ini (seperti file header). Oleh karena itu, jika ingin menganalisis header, header harus disertakan dengan file sumber yang disertakan dalam database kompilasi.
list ( APPEND RUN_CLANG_TIDY_BIN_ARGS
-clang-tidy-binary ${CLANG_TIDY_BIN}
-header- filter =.*
-checks=clan*,cert*,misc*,perf*,cppc*,read*,mode*,-cert-err58-cpp,-misc-noexcept-move-constructor
)
add_custom_target (
tidy
COMMAND ${RUN_CLANG_TIDY_BIN} ${RUN_CLANG_TIDY_BIN_ARGS}
COMMENT "running clang tidy"
)
Terakhir, Clang Tidy diberikan target make tersendiri untuk mempermudah penggunaannya. Di sini kami memberi tahu skrip run-clang-tidy-4.0.py
biner clang rapi mana yang akan digunakan, serta pemeriksaan mana yang harus dilakukan, dan file header apa yang harus disertakan, dan semuanya. Kami mematikan pengujian -cert-err58-cpp karena memicu kode dari catch.hpp, dan -misc-noException-move-constructor karena masih bermasalah di versi 4.0. Perhatikan bahwa kami memilih versi tertentu dari Clang Tidy yang penting karena setiap versi baru Clang Tidy memperbaiki bug dan menambahkan pemeriksaan baru, sehingga menghasilkan hasil yang berbeda tergantung pada versi yang Anda gunakan.
- cmake -DENABLE_CLANG_TIDY=ON -DCMAKE_CXX_COMPILER="g++-6" ..
- make
- make tidy > output.txt
- |
if [[ -n $(grep "warning: " output.txt) ]] || [[ -n $(grep "error: " output.txt) ]]; then
echo "You must pass the clang tidy checks before submitting a pull request"
echo ""
grep --color -E '^|warning: |error: ' output.txt
exit -1;
else
echo -e " 33[1;32mxE2x9Cx93 passed: 33[0m $1";
fi
Dari Travis CI, kami mengaktifkan Clang Tidy, dan membuang outputnya ke file. Jika file ini berisi "peringatan" atau "kesalahan", kami gagal dalam pengujian, dan menampilkan masalah yang dilaporkan oleh Clang Tidy kepada pengguna untuk diperbaiki. Hal ini memastikan bahwa setiap PR telah diperiksa secara statis.
CppCheck adalah alat analisis statis lainnya.
list ( APPEND CPPCHECK_CMAKE_ARGS
"-DCMAKE_INSTALL_PREFIX= ${CMAKE_BINARY_DIR} "
)
ExternalProject_Add(
cppcheck
GIT_REPOSITORY https://github.com/danmar/cppcheck.git
GIT_TAG 1.79
GIT_SHALLOW 1
CMAKE_ARGS ${CPPCHECK_CMAKE_ARGS}
PREFIX ${CMAKE_BINARY_DIR} /external/cppcheck/ prefix
TMP_DIR ${CMAKE_BINARY_DIR} /external/cppcheck/tmp
STAMP_DIR ${CMAKE_BINARY_DIR} /external/cppcheck/stamp
DOWNLOAD_DIR ${CMAKE_BINARY_DIR} /external/cppcheck/download
SOURCE_DIR ${CMAKE_BINARY_DIR} /external/cppcheck/src
BINARY_DIR ${CMAKE_BINARY_DIR} /external/cppcheck/ build
)
Versi CppCheck yang disediakan oleh Ubuntu 14.04 sudah lama, dan tidak mendukung C++11 dengan baik, jadi kami mengambil versi spesifik CppCheck dari GitHub, yang memungkinkan semua pengguna proyek untuk menggunakan versi yang sama.
list ( APPEND CPPCHECK_ARGS
--enable=warning,style,performance,portability,unusedFunction
--std=c++11
--verbose
--error-exitcode=1
-- language =c++
-DMAIN=main
-I ${CMAKE_SOURCE_DIR} / include
${CMAKE_SOURCE_DIR} / include /*.h
${CMAKE_SOURCE_DIR} /src/*.cpp
${CMAKE_SOURCE_DIR} / test /*.cpp
)
add_custom_target (
check
COMMAND ${CMAKE_BINARY_DIR} /bin/cppcheck ${CPPCHECK_ARGS}
COMMENT "running cppcheck"
)
Kami kemudian menambahkan target khusus untuk aplikasi CppCheck yang baru kami buat, memberi tahu CppCheck untuk mengaktifkan semua pemeriksaannya (tanpa peringatan berlebihan) dan untuk memeriksa semua file sumber kami. Perhatikan bahwa CppCheck perlu mengetahui bahwa MAIN=main, jika tidak maka fungsi utama akan dianggap tidak dijalankan, dan kita perlu memberi tahu CppCheck agar melakukan kesalahan dengan kode kesalahan bukan 0 sehingga Travis CI melaporkan pengujian yang gagal jika salah satu dari pemeriksaan gagal.
- cmake -DENABLE_CPPCHECK=ON -DCMAKE_CXX_COMPILER="g++-6" ..
- make
- make check
Menjalankan pengujian Travis CI semudah menyalakan CppCheck, dan menjalankan target pembuatan khusus.
Coverity Scan adalah alat analisis statis lainnya yang sangat baik dalam menemukan masalah struktural yang sulit ditemukan pada kode Anda. Jika Anda memiliki akses ke Coverity Scan, ada baiknya Anda menambahkannya ke SDP Anda.
- os : linux
env :
- TEST="Coverity Scan"
addons :
apt :
sources :
- ubuntu-toolchain-r-test
packages :
- gcc-6
- g++-6
coverity_scan :
project :
name : " ainfosec/ci_helloworld "
description : " A simple example of how to setup a complete CI environment for C and C++ "
notification_email : [email protected]
build_command_prepend : " cmake -DCMAKE_CXX_COMPILER=g++-6 .. "
build_command : " make "
branch_pattern : master
script :
- echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
Coverity Scan juga sangat mudah diatur. Tes Travis CI di atas adalah potongan/tempel dari situs web mereka setelah Anda mendaftarkan proyek Anda. Yang harus kita lakukan adalah mengkompilasi sumber yang memberitahukan Coverity Scan bagaimana kode sumber dikompilasi. Dari sana, situs web mereka akan menyediakan sarana untuk mengecualikan direktori dan melihat masalah dengan kode. Dalam contoh kita, kita melakukan pemindaian pada setiap perubahan pada master karena jumlah perubahan pada master sedikit, namun pada proyek besar dengan banyak penggabungan per hari, Coverity Scan menyarankan penggunaan cabang coverity_scan tertentu untuk pemindaian. Jika ini dilakukan, pemindaian malam hari harus diatur dengan mengambil cabang master, dan mendorongnya ke cabang coverity_scan setiap malam. Dengan cara ini, masalah pada Coverity Scan dapat diidentifikasi dengan cepat.
Codecov adalah alat cakupan yang kuat namun mudah diatur.
if (ENABLE_COVERAGE)
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -g " )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -O0" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fprofile-arcs" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -ftest-coverage" )
set ( CMAKE_EXE_LINKER_FLAGS " ${CMAKE_EXE_LINKER_FLAGS} --coverage" )
endif ()
Untuk mengatur cakupan, kita harus mengaktifkan dukungan GCOV di compiler kita (asumsikan GCC atau Clang). Setelah dukungan ini diaktifkan, menjalankan make test
akan menghasilkan statistik cakupan yang dapat dianalisis Codecov untuk memberi Anda laporan tentang kode apa yang telah atau belum diuji unitnya.
- cmake -DENABLE_COVERAGE=ON -DCMAKE_CXX_COMPILER="g++-6" ..
- make
- make test
- cd ..
- bash <(curl -s https://codecov.io/bash)
Pengujian Travis CI sesederhana mengkompilasi dan menjalankan pengujian unit, lalu menjalankan skrip bash Codecov. Setelah ini selesai, hasilnya bisa lihat di situs Codecov.
Baju adalah alat cakupan lainnya.
if (ENABLE_COVERAGE)
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -g " )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -O0" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fprofile-arcs" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -ftest-coverage" )
set ( CMAKE_EXE_LINKER_FLAGS " ${CMAKE_EXE_LINKER_FLAGS} --coverage" )
endif ()
Seperti Codecov, GCOV harus diaktifkan.
- pip install --user git+git://github.com/eddyxu/cpp-coveralls.git
- cmake -DENABLE_COVERAGE=ON -DCMAKE_CXX_COMPILER="g++-6" ..
- make
- make test
- cd ..
- |
coveralls --build-root build --gcov-options '-lp'
-e build/external
-e build/include
-e build/CMakeFiles/3.8.0
-e build/CMakeFiles/feature_tests.c
-e build/CMakeFiles/feature_tests.cxx
Tidak seperti Codecov, Coverall jauh lebih sulit untuk diatur. Codecov melacak file mana yang ada di repositori git Anda dan hanya menghasilkan laporan untuk file di repo, sementara Coveralls akan menghasilkan laporan cakupan untuk semua file yang dilihatnya, termasuk file yang dihasilkan oleh CMake. Coverall juga tidak memiliki skrip bash sederhana untuk melaporkan data cakupan ke server mereka, melainkan memerlukan instalasi alat khusus C++ eksternal untuk mengumpulkan data GCOV. Untuk alasan ini, kita harus menginstal cpp-coveralls, dan kemudian memerintahkannya untuk mengecualikan file/direktori tertentu yang tidak seharusnya dikumpulkan.
Google Sanitizers adalah alat analisis dinamis yang disertakan dalam GCC dan Clang/LLVM.
if (ENABLE_ASAN)
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -g" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -O1" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fuse-ld=gold" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=address" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=leak" )
endif ()
if (ENABLE_USAN)
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fuse-ld=gold" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=undefined" )
endif ()
if (ENABLE_TSAN)
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fuse-ld=gold" )
set ( CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=thread" )
endif ()
Setiap alat pembersih harus dijalankan secara terpisah, sehingga kami mempunyai satu pengujian untuk setiap kelompok alat pembersih. Bendera untuk setiap set dapat ditemukan di halaman GitHub Google serta dokumentasi penggunaan Clang.
- cmake -DENABLE_ASAN= ON -DCMAKE_CXX_COMPILER= "g++-6" ..
- make
- make test
Untuk setiap pengujian, kami mengaktifkan pemeriksaan khusus, dan pengujian unit, dan jika pemeriksaan gagal, pengujian unit akan keluar dengan kode keluar bukan-0, menyebabkan Travis CI gagal dalam pengujian. Perlu dicatat bahwa setiap versi baru GCC dan Clang hadir dengan dukungan yang lebih baik, dan oleh karena itu, seperti beberapa alat lainnya, Anda harus tetap menggunakan versi tertentu.
Valgrind adalah alat analisis dinamis lainnya yang menyediakan deteksi kebocoran.
set (MEMORYCHECK_COMMAND_OPTIONS " ${MEMORYCHECK_COMMAND_OPTIONS} --leak-check=full" )
set (MEMORYCHECK_COMMAND_OPTIONS " ${MEMORYCHECK_COMMAND_OPTIONS} --track-fds=yes" )
set (MEMORYCHECK_COMMAND_OPTIONS " ${MEMORYCHECK_COMMAND_OPTIONS} --trace-children=yes" )
set (MEMORYCHECK_COMMAND_OPTIONS " ${MEMORYCHECK_COMMAND_OPTIONS} --error-exitcode=1" )
Cara termudah untuk menjalankan Valgrind adalah dengan menggunakan dukungan bawaan CMake karena ini akan menangani logika kesalahan untuk Anda. Untuk alasan ini, kita perlu memberi tahu CMake flag apa yang akan diberikan pada Valgrind. Dalam hal ini kami mengaktifkan semua pemeriksaannya dan memberitahu Valgrind untuk keluar dengan kode keluar bukan-0 sehingga jika pemeriksaan gagal, Travis CI akan gagal dalam pengujian.
- cmake -DCMAKE_CXX_COMPILER="g++-6" ..
- make
- ctest -T memcheck
Untuk menjalankan pengujian, yang perlu kita lakukan hanyalah mengkompilasi kode, dan menjalankan pengujian unit menggunakan ctest, mengaktifkan mode memcheck.
Proyek ini dilisensikan di bawah Lisensi MIT.