Publish Release #180
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 Release | |
| # 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.12" | |
| NODE_VERSION: "22.x" | |
| NODE_OPTIONS: --max_old_space_size=6144 | |
| # Set default workflow permissions | |
| permissions: | |
| contents: write | |
| jobs: | |
| create-release: | |
| name: Create Release | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ inputs.version }} | |
| steps: | |
| - name: Checkout the repository | |
| uses: actions/checkout@v5 | |
| - name: Generate release notes with Release Drafter | |
| id: release_drafter | |
| uses: release-drafter/[email protected] | |
| with: | |
| config-name: release-drafter.yml | |
| version: ${{ inputs.version }} | |
| publish: true | |
| prerelease: false | |
| env: | |
| GITHUB_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: Set up Node ${{ env.NODE_VERSION }} | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: yarn | |
| - name: Install dependencies | |
| run: | | |
| yarn install | |
| python3 -m 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: | | |
| yarn build | |
| rm -rf dist music_assistant_frontend.egg-info | |
| 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-frontend==$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-frontend 2>/dev/null | grep -q "$VERSION"; then | |
| echo "✅ Package music-assistant-frontend==$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: Checkout frontend repository for git history | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: music-assistant/frontend | |
| fetch-depth: 0 | |
| path: frontend-repo | |
| - name: Get release notes and contributors | |
| id: release_notes | |
| run: | | |
| VERSION="${{ inputs.version }}" | |
| # Get the release notes from the frontend release | |
| RELEASE_DATA=$(gh release view "$VERSION" --repo music-assistant/frontend --json body) | |
| RELEASE_NOTES=$(echo "$RELEASE_DATA" | jq -r '.body') | |
| # Fix relative links in release notes to point to frontend repo | |
| # Convert #123 to https://github.com/music-assistant/frontend/pull/123 | |
| RELEASE_NOTES=$(echo "$RELEASE_NOTES" | sed -E 's/#([0-9]+)/https:\/\/github.com\/music-assistant\/frontend\/pull\/\1/g') | |
| # Get contributors for this release | |
| cd frontend-repo | |
| # Get previous release tag | |
| PREVIOUS_TAG=$(gh release list --repo music-assistant/frontend --exclude-drafts --limit 2 --json tagName --jq '.[1].tagName' 2>/dev/null || echo "") | |
| if [ -z "$PREVIOUS_TAG" ]; then | |
| # First release or can't find previous, get last 20 commits | |
| RAW_CONTRIBUTORS=$(git log -20 --format='%an|%ae' 2>/dev/null | sort -u || echo "") | |
| else | |
| # Get contributors between releases | |
| RAW_CONTRIBUTORS=$(git log --format='%an|%ae' ${PREVIOUS_TAG}..${VERSION} 2>/dev/null | sort -u || echo "") | |
| fi | |
| cd .. | |
| # Format contributors with GitHub avatars | |
| CONTRIBUTORS_MD="" | |
| while IFS='|' read -r name email; do | |
| if [ -n "$name" ]; then | |
| # Extract GitHub username from email | |
| if echo "$email" | grep -q "users.noreply.github.com"; then | |
| # Format: [email protected] or [email protected] | |
| GITHUB_USER=$(echo "$email" | sed 's/@users.noreply.github.com//' | sed 's/^[0-9]*+//') | |
| elif echo "$email" | grep -q "@github.com"; then | |
| # Format: [email protected] | |
| GITHUB_USER=$(echo "$email" | sed 's/@github.com//') | |
| else | |
| # Fallback: try lowercase name without spaces | |
| GITHUB_USER=$(echo "$name" | tr '[:upper:]' '[:lower:]' | tr -d ' ' | tr -d ',' | tr -d '.') | |
| fi | |
| # Create markdown with avatar | |
| if [ -n "$GITHUB_USER" ]; then | |
| CONTRIBUTORS_MD="${CONTRIBUTORS_MD}<img src=\"https://github.com/${GITHUB_USER}.png?size=40\" width=\"40\" height=\"40\" alt=\"${name}\" /> [@${GITHUB_USER}](https://github.com/${GITHUB_USER}) " | |
| else | |
| CONTRIBUTORS_MD="${CONTRIBUTORS_MD}**${name}** " | |
| fi | |
| CONTRIBUTORS_MD="${CONTRIBUTORS_MD}"$'\n' | |
| fi | |
| done <<< "$RAW_CONTRIBUTORS" | |
| # Set multiline output | |
| { | |
| echo 'notes<<EOF' | |
| echo "$RELEASE_NOTES" | |
| echo EOF | |
| } >> $GITHUB_OUTPUT | |
| { | |
| echo 'contributors<<EOF' | |
| echo "$CONTRIBUTORS_MD" | |
| echo EOF | |
| } >> $GITHUB_OUTPUT | |
| env: | |
| GH_TOKEN: ${{ secrets.PRIVILEGED_GITHUB_TOKEN }} | |
| - name: Checkout server repository | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: music-assistant/server | |
| token: ${{ secrets.PRIVILEGED_GITHUB_TOKEN }} | |
| path: . | |
| - name: Update frontend version | |
| run: | | |
| VERSION="${{ inputs.version }}" | |
| # Update pyproject.toml | |
| sed -i.bak "s/music-assistant-frontend==.*/music-assistant-frontend==$VERSION\",/" pyproject.toml | |
| # Update requirements_all.txt | |
| sed -i.bak "s/music-assistant-frontend==.*/music-assistant-frontend==$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-frontend to ${{ inputs.version }}" | |
| branch: "auto-update-frontend-${{ inputs.version }}" | |
| delete-branch: true | |
| title: "⬆️ Update music-assistant-frontend to ${{ inputs.version }}" | |
| body: | | |
| Update music-assistant-frontend to version [${{ inputs.version }}](https://github.com/music-assistant/frontend/releases/tag/${{ inputs.version }}) | |
| ${{ steps.release_notes.outputs.notes }} | |
| --- | |
| ## Contributors | |
| ${{ steps.release_notes.outputs.contributors }} | |
| labels: | | |
| dependencies |