From c8d09969df0bb8a0041771492e620bdca16ad289 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 2 Jan 2026 11:29:19 +0000 Subject: [PATCH] Add comprehensive GitHub Actions CI/CD workflows Implemented automated testing and quality assurance pipelines: Workflows added: - python-package.yml: Main CI pipeline * Multi-OS testing (Ubuntu, Windows, macOS) * Python 3.9-3.12 compatibility testing * Linting with flake8 * Code formatting checks with black * Type checking with mypy * Import and compilation tests * Unit tests for core components - codeql.yml: Security scanning * Weekly automated security analysis * CodeQL vulnerability detection * Extended security and quality queries - dependency-review.yml: Dependency safety * Automatic dependency vulnerability checks * License compliance verification * Blocks moderate+ severity issues - pr-labeler.yml: PR automation * Auto-labels based on changed files * PR size labeling (xs/s/m/l/xl) * Metadata extraction for better organization - welcome.yml: Community engagement * Welcomes first-time contributors * Provides helpful guidelines * Improves contributor experience Configuration: - labeler.yml: Label mapping for automatic categorization All workflows include proper permissions and error handling. --- .github/labeler.yml | 41 ++++++ .github/workflows/codeql.yml | 41 ++++++ .github/workflows/dependency-review.yml | 21 +++ .github/workflows/pr-labeler.yml | 91 +++++++++++++ .github/workflows/python-package.yml | 166 ++++++++++++++++++++++++ .github/workflows/welcome.yml | 35 +++++ 6 files changed, 395 insertions(+) create mode 100644 .github/labeler.yml create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/dependency-review.yml create mode 100644 .github/workflows/pr-labeler.yml create mode 100644 .github/workflows/python-package.yml create mode 100644 .github/workflows/welcome.yml diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..575c375 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,41 @@ +documentation: + - '**/*.md' + - '**/*.txt' + - 'docs/**/*' + +dependencies: + - 'requirements.txt' + - 'setup.py' + - 'pyproject.toml' + +configuration: + - '**/*.yml' + - '**/*.yaml' + - '**/*.json' + - '**/*.toml' + - '.env.example' + +core: + - 'chatbot.py' + +gui: + - 'gui.py' + +api: + - 'ai_provider.py' + +memory: + - 'memory.py' + +config: + - 'config.py' + +utilities: + - 'utils.py' + +ci/cd: + - '.github/workflows/**/*' + +tests: + - 'test_*.py' + - 'tests/**/*' diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..a114ff4 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,41 @@ +name: CodeQL Security Scan + +on: + push: + branches: [ main, master, develop ] + pull_request: + branches: [ main, master ] + schedule: + - cron: '0 0 * * 1' # Weekly on Monday + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'python' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + queries: security-extended,security-and-quality + + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..d3e38fc --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,21 @@ +name: Dependency Review + +on: + pull_request: + branches: [ main, master ] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Dependency Review + uses: actions/dependency-review-action@v3 + with: + fail-on-severity: moderate + deny-licenses: GPL-3.0, AGPL-3.0 diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml new file mode 100644 index 0000000..51a6e02 --- /dev/null +++ b/.github/workflows/pr-labeler.yml @@ -0,0 +1,91 @@ +name: PR Labeler + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + label: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + + steps: + - uses: actions/labeler@v4 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + + size-label: + runs-on: ubuntu-latest + permissions: + pull-requests: write + + steps: + - uses: codelytv/pr-size-labeler@v1 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + xs_label: 'size/xs' + xs_max_size: '10' + s_label: 'size/s' + s_max_size: '100' + m_label: 'size/m' + m_max_size: '500' + l_label: 'size/l' + l_max_size: '1000' + xl_label: 'size/xl' + fail_if_xl: 'false' + + pr-metadata: + runs-on: ubuntu-latest + permissions: + pull-requests: write + + steps: + - uses: actions/checkout@v4 + + - name: Add labels based on files changed + uses: actions/github-script@v7 + with: + script: | + const pr = context.payload.pull_request; + const labels = []; + + // Get list of files changed + const { data: files } = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pr.number, + }); + + // Add labels based on file patterns + const filePatterns = { + 'documentation': /\.(md|txt|rst)$/, + 'configuration': /\.(yml|yaml|json|toml|ini|env)$/, + 'dependencies': /requirements\.txt|setup\.py|pyproject\.toml/, + 'core': /chatbot\.py/, + 'gui': /gui\.py/, + 'api': /ai_provider\.py/, + 'memory': /memory\.py/, + 'config': /config\.py/, + 'utilities': /utils\.py/, + 'ci/cd': /\.github\/workflows/, + }; + + for (const file of files) { + for (const [label, pattern] of Object.entries(filePatterns)) { + if (pattern.test(file.filename) && !labels.includes(label)) { + labels.push(label); + } + } + } + + // Add the labels + if (labels.length > 0) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + labels: labels + }); + } diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml new file mode 100644 index 0000000..10a65ba --- /dev/null +++ b/.github/workflows/python-package.yml @@ -0,0 +1,166 @@ +name: Python Package CI + +on: + push: + branches: [ main, master, develop, claude/** ] + pull_request: + branches: [ main, master, develop ] + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + python-version: ['3.9', '3.10', '3.11', '3.12'] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Lint with flake8 + run: | + pip install flake8 + # Stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # Exit-zero treats all errors as warnings + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + continue-on-error: true + + - name: Check code formatting with black + run: | + pip install black + black --check --diff . + continue-on-error: true + + - name: Type checking with mypy + run: | + pip install mypy + mypy --install-types --non-interactive --ignore-missing-imports *.py + continue-on-error: true + + - name: Compile all Python files + run: | + python -m compileall -q . + + - name: Run basic import tests + run: | + python -c "import config; print('config.py OK')" + python -c "import utils; print('utils.py OK')" + python -c "import memory; print('memory.py OK')" + python -c "import ai_provider; print('ai_provider.py OK')" + python -c "import gui; print('gui.py OK')" + + - name: Test configuration loading + run: | + python -c "from config import Config; c = Config(); print('Config loads successfully')" + env: + TWITCH_OAUTH_TOKEN: oauth:test_token + TWITCH_CHANNEL: '#test_channel' + TWITCH_BOT_NICKNAME: TestBot + PERPLEXITY_API_KEY: pplx-test_key + + - name: Test utility classes + run: | + python -c " + from utils import MentionDetector, Logger + detector = MentionDetector('TestBot') + assert detector.is_mentioned('@TestBot hello') + assert detector.is_mentioned('TestBot: hello') + assert not detector.is_mentioned('hello world') + print('MentionDetector tests passed') + + logger = Logger(debug_mode=True) + logger.info('Test message') + print('Logger tests passed') + " + + - name: Test memory system + run: | + python -c " + from memory import ConversationMemory + mem = ConversationMemory(data_dir='test_data') + mem.add_message('testuser', 'user', 'Hello') + mem.add_message('testuser', 'assistant', 'Hi there') + history = mem.get_user_history('testuser') + assert len(history) == 2 + print('ConversationMemory tests passed') + " + + security-scan: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Security scan with bandit + run: | + pip install bandit + bandit -r . -f json -o bandit-report.json + continue-on-error: true + + - name: Check for known vulnerabilities + run: | + pip install safety + safety check --json + continue-on-error: true + + code-quality: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pylint radon + + - name: Analyze code with pylint + run: | + pylint --exit-zero --output-format=text *.py + continue-on-error: true + + - name: Calculate code metrics + run: | + radon cc . -a -nb + radon mi . -nb + continue-on-error: true + + build-status: + runs-on: ubuntu-latest + needs: [test, security-scan, code-quality] + if: always() + + steps: + - name: Check build status + run: | + echo "Tests: ${{ needs.test.result }}" + echo "Security: ${{ needs.security-scan.result }}" + echo "Quality: ${{ needs.code-quality.result }}" diff --git a/.github/workflows/welcome.yml b/.github/workflows/welcome.yml new file mode 100644 index 0000000..bfddb19 --- /dev/null +++ b/.github/workflows/welcome.yml @@ -0,0 +1,35 @@ +name: Welcome + +on: + issues: + types: [opened] + pull_request_target: + types: [opened] + +jobs: + welcome: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + + steps: + - uses: actions/first-interaction@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + issue-message: | + 👋 Thanks for opening your first issue! We appreciate your contribution to the Eugen Twitch Bot project. + + Please make sure you've provided all the necessary information and followed our issue template (if applicable). + + A maintainer will review your issue soon! + pr-message: | + 🎉 Thanks for opening your first pull request! We're excited to review your contribution. + + Before we can merge, please make sure: + - [ ] Your code follows our style guidelines + - [ ] You've tested your changes + - [ ] You've updated documentation if needed + - [ ] All CI checks pass + + A maintainer will review your PR as soon as possible. Thanks for contributing to Eugen!