-
-
Notifications
You must be signed in to change notification settings - Fork 1
456 lines (370 loc) · 16.4 KB
/
ci.yml
File metadata and controls
456 lines (370 loc) · 16.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
build-and-test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
build_type: [Debug, Release]
include:
- os: ubuntu-latest
cc: clang
cxx: clang++
- os: macos-latest
cc: clang
cxx: clang++
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install dependencies (Ubuntu)
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake clang-format clang-tidy libzstd-dev libsodium-dev
- name: Install dependencies (macOS)
if: matrix.os == 'macos-latest'
run: |
brew install clang-format zstd libsodium || true
# cmake is already available on macOS runners
- name: Set up environment
run: |
echo "CC=${{ matrix.cc }}" >> $GITHUB_ENV
echo "CXX=${{ matrix.cxx }}" >> $GITHUB_ENV
- name: Configure CMake
run: |
cmake -B build \
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
-DCMAKE_C_COMPILER=${{ matrix.cc }} \
-DCMAKE_CXX_COMPILER=${{ matrix.cxx }} \
-DBFC_WITH_ZSTD=ON \
-DBFC_WITH_SODIUM=ON
- name: Build
run: cmake --build build --config ${{ matrix.build_type }} -j$(nproc 2>/dev/null || sysctl -n hw.ncpu)
- name: Run tests
if: matrix.build_type == 'Debug'
run: |
cd build
ctest --output-on-failure --parallel $(nproc 2>/dev/null || sysctl -n hw.ncpu)
- name: Test CLI functionality
run: |
# Create test data
mkdir -p test_data
echo "Hello World" > test_data/hello.txt
echo "Goodbye" > test_data/bye.txt
mkdir -p test_data/subdir
echo "Nested file" > test_data/subdir/nested.txt
# Test CLI workflow
./build/bin/bfc create test.bfc test_data/
./build/bin/bfc list test.bfc
./build/bin/bfc info test.bfc
./build/bin/bfc verify test.bfc
./build/bin/bfc verify --deep test.bfc
# Test compression functionality
./build/bin/bfc create -c zstd test_compressed.bfc test_data/
./build/bin/bfc info test_compressed.bfc test_data/hello.txt
./build/bin/bfc verify test_compressed.bfc
# Test different compression levels
./build/bin/bfc create -c zstd -l 1 test_fast.bfc test_data/
./build/bin/bfc create -c zstd -l 6 test_balanced.bfc test_data/
./build/bin/bfc info test_balanced.bfc test_data/hello.txt
# Test extraction
mkdir -p extract_test
cd extract_test
../build/bin/bfc extract ../test.bfc
# Verify extracted files
[ -f hello.txt ] && echo "hello.txt extracted"
[ -f bye.txt ] && echo "bye.txt extracted"
[ -f subdir/nested.txt ] && echo "nested.txt extracted"
cd ..
rm -rf extract_test
# Test symlink functionality
echo "Testing symlink functionality..."
# Create test data with symlinks
mkdir -p test_symlinks
cd test_symlinks
echo "Target file content" > target.txt
mkdir subdir
echo "Nested target" > subdir/nested.txt
# Create various types of symlinks
ln -sf target.txt simple_link.txt
ln -sf subdir/nested.txt relative_link.txt
ln -sf /tmp/absolute_target absolute_link.txt
ln -sf nonexistent_file broken_link.txt
ln -sf subdir dir_link
cd ..
# Test container creation with symlinks
./build/bin/bfc create test_symlinks.bfc test_symlinks/
echo "Container with symlinks created"
# Test symlink listing - verify 'l' prefix appears
./build/bin/bfc list -l test_symlinks.bfc | grep "lrwxr-xr-x.*simple_link.txt" && echo "Simple symlink listed correctly" || echo "Simple symlink listing failed"
./build/bin/bfc list -l test_symlinks.bfc | grep "lrwxr-xr-x.*absolute_link.txt" && echo "Absolute symlink listed correctly" || echo "Absolute symlink listing failed"
# Test symlink counting in container info
./build/bin/bfc info test_symlinks.bfc | grep "Symlinks:" && echo "Symlinks counted in container info" || echo "Symlink counting failed"
# Test symlink-specific info
./build/bin/bfc info test_symlinks.bfc simple_link.txt | grep "Type: Symlink" && echo "Symlink type displayed correctly" || echo "Symlink type display failed"
# Test symlink extraction
mkdir -p extract_symlinks
cd extract_symlinks
../build/bin/bfc extract ../test_symlinks.bfc
# Verify symlinks were extracted correctly
[ -L simple_link.txt ] && echo "Simple symlink extracted as symlink" || echo "Simple symlink not extracted as symlink"
[ -L broken_link.txt ] && echo "Broken symlink extracted as symlink" || echo "Broken symlink not extracted as symlink"
# Verify symlink targets
if [ -L simple_link.txt ]; then
TARGET=$(readlink simple_link.txt)
[ "$TARGET" = "target.txt" ] && echo "Simple symlink target correct" || echo "Simple symlink target incorrect: $TARGET"
fi
if [ -L absolute_link.txt ]; then
TARGET=$(readlink absolute_link.txt)
[ "$TARGET" = "/tmp/absolute_target" ] && echo "Absolute symlink target correct" || echo "Absolute symlink target incorrect: $TARGET"
fi
cd ..
rm -rf extract_symlinks
# Test symlinks with compression and encryption
./build/bin/bfc create -c zstd -e testpass symlinks_comp_enc.bfc test_symlinks/simple_link.txt test_symlinks/absolute_link.txt
echo "Symlinks work with compression and encryption"
mkdir -p extract_comp_enc
cd extract_comp_enc
../build/bin/bfc extract -p testpass ../symlinks_comp_enc.bfc
[ -L simple_link.txt ] && echo "Compressed+encrypted symlink extracted correctly" || echo "Compressed+encrypted symlink extraction failed"
cd ..
rm -rf extract_comp_enc
# Clean up symlink test files
rm -rf test_symlinks test_symlinks.bfc symlinks_comp_enc.bfc
# Test encryption functionality
echo "Testing encryption features..."
./build/bin/bfc create -e testpassword123 test_encrypted.bfc test_data/
./build/bin/bfc info test_encrypted.bfc
./build/bin/bfc info test_encrypted.bfc test_data/hello.txt | grep -i encrypt
# Test encrypted extraction
mkdir -p extract_encrypted
cd extract_encrypted
../build/bin/bfc extract -p testpassword123 ../test_encrypted.bfc
# Verify extracted files from encrypted container
[ -f hello.txt ] && echo "hello.txt extracted from encrypted container"
[ -f bye.txt ] && echo "bye.txt extracted from encrypted container"
[ -f subdir/nested.txt ] && echo "nested.txt extracted from encrypted container"
cd ..
rm -rf extract_encrypted
# Test wrong password failure
mkdir -p extract_fail_test
cd extract_fail_test
! ../build/bin/bfc extract -p wrongpassword ../test_encrypted.bfc && echo "Correctly failed with wrong password"
cd ..
rm -rf extract_fail_test
# Test key file encryption
echo -n "0123456789abcdef0123456789abcdef" > test.key
./build/bin/bfc create -k test.key test_keyfile.bfc test_data/
./build/bin/bfc info test_keyfile.bfc | grep -i encrypt
mkdir -p extract_keyfile
cd extract_keyfile
../build/bin/bfc extract -K ../test.key ../test_keyfile.bfc
[ -f hello.txt ] && echo "hello.txt extracted with key file"
cd ..
rm -rf extract_keyfile
# Test encryption with compression
echo "This is a larger test file with enough content to be compressed by zstd compression algorithm." > test_data/large.txt
./build/bin/bfc create -e testpass -c zstd test_enc_comp.bfc test_data/
./build/bin/bfc info test_enc_comp.bfc test_data/large.txt | grep -i encrypt
./build/bin/bfc info test_enc_comp.bfc test_data/large.txt | grep -i zstd
# Clean up
rm -rf test.bfc test_data test_compressed.bfc test_fast.bfc test_balanced.bfc
rm -rf test_encrypted.bfc test_keyfile.bfc test_enc_comp.bfc test.key
- name: Run benchmarks
run: |
cd build/benchmarks
./benchmark_crc32c
# Run compression benchmark (quick test)
timeout 60s ./benchmark_compress || gtimeout 60s ./benchmark_compress || echo "Compression benchmark completed or timed out"
# Run with timeout (different commands for Linux vs macOS)
if command -v timeout >/dev/null 2>&1; then
timeout 30s ./benchmark_writer || true
timeout 30s ./benchmark_reader || true
elif command -v gtimeout >/dev/null 2>&1; then
gtimeout 30s ./benchmark_writer || true
gtimeout 30s ./benchmark_reader || true
else
# macOS without coreutils - run without timeout
echo "Running benchmarks without timeout on macOS..."
./benchmark_writer &
WRITER_PID=$!
sleep 10 && kill $WRITER_PID 2>/dev/null || true
wait $WRITER_PID 2>/dev/null || true
./benchmark_reader &
READER_PID=$!
sleep 10 && kill $READER_PID 2>/dev/null || true
wait $READER_PID 2>/dev/null || true
fi
- name: Check code formatting (Ubuntu Debug only)
if: matrix.os == 'ubuntu-latest' && matrix.build_type == 'Debug'
run: |
find src include tests examples -name "*.c" -o -name "*.h" | xargs clang-format --dry-run --Werror
coverage:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake lcov bc libzstd-dev libsodium-dev
- name: Configure CMake with coverage
run: |
cmake -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DBFC_COVERAGE=ON \
-DBFC_WITH_ZSTD=ON \
-DBFC_WITH_SODIUM=ON \
-DBFC_BUILD_BENCHMARKS=OFF \
-DCMAKE_C_FLAGS="--coverage -fprofile-arcs -ftest-coverage"
- name: Build
run: cmake --build build -j$(nproc)
- name: Run tests
run: |
cd build
ctest --output-on-failure
- name: Generate coverage report
run: |
cd build
lcov --capture --directory . --output-file coverage.info \
--rc branch_coverage=1 \
--ignore-errors deprecated,unsupported,unused
lcov --remove coverage.info \
'*/tests/*' \
--output-file coverage_filtered.info \
--rc branch_coverage=1 \
--ignore-errors deprecated,unsupported,unused
lcov --list coverage_filtered.info \
--rc branch_coverage=1 \
--ignore-errors deprecated,unsupported,unused
- name: Check coverage thresholds
run: |
cd build
# Generate summary and check thresholds
lcov --summary coverage_filtered.info \
--rc branch_coverage=1 \
--ignore-errors deprecated,unsupported,unused > coverage_summary.txt 2>&1
# Extract coverage percentages
LINE_COV=$(grep "lines" coverage_summary.txt | grep -o '[0-9]\+\.[0-9]\+%' | head -1 | sed 's/%//')
FUNC_COV=$(grep "functions" coverage_summary.txt | grep -o '[0-9]\+\.[0-9]\+%' | head -1 | sed 's/%//')
BRANCH_COV=$(grep "branches" coverage_summary.txt | grep -o '[0-9]\+\.[0-9]\+%' | head -1 | sed 's/%//')
echo "Coverage Summary:"
echo "Lines: ${LINE_COV}%"
echo "Functions: ${FUNC_COV}%"
echo "Branches: ${BRANCH_COV}%"
# Set coverage threshold
THRESHOLD=75
# Check thresholds using bc for floating point comparison
if command -v bc >/dev/null 2>&1; then
LINE_FAIL=$(echo "${LINE_COV} < ${THRESHOLD}" | bc -l)
FUNC_FAIL=$(echo "${FUNC_COV} < 95" | bc -l) # High threshold for functions
if [ "${LINE_FAIL}" = "1" ]; then
echo "ERROR: Line coverage ${LINE_COV}% is below threshold ${THRESHOLD}%"
exit 1
fi
if [ "${FUNC_FAIL}" = "1" ]; then
echo "ERROR: Function coverage ${FUNC_COV}% is below threshold 95%"
exit 1
fi
echo "All coverage thresholds met!"
else
echo "bc not available, skipping threshold checks"
fi
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: build/coverage_filtered.info
fail_ci_if_error: false
static-analysis:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake clang-tidy cppcheck libzstd-dev libsodium-dev
- name: Configure CMake
run: cmake -B build -DCMAKE_BUILD_TYPE=Debug -DBFC_WITH_ZSTD=ON -DBFC_WITH_SODIUM=ON
- name: Run clang-tidy
run: |
cd build
run-clang-tidy -p . ../src/ || true
- name: Run cppcheck
run: |
cppcheck --enable=all --inconclusive --xml --xml-version=2 \
--suppress=missingIncludeSystem \
--suppress=unmatchedSuppression \
src/ include/ 2> cppcheck.xml || true
# Show results (non-blocking)
cat cppcheck.xml
security:
runs-on: ubuntu-latest
# Add permissions for security scanning
permissions:
contents: read
security-events: write
actions: read
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run CodeQL Analysis
uses: github/codeql-action/init@v3
with:
languages: cpp
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake libzstd-dev libsodium-dev
- name: Build for CodeQL
run: |
cmake -B build -DCMAKE_BUILD_TYPE=Release -DBFC_WITH_ZSTD=ON -DBFC_WITH_SODIUM=ON -DBFC_BUILD_BENCHMARKS=OFF
cmake --build build
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
documentation:
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
# Add permissions for GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Environment for GitHub Pages deployment
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y doxygen graphviz
- name: Generate documentation
run: |
# Create Doxygen config if it doesn't exist
if [ ! -f Doxyfile ]; then
doxygen -g
sed -i 's/PROJECT_NAME = "My Project"/PROJECT_NAME = "BFC"/' Doxyfile
sed -i 's/INPUT =/INPUT = include\/ src\/ README.md/' Doxyfile
sed -i 's/RECURSIVE = NO/RECURSIVE = YES/' Doxyfile
sed -i 's/GENERATE_HTML = YES/GENERATE_HTML = YES/' Doxyfile
sed -i 's/OUTPUT_DIRECTORY =/OUTPUT_DIRECTORY = docs/' Doxyfile
fi
doxygen Doxyfile
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: docs/html
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4