Skip to content
This repository was archived by the owner on Jun 18, 2026. It is now read-only.

security: HTML-escape vertex names in Swing panel controllers (CWE-79) #632

security: HTML-escape vertex names in Swing panel controllers (CWE-79)

security: HTML-escape vertex names in Swing panel controllers (CWE-79) #632

Workflow file for this run

name: Code Coverage
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
permissions:
contents: read
jobs:
coverage:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up JDK 17
uses: actions/setup-java@v5
with:
java-version: 17
distribution: temurin
- name: Download test dependencies
run: |
mkdir -p Gvisual/lib/test
# JUnit 4 + Hamcrest
curl -sL -o Gvisual/lib/test/junit-4.13.2.jar \
https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar
curl -sL -o Gvisual/lib/test/hamcrest-core-1.3.jar \
https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
# JaCoCo agent + CLI for coverage instrumentation and reporting
curl -sL -o /tmp/jacoco.zip \
https://repo1.maven.org/maven2/org/jacoco/jacoco/0.8.12/jacoco-0.8.12.zip
unzip -o /tmp/jacoco.zip -d /tmp/jacoco
cp /tmp/jacoco/lib/jacocoagent.jar Gvisual/lib/test/jacocoagent.jar
cp /tmp/jacoco/lib/jacococli.jar Gvisual/lib/test/jacococli.jar
- name: Compile source
working-directory: Gvisual
run: |
mkdir -p build/classes
find src -name '*.java' > sources.txt
javac -source 8 -target 8 \
-cp "$(find lib -name '*.jar' -not -path 'lib/test/*' | tr '\n' ':')" \
-d build/classes \
@sources.txt
- name: Compile tests
working-directory: Gvisual
run: |
mkdir -p build/test/classes
find test -name '*.java' > test-sources.txt
javac -source 8 -target 8 \
-cp "build/classes:$(find lib -name '*.jar' | tr '\n' ':')" \
-d build/test/classes \
@test-sources.txt
- name: Run tests with JaCoCo coverage
working-directory: Gvisual
run: |
java \
-javaagent:lib/test/jacocoagent.jar=destfile=build/jacoco.exec,includes=gvisual.*:app.* \
-cp "build/classes:build/test/classes:$(find lib -name '*.jar' | tr '\n' ':')" \
org.junit.runner.JUnitCore \
app.UtilMethodsTest \
gvisual.EdgeTest \
gvisual.GraphStatsTest \
gvisual.ShortestPathFinderTest \
gvisual.CommunityDetectorTest \
gvisual.GraphMLExporterTest
- name: Generate coverage report
working-directory: Gvisual
run: |
mkdir -p build/coverage
# Generate HTML report
java -jar lib/test/jacococli.jar report build/jacoco.exec \
--classfiles build/classes \
--sourcefiles src \
--html build/coverage/html \
--xml build/coverage/coverage.xml \
--csv build/coverage/coverage.csv \
--name "GraphVisual Coverage Report"
- name: Coverage summary
working-directory: Gvisual
run: |
echo "## 📊 Code Coverage Report" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Parse CSV for summary (skip header, sum instruction covered/missed)
if [ -f build/coverage/coverage.csv ]; then
echo "| Package | Class | Instruction Coverage |" >> $GITHUB_STEP_SUMMARY
echo "|---------|-------|---------------------|" >> $GITHUB_STEP_SUMMARY
tail -n +2 build/coverage/coverage.csv | while IFS=',' read -r group package class inst_missed inst_covered branch_missed branch_covered line_missed line_covered complexity_missed complexity_covered method_missed method_covered; do
total=$((inst_missed + inst_covered))
if [ "$total" -gt 0 ]; then
pct=$((inst_covered * 100 / total))
echo "| $package | $class | ${pct}% (${inst_covered}/${total}) |" >> $GITHUB_STEP_SUMMARY
fi
done
fi
- name: Upload coverage report
uses: actions/upload-artifact@v7
with:
name: coverage-report
path: Gvisual/build/coverage/
retention-days: 30
- name: Enforce coverage threshold
working-directory: Gvisual
run: |
if [ -f build/coverage/coverage.csv ]; then
# Calculate overall instruction coverage
total_covered=0
total_missed=0
while IFS=',' read -r group package class inst_missed inst_covered rest; do
total_missed=$((total_missed + inst_missed))
total_covered=$((total_covered + inst_covered))
done < <(tail -n +2 build/coverage/coverage.csv)
total=$((total_missed + total_covered))
if [ "$total" -gt 0 ]; then
pct=$((total_covered * 100 / total))
echo "Overall instruction coverage: ${pct}%"
THRESHOLD=50
if [ "$pct" -lt "$THRESHOLD" ]; then
echo "::error::Coverage ${pct}% is below threshold ${THRESHOLD}%"
exit 1
fi
echo "✅ Coverage ${pct}% meets threshold ${THRESHOLD}%"
fi
fi
- name: Comment coverage on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v9
with:
script: |
const fs = require('fs');
const csvPath = 'Gvisual/build/coverage/coverage.csv';
if (!fs.existsSync(csvPath)) return;
const lines = fs.readFileSync(csvPath, 'utf8').trim().split('\n').slice(1);
let totalCovered = 0, totalMissed = 0;
const rows = [];
for (const line of lines) {
const cols = line.split(',');
const pkg = cols[1], cls = cols[2];
const missed = parseInt(cols[3]), covered = parseInt(cols[4]);
const total = missed + covered;
const pct = total > 0 ? Math.round(covered * 100 / total) : 0;
totalMissed += missed;
totalCovered += covered;
rows.push(`| ${pkg} | ${cls} | ${pct}% (${covered}/${total}) |`);
}
const overallTotal = totalMissed + totalCovered;
const overallPct = overallTotal > 0 ? Math.round(totalCovered * 100 / overallTotal) : 0;
const body = [
'## 📊 Code Coverage Report',
'',
`**Overall: ${overallPct}%** (${totalCovered}/${overallTotal} instructions)`,
'',
'| Package | Class | Coverage |',
'|---------|-------|----------|',
...rows,
].join('\n');
// Find and update existing comment or create new
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existing = comments.find(c => c.body.includes('📊 Code Coverage Report'));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v6
with:
files: Gvisual/build/coverage/coverage.xml
fail_ci_if_error: false
continue-on-error: true