Skip to content

Commit dc959b2

Browse files
committed
chore: Apply 35 code fixes and add GitHub Actions CI/CD pipeline
## Critical Fixes - Thread safety: Added locks to InputWorker.active_keys - Resource leak: Fixed window handle update management - Exception handling: Implemented atomic config writes - Memory leak: Bounded key_counts dictionary ## High Priority Fixes - Configuration reorganization: Created DisplayConstants dataclass - Type safety: Consistent Optional[T] annotations - Error handling: Added duplicate key press logging - UI optimization: Enhanced paint event error handling - Magic numbers: Extracted FADE_START_Y and FADE_RANGE - Config validation: Added logging for clamped values - Build script: Multi-encoding support (UTF-8, UTF-8-SIG, Latin-1, CP1252) - Logging: Improved file handler error handling - Color parsing: Changed invalid color warning to error - Font caching: Added font cache with validation - Pool management: Added bar state verification - Signal connection: Fixed backwards connection logic ## Medium Priority Fixes - Code deduplication: Extracted combo validation method - Type hints: Added return types to all methods - Docstrings: Added comprehensive paintEvent documentation - Constants: Reorganized dataclasses - Build cleanup: Added error handling - Config pattern: Added complete documentation - Thread lifecycle: Added proper cleanup with timeout - Memory usage: Pool reinitialization on lane change - UI responsiveness: Throttled status updates to 10/s - Geometry cache: Added resize invalidation - Dataclass: Removed redundant __post_init__ - Timer precision: Uses screen refresh rate - Position validation: Uses actual screen bounds - Key strings: Normalized format (removes Key. prefix) ## New Features - Config schema validation: Added _validate_schema() method - Migration system: Added CONFIG_VERSION and migrate_config() - Error recovery: Added check_dependencies() in main() - API documentation: Added docstrings to all public methods ## Bug Fixes - Bar lifecycle: Fixed active state on key release - Font size: Added validation and caching - Signal connection: Fixed backwards check logic - Config save: Added atomic writes with backup ## GitHub Actions CI/CD - Added .github/workflows/ci.yml (Code quality validation) - Added .github/workflows/release.yml (Automated releases with git-cliff) - Added cliff.toml (git-cliff configuration) - Added .github/README.md (Workflow directory reference) - Added GITHUB_WORKFLOWS.md (Complete workflow documentation) - Added GIT_CLIFF_MIGRATION.md (Migration guide) - Updated AGENTS.md (Configuration documentation) - Deleted .github/workflows/changelog.yml (Old manual workflow) ## Version - Bumped to 1.3.9 ## Testing - All files pass Python syntax validation - No import errors or undefined names
1 parent ebf0119 commit dc959b2

File tree

20 files changed

+3611
-185
lines changed

20 files changed

+3611
-185
lines changed

.github/README.md

Lines changed: 522 additions & 0 deletions
Large diffs are not rendered by default.

