Skip to content

Commit 82d04e5

Browse files
committed
feature: Add support for sysman python bindings
Related-To: NEO-NEO-17257 Signed-off-by: shubham kumar <shubham.kumar@intel.com>
1 parent 26ce6a4 commit 82d04e5

20 files changed

Lines changed: 4839 additions & 0 deletions
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Bindings - Sysman Python - Bandit Security Scan
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- '**'
7+
paths:
8+
- 'bindings/sysman/python/**.py'
9+
- '.github/workflows/bindings-sysman-python-security-scan.yml'
10+
push:
11+
branches:
12+
- main
13+
- master
14+
paths:
15+
- 'bindings/sysman/python/**.py'
16+
- '.github/workflows/bindings-sysman-python-security-scan.yml'
17+
workflow_dispatch:
18+
19+
jobs:
20+
bandit:
21+
name: Bandit Security Analysis
22+
runs-on: ubuntu-latest
23+
permissions:
24+
contents: read
25+
26+
defaults:
27+
run:
28+
working-directory: bindings/sysman/python
29+
30+
steps:
31+
- name: Checkout code
32+
uses: actions/checkout@v4
33+
34+
- name: Set up Python
35+
uses: actions/setup-python@v5
36+
with:
37+
python-version: '3.x'
38+
39+
- name: Install Bandit
40+
run: |
41+
python -m pip install --upgrade pip
42+
pip install bandit
43+
44+
- name: Run Bandit security scan
45+
run: |
46+
bandit -r source/ test/ -f json -o bandit-report.json
47+
bandit -r source/ test/ -ll -f screen
48+
49+
- name: Upload Bandit results as artifact
50+
uses: actions/upload-artifact@v4
51+
if: always()
52+
with:
53+
name: bindings-sysman-python-bandit-security-report
54+
path: bindings/sysman/python/bandit-report.json
55+
retention-days: 30
Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
name: Bindings - Sysman Python - Unit Tests & Coverage
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- '**'
7+
paths:
8+
- 'bindings/sysman/python/**.py'
9+
- 'bindings/sysman/python/test/**'
10+
- 'bindings/sysman/python/source/**'
11+
- '.github/workflows/bindings-sysman-python-unit-tests-coverage.yml'
12+
- 'bindings/sysman/python/pytest.ini'
13+
push:
14+
branches:
15+
- main
16+
- master
17+
paths:
18+
- 'bindings/sysman/python/**.py'
19+
- 'bindings/sysman/python/test/**'
20+
- 'bindings/sysman/python/source/**'
21+
- '.github/workflows/bindings-sysman-python-unit-tests-coverage.yml'
22+
- 'bindings/sysman/python/pytest.ini'
23+
workflow_dispatch:
24+
25+
env:
26+
PYTHON_VERSION: '3.10'
27+
28+
jobs:
29+
unit-tests-linux:
30+
name: Linux - Unit Tests & Coverage Analysis
31+
runs-on: ubuntu-latest
32+
33+
defaults:
34+
run:
35+
working-directory: bindings/sysman/python
36+
37+
permissions:
38+
contents: read
39+
pull-requests: write # For PR comments
40+
checks: write # For check results
41+
42+
steps:
43+
- name: Checkout code
44+
uses: actions/checkout@v4
45+
with:
46+
fetch-depth: 0 # Full history for better coverage comparison
47+
48+
- name: Set up Python ${{ env.PYTHON_VERSION }}
49+
uses: actions/setup-python@v5
50+
with:
51+
python-version: ${{ env.PYTHON_VERSION }}
52+
cache: 'pip'
53+
54+
- name: Install dependencies
55+
run: |
56+
python -m pip install --upgrade pip
57+
pip install pytest pytest-cov pytest-html pytest-xdist
58+
pip install coverage[toml]
59+
# Linting, formatting, and type checking tools
60+
pip install flake8 black isort mypy
61+
62+
# Install any project-specific dependencies if requirements.txt exists
63+
if [ -f requirements.txt ]; then
64+
pip install -r requirements.txt
65+
fi
66+
67+
- name: Code Quality Checks
68+
run: |
69+
echo "Running code quality checks..."
70+
71+
# Check code formatting with black
72+
echo "Checking code formatting..."
73+
black --check --diff source/ test/ || {
74+
echo "❌ Code formatting issues found. Run 'black source/ test/' to fix."
75+
exit 1
76+
}
77+
78+
# Check import sorting
79+
echo "Checking import sorting..."
80+
isort --check-only --diff source/ test/ || {
81+
echo "❌ Import sorting issues found. Run 'isort source/ test/' to fix."
82+
exit 1
83+
}
84+
85+
# Run linting
86+
echo "Running flake8 linting..."
87+
flake8 source/ test/ || {
88+
echo "❌ Linting issues found. Check flake8 output above."
89+
exit 1
90+
}
91+
92+
# Run type checking
93+
echo "Running mypy type checking..."
94+
mypy source/ --ignore-missing-imports --no-strict-optional || {
95+
echo "❌ Type checking issues found. Check mypy output above."
96+
exit 1
97+
}
98+
99+
echo "✅ All code quality checks passed!"
100+
101+
- name: Run Unit Tests with Coverage
102+
run: |
103+
# Run tests with coverage and generate multiple report formats
104+
python -m pytest test/unit_tests/ \
105+
--cov=source \
106+
--cov-report=term-missing \
107+
--cov-report=html:htmlcov \
108+
--cov-report=xml:coverage.xml \
109+
--cov-report=json:coverage.json \
110+
--junit-xml=test-results.xml \
111+
--html=test-report.html \
112+
--self-contained-html \
113+
-v \
114+
--tb=short \
115+
--durations=10
116+
117+
- name: Extract Coverage Percentage
118+
id: coverage
119+
run: |
120+
# Extract coverage percentage from JSON report
121+
COVERAGE_PCT=$(python -c 'import json; data = json.load(open("coverage.json")); print("{:.1f}".format(data["totals"]["percent_covered"]))')
122+
echo "coverage_pct=$COVERAGE_PCT" >> $GITHUB_OUTPUT
123+
echo "Current Coverage: $COVERAGE_PCT%"
124+
125+
- name: Get Baseline Coverage from Target Branch
126+
id: baseline
127+
run: |
128+
# Get the target branch (base of the PR or parent commit for push events)
129+
if [ "${{ github.event_name }}" == "pull_request" ]; then
130+
TARGET_BRANCH="${{ github.event.pull_request.base.ref }}"
131+
echo "Pull request detected - comparing against base branch: $TARGET_BRANCH"
132+
else
133+
# For push events, compare against the parent commit
134+
TARGET_BRANCH="${{ github.ref_name }}"
135+
echo "Push event detected - comparing against parent commit on branch: $TARGET_BRANCH"
136+
# Use HEAD~1 to get the previous commit
137+
git checkout HEAD~1 2>/dev/null || {
138+
echo "⚠️ No parent commit found (possibly first commit). Using current commit as baseline."
139+
echo "baseline_coverage=${{ steps.coverage.outputs.coverage_pct }}" >> $GITHUB_OUTPUT
140+
exit 0
141+
}
142+
fi
143+
144+
echo "Target branch/commit: $TARGET_BRANCH"
145+
146+
# Checkout target branch/commit to get baseline coverage
147+
if [ "${{ github.event_name }}" == "pull_request" ]; then
148+
git fetch origin $TARGET_BRANCH
149+
git checkout origin/$TARGET_BRANCH
150+
fi
151+
152+
# Install dependencies and run tests to get baseline coverage
153+
python -m pip install --upgrade pip
154+
pip install pytest pytest-cov coverage[toml]
155+
156+
# Run tests with coverage for baseline
157+
python -m pytest test/unit_tests/ \
158+
--cov=source \
159+
--cov-report=json:baseline-coverage.json \
160+
-q || {
161+
if [ "${{ github.event_name }}" == "pull_request" ]; then
162+
echo "❌ CRITICAL: Baseline tests failed on target branch"
163+
echo ""
164+
echo "This indicates the target branch has broken tests."
165+
echo "The PR cannot be properly validated against a broken baseline."
166+
echo ""
167+
echo "Action required:"
168+
echo " 1. Check if there's an ongoing incident with the target branch"
169+
echo " 2. Fix the target branch tests first"
170+
echo " 3. Then rebase and re-run this PR"
171+
else
172+
echo "❌ CRITICAL: Baseline tests failed on parent commit"
173+
echo ""
174+
echo "This indicates the previous commit had broken tests."
175+
echo "The current commit cannot be properly validated."
176+
fi
177+
echo ""
178+
exit 1
179+
}
180+
181+
# Extract baseline coverage
182+
BASELINE_COVERAGE=$(python -c 'import json; data = json.load(open("baseline-coverage.json")); print("{:.1f}".format(data["totals"]["percent_covered"]))')
183+
echo "baseline_coverage=$BASELINE_COVERAGE" >> $GITHUB_OUTPUT
184+
echo "Baseline Coverage: $BASELINE_COVERAGE%"
185+
186+
# Switch back to PR branch
187+
git checkout ${{ github.sha }}
188+
189+
- name: Check Coverage Threshold
190+
run: |
191+
CURRENT_COVERAGE="${{ steps.coverage.outputs.coverage_pct }}"
192+
BASELINE_COVERAGE="${{ steps.baseline.outputs.baseline_coverage }}"
193+
194+
echo "Current Coverage: $CURRENT_COVERAGE%"
195+
echo "Target Branch Coverage: $BASELINE_COVERAGE%"
196+
197+
# Use awk for floating point comparison (more portable than bc)
198+
if [ $(echo "$CURRENT_COVERAGE >= $BASELINE_COVERAGE" | awk '{print ($1 >= $3)}') -eq 1 ]; then
199+
DELTA=$(echo "$CURRENT_COVERAGE - $BASELINE_COVERAGE" | awk '{printf "%.1f", $1 - $3}')
200+
echo "✅ Coverage check passed: $CURRENT_COVERAGE% >= $BASELINE_COVERAGE% (Δ ${DELTA}%)"
201+
else
202+
REGRESSION=$(echo "$BASELINE_COVERAGE - $CURRENT_COVERAGE" | awk '{printf "%.1f", $1 - $3}')
203+
echo "❌ Coverage regression detected!"
204+
echo "Current coverage ($CURRENT_COVERAGE%) is below target branch coverage ($BASELINE_COVERAGE%)"
205+
echo "Regression: -${REGRESSION}%"
206+
echo "This PR would cause coverage to regress from the target branch."
207+
echo "Please add tests to maintain or improve coverage."
208+
exit 1
209+
fi
210+
211+
- name: Coverage Summary
212+
if: always()
213+
run: |
214+
echo "## 📊 Test Coverage Report" >> $GITHUB_STEP_SUMMARY
215+
echo "" >> $GITHUB_STEP_SUMMARY
216+
echo "| Metric | Value |" >> $GITHUB_STEP_SUMMARY
217+
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
218+
echo "| Current Coverage | ${{ steps.coverage.outputs.coverage_pct }}% |" >> $GITHUB_STEP_SUMMARY
219+
echo "| Target Branch Coverage | ${{ steps.baseline.outputs.baseline_coverage }}% |" >> $GITHUB_STEP_SUMMARY
220+
221+
THRESHOLD="${{ steps.baseline.outputs.baseline_coverage }}"
222+
if [ $(echo "${{ steps.coverage.outputs.coverage_pct }} >= $THRESHOLD" | awk '{print ($1 >= $3)}') -eq 1 ]; then
223+
echo "| Status | ✅ PASSED |" >> $GITHUB_STEP_SUMMARY
224+
else
225+
echo "| Status | ❌ FAILED |" >> $GITHUB_STEP_SUMMARY
226+
fi
227+
echo "" >> $GITHUB_STEP_SUMMARY
228+
229+
# Add detailed coverage report
230+
echo "### Detailed Coverage Report" >> $GITHUB_STEP_SUMMARY
231+
echo '```' >> $GITHUB_STEP_SUMMARY
232+
python -m coverage report >> $GITHUB_STEP_SUMMARY
233+
echo '```' >> $GITHUB_STEP_SUMMARY
234+
235+
- name: Comment PR with Coverage
236+
if: github.event_name == 'pull_request'
237+
uses: actions/github-script@v7
238+
with:
239+
script: |
240+
const coverage = '${{ steps.coverage.outputs.coverage_pct }}';
241+
const baselineCoverage = '${{ steps.baseline.outputs.baseline_coverage }}';
242+
const passed = parseFloat(coverage) >= parseFloat(baselineCoverage);
243+
const improvement = parseFloat(coverage) - parseFloat(baselineCoverage);
244+
245+
const body = `## 📊 Unit Tests & Coverage Report
246+
247+
${passed ? '✅' : '❌'} **Coverage:** ${coverage}% vs ${baselineCoverage}% (target branch)
248+
249+
### Test Results
250+
- **Status:** ${passed ? 'PASSED' : 'FAILED'}
251+
- **Current Coverage:** ${coverage}%
252+
- **Target Branch Coverage:** ${baselineCoverage}%
253+
- **Change:** ${improvement > 0 ? '+' : ''}${improvement.toFixed(1)}%
254+
255+
${passed ?
256+
(improvement > 0 ?
257+
`🎉 Coverage improved by ${improvement.toFixed(1)}%! Great work on adding tests.` :
258+
'✅ Coverage maintained. No regression detected.') :
259+
'⚠️ Coverage regression detected. This PR would reduce test coverage. Please add more tests.'
260+
}
261+
262+
📁 Detailed reports are available in the workflow artifacts.
263+
`;
264+
265+
github.rest.issues.createComment({
266+
issue_number: context.issue.number,
267+
owner: context.repo.owner,
268+
repo: context.repo.repo,
269+
body: body
270+
});
271+
272+
- name: Upload Test Results
273+
uses: actions/upload-artifact@v4
274+
if: always()
275+
with:
276+
name: bindings-sysman-python-test-results-${{ github.run_number }}
277+
path: |
278+
test-results.xml
279+
test-report.html
280+
htmlcov/
281+
coverage.xml
282+
coverage.json
283+
retention-days: 30
284+
285+
- name: Upload Coverage Reports
286+
uses: actions/upload-artifact@v4
287+
if: always()
288+
with:
289+
name: bindings-sysman-python-coverage-report-${{ github.run_number }}
290+
path: |
291+
htmlcov/
292+
coverage.xml
293+
coverage.json
294+
retention-days: 30
295+
296+
297+
298+
# Optional: Run tests on multiple Python versions
299+
compatibility-tests:
300+
name: Python ${{ matrix.python-version }} Compatibility
301+
runs-on: ubuntu-latest
302+
303+
defaults:
304+
run:
305+
working-directory: bindings/sysman/python
306+
if: github.event_name == 'pull_request' # Only on PRs to save resources
307+
strategy:
308+
matrix:
309+
python-version: ['3.10']
310+
311+
steps:
312+
- name: Checkout code
313+
uses: actions/checkout@v4
314+
315+
- name: Set up Python ${{ matrix.python-version }}
316+
uses: actions/setup-python@v5
317+
with:
318+
python-version: ${{ matrix.python-version }}
319+
cache: 'pip'
320+
321+
- name: Install dependencies
322+
run: |
323+
python -m pip install --upgrade pip
324+
pip install pytest pytest-cov
325+
326+
- name: Run Unit Tests
327+
run: |
328+
python -m pytest test/unit_tests/ \
329+
--cov=source \
330+
--cov-report=term-missing \
331+
-v \
332+
--tb=short

0 commit comments

Comments
 (0)