name: Release on: push: tags: - 'v*' permissions: contents: write jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: 'recursive' - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.10' cache: 'pip' - name: Install uv run: | curl -LsSf https://astral.sh/uv/install.sh | sh echo "$HOME/.cargo/bin" >> $GITHUB_PATH - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt if [ -f skill_seeker_mcp/requirements.txt ]; then pip install -r skill_seeker_mcp/requirements.txt; fi # Install package in editable mode for tests (required for src/ layout) pip install -e . - name: Run tests run: | python -m pytest tests/ -v - name: Extract version from tag id: get_version run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT - name: Verify Python version run: | python --version python -c "import sys; assert sys.version_info >= (3, 10), f'Python {sys.version} is not >= 3.10'" - name: Verify version consistency run: | TAG_VERSION="${{ steps.get_version.outputs.VERSION }}" PKG_VERSION=$(python -c "import skill_seekers; print(skill_seekers.__version__)") TOML_VERSION=$(grep -m1 '^version' pyproject.toml | sed 's/version *= *"\(.*\)"/\1/') echo "Tag version: $TAG_VERSION" echo "Package version: $PKG_VERSION" echo "TOML version: $TOML_VERSION" if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then echo "::error::Version mismatch! Tag=$TAG_VERSION but package reports=$PKG_VERSION" exit 1 fi if [ "$TAG_VERSION" != "$TOML_VERSION" ]; then echo "::error::Version mismatch! Tag=$TAG_VERSION but pyproject.toml has=$TOML_VERSION" exit 1 fi echo "✅ All versions match: $TAG_VERSION" - name: Create Release Notes id: release_notes run: | if [ -f CHANGELOG.md ]; then # Extract changelog for this version (escape dots for exact match) VERSION="${{ steps.get_version.outputs.VERSION }}" ESCAPED_VERSION=$(echo "$VERSION" | sed 's/\./\\./g') sed -n "/## \[${ESCAPED_VERSION}\]/,/## \[/p" CHANGELOG.md | sed '$d' > release_notes.md fi # Fallback if extraction produced empty file or CHANGELOG.md missing if [ ! -s release_notes.md ]; then echo "Release v${{ steps.get_version.outputs.VERSION }}" > release_notes.md fi - name: Check if release exists id: check_release run: | if gh release view ${{ github.ref_name }} > /dev/null 2>&1; then echo "exists=true" >> $GITHUB_OUTPUT else echo "exists=false" >> $GITHUB_OUTPUT fi env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Create GitHub Release if: steps.check_release.outputs.exists == 'false' uses: softprops/action-gh-release@v1 with: name: v${{ steps.get_version.outputs.VERSION }} tag_name: ${{ github.ref_name }} body_path: release_notes.md draft: false prerelease: false env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Skip Release Creation if: steps.check_release.outputs.exists == 'true' run: | echo "ℹ️ Release ${{ github.ref_name }} already exists, skipping creation" echo "View at: https://github.com/${{ github.repository }}/releases/tag/${{ github.ref_name }}" - name: Build package run: | uv build - name: Publish to PyPI env: UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} run: | uv publish --token $UV_PUBLISH_TOKEN