blob: ae41f862a1dfb2b2443566f6c2e34a3a21e828bf [file] [log] [blame]
Dmytro Shteflyuk3346c012026-02-13 17:40:41 -05001name: "Static Code Analysis"
2
3on:
4 push:
5 branches: ["*"]
6 pull_request:
7 branches: ["*"]
8 workflow_dispatch:
9
10env:
11 BUILD_DEPS: automake bison flex git libboost-all-dev libevent-dev libssl-dev libtool make pkg-config
12 SCA_DEPS: cppcheck python3-flake8 sloccount libglib2.0-dev
13 # Disable all languages for which we don't have SCA checks in place
14 CONFIG_ARGS_FOR_SCA: >
15 --enable-tutorial=no
16 --disable-debug
17 --disable-tests
18 --disable-dependency-tracking
19 --without-java
20 --without-kotlin
21 --without-netstd
22 --without-nodejs
23 --without-nodets
24 --without-swift
25 --without-go
26 --without-dart
27 --without-erlang
28 --without-haxe
29 --without-ruby
30 --without-rs
31 --without-lua
32 --without-perl
33 --without-d
34 --without-cl
35
36permissions:
37 contents: read
38
39jobs:
40 sca:
41 runs-on: ubuntu-24.04
42 steps:
43 - uses: actions/checkout@v6
44
45 - name: Install dependencies
46 run: |
47 sudo apt-get update -yq
48 sudo apt-get install -y --no-install-recommends g++ $BUILD_DEPS $SCA_DEPS
49
50 - name: Set up PHP
51 uses: shivammathur/setup-php@v2
52 with:
53 # Lowest supported PHP version
54 php-version: "7.1"
55 extensions: mbstring, xml, curl, pcntl
56
57 - uses: actions/setup-python@v6
58 with:
59 python-version: "3.12"
60
61 - name: Install Python test dependencies
62 run: |
63 python -m pip install --upgrade pip setuptools wheel flake8
64
Dmytro Shteflyukdf22bb12025-12-20 13:41:21 -050065 - name: Set up Ruby
66 uses: ruby/setup-ruby@v1
67 with:
68 ruby-version: "2.7"
69 bundler-cache: true
70 working-directory: "lib/rb"
71
Dmytro Shteflyuk3346c012026-02-13 17:40:41 -050072 # Generate thrift files so the static code analysis includes an analysis
73 # of the files the thrift compiler spits out.
74 - name: Build compiler
75 id: compile
76 run: |
77 ./bootstrap.sh
78 ./configure $CONFIG_ARGS_FOR_SCA
79 make -j$(nproc) -C compiler/cpp
80
81 - name: Run cppcheck
82 id: cppcheck
83 continue-on-error: true
84 run: |
85 make -j$(nproc) -C lib/cpp
86 make -j$(nproc) -C test/cpp precross
87
88 make -j$(nproc) -C lib/c_glib
89 make -j$(nproc) -C test/c_glib precross
90
91 # Compiler cppcheck (All)
92 cppcheck --force --quiet --inline-suppr --enable=all -j2 compiler/cpp/src
93
94 # C++ cppcheck (All)
95 cppcheck --force --quiet --inline-suppr --enable=all -j2 lib/cpp/src lib/cpp/test test/cpp tutorial/cpp
96
97 # C Glib cppcheck (All)
98 cppcheck --force --quiet --inline-suppr --enable=all -j2 lib/c_glib/src lib/c_glib/test test/c_glib/src tutorial/c_glib
99
100 # Silent error checks
101 # See THRIFT-4371: flex generated scanner code causes false positives in cppcheck.
102 # suppress *:thrift/thriftl.cc -> flex-generated lexer triggers false null pointer paths.
103 # suppress syntaxError:thrift/thrifty.cc -> bison-generated parser is not fully parseable.
104 # suppress normalCheckLevelMaxBranches:compiler/cpp/src/* -> avoid info-only branch limit noise.
105 cppcheck --force --quiet --inline-suppr \
106 --suppress="*:thrift/thriftl.cc" \
107 --suppress="syntaxError:thrift/thrifty.cc" \
108 --suppress="normalCheckLevelMaxBranches:compiler/cpp/src/*" \
109 --error-exitcode=1 -j2 compiler/cpp/src
110
111 # suppress unknownMacro:lib/cpp/src/thrift/qt/* -> Qt namespace macro needs Qt preprocessing.
112 # suppress unknownMacro:lib/cpp/test/* -> Boost.Test macros are unresolved in standalone analysis.
113 # suppress syntaxError:lib/cpp/src/thrift/transport/TSSLSocket.cpp -> OpenSSL macro branches confuse parser.
114 # suppress normalCheckLevelMaxBranches:* -> avoid info-only branch limit noise.
115 # exclude lib/cpp/test/gen-cpp and test/cpp/gen-* -> generated fixtures duplicate source/test coverage.
116 cppcheck --force --quiet --inline-suppr \
117 --suppress="unknownMacro:lib/cpp/src/thrift/qt/*" \
118 --suppress="unknownMacro:lib/cpp/test/*" \
119 --suppress="syntaxError:lib/cpp/src/thrift/transport/TSSLSocket.cpp" \
120 --suppress="normalCheckLevelMaxBranches:lib/cpp/src/*" \
121 --suppress="normalCheckLevelMaxBranches:lib/cpp/test/*" \
122 --suppress="normalCheckLevelMaxBranches:test/cpp/*" \
123 --suppress="normalCheckLevelMaxBranches:tutorial/cpp/*" \
124 -i lib/cpp/test/gen-cpp \
125 -i test/cpp/gen-cpp \
126 -i test/cpp/gen-cpp-forward \
127 -i test/cpp/gen-cpp-private \
128 -i test/cpp/gen-cpp-enumclass \
129 --error-exitcode=1 -j2 lib/cpp/src lib/cpp/test test/cpp tutorial/cpp
130
131 # suppress unknownMacro:lib/c_glib/src/* -> GObject type macros are unresolved in standalone analysis.
132 # suppress unknownMacro:lib/c_glib/test/* -> test-side GLib macros are unresolved without full preprocess.
133 # suppress syntaxError:lib/c_glib/test/* -> GLib assert macros parse as syntax errors.
134 # suppress normalCheckLevelMaxBranches:* -> avoid info-only branch limit noise.
135 # exclude lib/c_glib/test/gen-c_glib -> generated bindings are covered by generator output checks.
136 # exclude lib/c_glib/test/gen-cpp -> generated skeleton has placeholder methods without returns.
137 cppcheck --force --quiet --inline-suppr \
138 --suppress="unknownMacro:lib/c_glib/src/*" \
139 --suppress="unknownMacro:lib/c_glib/test/*" \
140 --suppress="syntaxError:lib/c_glib/test/*" \
141 --suppress="normalCheckLevelMaxBranches:lib/c_glib/src/*" \
142 --suppress="normalCheckLevelMaxBranches:lib/c_glib/test/*" \
143 --suppress="normalCheckLevelMaxBranches:test/c_glib/*" \
144 --suppress="normalCheckLevelMaxBranches:tutorial/c_glib/*" \
145 -i lib/c_glib/test/gen-c_glib \
146 -i lib/c_glib/test/gen-cpp \
147 --error-exitcode=1 -j2 lib/c_glib/src lib/c_glib/test test/c_glib/src tutorial/c_glib
148
149 - name: Run flake8
150 id: flake8
151 continue-on-error: true
152 run: |
153 make -j$(nproc) -C test/py precross
154
155 flake8
156
157 - name: Run phpcs
158 id: phpcs
159 continue-on-error: true
160 run: |
161 # PHP code style
162 composer install --quiet
163 ./vendor/bin/phpcs
164
Dmytro Shteflyukdf22bb12025-12-20 13:41:21 -0500165 - name: Run rubocop
166 id: rubocop
167 continue-on-error: true
168 working-directory: "lib/rb"
169 run: |
170 bundle exec rubocop --config .rubocop.yml --format progress --format github . ../../test/rb ../../tutorial/rb
171
Dmytro Shteflyuk3346c012026-02-13 17:40:41 -0500172 - name: Print statistics
173 if: ${{ always() }}
174 run: |
175 # TODO etc
176 echo "FIXMEs: $(grep -r FIXME * | wc -l)"
177 echo "HACKs: $(grep -r HACK * | wc -l)"
178 echo "TODOs: $(grep -r TODO * | wc -l)"
179
180 # LoC
181 sloccount .
182
183 # System info
184 # dpkg -l
185 uname -a
186
187 - name: Fail if any SCA check failed
188 if: ${{ always() && steps.compile.outcome == 'success' }}
189 env:
190 CPPCHECK_OUTCOME: ${{ steps.cppcheck.outcome }}
191 FLAKE8_OUTCOME: ${{ steps.flake8.outcome }}
192 PHPCS_OUTCOME: ${{ steps.phpcs.outcome }}
Dmytro Shteflyukdf22bb12025-12-20 13:41:21 -0500193 RUBOCOP_OUTCOME: ${{ steps.rubocop.outcome }}
Dmytro Shteflyuk3346c012026-02-13 17:40:41 -0500194 run: |
195 failed=0
196
197 if [ "$CPPCHECK_OUTCOME" != "success" ]; then
198 echo "::error::Step 'cppcheck' failed (outcome: $CPPCHECK_OUTCOME)"
199 failed=1
200 fi
201 if [ "$FLAKE8_OUTCOME" != "success" ]; then
202 echo "::error::Step 'flake8' failed (outcome: $FLAKE8_OUTCOME)"
203 failed=1
204 fi
205 if [ "$PHPCS_OUTCOME" != "success" ]; then
206 echo "::error::Step 'phpcs' failed (outcome: $PHPCS_OUTCOME)"
207 failed=1
208 fi
Dmytro Shteflyukdf22bb12025-12-20 13:41:21 -0500209 if [ "$RUBOCOP_OUTCOME" != "success" ]; then
210 echo "::error::Step 'rubocop' failed (outcome: $RUBOCOP_OUTCOME)"
211 failed=1
212 fi
Dmytro Shteflyuk3346c012026-02-13 17:40:41 -0500213
214 exit $failed