Publish releases #69
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish releases | |
| # Creates a GitHub release, builds and publishes to PyPI, and creates a PR in the server repo | |
| # Can be triggered manually with a version number or called by the auto-release workflow | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version number (e.g., 2.16.7) - Creates release, publishes to PyPI, and updates server repo" | |
| required: true | |
| type: string | |
| workflow_call: | |
| inputs: | |
| version: | |
| description: "Version number (e.g., 2.16.7)" | |
| required: true | |
| type: string | |
| secrets: | |
| PYPI_TOKEN: | |
| required: true | |
| PRIVILEGED_GITHUB_TOKEN: | |
| required: true | |
| env: | |
| PYTHON_VERSION: "3.13" | |
| jobs: | |
| test: | |
| name: Run Tests | |
| uses: ./.github/workflows/test.yml | |
| create-release: | |
| name: Create Release | |
| needs: test | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ inputs.version }} | |
| steps: | |
| - name: Checkout the repository | |
| uses: actions/checkout@v5 | |
| - name: Create and push tag | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git tag -a "${{ inputs.version }}" -m "Release ${{ inputs.version }}" | |
| git push origin "${{ inputs.version }}" | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Generate release notes with Release Drafter | |
| id: release_drafter | |
| uses: release-drafter/[email protected] | |
| with: | |
| config-name: release-drafter.yml | |
| version: ${{ inputs.version }} | |
| tag: ${{ inputs.version }} | |
| publish: true | |
| prerelease: false | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Check if release notes are empty and add commit log fallback | |
| run: | | |
| RELEASE_BODY=$(gh release view "${{ inputs.version }}" --json body -q .body) | |
| # Check if release body is empty or just says "No changes" | |
| if [[ -z "$RELEASE_BODY" ]] || [[ "$RELEASE_BODY" =~ "No changes" ]]; then | |
| echo "Release notes are empty or contain 'No changes'. Generating commit log..." | |
| # Get the previous tag | |
| PREV_TAG=$(git describe --tags --abbrev=0 "${{ inputs.version }}^" 2>/dev/null || echo "") | |
| if [[ -z "$PREV_TAG" ]]; then | |
| # If no previous tag, get all commits | |
| COMMIT_LOG=$(git log --pretty=format:"* %s (%h)" "${{ inputs.version }}") | |
| else | |
| # Get commits between previous tag and current tag | |
| COMMIT_LOG=$(git log --pretty=format:"* %s (%h)" "$PREV_TAG..${{ inputs.version }}") | |
| fi | |
| # Update release notes with commit log | |
| echo "## Changes" > /tmp/release_notes.md | |
| echo "" >> /tmp/release_notes.md | |
| echo "$COMMIT_LOG" >> /tmp/release_notes.md | |
| gh release edit "${{ inputs.version }}" --notes-file /tmp/release_notes.md | |
| echo "Release notes updated with commit log." | |
| else | |
| echo "Release notes already contain content from Release Drafter." | |
| fi | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| build-and-publish: | |
| name: Build and Publish | |
| needs: create-release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout the repository | |
| uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ inputs.version }} | |
| - name: Set up Python ${{ env.PYTHON_VERSION }} | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install build dependencies | |
| run: >- | |
| pip install build tomli tomli-w | |
| - name: Set Python project version | |
| shell: python | |
| run: |- | |
| import tomli | |
| import tomli_w | |
| with open("pyproject.toml", "rb") as f: | |
| pyproject = tomli.load(f) | |
| pyproject["project"]["version"] = "${{ inputs.version }}" | |
| with open("pyproject.toml", "wb") as f: | |
| tomli_w.dump(pyproject, f) | |
| - name: Build package | |
| run: | | |
| python3 -m build | |
| - name: Publish release to PyPI | |
| uses: pypa/[email protected] | |
| with: | |
| user: __token__ | |
| password: ${{ secrets.PYPI_TOKEN }} | |
| - name: Upload release assets | |
| run: | | |
| gh release upload "${{ inputs.version }}" dist/*.whl dist/*.tar.gz | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| server-repo-pr: | |
| name: Server repo PR | |
| needs: build-and-publish | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Wait for PyPI availability | |
| run: | | |
| VERSION="${{ inputs.version }}" | |
| echo "Waiting for music-assistant-models==$VERSION to be available on PyPI..." | |
| # Wait up to 5 minutes (30 attempts * 10 seconds) | |
| MAX_ATTEMPTS=30 | |
| ATTEMPT=1 | |
| while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do | |
| echo "Attempt $ATTEMPT/$MAX_ATTEMPTS: Checking PyPI..." | |
| # Check if the package version is available on PyPI | |
| if pip index versions music-assistant-models 2>/dev/null | grep -q "$VERSION"; then | |
| echo "✅ Package music-assistant-models==$VERSION is now available on PyPI!" | |
| exit 0 | |
| fi | |
| if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then | |
| echo "Package not yet available, waiting 10 seconds..." | |
| sleep 10 | |
| fi | |
| ATTEMPT=$((ATTEMPT + 1)) | |
| done | |
| echo "⚠️ Warning: Package not found on PyPI after 5 minutes, proceeding anyway..." | |
| exit 0 | |
| - name: Get release notes | |
| id: release_notes | |
| run: | | |
| VERSION="${{ inputs.version }}" | |
| # Get the release notes from the models release | |
| RELEASE_DATA=$(gh release view "$VERSION" --repo music-assistant/models --json body) | |
| RELEASE_NOTES=$(echo "$RELEASE_DATA" | jq -r '.body') | |
| # Fix relative links in release notes to point to models repo | |
| # Convert models#123 or #123 to [#123](https://github.com/music-assistant/models/pull/123) | |
| RELEASE_NOTES=$(echo "$RELEASE_NOTES" | sed -E 's/(^|[^[])(models)?#([0-9]+)/\1[#\3](https:\/\/github.com\/music-assistant\/models\/pull\/\3)/g') | |
| # Set multiline output | |
| { | |
| echo 'notes<<EOF' | |
| echo "$RELEASE_NOTES" | |
| echo EOF | |
| } >> $GITHUB_OUTPUT | |
| env: | |
| GH_TOKEN: ${{ secrets.PRIVILEGED_GITHUB_TOKEN }} | |
| - name: Checkout server repository | |
| uses: actions/checkout@v5 | |
| with: | |
| repository: music-assistant/server | |
| token: ${{ secrets.PRIVILEGED_GITHUB_TOKEN }} | |
| path: . | |
| - name: Update models version | |
| run: | | |
| VERSION="${{ inputs.version }}" | |
| # Update pyproject.toml | |
| sed -i.bak "s/music-assistant-models==.*/music-assistant-models==$VERSION\",/" pyproject.toml | |
| # Update requirements_all.txt | |
| sed -i.bak "s/music-assistant-models==.*/music-assistant-models==$VERSION/" requirements_all.txt | |
| # Remove backup files | |
| rm -f pyproject.toml.bak requirements_all.txt.bak | |
| - name: Create Pull Request | |
| id: create_pr | |
| uses: peter-evans/create-pull-request@v7 | |
| with: | |
| token: ${{ secrets.PRIVILEGED_GITHUB_TOKEN }} | |
| commit-message: "⬆️ Update music-assistant-models to ${{ inputs.version }}" | |
| branch: "auto-update-models-${{ inputs.version }}" | |
| delete-branch: true | |
| title: "⬆️ Update music-assistant-models to ${{ inputs.version }}" | |
| body: | | |
| Update music-assistant-models to version [${{ inputs.version }}](https://github.com/music-assistant/models/releases/tag/${{ inputs.version }}) | |
| ${{ steps.release_notes.outputs.notes }} | |
| labels: | | |
| dependencies |