در تحلیلگر PVS-Studio برای زبان های C و C++ در لینوکس و macOS، از نسخه 7.04، یک فرصت آزمایشی برای بررسی لیست فایل های مشخص شده ظاهر شده است. با استفاده از حالت جدید، می توانید تحلیلگر را برای بررسی commit ها و درخواست ها پیکربندی کنید. این مقاله به شما نشان می دهد که چگونه یک بررسی لیست فایل پروژه GitHub را در سیستم های محبوب CI (ادغام پیوسته) مانند Travis CI، Buddy و AppVeyor تنظیم کنید.
حالت بررسی لیست فایل
نسخه PVS-Studio 7.04 برای لینوکس و macOS حالتی برای بررسی لیست فایل های منبع دارد. این برای پروژه هایی کار می کند که سیستم ساخت آنها به شما امکان می دهد یک فایل تولید کنید
همچنین می توان از حالت بررسی لیست فایل ها به همراه ردیابی strace اجراهای کامپایلر (pvs-studio-analyzer trace) استفاده کرد. برای انجام این کار، ابتدا باید ساخت کامل پروژه را انجام دهید و آن را ردیابی کنید تا تحلیلگر اطلاعات کاملی در مورد پارامترهای کامپایل تمام فایل های در حال بررسی جمع آوری کند.
با این حال، این گزینه یک اشکال قابل توجه دارد - شما یا باید در هر راه اندازی یک ردیابی کامل از کل پروژه را انجام دهید، که به خودی خود با ایده بررسی تعهد سریع در تضاد است. یا اگر خود نتیجه ردیابی را در حافظه پنهان ذخیره کنید، اگر ساختار وابستگی فایل منبع پس از ردیابی تغییر کند، راه اندازی های بعدی تحلیلگر ممکن است ناقص باشد (به عنوان مثال، یک #include جدید به یکی از فایل های منبع اضافه شود).
بنابراین، ما استفاده از حالت بررسی لیست فایل با گزارش ردیابی را برای بررسی commit ها یا درخواست ها توصیه نمی کنیم. در صورتی که می توانید هنگام بررسی یک commit یک ساخت افزایشی انجام دهید، از حالت استفاده کنید
لیست فایل های منبع برای تجزیه و تحلیل در یک فایل متنی ذخیره می شود و با استفاده از پارامتر به تحلیلگر ارسال می شود -S:
pvs-studio-analyzer analyze ... -f build/compile_commands.json -S check-list.txt
این فایل مسیرهای نسبی یا مطلق فایل ها را مشخص می کند و هر فایل جدید باید در یک خط جدید باشد. مشخص کردن نه تنها نام فایل ها برای تجزیه و تحلیل، بلکه متن های مختلف نیز مجاز است. تجزیه کننده می بیند که این یک فایل نیست و خط را نادیده می گیرد. اگر فایل ها به صورت دستی مشخص شده باشند، این می تواند برای اظهار نظر مفید باشد. با این حال، اغلب لیستی از فایل ها در طول تجزیه CI تولید می شود، برای مثال فایل هایی از یک commit یا یک درخواست pull.
اکنون، با استفاده از این حالت، می توانید به سرعت کدهای جدید را قبل از ورود به شاخه اصلی توسعه آزمایش کنید. برای اینکه سیستم تأیید به هشدارهای تحلیلگر واکنش نشان دهد، ابزار Plog-Converter پرچم اضافه شد -- نشان می دهد - هشدارها:
plog-converter ... --indicate-warnings ... -o /path/to/report.tasks ...
با این پرچم، در صورت وجود هشدار در گزارش تحلیلگر، مبدل یک کد غیر صفر را برمی گرداند. با استفاده از کد بازگشتی، میتوانید یک قلاب پیشاختصاصی را مسدود کنید، درخواست را commit یا pull کنید و گزارش تحلیلگر تولید شده را روی صفحه نمایش دهید، آن را به اشتراک بگذارید یا از طریق پست ارسال کنید.
توجه داشته باشید. اولین باری که شروع به تجزیه و تحلیل لیست فایل ها می کنید، کل پروژه تجزیه و تحلیل می شود، زیرا تحلیلگر باید فایلی از وابستگیهای فایلهای منبع پروژه روی فایلهای هدر ایجاد کند. این یکی از ویژگی های تجزیه فایل های C و C++ است. در آینده، فایل وابستگی را می توان کش کرد و به طور خودکار توسط تحلیلگر به روز می شود. مزیت بررسی commit ها هنگام استفاده از حالت بررسی لیست فایل نسبت به حالت تجزیه افزایشی این است که فقط آن فایل باید کش شود، نه فایل های شی.
اصول کلی تحلیل درخواست کشش
تجزیه و تحلیل کل پروژه زمان زیادی می برد، بنابراین منطقی است که فقط بخشی از آن را بررسی کنید. مشکل اینجاست که باید فایل های جدید را از بقیه فایل های پروژه جدا کنید.
مثالی از درخت commit با دو شاخه را در نظر بگیرید:
بیایید وانمود کنیم که متعهد است A1 حاوی مقدار نسبتاً زیادی کد است که قبلاً بررسی شده است. کمی زودتر از commit یک شاخه ساختیم A1 و چند فایل را تغییر داد.
البته بعد از آن متوجه شدید A1 دو تعهد دیگر وجود داشت، اما اینها ادغام شاخه های دیگر نیز بود، زیرا ما در استاد. و اکنون زمان آن فرا رسیده است که هات اسپات آماده. بنابراین، یک درخواست کشش برای ادغام ظاهر شد B3 и A3.
البته، بررسی کل نتیجه ادغام آنها ممکن است، اما این بسیار طولانی و غیر قابل توجیه است، زیرا فقط چند فایل تغییر کرده است. بنابراین، تجزیه و تحلیل تنها موارد تغییر یافته کارآمدتر است.
برای انجام این کار، ما تفاوت بین شاخه ها را به دست می آوریم، در HEAD شاخه ای که می خواهیم از آن به Master ادغام شویم:
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
$MERGE_BASE بعداً به تفصیل در نظر خواهیم گرفت. واقعیت این است که هر سرویس CI اطلاعات لازم را در مورد پایه ادغام ارائه نمی دهد، بنابراین هر بار باید راه های جدیدی برای دریافت این داده ها پیدا کنید. این در زیر در هر یک از خدمات وب توضیح داده شده به تفصیل توضیح داده خواهد شد.
بنابراین، تفاوت بین شاخه ها، یا بهتر است بگوییم، لیست نام فایل هایی که تغییر کرده اند را دریافتیم. حالا باید فایل را بدهیم pvs-pr.list (ما خروجی بالا را به آن هدایت کردیم) به تحلیلگر:
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
-S .pvs-pr.list
پس از تجزیه و تحلیل، باید فایل log (PVS-Studio.log) را به یک فرمت قابل خواندن تبدیل کنیم:
plog-converter -t errorfile PVS-Studio.log --cerr -w
این دستور خطاهای موجود را فهرست می کند
فقط در اینجا ما نه تنها باید خطاها را نمایش دهیم، بلکه باید سرویس خود را برای مونتاژ و آزمایش در مورد وجود مشکلات مطلع کنیم. برای این، یک پرچم به مبدل اضافه شد -W (-- نشان می دهد - هشدارها). اگر حداقل یک هشدار آنالیزور وجود داشته باشد، کد برگشتی ابزار Plog-Converter به 2 تغییر می کند، که به نوبه خود به سرویس CI اطلاع می دهد که خطاهای احتمالی در فایل های درخواست کشش وجود دارد.
تراویس CI
پیکربندی در قالب یک فایل انجام می شود .travis.yml. برای راحتی، من به شما توصیه می کنم همه چیز را در یک اسکریپت bash جداگانه با توابعی قرار دهید که از فایل فراخوانی می شود. .travis.yml (bash scriptname.sh function_name).
ما کد لازم را به اسکریپت اضافه می کنیم بر هم زدن، بنابراین عملکرد بیشتری دریافت می کنیم. در بخش نصب بیایید موارد زیر را بنویسیم:
install:
- bash .travis.sh travis_install
اگر دستورالعملی داشتید، می توانید با حذف خط فاصله، آنها را به اسکریپت منتقل کنید.
بیایید فایل را باز کنیم تراویس.ش و تنظیمات آنالیزور را به تابع اضافه کنید 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
}
حالا بیایید به بخش اضافه کنیم خط تجزیه و تحلیل اجرا:
script:
- bash .travis.sh travis_script
و در اسکریپت 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
}
این کد باید پس از ساخت پروژه اجرا شود، به عنوان مثال، اگر یک ساخت CMake داشته باشید:
travis_script() {
CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
cmake $CMAKE_ARGS CMakeLists.txt
make -j8
}
اینجوری میشه:
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
}
احتمالاً قبلاً به متغیرهای محیطی مشخص شده توجه کرده اید. TRAVIS_PULL_REQUEST $ и $TRAVIS_BRANCH. Travis CI به تنهایی آنها را اعلام می کند:
- TRAVIS_PULL_REQUEST $ شماره درخواست کشش یا را ذخیره می کند غلطاگر یک شاخه معمولی باشد;
- $TRAVIS_REPO_SLUG نام مخزن پروژه را ذخیره می کند.
الگوریتم این تابع:
Travis CI به کدهای برگشتی پاسخ می دهد، بنابراین وجود اخطارها به سرویس می گوید که commit را به عنوان حشره پرچم گذاری کند.
بیایید نگاهی دقیق تر به این خط کد بیندازیم:
git diff --name-only origin/HEAD > .pvs-pr.list
واقعیت این است که Travis CI به طور خودکار شاخه ها را در طول تجزیه و تحلیل درخواست کشش ادغام می کند:
بنابراین، ما تجزیه و تحلیل می کنیم A4و نه B3->A3. به دلیل این ویژگی، ما باید تفاوت را محاسبه کنیم A3، که فقط بالای شاخه از منشاء.
یکی از جزئیات مهم باقی می ماند - کش کردن وابستگی های فایل های هدر به واحدهای ترجمه کامپایل شده (*.c، *.cc، *.cpp، و غیره). تحلیلگر این وابستگی ها را در اولین شروع در حالت بررسی لیست فایل ها محاسبه می کند و سپس آنها را در دایرکتوری PVS-Studio ذخیره می کند. Travis CI به شما امکان می دهد پوشه ها را کش کنید، بنابراین ما داده های دایرکتوری را ذخیره خواهیم کرد .PVS-Studio/:
cache:
directories:
- .PVS-Studio/
این کد باید به فایل اضافه شود .travis.yml. این دایرکتوری داده های مختلف جمع آوری شده پس از تجزیه و تحلیل را ذخیره می کند، که به طور قابل توجهی سرعت اجرای بعدی تجزیه و تحلیل لیست فایل یا تجزیه و تحلیل افزایشی را افزایش می دهد. اگر این کار انجام نشود، آنالایزر در واقع همه فایل ها را هر بار تجزیه و تحلیل می کند.
رفیق
مانند تراویس سی.آی.
اول از همه، باید یک اکشن جدید به خط ساخت اضافه کنیم:
کامپایلری را که برای ساخت پروژه استفاده شده است را مشخص کنید. به کانتینر docker که در این اکتیویتی نصب شده است توجه کنید. به عنوان مثال، یک ظرف مخصوص برای GCC وجود دارد:
حالا بیایید PVS-Studio و ابزارهای ضروری را نصب کنیم:
خطوط زیر را به ویرایشگر اضافه کنید:
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
حالا بیایید به تب Run (آیکون اول) برویم و کد زیر را به قسمت ویرایشگر مربوطه اضافه کنیم:
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
اگر بخش Travs-CI را خوانده اید، این کد قبلاً برای شما آشنا است، با این حال، اکنون یک مرحله جدید وجود دارد:
واقعیت این است که اکنون ما نتیجه ادغام را تجزیه و تحلیل نمی کنیم، بلکه HEAD شاخه ای را که درخواست کشش از آن انجام می شود، تجزیه و تحلیل می کنیم:
بنابراین ما در یک تعهد مشروط هستیم B3 و ما باید تفاوت را از آن دریافت کنیم 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
برای تعیین A3 بیایید از GitHub API استفاده کنیم:
https://api.github.com/repos/${USERNAME}/${REPO}/pulls/${PULL_REQUEST_ID}
ما از متغیرهای زیر ارائه شده توسط بادی استفاده کردیم:
- $BUDDY_EXECUTION_PULL_REQEUST_NO - شماره درخواست کشش؛
- $BUDDY_REPO_SLUG - ترکیبی از نام کاربری و مخزن (به عنوان مثال حداکثر / تست).
حالا بیایید تغییرات را با استفاده از دکمه زیر ذخیره کنیم و تجزیه و تحلیل درخواست کشش را فعال کنیم:
بر خلاف Travis CI، ما نیازی به مشخص کردن نداریم .pvs-studio برای کش کردن، زیرا بادی به طور خودکار همه فایل ها را برای راه اندازی های بعدی ذخیره می کند. بنابراین، آخرین چیزی که باقی میماند این است که لاگین و رمز عبور PVS-Studio را در Buddy ذخیره کنید. پس از ذخیره تغییرات، به Pipeline باز خواهیم گشت. ما باید به تنظیمات متغیرها برویم و ورود و کلید را برای PVS-Studio اضافه کنیم:
پس از آن، ظاهر شدن یک درخواست کشش یا commit جدید، یک چک را آغاز می کند. اگر یک commit دارای خطا باشد، بادی آن را در صفحه درخواست کشش نشان می دهد.
AppVeyor
راه اندازی AppVeyor مشابه بادی است، زیرا همه چیز در رابط وب اتفاق می افتد و نیازی به افزودن یک فایل *.yml به مخزن پروژه نیست.
بیایید به تب تنظیمات در نمای کلی پروژه برویم:
بیایید این صفحه را به پایین اسکرول کنیم و ذخیره کش را برای ساختن درخواست های کششی فعال کنیم:
حال به تب Environment می رویم، در آنجا تصویر مورد نظر و متغیرهای محیط لازم را مشخص می کنیم:
اگر قسمت های قبلی را مطالعه کرده باشید، با این دو متغیر بسیار آشنا هستید PVS_KEY и PVS_USERNAME. اگر نه، پس اجازه دهید یادآوری کنم که آنها برای بررسی مجوز تحلیلگر PVS-Studio ضروری هستند. در آینده، دوباره آنها را در اسکریپت های Bash ملاقات خواهیم کرد.
در همان صفحه زیر، پوشه ذخیره سازی را مشخص کنید:
اگر این کار را انجام ندهیم، به جای چند فایل، کل پروژه را آنالیز می کنیم، اما بر اساس فایل های مشخص شده، خروجی را دریافت می کنیم. بنابراین، مهم است که نام دایرکتوری صحیح را وارد کنید.
حالا نوبت تست اسکریپت است. تب Tests را باز کرده و Script را انتخاب کنید:
کد زیر را در این فرم قرار دهید:
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
بیایید نگاهی به قسمت زیر از کد بیندازیم:
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
انتساب نسبتاً خاص مقدار دستور pwd به متغیری که باید این مقدار پیش فرض را ذخیره کند در نگاه اول عجیب به نظر می رسد، با این حال، من همه چیز را در یک لحظه توضیح خواهم داد.
هنگام راه اندازی آنالایزر در AppVeyor، با رفتار بسیار عجیب آنالایزر مواجه شدم. از یک طرف، همه چیز به درستی کار کرد، اما تجزیه و تحلیل شروع نشد. من زمان زیادی را صرف کردم و متوجه شدم که ما در پوشه /home/appveyor/projects/testcalc/ هستیم و تحلیلگر مطمئن است که ما در /opt/appveyor/build-agent/ هستیم. سپس متوجه شدم که متغیر $PWD کمی دروغ است. به همین دلیل، قبل از شروع تجزیه و تحلیل، مقدار آن را به صورت دستی به روز کردم.
و سپس همه چیز، مانند قبل:
اکنون قطعه زیر را در نظر بگیرید:
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"`
در آن تفاوت بین شاخه هایی که درخواست کشش بر روی آنها اعلام شده است را دریافت می کنیم. برای این کار به متغیرهای محیطی زیر نیاز داریم:
- $APPVEYOR_PULL_REQUEST_NUMBER - شماره درخواست کشش.
- $APPVEYOR_REPO_NAME - نام کاربری و مخزن پروژه.
نتیجه
البته، ما همه خدمات یکپارچه سازی مداوم ممکن را در نظر نگرفته ایم، با این حال، همه آنها ویژگی های کاری بسیار مشابهی دارند. به استثنای کش، هر سرویس "دوچرخه" خود را می سازد، بنابراین همه چیز همیشه متفاوت است.
در جایی، مانند Travis-CI، چند خط کد و حافظه پنهان کار می کنند. در جایی، مانند AppVeyor، فقط باید پوشه را در تنظیمات مشخص کنید. اما در جایی باید کلیدهای منحصر به فرد ایجاد کنید و سعی کنید سیستم را متقاعد کنید تا به شما فرصت بازنویسی قطعه ذخیره شده را بدهد. بنابراین، اگر میخواهید تجزیه و تحلیل درخواست کشش را بر روی یک سرویس یکپارچهسازی پیوسته که در بالا توضیح داده نشده است، راهاندازی کنید، ابتدا مطمئن شوید که مشکلی با حافظه پنهان نخواهید داشت.
با تشکر از توجه شما. اگر چیزی درست نشد، در صورت تمایل به ما بنویسید
اگر می خواهید این مقاله را با مخاطبان انگلیسی زبان به اشتراک بگذارید، لطفاً از پیوند ترجمه استفاده کنید: Maxim Zvyagintsev.
منبع: www.habr.com