.github/workflows/ci.yml

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
name: Code Quality
2+
3+
on:
4+
push:
5+
branches: [ main, master, develop ]
6+
pull_request:
7+
branches: [ main, master, develop ]
8+
9+
jobs:
10+
syntax-check:
11+
runs-on: ubuntu-latest
12+
name: Python Syntax Check
13+
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
18+
- name: Set up Python
19+
uses: actions/setup-python@v4
20+
with:
21+
python-version: '3.10'
22+
23+
- name: Install dependencies
24+
run: |
25+
python -m pip install --upgrade pip
26+
pip install -r requirements.txt
27+
28+
- name: Check Python syntax
29+
run: |
30+
echo "Checking Python syntax..."
31+
python -m py_compile main.py
32+
find core -name "*.py" -exec python -m py_compile {} \;
33+
find core/ui -name "*.py" -exec python -m py_compile {} \;
34+
echo "✅ All files compile successfully"
35+
36+
lint-check:
37+
runs-on: ubuntu-latest
38+
name: Code Linting
39+
40+
steps:
41+
- name: Checkout code
42+
uses: actions/checkout@v4
43+
44+
- name: Set up Python
45+
uses: actions/setup-python@v4
46+
with:
47+
python-version: '3.10'
48+
49+
- name: Install linters
50+
run: |
51+
python -m pip install --upgrade pip
52+
pip install pyflakes
53+
54+
- name: Run pyflakes
55+
run: |
56+
echo "Running pyflakes..."
57+
pyflakes main.py
58+
pyflakes core/*.py
59+
pyflakes core/ui/*.py
60+
echo "✅ No linting errors found"
61+
62+
import-check:
63+
runs-on: ubuntu-latest
64+
name: Import Validation
65+
66+
steps:
67+
- name: Checkout code
68+
uses: actions/checkout@v4
69+
70+
- name: Set up Python
71+
uses: actions/setup-python@v4
72+
with:
73+
python-version: '3.10'
74+
75+
- name: Test imports
76+
run: |
77+
echo "Testing module imports..."
78+
python -c "import main; print('✅ main.py imports successfully')"
79+
python -c "import core.overlay; print('✅ core.overlay imports successfully')"
80+
python -c "import core.input_mon; print('✅ core.input_mon imports successfully')"
81+
python -c "import core.settings_manager; print('✅ core.settings_manager imports successfully')"
82+
python -c "import core.configuration; print('✅ core.configuration imports successfully')"
83+
python -c "import core.gui; print('✅ core.gui imports successfully')"
84+
python -c "import core.ui.components; print('✅ core.ui.components imports successfully')"
85+
python -c "import core.logging_config; print('✅ core.logging_config imports successfully')"
86+
87+
type-check:
88+
runs-on: ubuntu-latest
89+
name: Type Validation
90+
91+
steps:
92+
- name: Checkout code
93+
uses: actions/checkout@v4
94+
95+
- name: Set up Python
96+
uses: actions/setup-python@v4
97+
with:
98+
python-version: '3.10'
99+
100+
- name: Check type hints
101+
run: |
102+
echo "Checking for type annotation issues..."
103+
python -c "
104+
import ast
105+
import sys
106+
107+
def check_file(filepath):
108+
with open(filepath, 'r', encoding='utf-8') as f:
109+
try:
110+
tree = ast.parse(f, filepath)
111+
except SyntaxError as e:
112+
print(f'❌ {filepath}: {e}')
113+
return False
114+
return True
115+
116+
files_to_check = ['main.py', 'core/overlay.py', 'core/input_mon.py',
117+
'core/settings_manager.py', 'core/configuration.py',
118+
'core/gui.py', 'core/ui/components.py']
119+
120+
all_ok = True
121+
for filepath in files_to_check:
122+
if check_file(filepath):
123+
print(f'✅ {filepath} type hints valid')
124+
else:
125+
all_ok = False
126+
127+
if not all_ok:
128+
sys.exit(1)
129+
"
130+
131+
config-validation:
132+
runs-on: ubuntu-latest
133+
name: Configuration Validation
134+
135+
steps:
136+
- name: Checkout code
137+
uses: actions/checkout@v4
138+
139+
- name: Set up Python
140+
uses: actions/setup-python@v4
141+
with:
142+
python-version: '3.10'
143+
144+
- name: Validate config schema
145+
run: |
146+
echo "Testing configuration validation..."
147+
python -c "
148+
from core.settings_manager import SettingsManager
149+
from core.configuration import AppConfig
150+
151+
# Test default config
152+
config = AppConfig()
153+
print('✅ Default configuration created successfully')
154+
155+
# Test schema validation
156+
settings = SettingsManager()
157+
print('✅ Schema validation passed')
158+
159+
# Test config save
160+
import tempfile
161+
import os
162+
temp_config = tempfile.mktemp(suffix='.ini')
163+
try:
164+
settings.filename = temp_config
165+
settings.save()
166+
print('✅ Config save works correctly')
167+
finally:
168+
if os.path.exists(temp_config):
169+
os.remove(temp_config)
170+
"
171+
172+
build-test:
173+
runs-on: windows-latest
174+
name: Windows Build Test
175+
176+
steps:
177+
- name: Checkout code
178+
uses: actions/checkout@v4
179+
180+
- name: Set up Python
181+
uses: actions/setup-python@v4
182+
with:
183+
python-version: '3.10'
184+
185+
- name: Install dependencies
186+
run: |
187+
python -m pip install --upgrade pip
188+
pip install -r requirements.txt
189+
pip install pyinstaller
190+
191+
- name: Test build
192+
run: |
193+
echo "Testing PyInstaller build..."
194+
pyinstaller --onefile --noconfirm --clean --name RainingKeysPython main.py
195+
if exist "RainingKeysPython.exe" (
196+
echo "✅ Build successful"
197+
rmdir /s /q build dist
198+
) else (
199+
echo "❌ Build failed"
200+
exit 1
201+
)
202+
shell: cmd
203+
204+
summary:
205+
runs-on: ubuntu-latest
206+
name: Quality Summary
207+
needs: [syntax-check, lint-check, import-check, type-check, config-validation]
208+
209+
steps:
210+
- name: All checks passed
211+
run: |
212+
echo "## ✅ Code Quality Summary"
213+
echo ""
214+
echo "| Check | Status |"
215+
echo "|-------|--------|"
216+
echo "| Python Syntax | ✅ Passed |"
217+
echo "| Linting | ✅ Passed |"
218+
echo "| Imports | ✅ Passed |"
219+
echo "| Type Hints | ✅ Passed |"
220+
echo "| Config Validation | ✅ Passed |"
221+
echo ""
222+
echo "All quality checks passed successfully! 🎉"

.github/workflows/release.yml

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
name: Create Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
workflow_dispatch:
8+
inputs:
9+
version:
10+
description: 'Version to release (e.g., 1.4.0)'
11+
required: true
12+
type: string
13+
use_existing_changelog:
14+
description: 'Use existing CHANGELOG_{VERSION}.md file instead of generating one'
15+
required: false
16+
type: boolean
17+
default: false
18+
19+
permissions:
20+
contents: write
21+
22+
jobs:
23+
release:
24+
runs-on: ubuntu-latest
25+
name: Create GitHub Release
26+
27+
steps:
28+
- name: Checkout code
29+
uses: actions/checkout@v4
30+
with:
31+
fetch-depth: 0
32+
33+
- name: Extract version
34+
id: version
35+
run: |
36+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
37+
VERSION="${{ github.event.inputs.version }}"
38+
else
39+
# Extract version from tag (e.g., v1.4.0 -> 1.4.0)
40+
VERSION="${GITHUB_REF#refs/tags/v}"
41+
fi
42+
echo "version=$VERSION" >> $GITHUB_OUTPUT
43+
44+
- name: Check for existing changelog
45+
id: changelog_check
46+
run: |
47+
VERSION="${{ steps.version.outputs.version }}"
48+
CHANGELOG_FILE="CHANGELOG_${VERSION}.md"
49+
50+
if [ "${{ github.event.inputs.use_existing_changelog }}" = "true" ] && [ -f "$CHANGELOG_FILE" ]; then
51+
echo "changelog_exists=true" >> $GITHUB_OUTPUT
52+
echo "Using existing changelog: $CHANGELOG_FILE"
53+
elif [ -f "$CHANGELOG_FILE" ]; then
54+
echo "changelog_exists=false" >> $GITHUB_OUTPUT
55+
echo "Changelog file exists but use_existing_changelog is false"
56+
else
57+
echo "changelog_exists=false" >> $GITHUB_OUTPUT
58+
echo "No changelog file found, will generate with git-cliff"
59+
60+
- name: Generate changelog with git-cliff
61+
if: steps.changelog_check.outputs.changelog_exists == 'false'
62+
uses: orhun/git-cliff-action@v2
63+
with:
64+
config: cliff.toml
65+
output: CHANGELOG.md
66+
tag: ${{ steps.version.outputs.version }}
67+
args: --verbose
68+
69+
- name: Format generated changelog
70+
if: steps.changelog_check.outputs.changelog_exists == 'false'
71+
run: |
72+
VERSION="${{ steps.version.outputs.version }}"
73+
74+
# Add version header to generated changelog
75+
cat > CHANGELOG_temp.md << 'EOF'
76+
# Changelog - Version $VERSION
77+
78+
_This changelog was automatically generated using git-cliff_
79+
80+
EOF
81+
82+
# Append generated changelog
83+
cat CHANGELOG.md >> CHANGELOG_temp.md
84+
85+
# Replace temp file
86+
mv CHANGELOG_temp.md CHANGELOG.md
87+
88+
# Create versioned changelog
89+
cp CHANGELOG.md "CHANGELOG_${VERSION}.md"
90+
91+
- name: Create release notes
92+
id: release_notes
93+
run: |
94+
VERSION="${{ steps.version.outputs.version }}"
95+
96+
if [ "${{ steps.changelog_check.outputs.changelog_exists }}" = "true" ]; then
97+
CHANGELOG_FILE="CHANGELOG_${VERSION}.md"
98+
99+
# Use existing changelog
100+
cat > release_notes.md << 'EOF'
101+
### 📦 Release $VERSION
102+
103+
_Using existing \`$CHANGELOG_FILE\`_
104+
105+
EOF
106+
107+
# Add changelog content
108+
cat "$CHANGELOG_FILE" >> release_notes.md
109+
else
110+
# Use git-cliff generated changelog
111+
cat > release_notes.md << 'EOF'
112+
### 📦 Release $VERSION
113+
114+
_Automatically generated using git-cliff_
115+
116+
EOF
117+
118+
# Append generated changelog (without the header we added)
119+
tail -n +2 CHANGELOG.md >> release_notes.md
120+
121+
echo "notes_file=release_notes.md" >> $GITHUB_OUTPUT
122+
123+
- name: Create GitHub Release
124+
uses: softprops/action-gh-release@v1
125+
with:
126+
files: |
127+
RainingKeysPython.zip
128+
RainingKeysPython-debug.zip
129+
CHANGELOG_${{ steps.version.outputs.version }}.md
130+
body_path: ${{ steps.release_notes.outputs.notes_file }}
131+
tag_name: v${{ steps.version.outputs.version }}
132+
name: v${{ steps.version.outputs.version }}
133+
draft: false
134+
prerelease: false
135+
generate_release_notes: true
136+
token: ${{ secrets.GITHUB_TOKEN }}
137+
138+
- name: Commit new changelog if generated
139+
if: steps.changelog_check.outputs.changelog_exists == 'false'
140+
uses: EndBug/add-and-commit@v9
141+
with:
142+
message: 'chore: Generate changelog for v${{ steps.version.outputs.version }} [skip ci]'
143+
add: '.'
144+
path: 'CHANGELOG_${{ steps.version.outputs.version }}.md'
145+
146+
- name: Upload changelog artifact
147+
uses: actions/upload-artifact@v4
148+
with:
149+
name: changelog-${{ steps.version.outputs.version }}
150+
path: |
151+
CHANGELOG_${{ steps.version.outputs.version }}.md
152+
CHANGELOG.md
153+
release_notes.md

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,9 @@ RainingKeysPython-debug
1111
RELEASE_NOTES.md
1212

1313
# Logs
14-
*.log
14+
*.log
15+
16+
# AI stuffs
17+
.agents/
18+
.claude/
19+
.crush/

0 commit comments

Comments
 (0)