Trong bộ phân tích PVS-Studio dành cho ngôn ngữ C và C++ trên Linux và macOS, bắt đầu từ phiên bản 7.04, cơ hội thử nghiệm đã xuất hiện để kiểm tra danh sách các tệp được chỉ định. Sử dụng chế độ mới, bạn có thể định cấu hình bộ phân tích để kiểm tra các xác nhận và yêu cầu kéo. Bài viết này sẽ chỉ cho bạn cách thiết lập kiểm tra danh sách tệp dự án GitHub trong các hệ thống CI (Tích hợp liên tục) phổ biến như Travis CI, Buddy và AppVeyor.
Chế độ kiểm tra danh sách tập tin
Phiên bản PVS-Studio 7.04 cho Linux và macOS có chế độ kiểm tra danh sách các tệp nguồn. Điều này phù hợp với các dự án có hệ thống xây dựng cho phép bạn tạo tệp
Ngoài ra, chế độ kiểm tra danh sách các tệp có thể được sử dụng cùng với dấu vết của quá trình chạy trình biên dịch (dấu vết pvs-studio-analyzer). Để thực hiện việc này, trước tiên bạn cần tiến hành xây dựng toàn bộ dự án và theo dõi nó để bộ phân tích thu thập thông tin đầy đủ về các tham số biên dịch của tất cả các tệp đang được kiểm tra.
Tuy nhiên, tùy chọn này có một nhược điểm đáng kể - bạn sẽ cần thực hiện theo dõi bản dựng đầy đủ của toàn bộ dự án tại mỗi lần khởi chạy, điều này tự nó mâu thuẫn với ý tưởng kiểm tra cam kết nhanh. Hoặc, nếu bạn lưu chính kết quả theo dõi vào bộ đệm ẩn, các lần khởi chạy tiếp theo của bộ phân tích có thể không hoàn chỉnh nếu cấu trúc phụ thuộc tệp nguồn thay đổi sau khi theo dõi (ví dụ: một #include mới được thêm vào một trong các tệp nguồn).
Do đó, chúng tôi khuyên bạn không nên sử dụng chế độ kiểm tra danh sách tệp có nhật ký theo dõi để kiểm tra các lần xác nhận hoặc yêu cầu kéo. Trong trường hợp bạn có thể thực hiện một bản dựng gia tăng khi kiểm tra một cam kết, hãy cân nhắc sử dụng chế độ
Danh sách các tệp nguồn để phân tích được lưu vào tệp văn bản và được chuyển đến bộ phân tích bằng tham số -S:
pvs-studio-analyzer analyze ... -f build/compile_commands.json -S check-list.txt
Tệp này chỉ định đường dẫn tương đối hoặc tuyệt đối tới tệp và mỗi tệp mới phải nằm trên một dòng mới. Được phép chỉ định không chỉ tên của các tệp để phân tích mà còn cả các văn bản khác nhau. Trình phân tích cú pháp sẽ thấy rằng đây không phải là một tệp và sẽ bỏ qua dòng này. Điều này có thể hữu ích để nhận xét nếu tệp được chỉ định thủ công. Tuy nhiên, thường thì danh sách tệp sẽ được tạo trong quá trình phân tích cú pháp CI, chẳng hạn như tệp từ một cam kết hoặc yêu cầu kéo.
Bây giờ, bằng cách sử dụng chế độ này, bạn có thể nhanh chóng kiểm tra mã mới trước khi nó được đưa vào nhánh phát triển chính. Để hệ thống xác minh phản ứng với các cảnh báo của máy phân tích, tiện ích chuyển đổi plog thêm cờ --indicate-cảnh báo:
plog-converter ... --indicate-warnings ... -o /path/to/report.tasks ...
Với cờ này, trình chuyển đổi sẽ trả về mã khác không nếu có cảnh báo trong báo cáo của trình phân tích. Sử dụng mã trả về, bạn có thể chặn một yêu cầu móc, cam kết hoặc kéo trước, đồng thời hiển thị báo cáo bộ phân tích đã tạo trên màn hình, chia sẻ hoặc gửi báo cáo qua thư.
Ghi chú. Lần đầu tiên bạn bắt đầu phân tích danh sách tệp, toàn bộ dự án sẽ được phân tích, bởi vì bộ phân tích cần tạo một tệp phụ thuộc của các tệp nguồn của dự án trên các tệp tiêu đề. Đây là một tính năng phân tích tệp C và C++. Trong tương lai, tệp phụ thuộc có thể được lưu vào bộ đệm và nó sẽ được cập nhật tự động bởi bộ phân tích. Ưu điểm của việc kiểm tra các xác nhận khi sử dụng chế độ kiểm tra danh sách tệp so với sử dụng chế độ phân tích cú pháp gia tăng là chỉ tệp đó cần được lưu vào bộ nhớ đệm chứ không phải các tệp đối tượng.
Nguyên tắc chung của phân tích yêu cầu kéo
Việc phân tích toàn bộ dự án mất rất nhiều thời gian, vì vậy chỉ nên kiểm tra một phần của dự án. Vấn đề là bạn cần tách các tệp mới khỏi phần còn lại của các tệp dự án.
Xem xét một ví dụ về cây cam kết có hai nhánh:
Hãy giả sử rằng cam kết A1 chứa một lượng mã khá lớn đã được kiểm tra. Trước đó một chút, chúng tôi đã tạo một nhánh từ cam kết A1 và thay đổi một số tập tin.
Tất nhiên, bạn nhận thấy rằng sau khi A1 có thêm hai cam kết, nhưng đây cũng là sự hợp nhất của các chi nhánh khác, bởi vì chúng tôi không cam kết chủ. Và bây giờ đã đến lúc bản sửa lỗi sẵn sàng. Do đó, một yêu cầu kéo đã xuất hiện để hợp nhất B3 и A3.
Tất nhiên, có thể kiểm tra toàn bộ kết quả hợp nhất của chúng, nhưng điều này sẽ quá dài và không chính đáng, vì chỉ một số tệp được thay đổi. Do đó, sẽ hiệu quả hơn nếu chỉ phân tích những cái đã thay đổi.
Để làm điều này, chúng tôi nhận được sự khác biệt giữa các nhánh, nằm trong ĐẦU của nhánh mà chúng tôi muốn hợp nhất thành nhánh chính:
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
$MERGE_BASE chúng ta sẽ xem xét chi tiết sau. Thực tế là không phải mọi dịch vụ CI đều cung cấp thông tin cần thiết về cơ sở để hợp nhất, vì vậy mỗi lần bạn phải nghĩ ra những cách mới để lấy dữ liệu này. Điều này sẽ được trình bày chi tiết bên dưới trong từng dịch vụ web được mô tả.
Vì vậy, chúng tôi đã nhận được sự khác biệt giữa các nhánh, hay đúng hơn là danh sách tên tệp đã được thay đổi. Bây giờ chúng ta cần cung cấp tập tin .pvs-pr.list (chúng tôi đã chuyển hướng đầu ra ở trên tới nó) tới máy phân tích:
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
-S .pvs-pr.list
Sau khi phân tích, chúng ta cần chuyển đổi tệp nhật ký (PVS-Studio.log) sang định dạng có thể đọc được:
plog-converter -t errorfile PVS-Studio.log --cerr -w
Lệnh này sẽ liệt kê các lỗi trong
Chỉ ở đây, chúng tôi không chỉ cần hiển thị lỗi mà còn thông báo cho dịch vụ lắp ráp và thử nghiệm của chúng tôi về sự hiện diện của các vấn đề. Đối với điều này, một lá cờ đã được thêm vào bộ chuyển đổi -W (--indicate-cảnh báo). Nếu có ít nhất một cảnh báo máy phân tích, mã trả về của tiện ích chuyển đổi plog sẽ thay đổi thành 2, do đó sẽ thông báo cho dịch vụ CI rằng có các lỗi tiềm ẩn trong các tệp yêu cầu kéo.
Travis C.I.
Cấu hình được thực hiện dưới dạng tệp .travis.yml. Để thuận tiện, tôi khuyên bạn nên đặt mọi thứ trong một tập lệnh bash riêng với các hàm sẽ được gọi từ tệp .travis.yml (bash scriptname.sh function_name).
Chúng tôi sẽ thêm mã cần thiết vào tập lệnh trên bash, vì vậy chúng tôi nhận được nhiều chức năng hơn. trong phần cài đặt, dựng lên hãy viết như sau:
install:
- bash .travis.sh travis_install
Nếu bạn có bất kỳ hướng dẫn nào, bạn có thể chuyển chúng vào tập lệnh bằng cách xóa dấu gạch nối.
Hãy mở tập tin .travis.sh và thêm thiết lập máy phân tích vào chức năng 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
}
Bây giờ hãy thêm vào phần kịch bản chạy phân tích:
script:
- bash .travis.sh travis_script
Và trong tập lệnh 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
}
Mã này phải được chạy sau khi dự án được tạo, ví dụ: nếu bạn có bản dựng CMake:
travis_script() {
CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
cmake $CMAKE_ARGS CMakeLists.txt
make -j8
}
Nó sẽ thành ra như thế này:
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
}
Bạn có thể đã nhận thấy các biến môi trường được chỉ định. $TRAVIS_PULL_REQUEST и $TRAVIS_BRANCH. Travis CI tự khai báo chúng:
- $TRAVIS_PULL_REQUEST lưu trữ số yêu cầu kéo, hoặc sainếu là nhánh bình thường;
- $TRAVIS_REPO_SLUG lưu trữ tên của kho lưu trữ dự án.
Thuật toán của hàm này:
Travis CI phản hồi các mã trả về, do đó, sự hiện diện của các cảnh báo sẽ yêu cầu dịch vụ gắn cờ cam kết là có lỗi.
Chúng ta hãy xem xét kỹ hơn dòng mã này:
git diff --name-only origin/HEAD > .pvs-pr.list
Thực tế là Travis CI tự động hợp nhất các nhánh trong quá trình phân tích yêu cầu kéo:
Vì vậy, chúng tôi phân tích A4, А не B3->A3. Do tính năng này, chúng ta cần tính toán sự khác biệt từ A3, đó chỉ là đỉnh của nhánh từ nguồn gốc.
Một chi tiết quan trọng vẫn còn - lưu vào bộ nhớ đệm các phần phụ thuộc của tệp tiêu đề trên các đơn vị dịch đã biên dịch (*.c, *.cc, *.cpp, v.v.). Máy phân tích sẽ tính toán các phụ thuộc này khi bắt đầu lần đầu tiên ở chế độ kiểm tra danh sách tệp và sau đó lưu chúng vào thư mục .PVS-Studio. Travis CI cho phép bạn lưu các thư mục vào bộ đệm, vì vậy chúng tôi sẽ lưu dữ liệu thư mục .PVS-Studio/:
cache:
directories:
- .PVS-Studio/
Mã này cần phải được thêm vào tập tin .travis.yml. Thư mục này lưu trữ các dữ liệu khác nhau được thu thập sau khi phân tích, điều này sẽ tăng tốc đáng kể các lần chạy tiếp theo của phân tích danh sách tệp hoặc phân tích gia tăng. Nếu điều này không được thực hiện, thì bộ phân tích sẽ thực sự phân tích tất cả các tệp mỗi lần.
Buddy
Giống như Travis C.I.,
Trước hết, chúng ta cần thêm một hành động mới vào dòng xây dựng:
Chỉ định trình biên dịch đã được sử dụng để xây dựng dự án. Lưu ý bộ chứa docker được cài đặt trong hoạt động này. Ví dụ: có một vùng chứa đặc biệt cho GCC:
Bây giờ hãy cài đặt PVS-Studio và các tiện ích cần thiết:
Thêm các dòng sau vào trình chỉnh sửa:
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
Bây giờ, hãy chuyển đến tab Run (biểu tượng đầu tiên) và thêm đoạn mã sau vào trường trình chỉnh sửa tương ứng:
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
Nếu bạn đã đọc phần trên Travs-CI, thì mã này đã quen thuộc với bạn, tuy nhiên, bây giờ có một bước mới:
Thực tế là bây giờ chúng tôi không phân tích kết quả của việc hợp nhất, mà là HEAD của nhánh mà yêu cầu kéo được thực hiện:
Vì vậy, chúng tôi đang trong một cam kết có điều kiện B3 và chúng ta cần nhận được sự khác biệt từ 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
Để xác định A3 Hãy sử dụng API GitHub:
https://api.github.com/repos/${USERNAME}/${REPO}/pulls/${PULL_REQUEST_ID}
Chúng tôi đã sử dụng các biến sau do Buddy cung cấp:
- $BUDDY_EXECUTION_PULL_REQEUT_NO - số yêu cầu kéo;
- $BUDDY_REPO_SLUG - sự kết hợp giữa tên người dùng và kho lưu trữ (ví dụ: max / test).
Bây giờ, hãy lưu các thay đổi bằng nút bên dưới và bật phân tích yêu cầu kéo:
Không giống như Travis CI, chúng tôi không cần chỉ định .pvs-studio để tạo bộ nhớ đệm, vì Buddy tự động lưu trữ tất cả các tệp cho các lần khởi chạy tiếp theo. Do đó, điều cuối cùng còn lại là lưu tên đăng nhập và mật khẩu cho PVS-Studio trong Buddy. Sau khi lưu các thay đổi, chúng tôi sẽ quay lại Đường ống. Chúng ta cần vào phần cài đặt biến và thêm đăng nhập và khóa cho PVS-Studio:
Sau đó, sự xuất hiện của một yêu cầu kéo hoặc cam kết mới sẽ kích hoạt kiểm tra. Nếu một cam kết có lỗi, thì Buddy sẽ chỉ ra nó trên trang yêu cầu kéo.
Ứng dụngVeyor
Thiết lập AppVeyor tương tự như Buddy, vì mọi thứ diễn ra trong giao diện web và không cần thêm tệp *.yml vào kho dự án.
Hãy chuyển đến tab Cài đặt trong tổng quan dự án:
Hãy cuộn xuống trang này và kích hoạt tính năng tiết kiệm bộ đệm để xây dựng các yêu cầu kéo:
Bây giờ, hãy chuyển đến tab Môi trường, nơi chúng tôi chỉ định hình ảnh sẽ xây dựng và các biến môi trường cần thiết:
Nếu bạn đã đọc các phần trước, thì bạn đã rất quen thuộc với hai biến này - PVS_KEY и PVS_USERNAME. Nếu không, hãy để tôi nhắc bạn rằng họ cần phải kiểm tra giấy phép của máy phân tích PVS-Studio. Trong tương lai, chúng ta sẽ gặp lại chúng trong Bash script.
Trên cùng một trang bên dưới, chỉ định thư mục cho bộ nhớ đệm:
Nếu chúng tôi không làm điều này, thì chúng tôi sẽ phân tích toàn bộ dự án thay vì một vài tệp, nhưng chúng tôi sẽ nhận được đầu ra dựa trên các tệp đã chỉ định. Do đó, điều quan trọng là phải nhập đúng tên thư mục.
Bây giờ là lúc để kịch bản thử nghiệm. Mở tab Kiểm tra và chọn Tập lệnh:
Dán đoạn mã sau vào biểu mẫu này:
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
Chúng ta hãy xem phần sau của mã:
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
Việc gán giá trị khá cụ thể của lệnh pwd cho một biến lưu trữ giá trị mặc định này thoạt nhìn có vẻ lạ, tuy nhiên, tôi sẽ giải thích mọi thứ ngay sau đây.
Trong khi thiết lập bộ phân tích trong AppVeyor, tôi gặp phải một hành vi cực kỳ lạ của bộ phân tích. Một mặt, mọi thứ hoạt động chính xác, nhưng quá trình phân tích không bắt đầu. Tôi đã dành nhiều thời gian để nhận thấy rằng chúng tôi đang ở trong thư mục /home/appveyor/projects/testcalc/ và bộ phân tích chắc chắn rằng chúng tôi đang ở trong /opt/appveyor/build-agent/. Sau đó, tôi nhận ra rằng biến $PWD là một lời nói dối. Vì lý do này, tôi đã cập nhật thủ công giá trị của nó trước khi bắt đầu phân tích.
Và sau đó mọi thứ, như trước đây:
Bây giờ hãy xem xét đoạn mã sau:
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"`
Trong đó, chúng tôi nhận được sự khác biệt giữa các nhánh mà yêu cầu kéo được khai báo. Đối với điều này, chúng ta cần các biến môi trường sau:
- $APPVEYOR_PULL_REQUEST_NUMBER - số yêu cầu kéo;
- $APPVEYOR_REPO_NAME - tên người dùng và kho lưu trữ dự án.
Kết luận
Tất nhiên, chúng tôi chưa xem xét tất cả các dịch vụ tích hợp liên tục có thể có, tuy nhiên, tất cả chúng đều có đặc điểm công việc rất giống nhau. Ngoại trừ bộ nhớ đệm, mỗi dịch vụ đều tạo ra "chiếc xe đạp" của riêng mình, vì vậy mọi thứ luôn khác biệt.
Ở đâu đó, chẳng hạn như trong Travis-CI, một vài dòng mã và bộ nhớ đệm hoạt động hoàn hảo; ở đâu đó, như trong AppVeyor, bạn chỉ cần chỉ định thư mục trong cài đặt; nhưng ở đâu đó bạn cần tạo các khóa duy nhất và cố gắng thuyết phục hệ thống cho bạn cơ hội ghi đè lên đoạn đã lưu trong bộ nhớ cache. Do đó, nếu bạn muốn thiết lập phân tích yêu cầu kéo trên một dịch vụ tích hợp liên tục chưa được thảo luận ở trên, thì trước tiên hãy đảm bảo rằng bạn sẽ không gặp sự cố với bộ nhớ đệm.
Cám ơn vì sự quan tâm của bạn. Nếu một cái gì đó không thành công, thì hãy viết thư cho chúng tôi tại
Nếu bạn muốn chia sẻ bài viết này với độc giả nói tiếng Anh, vui lòng sử dụng liên kết bản dịch: Maxim Zvyagintsev.
Nguồn: www.habr.com