Merge pull request #17 from PatrykIti/feat/comprehensive-project-improvements
ci+docker: Comprehensive project improvements - CI/CD automation, documentation system, multi-platform support
This commit is contained in:
81
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
81
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -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
|
||||||
|
|
||||||
12
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
12
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -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
|
||||||
|
|
||||||
68
.github/ISSUE_TEMPLATE/documentation.yml
vendored
Normal file
68
.github/ISSUE_TEMPLATE/documentation.yml
vendored
Normal file
@@ -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
|
||||||
|
|
||||||
52
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
52
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -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.
|
||||||
|
|
||||||
75
.github/ISSUE_TEMPLATE/tool_addition.yml
vendored
Normal file
75
.github/ISSUE_TEMPLATE/tool_addition.yml
vendored
Normal file
@@ -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).
|
||||||
|
|
||||||
60
.github/pull_request_template.md
vendored
Normal file
60
.github/pull_request_template.md
vendored
Normal file
@@ -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: <description>` - New features (triggers MINOR version bump)
|
||||||
|
- `fix: <description>` - Bug fixes (triggers PATCH version bump)
|
||||||
|
- `breaking: <description>` or `BREAKING CHANGE: <description>` - Breaking changes (triggers MAJOR version bump)
|
||||||
|
- `perf: <description>` - Performance improvements (triggers PATCH version bump)
|
||||||
|
- `refactor: <description>` - Code refactoring (triggers PATCH version bump)
|
||||||
|
|
||||||
|
### Non-Version Prefixes (no version bump):
|
||||||
|
- `docs: <description>` - Documentation only
|
||||||
|
- `chore: <description>` - Maintenance tasks
|
||||||
|
- `test: <description>` - Test additions/changes
|
||||||
|
- `ci: <description>` - CI/CD changes
|
||||||
|
- `style: <description>` - Code style changes
|
||||||
|
|
||||||
|
### Docker Build Options:
|
||||||
|
- `docker: <description>` - Force Docker build without version bump
|
||||||
|
- `docs+docker: <description>` - Documentation + Docker build
|
||||||
|
- `chore+docker: <description>` - Maintenance + Docker build
|
||||||
|
- `test+docker: <description>` - Tests + Docker build
|
||||||
|
- `ci+docker: <description>` - CI changes + Docker build
|
||||||
|
- `style+docker: <description>` - 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.
|
||||||
248
.github/workflows/auto-version.yml
vendored
Normal file
248
.github/workflows/auto-version.yml
vendored
Normal file
@@ -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
|
||||||
|
|
||||||
197
.github/workflows/build_and_publish_docker.yml
vendored
Normal file
197
.github/workflows/build_and_publish_docker.yml
vendored
Normal file
@@ -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
|
||||||
|
|
||||||
32
.github/workflows/docker-test.yml
vendored
Normal file
32
.github/workflows/docker-test.yml
vendored
Normal file
@@ -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
|
||||||
|
|
||||||
@@ -971,4 +971,4 @@ Built with the power of **Multi-Model AI** collaboration 🤝
|
|||||||
- [MCP (Model Context Protocol)](https://modelcontextprotocol.com) by Anthropic
|
- [MCP (Model Context Protocol)](https://modelcontextprotocol.com) by Anthropic
|
||||||
- [Claude Code](https://claude.ai/code) - Your AI coding assistant & orchestrator
|
- [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
|
- [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
|
||||||
114
scripts/bump_version.py
Executable file
114
scripts/bump_version.py
Executable file
@@ -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 <major|minor|patch>")
|
||||||
|
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()
|
||||||
Reference in New Issue
Block a user