diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..03434c7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,81 @@ +name: 🐞 Bug Report +description: Create a report to help us improve +labels: ["bug", "needs-triage"] +body: + - type: markdown + attributes: + value: | + Thank you for taking the time to file a bug report! Please provide as much detail as possible to help us reproduce and fix the issue. + + - type: input + id: version + attributes: + label: Project Version + description: "Which version are you using? (e.g., Docker image tag like `latest` or `v1.2.3`, or a git commit SHA)" + placeholder: "e.g., ghcr.io/beehiveinnovations/zen-mcp-server:latest" + validations: + required: true + + - type: textarea + id: description + attributes: + label: Bug Description + description: A clear and concise description of what the bug is. + placeholder: "When I run the `codereview` tool on a Python file with syntax errors, it hangs instead of reporting an error." + validations: + required: true + + - type: textarea + id: reproduction-steps + attributes: + label: Steps to Reproduce + description: "Provide the exact steps to reproduce the behavior. Include the full command you ran." + placeholder: | + 1. Create a file `test.py` with the content `def my_func(a,b)` + 2. Run the command: `docker exec -i zen-mcp-server python server.py` + 3. Use Claude Desktop with gemini codereview tool on test.py + 4. Observe the behavior... + validations: + required: true + + - type: textarea + id: expected-behavior + attributes: + label: Expected Behavior + description: A clear and concise description of what you expected to happen. + placeholder: "I expected the tool to exit with an error message about the invalid Python syntax." + validations: + required: true + + - type: textarea + id: logs + attributes: + label: Relevant Log Output + description: "Please copy and paste any relevant log output. This will be automatically formatted into a code block." + render: shell + + - type: dropdown + id: environment + attributes: + label: Operating System + description: What operating system are you running the Docker client on? + options: + - Windows (via WSL2) + - Windows (via Docker Desktop) + - macOS (Intel) + - macOS (Apple Silicon) + - Linux + validations: + required: true + + - type: checkboxes + id: no-duplicate-issues + attributes: + label: Sanity Checks + description: "Before submitting, please confirm the following:" + options: + - label: I have searched the existing issues and this is not a duplicate. + required: true + - label: I have confirmed that my `GEMINI_API_KEY` is set correctly. + required: true + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..774c56a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,12 @@ +blank_issues_enabled: false +contact_links: + - name: đŸ’Ŧ General Discussion + url: https://github.com/BeehiveInnovations/zen-mcp-server/discussions + about: Ask questions, share ideas, or discuss usage patterns with the community + - name: 📚 Documentation + url: https://github.com/BeehiveInnovations/zen-mcp-server/blob/main/README.md + about: Check the README for setup instructions and usage examples + - name: 🤝 Contributing Guide + url: https://github.com/BeehiveInnovations/zen-mcp-server/blob/main/CONTRIBUTING.md + about: Learn how to contribute to the project + diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml new file mode 100644 index 0000000..0a4fd56 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -0,0 +1,68 @@ +name: 📖 Documentation Improvement +description: Report an issue or suggest an improvement for the documentation +labels: ["documentation", "good first issue"] +body: + - type: input + id: location + attributes: + label: Documentation Location + description: "Which file or page has the issue? (e.g., README.md, CONTRIBUTING.md, CLAUDE.md)" + placeholder: "e.g., README.md" + validations: + required: true + + - type: dropdown + id: issue-type + attributes: + label: Type of Documentation Issue + description: What kind of documentation improvement is this? + options: + - Typo or grammar error + - Unclear or confusing explanation + - Outdated information + - Missing information + - Code example doesn't work + - Installation/setup instructions unclear + - Tool usage examples need improvement + - Other + validations: + required: true + + - type: textarea + id: problem + attributes: + label: What is wrong with the documentation? + description: "Please describe the problem. Be specific about what is unclear, incorrect, or missing." + placeholder: "The Docker setup command in the README is missing the `--pull=always` flag, which means users might use an outdated image version." + validations: + required: true + + - type: textarea + id: suggestion + attributes: + label: Suggested Improvement + description: "How can we make it better? If you can, please provide the exact text or changes you'd like to see." + placeholder: | + Change: + ``` + docker run ghcr.io/beehiveinnovations/zen-mcp-server:latest + ``` + + To: + ``` + docker run --pull=always ghcr.io/beehiveinnovations/zen-mcp-server:latest + ``` + + - type: dropdown + id: audience + attributes: + label: Target Audience + description: Which audience would benefit most from this improvement? + options: + - New users (first-time setup) + - Developers (contributing to the project) + - Advanced users (complex workflows) + - All users + validations: + required: true + diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..28ae33c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,52 @@ +name: ✨ Feature Request +description: Suggest an idea for this project +labels: ["enhancement", "needs-triage"] +body: + - type: textarea + id: problem-description + attributes: + label: What problem is this feature trying to solve? + description: "A clear and concise description of the problem or user need. Why is this change needed?" + placeholder: "Currently, I can only use one Gemini tool at a time. I want to be able to chain multiple tools together (e.g., analyze -> codereview -> thinkdeep) in a single workflow." + validations: + required: true + + - type: textarea + id: proposed-solution + attributes: + label: Describe the solution you'd like + description: A clear and concise description of what you want to happen. How would it work from a user's perspective? + placeholder: "I'd like to be able to specify a workflow like 'analyze src/ then codereview the findings then use thinkdeep to suggest improvements' in a single command or configuration." + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Describe alternatives you've considered + description: A clear and concise description of any alternative solutions or features you've considered. + placeholder: "I considered manually running each tool sequentially, but automatic workflow chaining would be more efficient and ensure context is preserved between steps." + + - type: dropdown + id: feature-type + attributes: + label: Feature Category + description: What type of enhancement is this? + options: + - New Gemini tool (chat, codereview, debug, etc.) + - Workflow improvement + - Integration enhancement + - Performance optimization + - User experience improvement + - Documentation enhancement + - Other + validations: + required: true + + - type: checkboxes + id: contribution + attributes: + label: Contribution + options: + - label: I am willing to submit a Pull Request to implement this feature. + diff --git a/.github/ISSUE_TEMPLATE/tool_addition.yml b/.github/ISSUE_TEMPLATE/tool_addition.yml new file mode 100644 index 0000000..460010d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/tool_addition.yml @@ -0,0 +1,75 @@ +name: đŸ› ī¸ New Gemini Tool Proposal +description: Propose a new Gemini MCP tool (e.g., `summarize`, `testgen`, `refactor`) +labels: ["enhancement", "new-tool"] +body: + - type: input + id: tool-name + attributes: + label: Proposed Tool Name + description: "What would the tool be called? (e.g., `summarize`, `testgen`, `refactor`)" + placeholder: "e.g., `docgen`" + validations: + required: true + + - type: textarea + id: purpose + attributes: + label: What is the primary purpose of this tool? + description: "Explain the tool's core function and the value it provides to developers using Claude + Gemini." + placeholder: "This tool will automatically generate comprehensive documentation from code, extracting class and function signatures, docstrings, and creating usage examples." + validations: + required: true + + - type: textarea + id: example-usage + attributes: + label: Example Usage in Claude Desktop + description: "Show how a user would invoke this tool through Claude and what the expected output would look like." + placeholder: | + **User prompt to Claude:** + "Use gemini to generate documentation for my entire src/ directory" + + **Expected Gemini tool behavior:** + - Analyze all Python files in src/ + - Extract classes, functions, and their docstrings + - Generate structured markdown documentation + - Include usage examples where possible + - Return organized documentation with table of contents + render: markdown + validations: + required: true + + - type: dropdown + id: tool-category + attributes: + label: Tool Category + description: What category does this tool fit into? + options: + - Code Analysis (like analyze) + - Code Quality (like codereview) + - Code Generation/Refactoring + - Documentation Generation + - Testing Support + - Debugging Support (like debug) + - Workflow Automation + - Architecture Planning (like thinkdeep) + - Other + validations: + required: true + + - type: textarea + id: system-prompt + attributes: + label: Proposed System Prompt (Optional) + description: "If you have ideas for how Gemini should be prompted for this tool, share them here." + placeholder: | + You are an expert technical documentation generator. Your task is to create comprehensive, user-friendly documentation from source code... + + - type: checkboxes + id: contribution + attributes: + label: Contribution + options: + - label: I am willing to submit a Pull Request to implement this new tool. + - label: I have checked that this tool doesn't overlap significantly with existing tools (analyze, codereview, debug, thinkdeep, chat). + diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..8a6b403 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,60 @@ +## PR Title Format + +**Please ensure your PR title follows one of these formats:** + +### Version Bumping Prefixes (trigger Docker build + version bump): +- `feat: ` - New features (triggers MINOR version bump) +- `fix: ` - Bug fixes (triggers PATCH version bump) +- `breaking: ` or `BREAKING CHANGE: ` - Breaking changes (triggers MAJOR version bump) +- `perf: ` - Performance improvements (triggers PATCH version bump) +- `refactor: ` - Code refactoring (triggers PATCH version bump) + +### Non-Version Prefixes (no version bump): +- `docs: ` - Documentation only +- `chore: ` - Maintenance tasks +- `test: ` - Test additions/changes +- `ci: ` - CI/CD changes +- `style: ` - Code style changes + +### Docker Build Options: +- `docker: ` - Force Docker build without version bump +- `docs+docker: ` - Documentation + Docker build +- `chore+docker: ` - Maintenance + Docker build +- `test+docker: ` - Tests + Docker build +- `ci+docker: ` - CI changes + Docker build +- `style+docker: ` - Style changes + Docker build + +## Description + +Please provide a clear and concise description of what this PR does. + +## Changes Made + +- [ ] List the specific changes made +- [ ] Include any breaking changes +- [ ] Note any dependencies added/removed + +## Testing + +- [ ] Unit tests pass +- [ ] Integration tests pass (if applicable) +- [ ] Manual testing completed +- [ ] Documentation updated (if needed) + +## Related Issues + +Fixes #(issue number) + +## Checklist + +- [ ] PR title follows the format guidelines above +- [ ] Code follows the project's style guidelines +- [ ] Self-review completed +- [ ] Tests added/updated as needed +- [ ] Documentation updated as needed +- [ ] All tests passing +- [ ] Ready for review + +## Additional Notes + +Any additional information that reviewers should know. \ No newline at end of file diff --git a/.github/workflows/auto-version.yml b/.github/workflows/auto-version.yml new file mode 100644 index 0000000..343d61d --- /dev/null +++ b/.github/workflows/auto-version.yml @@ -0,0 +1,248 @@ +name: Auto Version + +on: + pull_request: + types: [closed] + branches: [main] + +jobs: + version: + # Only run if PR was merged (not just closed) + if: github.event.pull_request.merged == true + 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 }} + + 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** + + This PR triggered a Docker image build because of the \`+docker\` suffix in the title. + + **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 }}\` + + **To test the image after build completes:** + \`\`\`bash + docker pull ghcr.io/${{ github.repository_owner }}/zen-mcp-server:pr-${{ github.event.pull_request.number }} + \`\`\` + + **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\" + } + } + } + } + \`\`\` + + 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 + 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 + diff --git a/.github/workflows/build_and_publish_docker.yml b/.github/workflows/build_and_publish_docker.yml new file mode 100644 index 0000000..9cf8011 --- /dev/null +++ b/.github/workflows/build_and_publish_docker.yml @@ -0,0 +1,197 @@ +name: Build and Publish Docker Image to GHCR + +on: + push: + tags: [ 'v*' ] + repository_dispatch: + types: [docker-build] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: beehiveinnovations/zen-mcp-server + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + id-token: write + attestations: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.PAT }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=tag + type=raw,value=latest,enable=${{ github.ref_type == 'tag' }} + type=sha,prefix=main-,enable=${{ github.event_name == 'repository_dispatch' }} + type=raw,value=pr-${{ github.event.client_payload.pr_number }},enable=${{ github.event_name == 'repository_dispatch' && github.event.client_payload.pr_number != '' }} + + - name: Build and push Docker image + id: build + 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: Generate artifact attestation + uses: actions/attest-build-provenance@v1 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + subject-digest: ${{ steps.build.outputs.digest }} + push-to-registry: true + + - name: Generate usage instructions + run: | + echo "## đŸŗ Docker Image Published Successfully!" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Image Registry:** GitHub Container Registry (GHCR)" >> $GITHUB_STEP_SUMMARY + echo "**Built Tags:** ${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + # Extract the first tag for the main pull command + MAIN_TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -n1) + + echo "### đŸ“Ĩ Pull the Image" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY + echo "docker pull $MAIN_TAG" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + echo "### âš™ī¸ Claude Desktop Configuration" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`json" >> $GITHUB_STEP_SUMMARY + echo "{" >> $GITHUB_STEP_SUMMARY + echo " \"mcpServers\": {" >> $GITHUB_STEP_SUMMARY + echo " \"gemini\": {" >> $GITHUB_STEP_SUMMARY + echo " \"command\": \"docker\"," >> $GITHUB_STEP_SUMMARY + echo " \"args\": [" >> $GITHUB_STEP_SUMMARY + echo " \"run\", \"--rm\", \"-i\"," >> $GITHUB_STEP_SUMMARY + echo " \"-e\", \"GEMINI_API_KEY\"," >> $GITHUB_STEP_SUMMARY + echo " \"$MAIN_TAG\"" >> $GITHUB_STEP_SUMMARY + echo " ]," >> $GITHUB_STEP_SUMMARY + echo " \"env\": {" >> $GITHUB_STEP_SUMMARY + echo " \"GEMINI_API_KEY\": \"your-gemini-api-key-here\"" >> $GITHUB_STEP_SUMMARY + echo " }" >> $GITHUB_STEP_SUMMARY + echo " }" >> $GITHUB_STEP_SUMMARY + echo " }" >> $GITHUB_STEP_SUMMARY + echo "}" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + echo "### đŸˇī¸ All Available Tags" >> $GITHUB_STEP_SUMMARY + echo "Built and pushed the following tags:" >> $GITHUB_STEP_SUMMARY + echo "${{ steps.meta.outputs.tags }}" | sed 's/^/- `/' | sed 's/$/`/' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [[ "${{ github.event_name }}" == "repository_dispatch" ]]; then + echo "**Note:** This is a development build triggered by PR #${{ github.event.client_payload.pr_number }}" >> $GITHUB_STEP_SUMMARY + echo "Use this image for testing the changes from that PR." >> $GITHUB_STEP_SUMMARY + elif [[ "${{ github.ref_type }}" == "tag" ]]; then + echo "**Note:** This is a release build from tag ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY + echo "This image represents a stable release version." >> $GITHUB_STEP_SUMMARY + fi + + echo "" >> $GITHUB_STEP_SUMMARY + echo "### đŸ“Ļ View in GitHub Container Registry" >> $GITHUB_STEP_SUMMARY + echo "[View all versions and tags →](https://github.com/${{ github.repository }}/pkgs/container/zen-mcp-server)" >> $GITHUB_STEP_SUMMARY + + - name: Update README with latest image info + if: false # Temporarily disabled as agreed with repo author + # if: github.ref_type == 'tag' || (github.event_name == 'repository_dispatch' && github.event.client_payload.pr_number != '') + run: | + # Checkout main branch to avoid detached HEAD when pushing + git fetch origin main:main + git checkout main + # Extract the primary image tag for updating README + if [[ "${{ github.ref_type }}" == "tag" ]]; then + # For tag releases, use the version tag + LATEST_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}" + UPDATE_TYPE="release" + elif [[ "${{ github.event_name }}" == "repository_dispatch" && "${{ github.event.client_payload.pr_number }}" != "" ]]; then + # For repository_dispatch (PR builds), use the PR tag + LATEST_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:pr-${{ github.event.client_payload.pr_number }}" + UPDATE_TYPE="development" + else + # For manual repository_dispatch without PR number, use latest tag + LATEST_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" + UPDATE_TYPE="manual" + fi + + echo "Updating README.md with latest Docker image: $LATEST_TAG" + + # Update README.md with the latest image tag + sed -i.bak "s|ghcr\.io/[^/]*/zen-mcp-server:[a-zA-Z0-9\._-]*|$LATEST_TAG|g" README.md + + # Also update docs/user-guides/installation.md + sed -i.bak "s|ghcr\.io/[^/]*/zen-mcp-server:[a-zA-Z0-9\._-]*|$LATEST_TAG|g" docs/user-guides/installation.md + + # Also update docs/user-guides/configuration.md + sed -i.bak "s|ghcr\.io/[^/]*/zen-mcp-server:[a-zA-Z0-9\._-]*|$LATEST_TAG|g" docs/user-guides/configuration.md + + # Check if there are any changes + if git diff --quiet README.md docs/user-guides/installation.md docs/user-guides/configuration.md; then + echo "No changes needed in documentation" + else + echo "Documentation updated with new image tag" + + # Configure git for automated commit + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + # Add and commit changes + git add README.md docs/user-guides/installation.md docs/user-guides/configuration.md + + if [[ "$UPDATE_TYPE" == "release" ]]; then + git commit -m "docs: Update Docker image references to ${{ github.ref_name }} + + Automated update after Docker image publish for release ${{ github.ref_name }}. + All documentation now references the latest stable image. + + 🤖 Automated by GitHub Actions" + elif [[ "$UPDATE_TYPE" == "development" ]]; then + git commit -m "docs: Update Docker image references for PR #${{ github.event.client_payload.pr_number }} + + Automated update after Docker image publish for development build. + Documentation updated to reference the latest development image. + + 🤖 Automated by GitHub Actions" + else + git commit -m "docs: Update Docker image references to latest + + Automated update after manual Docker image build. + Documentation updated to reference the latest image. + + 🤖 Automated by GitHub Actions" + fi + + # Push changes back to the repository + git push --set-upstream origin main + + echo "### 📝 Documentation Updated" >> $GITHUB_STEP_SUMMARY + echo "README.md and user guides have been automatically updated with the new Docker image tag: \`$LATEST_TAG\`" >> $GITHUB_STEP_SUMMARY + fi + diff --git a/.github/workflows/docker-test.yml b/.github/workflows/docker-test.yml new file mode 100644 index 0000000..12fcfad --- /dev/null +++ b/.github/workflows/docker-test.yml @@ -0,0 +1,32 @@ +name: Docker Build Test + +on: + pull_request: + branches: [ main ] + +jobs: + docker-build-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Test Docker build + uses: docker/build-push-action@v5 + with: + context: . + push: false + tags: test:latest + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Build test summary + run: | + echo "### ✅ Docker Build Test Passed" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Docker image builds successfully and is ready for production." >> $GITHUB_STEP_SUMMARY + diff --git a/README.md b/README.md index 8a54ed7..39d1c6d 100644 --- a/README.md +++ b/README.md @@ -971,4 +971,4 @@ Built with the power of **Multi-Model AI** collaboration 🤝 - [MCP (Model Context Protocol)](https://modelcontextprotocol.com) by Anthropic - [Claude Code](https://claude.ai/code) - Your AI coding assistant & orchestrator - [Gemini 2.5 Pro & 2.0 Flash](https://ai.google.dev/) - Extended thinking & fast analysis -- [OpenAI O3](https://openai.com/) - Strong reasoning & general intelligence +- [OpenAI O3](https://openai.com/) - Strong reasoning & general intelligence \ No newline at end of file diff --git a/scripts/bump_version.py b/scripts/bump_version.py new file mode 100755 index 0000000..57e34ad --- /dev/null +++ b/scripts/bump_version.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +""" +Version bumping utility for Gemini MCP Server + +This script handles semantic version bumping for the project by: +- Reading current version from config.py +- Applying the appropriate version bump (major, minor, patch) +- Updating config.py with new version and timestamp +- Preserving file structure and formatting +""" + +import re +import sys +from datetime import datetime +from pathlib import Path + + +def parse_version(version_string: str) -> tuple[int, int, int]: + """Parse semantic version string into tuple of integers.""" + match = re.match(r"^(\d+)\.(\d+)\.(\d+)", version_string) + if not match: + raise ValueError(f"Invalid version format: {version_string}") + return int(match.group(1)), int(match.group(2)), int(match.group(3)) + + +def bump_version(version: tuple[int, int, int], bump_type: str) -> tuple[int, int, int]: + """Apply version bump according to semantic versioning rules.""" + major, minor, patch = version + + if bump_type == "major": + return (major + 1, 0, 0) + elif bump_type == "minor": + return (major, minor + 1, 0) + elif bump_type == "patch": + return (major, minor, patch + 1) + else: + raise ValueError(f"Invalid bump type: {bump_type}") + + +def update_config_file(new_version: str) -> None: + """Update version and timestamp in config.py while preserving structure.""" + config_path = Path(__file__).parent.parent / "config.py" + + if not config_path.exists(): + raise FileNotFoundError(f"config.py not found at {config_path}") + + # Read the current content + content = config_path.read_text() + + # Update version using regex to preserve formatting + version_pattern = r'(__version__\s*=\s*["\'])[\d\.]+(["\'])' + content = re.sub(version_pattern, rf"\g<1>{new_version}\g<2>", content) + + # Update the __updated__ field with current date + current_date = datetime.now().strftime("%Y-%m-%d") + updated_pattern = r'(__updated__\s*=\s*["\'])[\d\-]+(["\'])' + content = re.sub(updated_pattern, rf"\g<1>{current_date}\g<2>", content) + + # Write back the updated content + config_path.write_text(content) + print(f"Updated config.py: version={new_version}, updated={current_date}") + + +def get_current_version() -> str: + """Extract current version from config.py.""" + config_path = Path(__file__).parent.parent / "config.py" + + if not config_path.exists(): + raise FileNotFoundError(f"config.py not found at {config_path}") + + content = config_path.read_text() + match = re.search(r'__version__\s*=\s*["\']([^"\']+)["\']', content) + + if not match: + raise ValueError("Could not find __version__ in config.py") + + return match.group(1) + + +def main(): + """Main entry point for version bumping.""" + if len(sys.argv) != 2: + print("Usage: python bump_version.py ") + sys.exit(1) + + bump_type = sys.argv[1].lower() + if bump_type not in ["major", "minor", "patch"]: + print(f"Invalid bump type: {bump_type}") + print("Valid types: major, minor, patch") + sys.exit(1) + + try: + # Get current version + current = get_current_version() + print(f"Current version: {current}") + + # Parse and bump version + version_tuple = parse_version(current) + new_version_tuple = bump_version(version_tuple, bump_type) + new_version = f"{new_version_tuple[0]}.{new_version_tuple[1]}.{new_version_tuple[2]}" + + # Update config file + update_config_file(new_version) + + # Output new version for GitHub Actions + print(f"New version: {new_version}") + + except Exception as e: + print(f"Error: {e}") + sys.exit(1) + + +if __name__ == "__main__": + main()