Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
W analizatorze PVS-Studio dla języków C i C++ na systemach Linux i macOS począwszy od wersji 7.04 pojawiła się opcja testowa pozwalająca sprawdzić listę określonych plików. Korzystając z nowego trybu, możesz skonfigurować analizator tak, aby sprawdzał zatwierdzenia i żądania ściągnięcia. W tym artykule dowiesz się jak skonfigurować sprawdzanie listy zmienionych plików projektu GitHub w tak popularnych systemach CI (Continious Integration), jak Travis CI, Buddy i AppVeyor.

Tryb sprawdzania listy plików

Studio PVS to narzędzie służące do identyfikacji błędów i potencjalnych podatności w kodzie źródłowym programów napisanych w językach C, C++, C# i Java. Działa na systemach 64-bitowych Windows, Linux i macOS.

W wersji PVS-Studio 7.04 dla systemów Linux i macOS pojawił się tryb sprawdzania listy plików źródłowych. Działa to w przypadku projektów, których system kompilacji umożliwia wygenerowanie pliku build_commands.json. Jest potrzebne, aby analizator wydobył informacje o kompilacji określonych plików. Jeśli Twój system kompilacji nie obsługuje generowania pliku Compare_commands.json, możesz spróbować wygenerować taki plik za pomocą narzędzia Niedźwiedź.

Ponadto trybu sprawdzania listy plików można używać razem z dziennikiem śledzenia uruchomień kompilatora (śledzenie pvs-studio-analyzer). Aby to zrobić, należy najpierw wykonać pełną kompilację projektu i prześledzić ją, aby analizator zebrał kompletną informację o parametrach kompilacji wszystkich sprawdzanych plików.

