Zum Inhalt

HACS-Validierung

Validiert eine über HACS verteilte Home-Assistant-Custom-Integration mit den beiden offiziellen Actions, sodass ein konsumierendes Repository dasselbe Gate erbt, das HACS und Home Assistant Core anwenden.

  • hacs/action führt denselben Code aus, den HACS zur Validierung eines Repositories nutzt (Existenz von hacs.json, Brands, Topics, …); category ist standardmäßig integration
  • home-assistant/actions/hassfest validiert das Integrations-Manifest und die Struktur, auch für Custom Integrations

Verwendung

.github/workflows/ci.yml
on:
  push:
  pull_request:

jobs:
  hacs-validate:
    uses: nolte/gh-plumbing/.github/workflows/reusable-hacs-validate.yaml@<tag>

Custom-Repository vs. Default-Store

Lasse ignore leer für einen Default-Store-tauglichen Lauf — HACS verbietet ignorierte Checks für die Default-Store-Aufnahme. Ein reines Custom-Repository darf nicht erfüllbare Checks ignorieren, z. B. with: { ignore: "brands" }.


Release-ZIP-Asset

Für HACS-Integrationen baut reusable-release-publish.yml ein <domain>.zip-Asset aus custom_components/<domain>/ am Ziel-Commit des Release und hängt es vor dem Umschalten auf draft=false an den Draft — so sieht HACS nie ein Release ohne seinen Download. Das geschieht automatisch, sobald das Repository eine custom_components/<domain>/manifest.json trägt; es ist keine zusätzliche Verdrahtung nötig.

Der vollständige Release-und-Distributions-Kontrakt ist in spec/ha/hacs-release in claude-home-assistant spezifiziert.


Zentrale Konfiguration

.github/workflows/reusable-hacs-validate.yaml
name: Reusable — HACS Validate

# Validates a HACS-distributed Home Assistant custom integration with the two
# official actions, so a consuming integration inherits the same gate HACS and
# Home Assistant Core apply. Spec: claude-home-assistant spec/ha/hacs-release.
#
#   - hacs/action       — runs the same code HACS uses to validate a repository
#                         (hacs.json existence, brands, topics, …). category is
#                         required; this reusable defaults it to "integration".
#   - hassfest          — Home Assistant Core's own manifest/structure validator,
#                         able to validate standalone/custom integrations.
#
# Consumers call this on push and pull_request:
#
#   jobs:
#     validate:
#       uses: ./.github/workflows/reusable-hacs-validate.yaml

on:
  workflow_call:
    inputs:
      category:
        description: |
          HACS repository category passed to hacs/action. One of: integration,
          plugin, theme, python_script, appdaemon, template. This reusable
          targets HACS integrations; the default is "integration".
        required: false
        type: string
        default: integration
      ignore:
        description: |
          Space-separated list of hacs/action checks to skip. Valid names:
          archived brands description hacsjson images information issues topics.
          Leave empty for a default-store-grade run — per
          spec/ha/hacs-release a default-store inclusion MUST NOT ignore any
          check. A pure custom repository MAY ignore checks it cannot satisfy.
        required: false
        type: string
        default: ""
      run_hassfest:
        description: |
          Run hassfest. Keep true for integrations (the default). Set false for
          non-integration HACS categories (plugin/theme/…) where hassfest does
          not apply.
        required: false
        type: boolean
        default: true

permissions:
  contents: read

jobs:
  hacs:
    name: HACS Action
    runs-on: ubuntu-latest
    steps:
      - name: Checkout sources
        uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0

      # A literal reference, not `hacs/action@${{ inputs.hacs_action_ref }}`.
      # GitHub Actions does not allow an expression in a step's `uses:`, so
      # that form made this whole file fail validation -- it never parsed and
      # never ran, from 2026-06-26 until issue #398. The `hacs_action_ref`
      # input existed only to feed the expression and is gone with it; there
      # were no working callers to keep compatible.
      #
      # main's head rather than the 22.5.0 tag: that tag dates from 2022 and
      # sits 15 commits behind, so pinning to it would trade mutability for a
      # four-year rollback. Same call as hassfest below.
      - name: HACS validation
        uses: hacs/action@1ebf01c408f29afcb6406bd431bc98fd8cbb15aa # main
        env:
          # hacs/action calls the GitHub API for the issues/topics/brands checks.
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          category: ${{ inputs.category }}
          ignore: ${{ inputs.ignore }}

  hassfest:
    name: Hassfest
    if: ${{ inputs.run_hassfest }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout sources
        uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0

      # The Home Assistant docs reference hassfest as @master, but a branch is
      # mutable, so it is pinned here instead. home-assistant/actions carries no
      # usable release tag: 1.0.0 dates from 2020 and sits 158 commits behind
      # master, so the pin tracks master's head. Pinned 2026-08-01 from a master
      # head dated 2026-07-30. The comment names the branch only, so a Renovate
      # digest bump can't leave a date behind -- and because a branch name is not
      # a tag, the github-actions manager's github-tags lookup finds nothing here;
      # renovate-configs/common.json carries a git-refs customManager that reads
      # this exact line so the pin still ages.
      - name: Hassfest validation
        uses: home-assistant/actions/hassfest@ab22029681aa532bfe7de5774a9972d67bfbd2c0 # master