From 8e573f97299b855738fbd4f113d3a1fd98ad685d Mon Sep 17 00:00:00 2001 From: sirmrak Date: Fri, 24 Jul 2026 11:27:23 +0300 Subject: [PATCH] Initial commit --- .gitea/workflows/create_dev_branch.yml | 41 ++++++ .gitea/workflows/update_version.yml | 45 +++++++ .github/workflows/release.yml | 162 +++++++++++++++++++++++ LICENSE | 21 +++ README.md | 66 +++++++++ custom_components/test_me/__init__.py | 23 ++++ custom_components/test_me/config_flow.py | 25 ++++ custom_components/test_me/manifest.json | 11 ++ hacs.json | 5 + pyproject.toml | 26 ++++ 10 files changed, 425 insertions(+) create mode 100644 .gitea/workflows/create_dev_branch.yml create mode 100644 .gitea/workflows/update_version.yml create mode 100644 .github/workflows/release.yml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 custom_components/test_me/__init__.py create mode 100644 custom_components/test_me/config_flow.py create mode 100644 custom_components/test_me/manifest.json create mode 100644 hacs.json create mode 100644 pyproject.toml diff --git a/.gitea/workflows/create_dev_branch.yml b/.gitea/workflows/create_dev_branch.yml new file mode 100644 index 0000000..c9af251 --- /dev/null +++ b/.gitea/workflows/create_dev_branch.yml @@ -0,0 +1,41 @@ +name: Create Dev Branch + +on: + push: + branches: + - main + - master + workflow_dispatch: # Позволяет запустить вручную + +jobs: + create-dev: + name: Create Dev Branch + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.PAT_TOKEN }} + + - name: Check if dev branch exists + id: check_branch + run: | + if git ls-remote --heads origin dev | grep -q "refs/heads/dev"; then + echo "dev_exists=true" >> $GITHUB_OUTPUT + else + echo "dev_exists=false" >> $GITHUB_OUTPUT + fi + + - name: Create dev branch + if: steps.check_branch.outputs.dev_exists == 'false' + run: | + git config --local user.email "actions@gitea.local" + git config --local user.name "Gitea Actions Bot" + + git checkout -b dev + git push origin dev + echo "Dev branch created successfully" \ No newline at end of file diff --git a/.gitea/workflows/update_version.yml b/.gitea/workflows/update_version.yml new file mode 100644 index 0000000..4579e10 --- /dev/null +++ b/.gitea/workflows/update_version.yml @@ -0,0 +1,45 @@ +name: Update Version + +on: + push: + branches: + - main + - master + - dev + +jobs: + update-version: + name: Update Version + runs-on: ubuntu-latest + if: github.actor != 'gitea-actions[bot]' && github.actor != 'Gitea Actions Bot' + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.PAT_TOKEN }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: pip install python-semantic-release + + - name: Configure Git + run: | + git config --local user.email "actions@gitea.local" + git config --local user.name "Gitea Actions Bot" + + - name: Run semantic-release + env: + GITEA_TOKEN: ${{ secrets.PAT_TOKEN }} + run: | + unset GITHUB_SERVER_URL + unset GITHUB_API_URL + unset GITHUB_REPOSITORY + semantic-release version \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..13473eb --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,162 @@ +name: Test and Release + +on: + push: + tags: + - 'v*' + workflow_dispatch: + +jobs: + validate: + name: Validate Integration + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Hassfest Validation + uses: home-assistant/actions/hassfest@master + + - name: HACS Validation + uses: hacs/action@main + with: + category: "integration" + + determine-integration: + name: Determine Integration Name + runs-on: ubuntu-latest + outputs: + integration_name: ${{ steps.get_name.outputs.integration_name }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Get integration name + id: get_name + run: | + INTEGRATION_NAME=$(find custom_components -mindepth 1 -maxdepth 1 -type d -exec test -f {}/manifest.json \; -print -quit | xargs basename) + echo "integration_name=$INTEGRATION_NAME" >> $GITHUB_OUTPUT + + test: + name: Run Tests + runs-on: ubuntu-latest + needs: [validate, determine-integration] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pytest pytest-homeassistant-custom-component + if [ -f requirements_test.txt ]; then pip install -r requirements_test.txt; fi + + - name: Run tests + run: | + if [ -d "tests" ]; then + pytest tests/ --cov=custom_components/${{ needs.determine-integration.outputs.integration_name }} --cov-report=xml + else + echo "No tests directory found, skipping tests" + fi + + lint: + name: Code Quality + runs-on: ubuntu-latest + needs: [validate, determine-integration] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install linters + run: | + pip install black ruff mypy + + - name: Check code formatting with black + run: | + black --check custom_components/${{ needs.determine-integration.outputs.integration_name }}/ || echo "Code formatting issues found" + + - name: Check code with ruff + run: | + ruff check custom_components/${{ needs.determine-integration.outputs.integration_name }}/ || echo "Ruff issues found" + + release: + name: Create Release + runs-on: ubuntu-latest + needs: [validate, test, lint] + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get tag info + id: tag + run: | + TAG=${GITHUB_REF#refs/tags/} + echo "tag=$TAG" >> $GITHUB_OUTPUT + + if [[ "$TAG" == *"beta"* ]]; then + echo "is_beta=true" >> $GITHUB_OUTPUT + else + echo "is_beta=false" >> $GITHUB_OUTPUT + fi + + PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") + if [ -z "$PREV_TAG" ]; then + COMMITS=$(git log --pretty=format:"- %s" --reverse) + else + COMMITS=$(git log ${PREV_TAG}..HEAD --pretty=format:"- %s" --reverse) + fi + + echo "commits<> $GITHUB_OUTPUT + echo "$COMMITS" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Create GitHub Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + TAG="${{ steps.tag.outputs.tag }}" + COMMITS="${{ steps.tag.outputs.commits }}" + IS_BETA="${{ steps.tag.outputs.is_beta }}" + + echo "Creating release $TAG in GitHub..." + + if [ "$IS_BETA" = "true" ]; then + TITLE="Beta Release $TAG" + else + TITLE="Release $TAG" + fi + + cat > /tmp/release_notes.md << EOF + ## $TITLE + + $COMMITS + EOF + + if [ "$IS_BETA" = "true" ]; then + gh release create "$TAG" \ + --title "$TITLE" \ + --notes-file /tmp/release_notes.md \ + --target main \ + --prerelease + else + gh release create "$TAG" \ + --title "$TITLE" \ + --notes-file /tmp/release_notes.md \ + --target main + fi + + echo "Release created successfully!" \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f7df838 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Your Name + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..218f829 --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +# test_me Integration for Home Assistant + +[![GitHub Release][releases-shield]][releases] +[![GitHub Activity][commits-shield]][commits] +[![License][license-shield]](LICENSE) + +[![hacs][hacsbadge]][hacs] + +Integration for Home Assistant to control test_me devices. + +## Installation + +### HACS (Recommended) + +1. Open HACS in Home Assistant +2. Go to "Integrations" +3. Click "+" button +4. Search for "test_me" +5. Click "Install" +6. Restart Home Assistant + +### Manual Installation + +1. Copy `custom_components/test_me` folder to your Home Assistant `custom_components` directory +2. Restart Home Assistant +3. Go to Settings > Devices & Services > Add Integration +4. Search for "test_me" + +## Configuration + +After installation, configure the integration through the Home Assistant UI: + +1. Go to Settings > Devices & Services +2. Click "Add Integration" +3. Search for "test_me" +4. Follow the configuration steps + +## Features + +- Feature 1 +- Feature 2 +- Feature 3 + +## Development + +### Beta Versions + +To test beta versions: +1. Enable "Show beta versions" in HACS settings +2. Update the integration to the latest beta version + +### Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. + +## License + +This project is under the MIT license. + +[commits-shield]: https://img.shields.io/github/commit-activity/y/USER_NAME/test_me.svg +[commits]: https://github.com/USER_NAME/test_me/commits/main +[hacs]: https://hacs.xyz +[hacsbadge]: https://img.shields.io/badge/HACS-Custom-orange.svg +[license-shield]: https://img.shields.io/github/license/USER_NAME/test_me.svg +[releases-shield]: https://img.shields.io/github/release/USER_NAME/test_me.svg +[releases]: https://github.com/USER_NAME/test_me/releases \ No newline at end of file diff --git a/custom_components/test_me/__init__.py b/custom_components/test_me/__init__.py new file mode 100644 index 0000000..528e3e9 --- /dev/null +++ b/custom_components/test_me/__init__.py @@ -0,0 +1,23 @@ +"""The test_me integration.""" +import logging +from homeassistant.core import HomeAssistant +from homeassistant.config_entries import ConfigEntry +from .const import DOMAIN + +_LOGGER = logging.getLogger(__name__) + +async def async_setup(hass: HomeAssistant, config: dict) -> bool: + """Set up the test_me component from yaml configuration.""" + hass.data.setdefault(DOMAIN, {}) + return True + +async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: + """Set up test_me from a config entry.""" + hass.data.setdefault(DOMAIN, {}) + hass.data[DOMAIN][entry.entry_id] = {} + await hass.config_entries.async_forward_entry_setups(entry, ["sensor"]) + return True + +async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: + """Unload a config entry.""" + return await hass.config_entries.async_unload_platforms(entry, ["sensor"]) \ No newline at end of file diff --git a/custom_components/test_me/config_flow.py b/custom_components/test_me/config_flow.py new file mode 100644 index 0000000..524f4cc --- /dev/null +++ b/custom_components/test_me/config_flow.py @@ -0,0 +1,25 @@ +"""Config flow for test_me integration.""" +from __future__ import annotations +import logging +from typing import Any +import voluptuous as vol +from homeassistant.config_entries import ConfigFlow +from homeassistant.core import HomeAssistant +from .const import DOMAIN + +_LOGGER = logging.getLogger(__name__) + +STEP_USER_DATA_SCHEMA = vol.Schema({ + vol.Required("host"): str, +}) + +class ConfigFlowHandler(ConfigFlow, domain=DOMAIN): + """Handle a config flow for test_me.""" + VERSION = 1 + + async def async_step_user(self, user_input: dict[str, Any] | None = None) -> Any: + """Handle the initial step.""" + errors: dict[str, str] = {} + if user_input is not None: + return self.async_create_entry(title="test_me Integration", data=user_input) + return self.async_show_form(step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors) \ No newline at end of file diff --git a/custom_components/test_me/manifest.json b/custom_components/test_me/manifest.json new file mode 100644 index 0000000..1712673 --- /dev/null +++ b/custom_components/test_me/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "test_me", + "name": "test_me Integration", + "codeowners": ["@sirmrak"], + "config_flow": true, + "documentation": "https://github.com/sirmrak/test_me", + "integration_type": "hub", + "iot_class": "local_polling", + "requirements": [], + "version": "1.0.0" +} \ No newline at end of file diff --git a/hacs.json b/hacs.json new file mode 100644 index 0000000..30d4c4a --- /dev/null +++ b/hacs.json @@ -0,0 +1,5 @@ +{ + "name": "test_me Integration", + "render_readme": true, + "homeassistant": "2024.1.0" +} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..54175b7 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,26 @@ +[tool.semantic_release] +tag_format = "v{version}" +version_variables = [ + "custom_components/test_me/manifest.json:version", +] +commit_message = "chore(release): v{version}" +upload_to_vcs_release = false + +[tool.semantic_release.remote] +type = "gitea" +domain = "git.darkmode.duckdns.org" +api_domain = "git.darkmode.duckdns.org" + +[tool.semantic_release.branches.main] +match = "(main|master)" +prerelease = false + +[tool.semantic_release.branches.dev] +match = "dev" +prerelease = true +prerelease_token = "beta" + +[tool.semantic_release.commit_parser_options] +allowed_tags = ["feat", "fix", "docs", "style", "refactor", "perf", "test", "chore", "revert"] +minor_tags = ["feat"] +patch_tags = ["fix", "perf"] \ No newline at end of file