Opcja ta ma jednak istotną wadę – albo przy każdym uruchomieniu będziesz musiał wykonać pełne śledzenie kompilacji całego projektu, co samo w sobie jest sprzeczne z ideą szybkiego sprawdzania zatwierdzenia. Lub, jeśli buforujesz sam wynik śledzenia, kolejne uruchomienia analizatora mogą być niekompletne, jeśli struktura zależności plików źródłowych zmieni się po śledzeniu (na przykład nowy #include zostanie dodany do jednego z plików źródłowych).

Dlatego nie zalecamy używania trybu sprawdzania listy plików z dziennikiem śledzenia do sprawdzania zatwierdzeń lub żądań ściągnięcia. Jeśli podczas sprawdzania zatwierdzenia możesz wykonać kompilację przyrostową, rozważ użycie tego trybu analiza przyrostowa.

Lista plików źródłowych do analizy zapisywana jest w pliku tekstowym i przekazywana do analizatora za pomocą parametru -S:

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

Ten plik określa względne lub bezwzględne ścieżki do plików, a każdy nowy plik musi znajdować się w nowej linii. Dopuszczalne jest podanie nie tylko nazw plików do analizy, ale także różnych tekstów. Analizator zobaczy, że nie jest to plik i zignoruje linię. Może to być przydatne do komentowania, jeśli pliki są określone ręcznie. Jednak często podczas analizy w CI generowana jest lista plików, na przykład mogą to być pliki z żądania zatwierdzenia lub ściągnięcia.

Teraz, korzystając z tego trybu, możesz szybko sprawdzić nowy kod, zanim trafi on do głównej gałęzi programistycznej. Aby mieć pewność, że system skanujący zareaguje na ostrzeżenia analizatora, narzędzie konwerter plogów dodana flaga --wskaż-ostrzeżenia:

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

Dzięki tej fladze konwerter zwróci niezerowy kod, jeśli w raporcie analizatora pojawią się ostrzeżenia. Korzystając z kodu powrotu, możesz zablokować żądanie przechwycenia wstępnego, zatwierdzenia lub ściągnięcia, a wygenerowany raport analizatora można wyświetlić, udostępnić lub wysłać pocztą elektroniczną.

Notatka. Kiedy po raz pierwszy zaczniesz analizować listę plików, analizowany będzie cały projekt, ponieważ analizator musi wygenerować plik zależności plików źródłowych projektu od plików nagłówkowych. Jest to funkcja analizy plików C i C++. W przyszłości plik zależności może zostać buforowany i będzie automatycznie aktualizowany przez analizator. Zaletą sprawdzania zatwierdzeń w trybie sprawdzania listy plików w porównaniu z trybem analizy przyrostowej jest to, że wystarczy buforować tylko ten plik, a nie pliki obiektowe.

Ogólne zasady analizy pull requestów

Analiza całego projektu zajmuje dużo czasu, dlatego warto sprawdzić tylko jego pewną część. Problem polega na tym, że musisz oddzielić nowe pliki od pozostałych plików projektu.

Spójrzmy na przykład drzewa zatwierdzeń z dwiema gałęziami:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio

Wyobraźmy sobie to zatwierdzenie A1 zawiera dość dużą ilość kodu, który został już przetestowany. Nieco wcześniej zrobiliśmy gałąź z zatwierdzenia A1 i zmieniłem niektóre pliki.

Oczywiście zauważyłeś to później A1 doszło do jeszcze dwóch zatwierdzeń, ale były to także fuzje innych oddziałów, bo się do tego nie zobowiązujemy mistrz. A teraz nadszedł czas, kiedy poprawka gotowy. Dlatego pojawił się pull request dotyczący fuzji B3 и A3.

Oczywiście dałoby się sprawdzić cały wynik ich połączenia, ale byłoby to zbyt czasochłonne i nieuzasadnione, gdyż zmienionych zostało tylko kilka plików. Dlatego bardziej efektywne jest analizowanie tylko tych zmienionych.

Aby to zrobić, uzyskujemy różnicę między gałęziami, będąc w HEAD gałęzi, z której chcemy się połączyć w master:

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

$MERGE_BASE przyjrzymy się temu szczegółowo później. Faktem jest, że nie każda usługa CI dostarcza niezbędnych informacji o bazie danych do fuzji, dlatego za każdym razem trzeba wymyślać nowe sposoby pozyskania tych danych. Zostanie to szczegółowo opisane poniżej w każdej z opisanych usług sieciowych.

Otrzymaliśmy więc różnicę między gałęziami, a raczej listę nazw plików, które zostały zmienione. Teraz musimy podać plik .pvs-pr.list (przekierowaliśmy do niego powyższe dane wyjściowe) do analizatora:

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

Po analizie musimy przekonwertować plik logu (PVS-Studio.log) do łatwego do odczytania formatu:

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

To polecenie wyświetli listę błędów stderr (standardowe wyjście komunikatu o błędzie).

Dopiero teraz musimy nie tylko wyświetlić błędy, ale także poinformować nasz serwis montażu i testowania o występowaniu problemów. W tym celu do konwertera dodana została flaga -W (--wskaż-ostrzeżenia). Jeśli występuje co najmniej jedno ostrzeżenie analizatora, kod powrotu narzędzia konwerter plogów zmieni się na 2, co z kolei poinformuje usługę CI o obecności potencjalnych błędów w plikach pull request.

Travis CI

Konfiguracja dokonywana jest w formie pliku .travis.yml. Dla wygody radzę umieścić wszystko w osobnym skrypcie bashowym z funkcjami, które będą wywoływane z pliku .travis.yml (bash nazwa_skryptu.sh nazwa_funkcji).

Niezbędny kod dodamy do skryptu pod adresem bash, w ten sposób uzyskamy większą funkcjonalność. W sekcji zainstalować napiszmy co następuje:

install:
  - bash .travis.sh travis_install

Jeśli miałeś jakieś instrukcje, możesz przenieść je do skryptu, usuwając łączniki.

Otwórzmy plik .travis.sh i dodaj ustawienie analizatora do funkcji 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 
}

Teraz dodajmy do sekcji scenariusz uruchom analizę:

script:
  - bash .travis.sh travis_script

A w skrypcie basha:

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
}

Ten kod należy uruchomić po zbudowaniu projektu, na przykład, jeśli masz kompilację na CMake:

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

To się okaże tak:

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
}

Prawdopodobnie zauważyłeś już te zmienne środowiskowe $TRAVIS_PULL_REQUEST и $TRAVIS_BRANCH. Travis CI deklaruje je niezależnie:

  • $TRAVIS_PULL_REQUEST przechowuje numer żądania ściągnięcia lub fałszywy, jeśli jest to zwykła gałąź;
  • $TRAVIS_REPO_SLUG przechowuje nazwę repozytorium projektu.

