Skip to content

Publish Release

Publish Release #180

Workflow file for this run

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