name: Release on: release: types: - published env: PYTHON_VERSION: "3.14" NODE_OPTIONS: --max_old_space_size=6144 # Set default workflow permissions # All scopes not mentioned here are set to no access # https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token permissions: actions: none jobs: release: name: Release runs-on: ubuntu-latest environment: pypi permissions: contents: write # Required to upload release assets id-token: write # For "Trusted Publisher" to PyPi if: github.repository_owner == 'home-assistant' steps: - name: Checkout the repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Verify version uses: home-assistant/actions/helpers/verify-version@58bff37c8947f690ace498be413a9b78d6f30f93 # master - name: Setup Node and install uses: ./.github/actions/setup with: immutable: false cache: false - name: Download Translations run: ./script/translations_download env: LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }} # The app fetches core (backend) translations live from HA, so the # release build does not need Lokalise's backend project. SKIP_BACKEND_TRANSLATIONS: "1" # Restore the content-addressed compression cache. Unchanged chunks and # static assets are then reused instead of re-run through brotli/zopfli. - name: Restore compression cache id: compress-cache continue-on-error: true uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .compress-cache key: compress-cache-${{ runner.os }}-${{ github.run_id }}-${{ github.run_attempt }} restore-keys: | compress-cache-${{ runner.os }}- - name: Build and release package env: COMPRESS_CACHE_DIR: ${{ github.workspace }}/.compress-cache run: | python3 -m pip install build export SKIP_FETCH_NIGHTLY_TRANSLATIONS=1 script/release # The build keeps the cache under its size budget, so saving stays bounded. # A unique key always writes; restore-keys picks the newest on the next # run. Not gated on the restore step: a transient restore failure (it is # continue-on-error) must not stop us persisting a freshly built cache. - name: Save compression cache if: success() continue-on-error: true uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .compress-cache key: compress-cache-${{ runner.os }}-${{ github.run_id }}-${{ github.run_attempt }} - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2 with: skip-existing: true - name: Upload release assets env: GH_TOKEN: ${{ github.token }} TAG_NAME: ${{ github.event.release.tag_name }} run: gh release upload "$TAG_NAME" dist/*.whl dist/*.tar.gz --clobber wheels-init: name: Init wheels build needs: release runs-on: ubuntu-latest steps: - name: Generate requirements.txt env: GITHUB_REF: ${{ github.ref }} run: | version=$(echo "$GITHUB_REF" | awk -F"/" '{print $NF}' ) # Wait for the exact wheel to appear on the simple index (the surface # the wheels build's pip uses). The JSON API can report a version as # available before it propagates here, which fails the wheels build. wheel="home_assistant_frontend-${version}-py3-none-any.whl" echo "Waiting for $wheel to appear on the PyPI simple index..." for i in $(seq 1 30); do if curl -sf "https://pypi.org/simple/home-assistant-frontend/" | grep -qF "$wheel"; then echo "Package is available on the PyPI simple index!" break fi if [ "$i" = "30" ]; then echo "Timed out waiting for package to appear on PyPI" exit 1 fi echo "Not available yet, retrying in 30 seconds... ($i/30)" sleep 30 done echo "home-assistant-frontend==$version" > ./requirements.txt # home-assistant/wheels doesn't support SHA pinning - name: Build wheels uses: home-assistant/wheels@9e17ab1ed5c4c79d8b61e29fa63de25ca2710716 # 2026.07.0 with: abi: cp314 tag: musllinux_1_2 arch: amd64 wheels-key: ${{ secrets.WHEELS_KEY }} requirements: "requirements.txt" release-landing-page: name: Release landing-page frontend if: github.event.release.prerelease == false runs-on: ubuntu-latest permissions: contents: write # Required to upload release assets steps: - name: Checkout the repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Setup Node and install uses: ./.github/actions/setup with: immutable: false cache: false - name: Download Translations run: ./script/translations_download env: LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }} # The landing-page build does not merge backend translations. SKIP_BACKEND_TRANSLATIONS: "1" - name: Build landing-page run: landing-page/script/build_landing_page - name: Tar folder env: TAG_NAME: ${{ github.event.release.tag_name }} run: tar -czf "landing-page/home_assistant_frontend_landingpage-${TAG_NAME}.tar.gz" -C landing-page/dist . - name: Upload release asset env: GH_TOKEN: ${{ github.token }} TAG_NAME: ${{ github.event.release.tag_name }} run: gh release upload "$TAG_NAME" "landing-page/home_assistant_frontend_landingpage-${TAG_NAME}.tar.gz" --clobber