--- name: Publish Release # Releases (production and beta) are named after the version they publish. # Dev builds are named after the dated dev tag, which is passed in by the # nightly workflow because a run name cannot compute it itself. run-name: ${{ github.event.inputs.tag || github.event.release.tag_name || format('Manual build ({0})', github.ref_name) }} on: workflow_dispatch: inputs: tag: description: >- Tag to build. Only supported on dev, where the nightly workflow uses it. Leave empty to build the version from esphome/const.py with today's date appended. required: false default: "" release: types: [published] permissions: contents: read # actions/checkout for all jobs; deploy jobs add their own scopes when they need to write jobs: init: name: Initialize build runs-on: ubuntu-latest outputs: tag: ${{ steps.tag.outputs.tag }} branch_build: ${{ steps.tag.outputs.branch_build }} deploy_env: ${{ steps.tag.outputs.deploy_env }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Get tag id: tag env: INPUT_TAG: ${{ github.event.inputs.tag }} # yamllint disable rule:line-length run: | if [[ "${{ github.event_name }}" = "release" ]]; then TAG="${{ github.event.release.tag_name}}" BRANCH_BUILD="false" if [[ "${{ github.event.release.prerelease }}" = "true" ]]; then ENVIRONMENT="beta" else ENVIRONMENT="production" fi else BRANCH=${GITHUB_REF#refs/heads/} # The nightly workflow passes the finished tag so that the run name # matches what is built. Without it, work it out here. TAG="${INPUT_TAG}" if [[ -n "$TAG" && "$BRANCH" != "dev" ]]; then echo "::error::The tag input is only supported on dev. A build from ${BRANCH} has to use the tag worked out here, which carries the branch name, so that it cannot publish over the dev, beta, latest or stable images." exit 1 fi if [[ -z "$TAG" ]]; then TAG=$(cat esphome/const.py | sed -n -E "s/^__version__\s+=\s+\"(.+)\"$/\1/p") today="$(date --utc '+%Y%m%d')" TAG="${TAG}${today}" if [[ "$BRANCH" != "dev" ]]; then TAG="${TAG}-${BRANCH}" fi fi if [[ "$BRANCH" != "dev" ]]; then BRANCH_BUILD="true" ENVIRONMENT="" else BRANCH_BUILD="false" ENVIRONMENT="dev" fi fi echo "tag=${TAG}" >> $GITHUB_OUTPUT echo "branch_build=${BRANCH_BUILD}" >> $GITHUB_OUTPUT echo "deploy_env=${ENVIRONMENT}" >> $GITHUB_OUTPUT # yamllint enable rule:line-length deploy-pypi: name: Build and publish to PyPi if: github.repository == 'esphome/esphome' && github.event_name == 'release' runs-on: ubuntu-latest permissions: contents: read # actions/checkout to build the sdist/wheel id-token: write # OIDC token for PyPI Trusted Publishing (pypa/gh-action-pypi-publish) steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.x" - name: Build run: |- pip3 install build python3 -m build - name: Publish uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2 with: skip-existing: true deploy-docker: name: Build ESPHome ${{ matrix.platform.arch }} if: github.repository == 'esphome/esphome' permissions: contents: read # actions/checkout to load Dockerfile and build context packages: write # docker/login-action + build-push-action push image digests to ghcr.io runs-on: ${{ matrix.platform.os }} needs: [init] strategy: fail-fast: false matrix: platform: - arch: amd64 os: "ubuntu-24.04" - arch: arm64 os: "ubuntu-24.04-arm" steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" - name: Set up Docker Buildx uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0 - name: Log in to docker hub uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to the GitHub container registry uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build docker uses: ./.github/actions/build-image with: target: final build_type: docker suffix: "" version: ${{ needs.init.outputs.tag }} - name: Build ha-addon uses: ./.github/actions/build-image with: target: final build_type: ha-addon suffix: "hassio" version: ${{ needs.init.outputs.tag }} # - name: Build lint # uses: ./.github/actions/build-image # with: # target: lint # build_type: lint # suffix: lint # version: ${{ needs.init.outputs.tag }} - name: Upload digests uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: digests-${{ matrix.platform.arch }} path: /tmp/digests retention-days: 1 deploy-manifest: name: Publish ESPHome ${{ matrix.image.build_type }} to ${{ matrix.registry }} runs-on: ubuntu-latest needs: - init - deploy-docker if: github.repository == 'esphome/esphome' permissions: contents: read # actions/checkout to load Dockerfile and build context packages: write # docker/login-action + build-push-action push image digests to ghcr.io strategy: fail-fast: false matrix: image: - build_type: "docker" suffix: "" - build_type: "ha-addon" suffix: "hassio" # - build_type: "lint" # suffix: "lint" registry: - ghcr - dockerhub steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Download digests uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: digests-* path: /tmp/digests merge-multiple: true - name: Set up Docker Buildx uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0 - name: Log in to docker hub if: matrix.registry == 'dockerhub' uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to the GitHub container registry if: matrix.registry == 'ghcr' uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Generate short tags id: tags run: | output=$(docker/generate_tags.py \ --tag "${{ needs.init.outputs.tag }}" \ --suffix "${{ matrix.image.suffix }}" \ --registry "${{ matrix.registry }}") echo $output for l in $output; do echo $l >> $GITHUB_OUTPUT done - name: Create manifest list and push working-directory: /tmp/digests/${{ matrix.image.build_type }}/${{ matrix.registry }} run: | docker buildx imagetools create $(jq -Rcnr 'inputs | . / "," | map("-t " + .) | join(" ")' <<< "${{ steps.tags.outputs.tags}}") \ $(printf '${{ steps.tags.outputs.image }}@sha256:%s ' *) version-notifier: if: github.repository == 'esphome/esphome' && needs.init.outputs.branch_build == 'false' runs-on: ubuntu-latest needs: - init - deploy-manifest steps: - name: Generate a token id: generate-token uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: client-id: ${{ vars.ESPHOME_GITHUB_APP_CLIENT_ID }} private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }} owner: esphome repositories: version-notifier permission-actions: write # actions.createWorkflowDispatch on the target repo (only API call made with this token) - name: Trigger Workflow uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: github-token: ${{ steps.generate-token.outputs.token }} script: | await github.rest.actions.createWorkflowDispatch({ owner: "esphome", repo: "version-notifier", workflow_id: "notify.yml", ref: "main", inputs: { version: "${{ needs.init.outputs.tag }}", } })