Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 121 additions & 13 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,138 @@ on:
- reopened

jobs:
linting:
validate-branch-name:
name: Validate Branch Name
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
permissions:
contents: read
pull-requests: read
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Check branch name
run: |
branch_name="${{ github.head_ref }}"
if [[ ! $branch_name =~ ^(feature|feat|fix|hotfix|chore|refactor)/.+ ]]; then
echo "❌ Branch name '$branch_name' does not follow the required pattern."
echo "Branch name must start with: feature/, feat/, fix/, hotfix/, chore/, or refactor/"
exit 1
fi
echo "✅ Branch name '$branch_name' is valid."

validate-pr-title:
name: Validate PR Title
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
permissions:
contents: read
pull-requests: read
steps:
- name: Check PR title follows conventional commits
run: |
pr_title="${{ github.event.pull_request.title }}"
if [[ ! $pr_title =~ ^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\(.+\))?!?:.+ ]]; then
echo "❌ PR title '$pr_title' does not follow conventional commits format."
echo "Expected format: type(optional-scope): description"
echo "Valid types: feat, fix, docs, style, refactor, perf, test, chore, ci, build, revert"
echo "Examples:"
echo " - feat: add user authentication"
echo " - fix(api): handle null response from external service"
echo " - feat!: breaking change to user API"
exit 1
fi
echo "✅ PR title '$pr_title' follows conventional commits format."

lint-python-black:
name: Check Python Formatting (Black)
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install Dependencies
- name: Install Black
run: pip install black==25.12.0

- name: Get changed Python files
id: changed-files
run: |
python -m pip install --upgrade pip
pip install poetry
poetry install
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
git fetch origin ${{ github.base_ref }}
FILES=$(git diff --name-only --diff-filter=ACMRT origin/${{ github.base_ref }}...HEAD | grep '\.py$' || true)
else
FILES=$(git diff --name-only --diff-filter=ACMRT HEAD~1 | grep '\.py$' || true)
fi
if [ -z "$FILES" ]; then
echo "No Python files changed"
echo "has_changes=false" >> $GITHUB_OUTPUT
else
echo "Changed Python files:"
echo "$FILES"
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "files<<EOF" >> $GITHUB_OUTPUT
echo "$FILES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
fi

- name: Format Code with Black
run: poetry run black --check .
- name: Run Black check on changed files
if: steps.changed-files.outputs.has_changes == 'true'
run: |
echo "${{ steps.changed-files.outputs.files }}" | xargs black --check --diff

lint-python-ruff:
name: Lint Python Code (Ruff)
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Lint Code with Ruff
run: poetry run ruff check .
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install Ruff
run: pip install ruff==0.14.9

- name: Get changed Python files
id: changed-files
run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
git fetch origin ${{ github.base_ref }}
FILES=$(git diff --name-only --diff-filter=ACMRT origin/${{ github.base_ref }}...HEAD | grep '\.py$' || true)
else
FILES=$(git diff --name-only --diff-filter=ACMRT HEAD~1 | grep '\.py$' || true)
fi
if [ -z "$FILES" ]; then
echo "No Python files changed"
echo "has_changes=false" >> $GITHUB_OUTPUT
else
echo "Changed Python files:"
echo "$FILES"
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "files<<EOF" >> $GITHUB_OUTPUT
echo "$FILES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
fi

- name: Run Ruff check on changed files
if: steps.changed-files.outputs.has_changes == 'true'
run: |
echo "${{ steps.changed-files.outputs.files }}" | xargs ruff check --output-format=github

run-tests:
permissions:
contents: read
runs-on: ubuntu-latest
strategy:
matrix:
Expand All @@ -51,7 +159,7 @@ jobs:
uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

