ha-deploy-kit 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ha_deploy_kit-0.1.0/.coveragerc-ha +10 -0
- ha_deploy_kit-0.1.0/.github/workflows/release.yml +56 -0
- ha_deploy_kit-0.1.0/.github/workflows/validate.yml +43 -0
- ha_deploy_kit-0.1.0/.gitignore +224 -0
- ha_deploy_kit-0.1.0/CHANGELOG.md +82 -0
- ha_deploy_kit-0.1.0/LICENSE +21 -0
- ha_deploy_kit-0.1.0/PKG-INFO +199 -0
- ha_deploy_kit-0.1.0/README.md +151 -0
- ha_deploy_kit-0.1.0/docs/adopting.md +110 -0
- ha_deploy_kit-0.1.0/docs/configuration.md +73 -0
- ha_deploy_kit-0.1.0/docs/install.md +76 -0
- ha_deploy_kit-0.1.0/docs/releasing.md +100 -0
- ha_deploy_kit-0.1.0/examples/backend_only/.env.example +6 -0
- ha_deploy_kit-0.1.0/examples/backend_only/deploy.py +36 -0
- ha_deploy_kit-0.1.0/examples/backend_only/deploy.sh +8 -0
- ha_deploy_kit-0.1.0/examples/frontend_card/.env.example +6 -0
- ha_deploy_kit-0.1.0/examples/frontend_card/deploy.py +40 -0
- ha_deploy_kit-0.1.0/examples/frontend_card/deploy.sh +8 -0
- ha_deploy_kit-0.1.0/examples/frontend_card/ha_adapter.py +48 -0
- ha_deploy_kit-0.1.0/examples/synthetic_widget/deploy.py +38 -0
- ha_deploy_kit-0.1.0/examples/synthetic_widget/ha_adapter.py +44 -0
- ha_deploy_kit-0.1.0/pyproject.toml +106 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/__init__.py +9 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/cli.py +144 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/comparison.py +202 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/config.py +63 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/frontend.py +87 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/ha/__init__.py +20 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/ha/repairs_flow.py +48 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/ha/repairs_issue.py +46 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/ha/service.py +52 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/ha/serving.py +63 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/inventory.py +50 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/metadata/services.yaml.tmpl +6 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/metadata/strings.snippet.fixflow.json +15 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/metadata/strings.snippet.json +14 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/notify.py +150 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/settings.py +56 -0
- ha_deploy_kit-0.1.0/src/ha_deploy_kit/transport.py +117 -0
- ha_deploy_kit-0.1.0/tests/conftest.py +10 -0
- ha_deploy_kit-0.1.0/tests/ha/conftest.py +7 -0
- ha_deploy_kit-0.1.0/tests/ha/test_example_adapters.py +92 -0
- ha_deploy_kit-0.1.0/tests/ha/test_real_http_to_service.py +86 -0
- ha_deploy_kit-0.1.0/tests/ha/test_repairs_flow.py +27 -0
- ha_deploy_kit-0.1.0/tests/ha/test_repairs_issue.py +50 -0
- ha_deploy_kit-0.1.0/tests/ha/test_service.py +86 -0
- ha_deploy_kit-0.1.0/tests/ha/test_serving.py +75 -0
- ha_deploy_kit-0.1.0/tests/test_cli.py +333 -0
- ha_deploy_kit-0.1.0/tests/test_comparison.py +131 -0
- ha_deploy_kit-0.1.0/tests/test_config.py +47 -0
- ha_deploy_kit-0.1.0/tests/test_frontend.py +168 -0
- ha_deploy_kit-0.1.0/tests/test_installed_smoke.py +94 -0
- ha_deploy_kit-0.1.0/tests/test_inventory.py +48 -0
- ha_deploy_kit-0.1.0/tests/test_multi_consumer.py +279 -0
- ha_deploy_kit-0.1.0/tests/test_notify.py +290 -0
- ha_deploy_kit-0.1.0/tests/test_packaging.py +88 -0
- ha_deploy_kit-0.1.0/tests/test_transport.py +153 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
# Automated release. On every push to main (i.e. a merged PR),
|
|
4
|
+
# python-semantic-release reads the Conventional Commit messages since the last
|
|
5
|
+
# release and, if there is anything to release, bumps project.version, updates the
|
|
6
|
+
# changelog, commits that back to main ([skip ci]), tags v<version>, creates a
|
|
7
|
+
# GitHub release, and builds the artifacts. The publish job then uploads to PyPI
|
|
8
|
+
# via Trusted Publishing (OIDC) — no long-lived API token is stored anywhere.
|
|
9
|
+
# See docs/releasing.md for the one-time PyPI setup and the manual fallback.
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
push:
|
|
13
|
+
branches:
|
|
14
|
+
- main
|
|
15
|
+
|
|
16
|
+
concurrency:
|
|
17
|
+
group: release
|
|
18
|
+
cancel-in-progress: false
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
release:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
permissions:
|
|
24
|
+
contents: write # push the bump commit + tag to main, create the GH release
|
|
25
|
+
outputs:
|
|
26
|
+
released: ${{ steps.release.outputs.released }}
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
with:
|
|
30
|
+
fetch-depth: 0 # full history so commit analysis can find the last tag
|
|
31
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
32
|
+
- name: Python Semantic Release
|
|
33
|
+
id: release
|
|
34
|
+
uses: python-semantic-release/python-semantic-release@v9
|
|
35
|
+
with:
|
|
36
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
37
|
+
- name: Upload artifacts
|
|
38
|
+
if: steps.release.outputs.released == 'true'
|
|
39
|
+
uses: actions/upload-artifact@v4
|
|
40
|
+
with:
|
|
41
|
+
name: dist
|
|
42
|
+
path: dist/
|
|
43
|
+
|
|
44
|
+
publish:
|
|
45
|
+
needs: release
|
|
46
|
+
if: needs.release.outputs.released == 'true'
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
environment: pypi
|
|
49
|
+
permissions:
|
|
50
|
+
id-token: write # OIDC token for Trusted Publishing; replaces an API token
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/download-artifact@v4
|
|
53
|
+
with:
|
|
54
|
+
name: dist
|
|
55
|
+
path: dist/
|
|
56
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# CI for ha-deploy-kit.
|
|
2
|
+
#
|
|
3
|
+
# This is a Python LIBRARY, not a Home Assistant integration, so there is no
|
|
4
|
+
# HACS / hassfest job. Two independent test jobs mirror the two dependency
|
|
5
|
+
# groups and Python environments:
|
|
6
|
+
# - tests-core: HA-free, runs on Python 3.10/3.11/3.12 with the dev-core group.
|
|
7
|
+
# - tests-ha: the HA adapter, runs on the HA dev Python with the dev-ha group.
|
|
8
|
+
# Every `uses:` is pinned to a 40-char commit SHA. A later per-consumer example
|
|
9
|
+
# may validate separately.
|
|
10
|
+
name: validate
|
|
11
|
+
|
|
12
|
+
on:
|
|
13
|
+
push:
|
|
14
|
+
branches: [master, main]
|
|
15
|
+
pull_request:
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
tests-core:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
strategy:
|
|
24
|
+
fail-fast: false
|
|
25
|
+
matrix:
|
|
26
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
29
|
+
- uses: astral-sh/setup-uv@f94ec6bedd8674c4426838e6b50417d36b6ab231 # v3.1.7
|
|
30
|
+
- name: Run core tests
|
|
31
|
+
run: uv run --python ${{ matrix.python-version }} --group dev-core pytest tests --ignore=tests/ha -m "not ha" --cov --cov-report=term-missing
|
|
32
|
+
- name: Lint
|
|
33
|
+
run: |
|
|
34
|
+
uv run --group dev-core ruff check
|
|
35
|
+
uv run --group dev-core ruff format --check
|
|
36
|
+
|
|
37
|
+
tests-ha:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
41
|
+
- uses: astral-sh/setup-uv@f94ec6bedd8674c4426838e6b50417d36b6ab231 # v3.1.7
|
|
42
|
+
- name: Run HA adapter tests
|
|
43
|
+
run: uv run --python 3.14 --group dev-ha --extra ha pytest tests/ha --cov --cov-config=.coveragerc-ha --cov-report=term-missing
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
*.lcov
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
cover/
|
|
54
|
+
|
|
55
|
+
# Translations
|
|
56
|
+
*.mo
|
|
57
|
+
*.pot
|
|
58
|
+
|
|
59
|
+
# Django stuff:
|
|
60
|
+
*.log
|
|
61
|
+
local_settings.py
|
|
62
|
+
db.sqlite3
|
|
63
|
+
db.sqlite3-journal
|
|
64
|
+
|
|
65
|
+
# Flask stuff:
|
|
66
|
+
instance/
|
|
67
|
+
.webassets-cache
|
|
68
|
+
|
|
69
|
+
# Scrapy stuff:
|
|
70
|
+
.scrapy
|
|
71
|
+
|
|
72
|
+
# Sphinx documentation
|
|
73
|
+
docs/_build/
|
|
74
|
+
|
|
75
|
+
# PyBuilder
|
|
76
|
+
.pybuilder/
|
|
77
|
+
target/
|
|
78
|
+
|
|
79
|
+
# Jupyter Notebook
|
|
80
|
+
.ipynb_checkpoints
|
|
81
|
+
|
|
82
|
+
# IPython
|
|
83
|
+
profile_default/
|
|
84
|
+
ipython_config.py
|
|
85
|
+
|
|
86
|
+
# pyenv
|
|
87
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
88
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
89
|
+
# .python-version
|
|
90
|
+
|
|
91
|
+
# pipenv
|
|
92
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
93
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
94
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
95
|
+
# install all needed dependencies.
|
|
96
|
+
# Pipfile.lock
|
|
97
|
+
|
|
98
|
+
# uv
|
|
99
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
100
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
101
|
+
# commonly ignored for libraries. ha-deploy-kit is a library, so the lock is ignored.
|
|
102
|
+
uv.lock
|
|
103
|
+
|
|
104
|
+
# poetry
|
|
105
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
106
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
107
|
+
# commonly ignored for libraries.
|
|
108
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
109
|
+
# poetry.lock
|
|
110
|
+
# poetry.toml
|
|
111
|
+
|
|
112
|
+
# pdm
|
|
113
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
114
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
115
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
116
|
+
# pdm.lock
|
|
117
|
+
# pdm.toml
|
|
118
|
+
.pdm-python
|
|
119
|
+
.pdm-build/
|
|
120
|
+
|
|
121
|
+
# pixi
|
|
122
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
123
|
+
# pixi.lock
|
|
124
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
125
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
126
|
+
.pixi/*
|
|
127
|
+
!.pixi/config.toml
|
|
128
|
+
|
|
129
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
130
|
+
__pypackages__/
|
|
131
|
+
|
|
132
|
+
# Celery stuff
|
|
133
|
+
celerybeat-schedule*
|
|
134
|
+
celerybeat.pid
|
|
135
|
+
|
|
136
|
+
# Redis
|
|
137
|
+
*.rdb
|
|
138
|
+
*.aof
|
|
139
|
+
*.pid
|
|
140
|
+
|
|
141
|
+
# RabbitMQ
|
|
142
|
+
mnesia/
|
|
143
|
+
rabbitmq/
|
|
144
|
+
rabbitmq-data/
|
|
145
|
+
|
|
146
|
+
# ActiveMQ
|
|
147
|
+
activemq-data/
|
|
148
|
+
|
|
149
|
+
# SageMath parsed files
|
|
150
|
+
*.sage.py
|
|
151
|
+
|
|
152
|
+
# Environments
|
|
153
|
+
.env
|
|
154
|
+
.envrc
|
|
155
|
+
.venv
|
|
156
|
+
env/
|
|
157
|
+
venv/
|
|
158
|
+
ENV/
|
|
159
|
+
env.bak/
|
|
160
|
+
venv.bak/
|
|
161
|
+
|
|
162
|
+
# Spyder project settings
|
|
163
|
+
.spyderproject
|
|
164
|
+
.spyproject
|
|
165
|
+
|
|
166
|
+
# Rope project settings
|
|
167
|
+
.ropeproject
|
|
168
|
+
|
|
169
|
+
# mkdocs/Zensical documentation
|
|
170
|
+
/site
|
|
171
|
+
|
|
172
|
+
# mypy
|
|
173
|
+
.mypy_cache/
|
|
174
|
+
.dmypy.json
|
|
175
|
+
dmypy.json
|
|
176
|
+
|
|
177
|
+
# Pyre type checker
|
|
178
|
+
.pyre/
|
|
179
|
+
|
|
180
|
+
# pytype static type analyzer
|
|
181
|
+
.pytype/
|
|
182
|
+
|
|
183
|
+
# Cython debug symbols
|
|
184
|
+
cython_debug/
|
|
185
|
+
|
|
186
|
+
# PyCharm
|
|
187
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
188
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
189
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
190
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
191
|
+
# .idea/
|
|
192
|
+
|
|
193
|
+
# Abstra
|
|
194
|
+
# Abstra is an AI-powered process automation framework.
|
|
195
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
196
|
+
# Learn more at https://abstra.io/docs
|
|
197
|
+
.abstra/
|
|
198
|
+
|
|
199
|
+
# Visual Studio Code
|
|
200
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore that
|
|
201
|
+
# can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
202
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer, you
|
|
203
|
+
# could uncomment the following to ignore the entire vscode folder
|
|
204
|
+
# .vscode/
|
|
205
|
+
# Temporary file for partial code execution
|
|
206
|
+
tempCodeRunnerFile.py
|
|
207
|
+
|
|
208
|
+
# Ruff stuff:
|
|
209
|
+
.ruff_cache/
|
|
210
|
+
|
|
211
|
+
# PyPI configuration file
|
|
212
|
+
.pypirc
|
|
213
|
+
|
|
214
|
+
# Marimo
|
|
215
|
+
marimo/_static/
|
|
216
|
+
marimo/_lsp/
|
|
217
|
+
__marimo__/
|
|
218
|
+
|
|
219
|
+
# Streamlit
|
|
220
|
+
.streamlit/secrets.toml
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
.plans
|
|
224
|
+
.vscode
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# CHANGELOG
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## v0.1.0 (2026-10-29)
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
- **notify**: Verify TLS against a real CA trust store (truststore/certifi)
|
|
9
|
+
([`cc95ca9`](https://github.com/latrekc-meta/ha-deploy-kit/commit/cc95ca97546118c8620bb8fb1ba0f383270a7180))
|
|
10
|
+
|
|
11
|
+
The HTTPS notification used Python's default SSL context, which has no usable CA store on macOS /
|
|
12
|
+
python.org / fresh venvs and misreported valid certs as tls-error. Add _verifying_ssl_context()
|
|
13
|
+
(truststore -> certifi -> stdlib, all strictly verifying) and pass it to both the service POST and
|
|
14
|
+
the probe. Add certifi + truststore as runtime deps; tls-error now reflects genuine failures.
|
|
15
|
+
|
|
16
|
+
### Continuous Integration
|
|
17
|
+
|
|
18
|
+
- Automate semantic versioning and PyPI publishing on merge to main
|
|
19
|
+
([`38ac841`](https://github.com/latrekc-meta/ha-deploy-kit/commit/38ac841e33421bae630c165fc834cd639f217a15))
|
|
20
|
+
|
|
21
|
+
python-semantic-release derives the next version from Conventional Commit messages on each push to
|
|
22
|
+
main, bumps project.version, tags, changelogs, and builds; a publish job then uploads to PyPI via
|
|
23
|
+
Trusted Publishing (OIDC, no token). allow_zero_version + major_on_zero=false keep 0.x semantics,
|
|
24
|
+
so the first merge publishes 0.1.0 and tags v0.1.0 automatically. Docs make PyPI the primary
|
|
25
|
+
install path and document the one-time PyPI/environment setup.
|
|
26
|
+
|
|
27
|
+
### Documentation
|
|
28
|
+
|
|
29
|
+
- Readme, install, configuration, and generic adoption guide
|
|
30
|
+
([`9a5c9a0`](https://github.com/latrekc-meta/ha-deploy-kit/commit/9a5c9a04d75812025379202b9450c0f894139834))
|
|
31
|
+
|
|
32
|
+
### Features
|
|
33
|
+
|
|
34
|
+
- Cli orchestration gated on backend changes
|
|
35
|
+
([`e6baa76`](https://github.com/latrekc-meta/ha-deploy-kit/commit/e6baa76a3bf7a31ab828902cf6069ae876b8a790))
|
|
36
|
+
|
|
37
|
+
- Config loading without global env mutation
|
|
38
|
+
([`22eeb50`](https://github.com/latrekc-meta/ha-deploy-kit/commit/22eeb505623ffa56bffd00c5fc222c928b937d7b))
|
|
39
|
+
|
|
40
|
+
- Ha adapter (service, repairs issue, opt-in fix flow, card serving)
|
|
41
|
+
([`fb11c1c`](https://github.com/latrekc-meta/ha-deploy-kit/commit/fb11c1c7a256d76a0e4207d9076b03716c5bdf07))
|
|
42
|
+
|
|
43
|
+
- Ha-deploy-kit package skeleton and settings
|
|
44
|
+
([`5df5334`](https://github.com/latrekc-meta/ha-deploy-kit/commit/5df533432d773eb2b04498077d9a29949e69bb66))
|
|
45
|
+
|
|
46
|
+
- Local inventory with component-relative keys
|
|
47
|
+
([`0cd1f7a`](https://github.com/latrekc-meta/ha-deploy-kit/commit/0cd1f7a3739d89077ee021b64afdb1786759f094))
|
|
48
|
+
|
|
49
|
+
- Optional frontend profile (publish + run, no restart)
|
|
50
|
+
([`07d5418`](https://github.com/latrekc-meta/ha-deploy-kit/commit/07d54181bd6886a7b3a1923160cbf75e795eaa00))
|
|
51
|
+
|
|
52
|
+
- Remote inventory wire format and comparison plan
|
|
53
|
+
([`16f3461`](https://github.com/latrekc-meta/ha-deploy-kit/commit/16f3461283fa4a18bcd97e60102825e2ed8351b8))
|
|
54
|
+
|
|
55
|
+
- Sanitized HTTP notification client with status taxonomy
|
|
56
|
+
([`22d7f21`](https://github.com/latrekc-meta/ha-deploy-kit/commit/22d7f218cf4a9b1de801e1fe967e319cda6cc9db))
|
|
57
|
+
|
|
58
|
+
- Ssh/tar transport with path validation
|
|
59
|
+
([`211ccd0`](https://github.com/latrekc-meta/ha-deploy-kit/commit/211ccd0154690791191614680a736293d65411b1))
|
|
60
|
+
|
|
61
|
+
- **cli**: Make run frontend-aware so card consumers need no pipeline
|
|
62
|
+
([`6eb8c3f`](https://github.com/latrekc-meta/ha-deploy-kit/commit/6eb8c3f154b5164c9b8ae6fee87e8fa628cc1f7d))
|
|
63
|
+
|
|
64
|
+
run now publishes the changed card (frontend_run) and applies a REMOTE_CONFIG env override via
|
|
65
|
+
dataclasses.replace, in addition to deploying the changed backend and notifying. A frontend-only
|
|
66
|
+
change publishes the card but never raises a restart. The three examples collapse to
|
|
67
|
+
build_settings(root)+run(), and frontend_run drops its now-contradictory backend-pending note.
|
|
68
|
+
|
|
69
|
+
- **ha**: Optional fixable flag for one-click restart Repairs card
|
|
70
|
+
([`d2aaee2`](https://github.com/latrekc-meta/ha-deploy-kit/commit/d2aaee23ad01d87b4fe4ff564bbf917f0f7b3d05))
|
|
71
|
+
|
|
72
|
+
async_register_restart_service gains a keyword-only fixable (default False), forwarded as is_fixable
|
|
73
|
+
to the raised issue so a wired fix flow is reachable. Backend-only/notification-only behavior is
|
|
74
|
+
unchanged; the frontend_card example and docs now register fixable=True.
|
|
75
|
+
|
|
76
|
+
### Testing
|
|
77
|
+
|
|
78
|
+
- Installed-wheel smoke test; fix py3.10 tomllib floor; ruff-format doc code blocks
|
|
79
|
+
([`c7ef321`](https://github.com/latrekc-meta/ha-deploy-kit/commit/c7ef3214363e57e53a338b91fdb1dfa63b0cca26))
|
|
80
|
+
|
|
81
|
+
- Real HTTP-to-service proof (notify + HA adapter integrate)
|
|
82
|
+
([`13b366f`](https://github.com/latrekc-meta/ha-deploy-kit/commit/13b366f6dab46e6333f49cad452ab1249bc5d902))
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 latrekc-meta
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: ha-deploy-kit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: HA-free SSH deploy / compare / notify / optional-frontend toolkit for Home Assistant custom components
|
|
5
|
+
Project-URL: Homepage, https://github.com/latrekc-meta/ha-deploy-kit
|
|
6
|
+
Project-URL: Repository, https://github.com/latrekc-meta/ha-deploy-kit
|
|
7
|
+
Project-URL: Issues, https://github.com/latrekc-meta/ha-deploy-kit/issues
|
|
8
|
+
Author: latrekc-meta
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2026 latrekc-meta
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Keywords: custom-component,deploy,home-assistant,homeassistant,lovelace,ssh
|
|
32
|
+
Classifier: Development Status :: 4 - Beta
|
|
33
|
+
Classifier: Intended Audience :: Developers
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Operating System :: OS Independent
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Topic :: Home Automation
|
|
41
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
42
|
+
Requires-Python: >=3.10
|
|
43
|
+
Requires-Dist: certifi
|
|
44
|
+
Requires-Dist: truststore>=0.9
|
|
45
|
+
Provides-Extra: ha
|
|
46
|
+
Requires-Dist: homeassistant; extra == 'ha'
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
|
+
|
|
49
|
+
# ha-deploy-kit
|
|
50
|
+
|
|
51
|
+
A small, reusable library for deploying a Home Assistant custom integration's
|
|
52
|
+
code to a running HA host over SSH, and (optionally) wiring the HA-side restart
|
|
53
|
+
notification. The core is Home-Assistant-free and standard-library only, so a
|
|
54
|
+
deploy script can import it without pulling in Home Assistant; the HA adapter is
|
|
55
|
+
a separate, explicitly-imported subpackage.
|
|
56
|
+
|
|
57
|
+
One process can deploy several integrations without cross-talk: all per-consumer
|
|
58
|
+
state lives in a frozen `DeploySettings` passed by argument — no module globals
|
|
59
|
+
and no `os.environ` mutation.
|
|
60
|
+
|
|
61
|
+
## What it does
|
|
62
|
+
|
|
63
|
+
- Builds a content-hash inventory of your `custom_components/<domain>` tree and
|
|
64
|
+
compares it to the remote tree, deploying only the changed files.
|
|
65
|
+
- Leaves remote-only files untouched (never deletes on the host).
|
|
66
|
+
- Streams files over SSH with an uncompressed, path-validated tar — no backups,
|
|
67
|
+
no lock files, no rollback, no auto-restart.
|
|
68
|
+
- Optionally publishes a separately-served Lovelace card.
|
|
69
|
+
- Optionally raises a Home Assistant *Repairs* issue (via an HA service) telling
|
|
70
|
+
the user a restart is needed. The engine never restarts HA itself; restart is
|
|
71
|
+
opt-in and happens only when a user confirms a Repairs fix flow.
|
|
72
|
+
|
|
73
|
+
## Install
|
|
74
|
+
|
|
75
|
+
Published on PyPI. Pin an exact version.
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
pip install "ha-deploy-kit==0.1.0"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The HA adapter needs Home Assistant, which is an optional extra:
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
pip install "ha-deploy-kit[ha]==0.1.0"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
- **Core** requires Python **3.10+** and only the standard library (plus a CA
|
|
88
|
+
trust store: `certifi`/`truststore`).
|
|
89
|
+
- **The `ha` adapter** requires the Python version Home Assistant itself
|
|
90
|
+
requires; install it in the HA runtime, not in your deploy tooling.
|
|
91
|
+
- **Home Assistant integrations** must pin a versioned PyPI requirement
|
|
92
|
+
(`"ha-deploy-kit==0.1.0"` in `manifest.json`), **never** a `git+…` VCS URL — HA
|
|
93
|
+
installs requirements in its own credential-less environment and treats URL
|
|
94
|
+
requirements as never-satisfied, retrying every startup.
|
|
95
|
+
|
|
96
|
+
See [docs/install.md](docs/install.md) for `pyproject.toml`, HA `manifest.json`,
|
|
97
|
+
and air-gapped host instructions, and [docs/releasing.md](docs/releasing.md) for
|
|
98
|
+
how releases are published.
|
|
99
|
+
|
|
100
|
+
## Public API
|
|
101
|
+
|
|
102
|
+
| Symbol | Import | Purpose |
|
|
103
|
+
| --- | --- | --- |
|
|
104
|
+
| `DeploySettings` | `ha_deploy_kit` | Frozen per-consumer settings (domain, source root, remote config, optional frontend, timeouts). |
|
|
105
|
+
| `FrontendAsset` | `ha_deploy_kit` | Optional served-card mapping (`source_rel`, `published_remote`). |
|
|
106
|
+
| `DeployError` | `ha_deploy_kit` | Raised for recoverable, sanitized deployment errors. |
|
|
107
|
+
| `run(settings, argv, ssh=None, environ=None)` | `ha_deploy_kit.cli` | Orchestrate end to end: compare, report, publish the changed card, deploy the changed backend, notify. Honors a `REMOTE_CONFIG` env override. |
|
|
108
|
+
| `raise_restart_issue(base_url, token, settings)` | `ha_deploy_kit.notify` | POST to the HA restart service; returns a sanitized status string. |
|
|
109
|
+
| `frontend_run(settings, plan, ssh, *, check)` | `ha_deploy_kit.frontend` | Deploy the card into the tree and/or publish the served copy. |
|
|
110
|
+
| `ha.async_register_restart_service(hass, domain, ...)` | `ha_deploy_kit.ha` | Idempotently register the restart service (empty schema). Pass `fixable=True` for a one-click Repairs card (pair with the fix flow). |
|
|
111
|
+
| `ha.async_raise_restart_issue(hass, domain, ...)` | `ha_deploy_kit.ha` | Raise the deduplicated, non-persistent restart Repairs issue. |
|
|
112
|
+
| `ha.async_clear_restart_issue(hass, domain, ...)` | `ha_deploy_kit.ha` | Clear the restart issue. |
|
|
113
|
+
| `ha.async_create_restart_fix_flow(hass, issue_id, ...)` | `ha_deploy_kit.ha` | Optional opt-in confirm-and-restart flow (restart only on submit). |
|
|
114
|
+
| `ha.register_card_serving(hass, domain, lovelace_dir, card_url)` | `ha_deploy_kit.ha` | Serve the card and register it as a frontend module. |
|
|
115
|
+
|
|
116
|
+
## CLI
|
|
117
|
+
|
|
118
|
+
The package installs a `ha-deploy` console script. It deploys by default; pass
|
|
119
|
+
`--check` (or its alias `--dry-run`) to preview without writing anything.
|
|
120
|
+
|
|
121
|
+
```sh
|
|
122
|
+
ha-deploy # deploy changed backend files, then notify
|
|
123
|
+
ha-deploy --check # compare and report only; no writes, no notify
|
|
124
|
+
ha-deploy --root /path/to/your/repo
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The source root is resolved from `--root`, then `HA_DEPLOY_SOURCE_ROOT`, then
|
|
128
|
+
the current directory. The domain is read from `HA_DEPLOY_DOMAIN`, or inferred
|
|
129
|
+
when the root has exactly one `custom_components/<domain>` subdirectory.
|
|
130
|
+
|
|
131
|
+
### One-liner for your own deploy script
|
|
132
|
+
|
|
133
|
+
`run` is fully frontend-aware, so a consumer's `deploy.py` is just settings + a
|
|
134
|
+
call — no pipeline to copy. It publishes a changed card and deploys a changed
|
|
135
|
+
backend; a frontend-only change publishes the card but never notifies a restart.
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
import sys
|
|
139
|
+
from pathlib import Path
|
|
140
|
+
|
|
141
|
+
from ha_deploy_kit import DeploySettings, FrontendAsset
|
|
142
|
+
from ha_deploy_kit.cli import run
|
|
143
|
+
|
|
144
|
+
settings = DeploySettings(
|
|
145
|
+
domain="your_domain",
|
|
146
|
+
source_root=Path(__file__).resolve().parent,
|
|
147
|
+
frontend=FrontendAsset( # omit entirely for backend-only
|
|
148
|
+
source_rel="lovelace/your-card.js",
|
|
149
|
+
published_remote="www/your_domain/your-card.js",
|
|
150
|
+
),
|
|
151
|
+
)
|
|
152
|
+
raise SystemExit(run(settings, sys.argv[1:]))
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`TARGET`/`HA_BASE_URL`/`HA_TOKEN` and an optional `REMOTE_CONFIG` override come
|
|
156
|
+
from `.env` or the process environment; `run` applies `REMOTE_CONFIG` for you.
|
|
157
|
+
|
|
158
|
+
See [docs/configuration.md](docs/configuration.md) for settings and `.env`, and
|
|
159
|
+
[docs/adopting.md](docs/adopting.md) for a step-by-step adoption guide.
|
|
160
|
+
|
|
161
|
+
## Design notes
|
|
162
|
+
|
|
163
|
+
This library deliberately differs from typical hand-rolled HA deploy scripts.
|
|
164
|
+
Each choice below is intentional:
|
|
165
|
+
|
|
166
|
+
- **No positional target and no `--restart` / `--no-restart` / `--card-only`
|
|
167
|
+
flags.** The target comes from the environment; the engine never restarts HA,
|
|
168
|
+
so there is no restart flag to pass.
|
|
169
|
+
- **The engine never executes a restart.** It can only raise a Repairs issue;
|
|
170
|
+
the actual restart is opt-in behind a user-confirmed fix flow.
|
|
171
|
+
- **A frontend-only change never notifies a backend restart.** Backend and
|
|
172
|
+
frontend are separate concerns.
|
|
173
|
+
- **Structured remote inventory.** The remote probe returns an explicit
|
|
174
|
+
four-field result (hashes, stale files, a missing-tree flag, published hash)
|
|
175
|
+
rather than guessing from text.
|
|
176
|
+
- **Environment precedence is explicit.** Process environment overrides `.env`;
|
|
177
|
+
the library never mutates `os.environ`.
|
|
178
|
+
- **Path validation.** Tar members are rejected if absolute, containing `..`,
|
|
179
|
+
NUL, or newlines, or escaping the component directory.
|
|
180
|
+
- **No backups, lock files, rollback, or auto-restart**, and tokens, raw bodies,
|
|
181
|
+
and secret-bearing errors are never printed. TLS and SSH verification are
|
|
182
|
+
never weakened.
|
|
183
|
+
- **Real CA trust store for the notification.** The HTTPS call to Home Assistant
|
|
184
|
+
verifies against the OS trust store via `truststore` (matching `curl`), falling
|
|
185
|
+
back to `certifi` then the stdlib default — all strictly verifying
|
|
186
|
+
(`CERT_REQUIRED` + hostname check). This avoids misreporting a valid cert as
|
|
187
|
+
`tls-error` on platforms whose default context has no usable CA store (macOS,
|
|
188
|
+
python.org, fresh venvs); `tls-error` is reserved for genuine failures.
|
|
189
|
+
|
|
190
|
+
## Releases
|
|
191
|
+
|
|
192
|
+
Releases are automated: every merge to `main` runs semantic-release, which picks
|
|
193
|
+
the next version from the [Conventional Commit] messages (`fix:` → patch,
|
|
194
|
+
`feat:` → minor, `feat!:`/`BREAKING CHANGE:` → major; `docs:`/`chore:`/`test:`
|
|
195
|
+
publish nothing) and publishes to PyPI via Trusted Publishing. Write PR
|
|
196
|
+
titles/commits in that form. See [docs/releasing.md](docs/releasing.md) for the
|
|
197
|
+
one-time setup and the manual fallback.
|
|
198
|
+
|
|
199
|
+
[Conventional Commit]: https://www.conventionalcommits.org/
|