From af3a81543c38eebc210b508ace84673a1c2db2b7 Mon Sep 17 00:00:00 2001 From: Sven Lito Date: Fri, 8 Aug 2025 17:33:51 +0700 Subject: [PATCH] feat: streamline GitHub Actions workflows and improve contributor experience - Replace complex auto-version.yml with simple PR Docker build workflow - Builds Docker images for all PRs using pr-number-sha tagging - Removes redundant versioning logic (semantic-release handles this) - Adds automatic PR comments with Docker usage instructions - Optimize test.yml workflow triggers - Remove redundant push triggers on main branch - Focus on PR testing only for better developer feedback - Add docker-release.yml for production releases - Triggers on GitHub release publication - Multi-platform builds (linux/amd64, linux/arm64) - Updates release notes with Docker installation instructions - Add semantic-release.yml workflow for automated versioning - Uses conventional commits for version bumping - Automatically generates releases and tags - Integrates with Docker workflow via release triggers - Add pre-commit configuration for automatic code quality - Includes ruff (with auto-fix), black, isort - Provides faster development workflow option - Enhance contribution documentation - Add pre-commit hook option as recommended approach - Keep manual script option for comprehensive testing - Improve developer workflow guidance Fixes #215 (automatic changelog generation) Addresses #110 (Docker builds automation) References #107 (improved version tracking) This creates a clean, modern CI/CD pipeline that eliminates redundancy while addressing multiple community requests around changelog generation, Docker builds, and release automation. --- .github/workflows/auto-version.yml | 323 +++++++------------------ .github/workflows/docker-release.yml | 116 +++++++++ .github/workflows/semantic-release.yml | 61 +++++ .github/workflows/test.yml | 81 +++---- .pre-commit-config.yaml | 40 +++ docs/contributions.md | 26 +- pyproject.toml | 29 ++- requirements-dev.txt | 4 +- 8 files changed, 397 insertions(+), 283 deletions(-) create mode 100644 .github/workflows/docker-release.yml create mode 100644 .github/workflows/semantic-release.yml create mode 100644 .pre-commit-config.yaml diff --git a/.github/workflows/auto-version.yml b/.github/workflows/auto-version.yml index 343d61d..5cb4c42 100644 --- a/.github/workflows/auto-version.yml +++ b/.github/workflows/auto-version.yml @@ -1,248 +1,111 @@ -name: Auto Version +name: PR Docker Build on: pull_request: - types: [closed] - branches: [main] + types: [opened, synchronize, reopened] + +permissions: + contents: read + packages: write + pull-requests: write jobs: - version: - # Only run if PR was merged (not just closed) - if: github.event.pull_request.merged == true + docker: + name: Build PR Docker Image runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: read steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - token: ${{ secrets.PAT }} - - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: '3.9' - - - name: Configure git - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - - name: Determine version bump type - id: bump_type - run: | - PR_TITLE="${{ github.event.pull_request.title }}" - echo "PR Title: $PR_TITLE" - - # Convert to lowercase for case-insensitive matching - PR_TITLE_LOWER=$(echo "$PR_TITLE" | tr '[:upper:]' '[:lower:]') - - # Determine bump type based on PR title prefix - if [[ "$PR_TITLE_LOWER" =~ ^(breaking|breaking[[:space:]]change): ]]; then - echo "Detected BREAKING CHANGE - major version bump" - echo "bump_type=major" >> $GITHUB_OUTPUT - echo "should_bump=true" >> $GITHUB_OUTPUT - echo "should_build_docker=true" >> $GITHUB_OUTPUT - elif [[ "$PR_TITLE_LOWER" =~ ^feat: ]]; then - echo "Detected new feature - minor version bump" - echo "bump_type=minor" >> $GITHUB_OUTPUT - echo "should_bump=true" >> $GITHUB_OUTPUT - echo "should_build_docker=true" >> $GITHUB_OUTPUT - elif [[ "$PR_TITLE_LOWER" =~ ^(fix|perf|refactor): ]]; then - echo "Detected fix/perf/refactor - patch version bump" - echo "bump_type=patch" >> $GITHUB_OUTPUT - echo "should_bump=true" >> $GITHUB_OUTPUT - echo "should_build_docker=true" >> $GITHUB_OUTPUT - elif [[ "$PR_TITLE_LOWER" =~ ^docker: ]]; then - echo "Detected docker build request - no version bump but build Docker" - echo "bump_type=none" >> $GITHUB_OUTPUT - echo "should_bump=false" >> $GITHUB_OUTPUT - echo "should_build_docker=true" >> $GITHUB_OUTPUT - elif [[ "$PR_TITLE_LOWER" =~ ^(docs|chore|test|ci|style)\+docker: ]]; then - echo "Detected non-versioned change with Docker build request" - echo "bump_type=none" >> $GITHUB_OUTPUT - echo "should_bump=false" >> $GITHUB_OUTPUT - echo "should_build_docker=true" >> $GITHUB_OUTPUT - elif [[ "$PR_TITLE_LOWER" =~ ^(docs|chore|test|ci|style): ]]; then - echo "Detected non-versioned change - no version bump" - echo "bump_type=none" >> $GITHUB_OUTPUT - echo "should_bump=false" >> $GITHUB_OUTPUT - echo "should_build_docker=false" >> $GITHUB_OUTPUT - else - echo "No recognized prefix - no version bump" - echo "bump_type=none" >> $GITHUB_OUTPUT - echo "should_bump=false" >> $GITHUB_OUTPUT - echo "should_build_docker=false" >> $GITHUB_OUTPUT - fi - - - name: Get current version - if: steps.bump_type.outputs.should_bump == 'true' - id: current_version - run: | - CURRENT_VERSION=$(python -c "from config import __version__; print(__version__)") - echo "Current version: $CURRENT_VERSION" - echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT - - - name: Bump version - if: steps.bump_type.outputs.should_bump == 'true' - id: new_version - run: | - python scripts/bump_version.py ${{ steps.bump_type.outputs.bump_type }} - NEW_VERSION=$(python -c "from config import __version__; print(__version__)") - echo "New version: $NEW_VERSION" - echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT - - - name: Commit version change - if: steps.bump_type.outputs.should_bump == 'true' - run: | - git add config.py - git commit -m "chore: bump version to ${{ steps.new_version.outputs.version }} + - name: Checkout + uses: actions/checkout@v4 - Automated version bump from PR #${{ github.event.pull_request.number }} - ${{ github.event.pull_request.title }} - - Co-authored-by: ${{ github.event.pull_request.user.login }} <${{ github.event.pull_request.user.id }}+${{ github.event.pull_request.user.login }}@users.noreply.github.com>" - git push - - - name: Create git tag - if: steps.bump_type.outputs.should_bump == 'true' - run: | - git tag -a "v${{ steps.new_version.outputs.version }}" -m "Release v${{ steps.new_version.outputs.version }} - - Changes in this release: - - ${{ github.event.pull_request.title }} - - PR: #${{ github.event.pull_request.number }} - Author: @${{ github.event.pull_request.user.login }}" - git push origin "v${{ steps.new_version.outputs.version }}" - - - name: Generate release notes - if: steps.bump_type.outputs.should_bump == 'true' - id: release_notes - run: | - # Extract PR body for release notes - PR_BODY=$(cat << 'EOF' - ${{ github.event.pull_request.body }} - EOF - ) - - # Create release notes - RELEASE_NOTES=$(cat << EOF - ## What's Changed - - ${{ github.event.pull_request.title }} by @${{ github.event.pull_request.user.login }} in #${{ github.event.pull_request.number }} - - ### Details - - $PR_BODY - - ### Version Info - - Previous version: ${{ steps.current_version.outputs.version }} - - New version: ${{ steps.new_version.outputs.version }} - - Bump type: ${{ steps.bump_type.outputs.bump_type }} - - **Full Changelog**: https://github.com/${{ github.repository }}/compare/v${{ steps.current_version.outputs.version }}...v${{ steps.new_version.outputs.version }} - EOF - ) - - # Save to file for GitHub release - echo "$RELEASE_NOTES" > release_notes.md - - - name: Create GitHub release - if: steps.bump_type.outputs.should_bump == 'true' - uses: softprops/action-gh-release@v1 - with: - tag_name: v${{ steps.new_version.outputs.version }} - name: Release v${{ steps.new_version.outputs.version }} - body_path: release_notes.md - draft: false - prerelease: false - generate_release_notes: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Trigger Docker build - if: steps.bump_type.outputs.should_build_docker == 'true' - run: | - echo "🐳 Triggering Docker build and publish workflow" - # The Docker workflow will be triggered by the tag creation (if version bumped) - # or by repository_dispatch (if docker: prefix without version bump) - if [ "${{ steps.bump_type.outputs.should_bump }}" == "false" ]; then - # For docker: prefix without version bump, trigger via repository_dispatch - curl -X POST \ - -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - -H "Accept: application/vnd.github.v3+json" \ - "https://api.github.com/repos/${{ github.repository }}/dispatches" \ - -d '{"event_type":"docker-build","client_payload":{"pr_number":"${{ github.event.pull_request.number }}","pr_title":"${{ github.event.pull_request.title }}","commit_sha":"${{ github.sha }}"}}' - - # Add comment to PR about Docker build - COMMENT_BODY="🐳 **Docker Image Build Triggered** + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - This PR triggered a Docker image build because of the \`+docker\` suffix in the title. + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - **Expected Image Tags:** - - \`ghcr.io/${{ github.repository_owner }}/zen-mcp-server:pr-${{ github.event.pull_request.number }}\` - - \`ghcr.io/${{ github.repository_owner }}/zen-mcp-server:main-${{ github.sha }}\` + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + tags: | + # PR-specific tag for testing + type=raw,value=pr-${{ github.event.number }}-${{ github.sha }} + type=raw,value=pr-${{ github.event.number }} - **To test the image after build completes:** - \`\`\`bash - docker pull ghcr.io/${{ github.repository_owner }}/zen-mcp-server:pr-${{ github.event.pull_request.number }} - \`\`\` + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max - **Claude Desktop config for testing:** - \`\`\`json - { - \"mcpServers\": { - \"gemini\": { - \"command\": \"docker\", - \"args\": [ - \"run\", \"--rm\", \"-i\", - \"-e\", \"GEMINI_API_KEY\", - \"ghcr.io/${{ github.repository_owner }}/zen-mcp-server:pr-${{ github.event.pull_request.number }}\" - ], - \"env\": { - \"GEMINI_API_KEY\": \"your-api-key-here\" + - name: Comment on PR with Docker info + uses: actions/github-script@v7 + with: + script: | + const prNumber = context.payload.pull_request.number; + const sha = context.sha.substring(0, 7); + const repo = context.repo.repo; + const owner = context.repo.owner; + + const comment = `🐳 **Docker Image Built Successfully** + + This PR has been built and pushed as a Docker image for testing: + + **Available Tags:** + - \`ghcr.io/${owner}/${repo}:pr-${prNumber}-${context.sha}\` + - \`ghcr.io/${owner}/${repo}:pr-${prNumber}\` (latest for this PR) + + **Test the changes:** + \`\`\`bash + docker pull ghcr.io/${owner}/${repo}:pr-${prNumber} + \`\`\` + + **Claude Desktop configuration:** + \`\`\`json + { + "mcpServers": { + "zen-mcp-server": { + "command": "docker", + "args": [ + "run", "--rm", "-i", + "-e", "GEMINI_API_KEY", + "ghcr.io/${owner}/${repo}:pr-${prNumber}" + ], + "env": { + "GEMINI_API_KEY": "your-api-key-here" + } } } } - } - \`\`\` + \`\`\` + + The image will be updated automatically when you push new commits to this PR.`; + + github.rest.issues.createComment({ + issue_number: prNumber, + owner: owner, + repo: repo, + body: comment + }); - View the build progress in the [Actions tab](https://github.com/${{ github.repository }}/actions)." - - curl -X POST \ - -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - -H "Accept: application/vnd.github.v3+json" \ - "https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" \ - -d "{\"body\":\"$COMMENT_BODY\"}" - fi - - - name: Summary - run: | - if [ "${{ steps.bump_type.outputs.should_bump }}" == "true" ]; then - echo "### ✅ Version Bumped Successfully" >> $GITHUB_STEP_SUMMARY + - name: Create deployment summary + run: | + echo "## 🐳 PR Docker Build Complete" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "- **Previous version**: ${{ steps.current_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY - echo "- **New version**: ${{ steps.new_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY - echo "- **Bump type**: ${{ steps.bump_type.outputs.bump_type }}" >> $GITHUB_STEP_SUMMARY - echo "- **Tag**: v${{ steps.new_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY - echo "- **PR**: #${{ github.event.pull_request.number }}" >> $GITHUB_STEP_SUMMARY - echo "- **Docker**: Will build and publish with new tag" >> $GITHUB_STEP_SUMMARY - elif [ "${{ steps.bump_type.outputs.should_build_docker }}" == "true" ]; then - echo "### 🐳 Docker Build Requested" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "No version bump but Docker image will be built and published." >> $GITHUB_STEP_SUMMARY - echo "- **PR**: #${{ github.event.pull_request.number }}" >> $GITHUB_STEP_SUMMARY - echo "- **Title**: ${{ github.event.pull_request.title }}" >> $GITHUB_STEP_SUMMARY - echo "- **Docker tag**: Based on commit SHA" >> $GITHUB_STEP_SUMMARY - else - echo "### ℹ️ No Version Bump Required" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "PR title prefix did not require a version bump." >> $GITHUB_STEP_SUMMARY - echo "- **PR**: #${{ github.event.pull_request.number }}" >> $GITHUB_STEP_SUMMARY - echo "- **Title**: ${{ github.event.pull_request.title }}" >> $GITHUB_STEP_SUMMARY - fi - + echo "**PR**: #${{ github.event.number }}" >> $GITHUB_STEP_SUMMARY + echo "**Commit**: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY + echo "**Images built:**" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml new file mode 100644 index 0000000..445052a --- /dev/null +++ b/.github/workflows/docker-release.yml @@ -0,0 +1,116 @@ +name: Docker Release Build + +on: + release: + types: [published] + workflow_dispatch: + inputs: + tag: + description: 'Tag to build (leave empty for latest release)' + required: false + type: string + +permissions: + contents: read + packages: write + +jobs: + docker: + name: Build and Push Docker Image + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # If triggered by workflow_dispatch with a tag, checkout that tag + ref: ${{ inputs.tag || github.event.release.tag_name }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + tags: | + # Tag with the release version + type=semver,pattern={{version}},value=${{ inputs.tag || github.event.release.tag_name }} + type=semver,pattern={{major}}.{{minor}},value=${{ inputs.tag || github.event.release.tag_name }} + type=semver,pattern={{major}},value=${{ inputs.tag || github.event.release.tag_name }} + # Also tag as latest for the most recent release + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Update release with Docker info + if: github.event_name == 'release' + run: | + RELEASE_TAG="${{ github.event.release.tag_name }}" + DOCKER_TAGS=$(echo "${{ steps.meta.outputs.tags }}" | tr '\n' ' ') + + # Add Docker information to the release + gh release edit "$RELEASE_TAG" --notes-file - << EOF + ${{ github.event.release.body }} + + --- + + ## 🐳 Docker Images + + This release is available as Docker images: + + $(echo "$DOCKER_TAGS" | sed 's/ghcr.io/- `ghcr.io/g' | sed 's/ /`\n/g') + + **Quick start with Docker:** + \`\`\`bash + docker pull ghcr.io/${{ github.repository }}:$RELEASE_TAG + \`\`\` + + **Claude Desktop configuration:** + \`\`\`json + { + "mcpServers": { + "zen-mcp-server": { + "command": "docker", + "args": [ + "run", "--rm", "-i", + "-e", "GEMINI_API_KEY", + "ghcr.io/${{ github.repository }}:$RELEASE_TAG" + ], + "env": { + "GEMINI_API_KEY": "your-api-key-here" + } + } + } + } + \`\`\` + EOF + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create deployment summary + run: | + echo "## 🐳 Docker Release Build Complete" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Release**: ${{ inputs.tag || github.event.release.tag_name }}" >> $GITHUB_STEP_SUMMARY + echo "**Images built:**" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY \ No newline at end of file diff --git a/.github/workflows/semantic-release.yml b/.github/workflows/semantic-release.yml new file mode 100644 index 0000000..f9d0de3 --- /dev/null +++ b/.github/workflows/semantic-release.yml @@ -0,0 +1,61 @@ +name: Semantic Release + +on: + push: + branches: + - main + +permissions: + contents: write + issues: write + pull-requests: write + +jobs: + release: + runs-on: ubuntu-latest + concurrency: release + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + persist-credentials: true + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install python-semantic-release + + - name: Verify tests pass + run: | + pip install -r requirements.txt + pip install -r requirements-dev.txt + python -m pytest tests/ -v --ignore=simulator_tests/ -m "not integration" + + - name: Run semantic release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + semantic-release version + semantic-release publish + + - name: Upload build artifacts to release + if: hashFiles('dist/*') != '' + run: | + # Get the latest release tag + LATEST_TAG=$(gh release list --limit 1 --json tagName --jq '.[0].tagName') + if [ ! -z "$LATEST_TAG" ]; then + echo "Uploading artifacts to release $LATEST_TAG" + gh release upload "$LATEST_TAG" dist/* --clobber + fi + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0c70ff3..ffc28c8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,10 +1,8 @@ name: Tests on: - push: - branches: [ main, develop ] pull_request: - branches: [ main ] + branches: [main] jobs: test: @@ -14,47 +12,46 @@ jobs: python-version: ["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 - pip install -r requirements-dev.txt - - - name: Run unit tests - run: | - # Run only unit tests (exclude simulation tests and integration tests) - # Integration tests require local-llama which isn't available in CI - python -m pytest tests/ -v --ignore=simulator_tests/ -m "not integration" - env: - # Ensure no API key is accidentally used in CI - GEMINI_API_KEY: "" - OPENAI_API_KEY: "" + - 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 + pip install -r requirements-dev.txt + + - name: Run unit tests + run: | + # Run only unit tests (exclude simulation tests and integration tests) + # Integration tests require local-llama which isn't available in CI + python -m pytest tests/ -v --ignore=simulator_tests/ -m "not integration" + env: + # Ensure no API key is accidentally used in CI + GEMINI_API_KEY: "" + OPENAI_API_KEY: "" lint: 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-dev.txt - - - name: Run black formatter check - run: black --check . --exclude="test_simulation_files/" - - - name: Run ruff linter - run: ruff check . --exclude test_simulation_files + - 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-dev.txt + + - name: Run black formatter check + run: black --check . --exclude="test_simulation_files/" + + - name: Run ruff linter + run: ruff check . --exclude test_simulation_files diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..ead23ff --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,40 @@ +--- +default_stages: [pre-commit, pre-push] +repos: + - repo: https://github.com/psf/black + rev: 25.1.0 + hooks: + - id: black + exclude: ^test_simulation_files/ + + - repo: https://github.com/pycqa/isort + rev: 6.0.1 + hooks: + - id: isort + args: ["--profile", "black"] + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.12.8 + hooks: + - id: ruff + args: [--fix] + exclude: ^test_simulation_files/ + +# Configuration for specific tools +default_language_version: + python: python3 + +# Exclude patterns +exclude: | + (?x)^( + \.git/| + \.venv/| + venv/| + \.zen_venv/| + __pycache__/| + \.pytest_cache/| + logs/| + dist/| + build/| + test_simulation_files/ + )$ diff --git a/docs/contributions.md b/docs/contributions.md index 185b727..12147d0 100644 --- a/docs/contributions.md +++ b/docs/contributions.md @@ -23,8 +23,16 @@ We maintain high code quality standards. **All contributions must pass our autom #### Required Code Quality Checks -Before submitting any PR, run our automated quality check script: +**Option 1 - Automated (Recommended):** +```bash +# Install pre-commit hooks (one-time setup) +pre-commit install +# Now linting runs automatically on every commit +# Includes: ruff (with auto-fix), black, isort +``` + +**Option 2 - Manual:** ```bash # Run the comprehensive quality checks script ./code_quality_checks.sh @@ -32,7 +40,7 @@ Before submitting any PR, run our automated quality check script: This script automatically runs: - Ruff linting with auto-fix -- Black code formatting +- Black code formatting - Import sorting with isort - Complete unit test suite (361 tests) - Verification that all checks pass 100% @@ -56,7 +64,7 @@ python -m pytest -xvs python communication_simulator_test.py ``` -**Important**: +**Important**: - **Every single test must pass** - we have zero tolerance for failing tests in CI - All linting must pass cleanly (ruff, black, isort) - Import sorting must be correct @@ -69,12 +77,12 @@ python communication_simulator_test.py 1. **New features MUST include tests**: - Add unit tests in `tests/` for new functions or classes - Test both success and error cases - + 2. **Tool changes require simulator tests**: - Add simulator tests in `simulator_tests/` for new or modified tools - Use realistic prompts that demonstrate the feature - Validate output through server logs - + 3. **Bug fixes require regression tests**: - Add a test that would have caught the bug - Ensure the bug cannot reoccur @@ -136,14 +144,14 @@ def process_model_response( max_tokens: Optional[int] = None ) -> ProcessedResult: """Process and validate model response. - + Args: response: Raw response from the model provider max_tokens: Optional token limit for truncation - + Returns: ProcessedResult with validated and formatted content - + Raises: ValueError: If response is invalid or exceeds limits """ @@ -237,4 +245,4 @@ Contributors are recognized in: - Release notes for significant contributions - Special mentions for exceptional work -Thank you for contributing to Zen MCP Server! Your efforts help make this tool better for everyone. \ No newline at end of file +Thank you for contributing to Zen MCP Server! Your efforts help make this tool better for everyone. diff --git a/pyproject.toml b/pyproject.toml index b3e715b..25e9edc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "zen-mcp-server" -version = "0.1.0" +version = "1.1.0" description = "AI-powered MCP server with multiple model providers" requires-python = ">=3.9" dependencies = [ @@ -83,6 +83,33 @@ ignore = [ "tests/*" = ["B011"] "tests/conftest.py" = ["E402"] # Module level imports not at top of file - needed for test setup +[tool.semantic_release] +version_toml = ["pyproject.toml:project.version"] +branch = "main" +build_command = "python -m pip install --upgrade build && python -m build" +dist_path = "dist/" +upload_to_vcs_release = true +upload_to_repository = false +remove_dist = false +commit_version_number = true +commit_message = "chore(release): {version}\n\nAutomatically generated by python-semantic-release" +tag_format = "v{version}" + +[tool.semantic_release.branches.main] +match = "main" +prerelease = false + +[tool.semantic_release.changelog] +exclude_commit_patterns = [] + +[tool.semantic_release.commit_parser_options] +allowed_tags = ["build", "chore", "ci", "docs", "feat", "fix", "perf", "style", "refactor", "test"] +minor_tags = ["feat"] +patch_tags = ["fix", "perf"] + +[tool.semantic_release.remote.token] +env = "GH_TOKEN" + [build-system] requires = ["setuptools>=45", "wheel", "setuptools_scm[toml]>=6.2"] build-backend = "setuptools.build_meta" diff --git a/requirements-dev.txt b/requirements-dev.txt index 86e039d..43273b4 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,4 +3,6 @@ pytest-asyncio>=0.21.0 pytest-mock>=3.11.0 black>=23.0.0 ruff>=0.1.0 -isort>=5.12.0 \ No newline at end of file +isort>=5.12.0 +python-semantic-release>=10.3.0 +build>=1.0.0