Expand Down
43 changes: 42 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,51 @@ jobs:
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Validate version matches release tag
if: github.event_name == 'release'
run: |
# Extract version from pyproject.toml
PYPROJECT_VERSION=$(python3 -c "
import tomllib
import sys
with open('pyproject.toml', 'rb') as f:
data = tomllib.load(f)
# Try old Poetry format first, then new PEP 621 format
if 'tool' in data and 'poetry' in data['tool'] and 'version' in data['tool']['poetry']:
print(data['tool']['poetry']['version'])
elif 'project' in data and 'version' in data['project']:
print(data['project']['version'])
else:
print('❌ Error: Could not find version in pyproject.toml', file=sys.stderr)
print('Expected tool.poetry.version or project.version', file=sys.stderr)
sys.exit(1)
")

# Extract tag from release (strip 'v' prefix if present)
RELEASE_TAG="${{ github.event.release.tag_name }}"
RELEASE_VERSION="${RELEASE_TAG#v}"

echo "pyproject.toml version: $PYPROJECT_VERSION"
echo "Release tag: $RELEASE_TAG"
echo "Release version (normalized): $RELEASE_VERSION"

# Compare versions
if [ "$PYPROJECT_VERSION" != "$RELEASE_VERSION" ]; then
echo "❌ ERROR: Version mismatch!"
echo " pyproject.toml version: $PYPROJECT_VERSION"
echo " Release tag version: $RELEASE_VERSION"
echo ""
echo "Please ensure the release tag matches the version in pyproject.toml"
echo "Expected tag: v$PYPROJECT_VERSION or $PYPROJECT_VERSION"
exit 1
fi

echo "✅ Version validation passed: $PYPROJECT_VERSION"

- name: Install Poetry
run: |
python -m pip install --upgrade pip
Expand Down
102 changes: 102 additions & 0 deletions .github/workflows/version-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: Plexe Version Check

on:
pull_request:
branches: [main]

jobs:
check-version-bump:
name: Verify Version Bump
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Fetch main branch
run: git fetch origin main:main

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install packaging module
run: pip install packaging

- name: Check for changes in plexe/
id: check-changes
run: |
if git diff --name-only origin/main...HEAD | grep '^plexe/' | grep -vq 'CODE_INDEX.md$'; then
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "✅ Changes detected in plexe/ (excluding auto-generated files)"
else
echo "has_changes=false" >> $GITHUB_OUTPUT
echo "ℹ️ No relevant changes detected in plexe/"
fi

- name: Verify version bump
if: steps.check-changes.outputs.has_changes == 'true'
run: |
# Extract version from current branch
CURRENT_VERSION=$(python3 -c "
import tomllib
import sys
with open('pyproject.toml', 'rb') as f:
data = tomllib.load(f)
# Try old Poetry format first, then new PEP 621 format
if 'tool' in data and 'poetry' in data['tool'] and 'version' in data['tool']['poetry']:
print(data['tool']['poetry']['version'])
elif 'project' in data and 'version' in data['project']:
print(data['project']['version'])
else:
print('❌ Error: Could not find version in pyproject.toml', file=sys.stderr)
print('Expected tool.poetry.version or project.version', file=sys.stderr)
sys.exit(1)
")

# Extract version from main branch
MAIN_VERSION=$(git show origin/main:pyproject.toml | python3 -c "
import tomllib
import sys
data = tomllib.loads(sys.stdin.read())
# Try old Poetry format first, then new PEP 621 format
if 'tool' in data and 'poetry' in data['tool'] and 'version' in data['tool']['poetry']:
print(data['tool']['poetry']['version'])
elif 'project' in data and 'version' in data['project']:
print(data['project']['version'])
else:
print('❌ Error: Could not find version in origin/main pyproject.toml', file=sys.stderr)
print('Expected tool.poetry.version or project.version', file=sys.stderr)
sys.exit(1)
")

echo "Current branch version: $CURRENT_VERSION"
echo "Main branch version: $MAIN_VERSION"

# Parse versions and compare
python3 << EOF
from packaging import version

current = version.parse("$CURRENT_VERSION")
main = version.parse("$MAIN_VERSION")

if current <= main:
print(f"❌ ERROR: Version must be incremented!")
print(f" Current: {current}")
print(f" Main: {main}")
print(f"")
print(f"Please bump the version in pyproject.toml")
exit(1)
else:
print(f"✅ Version properly incremented from {main} to {current}")
exit(0)
EOF

- name: Version check passed
if: steps.check-changes.outputs.has_changes == 'false'
run: |
echo "✅ No changes detected in plexe/, version check skipped"
19 changes: 17 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
repos:
- repo: https://github.com/psf/black
rev: 24.10.0
rev: 25.12.0
hooks:
- id: black
types: [python]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.1
rev: v0.14.9
hooks:
- id: ruff
args: [--fix]
types: [python]
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.0
hooks:
- id: gitleaks
- repo: local
hooks:
- id: generate-code-index
name: Generate code index
entry: bash -c 'python3 scripts/generate_code_index.py --include-tests && git add plexe/CODE_INDEX.md tests/CODE_INDEX.md'
language: system
pass_filenames: false
files: ^(plexe|tests)/.*\.py$
stages: [pre-commit]
Loading