Algorytm tej funkcji:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
Travis CI reaguje na kody zwrotne, więc obecność ostrzeżeń poinformuje usługę o oznaczeniu zatwierdzenia jako zawierającego błędy.

Przyjrzyjmy się teraz bliżej tej linijce kodu:

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

Faktem jest, że Travis CI automatycznie łączy gałęzie podczas analizy żądania ściągnięcia:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
Dlatego analizujemy A4I nie B3->A3. Ze względu na tę funkcję musimy obliczyć różnicę za pomocą A3, czyli dokładnie szczyt gałęzi pochodzenie.

Pozostał jeszcze jeden ważny szczegół - buforowanie zależności plików nagłówkowych od skompilowanych jednostek tłumaczeniowych (*.c, *.cc, *.cpp itp.). Analizator oblicza te zależności przy pierwszym uruchomieniu w trybie sprawdzania listy plików, a następnie zapisuje je w katalogu .PVS-Studio. Travis CI umożliwia buforowanie folderów, dzięki czemu zapiszemy dane katalogowe .PVS-Studio/:

cache:
  directories:
    - .PVS-Studio/

Ten kod należy dodać do pliku .travis.yml. W tym katalogu przechowywane są różne dane zebrane po analizie, co znacznie przyspieszy kolejne przebiegi analizy listy plików lub analizy przyrostowej. Jeśli tego nie zrobimy, analizator będzie faktycznie za każdym razem analizował wszystkie pliki.

Kumpel

Podobnie jak Travis CI, Kumpel zapewnia możliwość automatycznego budowania i testowania projektów przechowywanych w GitHub. W przeciwieństwie do Travis CI, konfiguruje się go w interfejsie WWW (dostępna jest obsługa basha), dzięki czemu nie ma potrzeby przechowywania plików konfiguracyjnych w projekcie.

Na początek musimy dodać nową akcję do linii montażowej:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
Wskażmy kompilator, który został użyty do zbudowania projektu. Zwróć uwagę na kontener dokowany, który jest zainstalowany w tej akcji. Na przykład istnieje specjalny kontener dla GCC:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
Teraz zainstalujmy PVS-Studio i niezbędne narzędzia:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
Dodajmy do edytora następujące linie:

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

Przejdźmy teraz do zakładki Uruchom (pierwsza ikona) i do odpowiedniego pola edytora dodajmy następujący kod:

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

Jeśli czytasz sekcję Travs-CI, to ten kod jest już ci znany, jednak teraz jest nowy etap:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
Faktem jest, że teraz analizujemy nie wynik scalania, ale HEAD gałęzi, z której pochodzi żądanie ściągnięcia:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
Jesteśmy więc w trakcie zatwierdzenia warunkowego B3 i musimy znaleźć różnicę 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

Aby określić A3 Skorzystajmy z API GitHuba:

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

Użyliśmy następujących zmiennych udostępnianych przez Buddy:

  • $BUDDY_EXECUTION_PULL_REQEUST_NO — numer żądania ściągnięcia;
  • $BUDDY_REPO_SLUG — kombinacja nazwy użytkownika i repozytorium (na przykład max/test).

Teraz zapiszmy zmiany za pomocą przycisku poniżej i włączmy analizę pull requestu:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
W przeciwieństwie do Travisa CI, nie musimy podawać szczegółów .pvs-studio do buforowania, ponieważ Buddy automatycznie buforuje wszystkie pliki przy kolejnych uruchomieniach. Dlatego ostatnią rzeczą, jaką pozostało, jest zapisanie loginu i hasła do PVS-Studio w Buddy. Po zapisaniu zmian zostaniemy przeniesieni z powrotem do Pipeline. Musimy przejść do ustawienia zmiennych oraz dodania loginu i klucza do PVS-Studio:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
Następnie pojawienie się nowego żądania ściągnięcia lub zatwierdzenia uruchomi przegląd. Jeśli zatwierdzenie zawiera błędy, Buddy wskaże to na stronie żądania ściągnięcia.

