Files
my-botty/.github/workflows/ci.yml
T
alexpolo1andClaude Opus 5 7763afdcb8 ci: don't fail the build when the coverage artifact upload hits the storage quota
Every test step passed; only 'Upload coverage' failed with

    Failed to CreateArtifact: Artifact storage quota has been hit.
    Unable to upload any new artifacts. Usage is recalculated every 6-12 hours.

That is an account storage condition, not a broken build, and it was marking the whole run
red. The artifact is a convenience, not a gate, so the step is now continue-on-error.

The underlying quota still needs clearing (Settings -> Billing -> Storage, or let old
artifacts age out) for coverage reports to reappear.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 19:22:35 +02:00

213 lines
6.2 KiB
YAML

name: CI
on:
push:
branches: [main, stable]
pull_request:
branches: [main, stable]
# Cancel in-progress runs on new push
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
install-and-test:
name: Install & Test (Windows)
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
cache: "pip"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-win11.txt
shell: bash
- name: Install Tesseract OCR
run: choco install tesseract --no-progress -y
- name: Python version
run: python -c "import sys; print(sys.version)"
- name: Syntax check
env:
PYTHONPATH: ./src
run: python -m compileall -q src tools test scripts
- name: Verify core imports
env:
PYTHONPATH: ./src
run: |
python -c "
import sys
sys.path.insert(0, 'src')
modules = [
'config',
'logger',
'screen',
'pather',
'template_finder',
'game_stats',
'health_manager',
'death_manager',
'd2r_image',
'item',
'item.pickit',
'transmute',
'shop',
'char',
'utils',
'utils.os_detect',
'messages',
]
for mod in modules:
try:
__import__(mod)
print(f' {mod}: OK')
except ImportError as e:
print(f' {mod}: FAILED - {e}')
sys.exit(1)
print('All core imports successful.')
"
- name: Verify botty runs (import main modules)
env:
PYTHONPATH: ./src
run: |
python -c "
import sys, os
sys.path.insert(0, 'src')
import ssl
ssl.SSLContext.load_default_certs = lambda *a, **k: None
from version import __version__
print(f' Version: {__version__}')
from config import Config
print(' Config: OK')
from game_controller import GameController
print(' GameController: OK')
from bot import Bot
print(' Bot: OK')
from run.diablo import Diablo
print(' Diablo run: OK')
from run.pindle import Pindle
print(' Pindle run: OK')
from run.arcane import Arcane
print(' Arcane run: OK')
from run.vizier import Vizier
print(' Vizier run: OK')
print('All botty entry modules import successfully.')
"
- name: Verify OCR (pytesseract)
env:
PYTHONPATH: ./src
run: |
python -c "
import sys, os, tempfile
sys.path.insert(0, 'src')
import pytesseract
pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
import cv2
import numpy as np
version = pytesseract.get_tesseract_version()
print(f' Tesseract version: {version}')
# Create a simple test image with text
img = np.full((50, 200), 255, dtype=np.uint8)
cv2.putText(img, 'Hello Botty', (20, 35),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 0), 1)
with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as f:
cv2.imwrite(f.name, img)
text = pytesseract.image_to_string(f.name, lang='eng').strip()
print(f' OCR result: {text}')
print('OCR pytesseract: OK')
"
- name: Verify OCR (botty ocr module)
env:
PYTHONPATH: ./src
PYTESSERACT_TESSERACT_CMD: C:\Program Files\Tesseract-OCR\tesseract.exe
run: |
python -c "
import sys, os
sys.path.insert(0, 'src')
# Import the botty OCR module - it reads PYTESSERACT_TESSERACT_CMD from env
from d2r_image.ocr import image_to_text, pytesseract
import cv2
import numpy as np
import tempfile
if pytesseract is None:
print(' pytesseract not available — skipping')
sys.exit(0)
# Create test image (3-channel for invert)
img = np.full((50, 200, 3), 255, dtype=np.uint8)
cv2.putText(img, '123', (80, 35),
cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 0, 0), 2)
# Run through botty's image_to_text
results = image_to_text(
[img],
model='hover-eng_inconsolata_inv_th_fast',
psm=7,
crop_pad=False,
invert=True,
threshold=25,
)
result_text = results[0].text if results else 'empty'
print(f' OCR result: {result_text}')
print('OCR botty module: OK')
"
- name: Log analyzer tests (self-healing framework)
env:
PYTHONPATH: ./src:.
RUN_ENV: test
run: |
python -m pytest test/auto/test_log_analyzer.py -v --tb=short
- name: Tests with coverage
env:
PYTHONPATH: ./src:.
RUN_ENV: test
run: |
python -m coverage run -m pytest -v --tb=short --ignore=test/auto/test_self_healing.py --ignore=test/smoke_test.py --ignore=test/test_version_consistency.py
python -m coverage xml --ignore-errors || true
- name: Upload coverage
uses: actions/upload-artifact@v4
if: always()
# Non-blocking: this is a convenience artifact, not a gate. When the account's
# artifact storage quota is full the upload fails with
# "Failed to CreateArtifact: Artifact storage quota has been hit" and marked the
# whole run red even though every test step passed. A quota problem is not a
# broken build.
continue-on-error: true
with:
name: coverage-report
path: coverage.xml
retention-days: 7