AppVeyor

Konfiguracja AppVeyor jest podobna do Buddy, ponieważ wszystko dzieje się w interfejsie internetowym i nie ma potrzeby dodawania pliku *.yml do repozytorium projektu.

Przejdźmy do zakładki Ustawienia w przeglądzie projektu:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
Przewińmy tę stronę w dół i włączmy zapisywanie pamięci podręcznej w celu gromadzenia żądań ściągnięcia:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
Przejdźmy teraz do zakładki Środowisko, gdzie określamy obraz do montażu oraz niezbędne zmienne środowiskowe:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
Jeśli przeczytałeś poprzednie sekcje, dobrze znasz te dwie zmienne − PVS_KEY и NAZWA UŻYTKOWNIKA PVS. Jeśli nie, przypominam, że są one niezbędne do weryfikacji licencji analizatora PVS-Studio. Zobaczymy je ponownie w skryptach Bash w przyszłości.

Na tej samej stronie poniżej wskazujemy folder do buforowania:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
Jeśli tego nie zrobimy, przeanalizujemy cały projekt zamiast kilku plików, ale wynik otrzymamy z określonych plików. Dlatego ważne jest, aby wprowadzić poprawną nazwę katalogu.

Teraz czas na testowanie skryptu. Otwórz zakładkę Testy i wybierz Skrypt:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
Musisz wkleić następujący kod do tego formularza:

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

Zwróćmy uwagę na następującą część kodu:

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

Dość specyficzne przypisanie wartości polecenia pwd do zmiennej, która powinna przechowywać tę domyślną wartość, na pierwszy rzut oka wydaje się dziwne, jednak wszystko wyjaśnię teraz.

Konfigurując analizator w AppVeyor, spotkałem się z niezwykle dziwnym zachowaniem analizatora. Z jednej strony wszystko działało poprawnie, ale analiza się nie rozpoczęła. Spędziłem dużo czasu zauważając, że jesteśmy w katalogu /home/appveyor/projects/testcalc/, a analizator jest pewien, że jesteśmy w /opt/appveyor/build-agent/. Potem zdałem sobie sprawę, że zmienna $PWD trochę kłamie. Z tego powodu ręcznie zaktualizowałem jego wartość przed rozpoczęciem analizy.

A potem wszystko jest jak poprzednio:

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio
Rozważmy teraz następujący fragment:

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"`

Otrzymujemy w nim różnicę między gałęziami, na których zadeklarowane jest żądanie ściągnięcia. Aby to zrobić, potrzebujemy następujących zmiennych środowiskowych:

  • $APPVEYOR_PULL_REQUEST_NUMBER — numer żądania ściągnięcia;
  • $APPVEYOR_REPO_NAME - nazwa użytkownika i repozytorium projektu.

wniosek

Oczywiście nie uwzględniliśmy wszystkich możliwych usług ciągłej integracji, jednak wszystkie mają do siebie niezwykle podobną specyfikę działania. Z wyjątkiem buforowania, każda usługa tworzy swój własny „rower”, więc wszystko jest zawsze inne.

Gdzieś, jak w Travis-CI, kilka linijek kodu i buforowanie działa bez zarzutu; gdzieś, jak w AppVeyor, wystarczy określić folder w ustawieniach; ale gdzieś musisz utworzyć unikalne klucze i spróbować przekonać system, aby dał ci możliwość zastąpienia fragmentu z pamięci podręcznej. Dlatego jeśli chcesz skonfigurować analizę pull requestów w usłudze ciągłej integracji, która nie została omówiona powyżej, najpierw upewnij się, że nie będziesz mieć problemów z buforowaniem.

Dziękuję za uwagę. Jeśli coś nie wyjdzie, śmiało napisz do nas na adres wsparcie. Doradzimy i pomożemy.

Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio

Jeśli chcesz udostępnić ten artykuł anglojęzycznej publiczności, skorzystaj z linku do tłumaczenia: Maxim Zwiagincew. Analiza zatwierdzeń i żądań ściągnięcia w Travis CI, Buddy i AppVeyor przy użyciu PVS-Studio.

Źródło: www.habr.com

Dodaj komentarz