diff --git a/.github/workflows/behave_pull_request.yml b/.github/workflows/behave_pull_request.yml index 64010ba5df..4ccc8a2dcf 100644 --- a/.github/workflows/behave_pull_request.yml +++ b/.github/workflows/behave_pull_request.yml @@ -1,4 +1,4 @@ -name: Test Councils (Pull Request Only) +name: PR - Test Councils on: workflow_dispatch: @@ -14,12 +14,12 @@ jobs: name: Setup Environment runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Poetry run: pipx install poetry==1.8.4 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: 3.12 @@ -31,7 +31,7 @@ jobs: - name: Get All Council Files That Have Changed id: changed-council-files - uses: tj-actions/changed-files@v46 + uses: tj-actions/changed-files@v47 with: files: | uk_bin_collection/uk_bin_collection/councils/**.py @@ -61,9 +61,9 @@ jobs: python-version: [3.12] poetry-version: [1.8.4] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} @@ -92,9 +92,9 @@ jobs: python-version: [3.12] poetry-version: [1.8.4] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} @@ -103,12 +103,13 @@ jobs: - name: Install Dependencies run: make install-dev - + - name: Check Parity of Councils / input.json / Feature file - run: | - repo=${{ github.event.pull_request.head.repo.full_name || 'robbrad/UKBinCollectionData' }} - branch=${{ github.event.pull_request.head.ref || 'master' }} - make parity-check repo=$repo branch=$branch + env: + repo: ${{ github.event.pull_request.head.repo.full_name || 'robbrad/UKBinCollectionData' }} + branch: ${{ github.event.pull_request.head.ref || 'master' }} + run: make parity-check repo="$repo" branch="$branch" + integration-tests: name: Run Integration Tests needs: setup @@ -124,9 +125,9 @@ jobs: ports: - 4444:4444 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} @@ -151,4 +152,4 @@ jobs: report_type: test_results file: build/${{ matrix.python-version }}/integration-test-results/junit.xml flags: integrationtestspr - name: integration-tests-pr \ No newline at end of file + name: integration-tests-pr diff --git a/.github/workflows/behave_schedule.yml b/.github/workflows/behave_schedule.yml index 05227d9b18..cfdfab5035 100644 --- a/.github/workflows/behave_schedule.yml +++ b/.github/workflows/behave_schedule.yml @@ -1,4 +1,4 @@ -name: Test Councils (Nightly Full Run) +name: Scheduled - Test All Councils on: workflow_dispatch: @@ -10,12 +10,12 @@ jobs: name: Setup Environment runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Poetry run: pipx install poetry==1.8.4 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: 3.12 @@ -43,9 +43,9 @@ jobs: python-version: [3.12] poetry-version: [1.8.4] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} @@ -74,9 +74,9 @@ jobs: python-version: [3.12] poetry-version: [1.8.4] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} @@ -107,9 +107,9 @@ jobs: ports: - 4444:4444 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/bump.yml b/.github/workflows/bump.yml index 327ca12d9f..7aac18acca 100644 --- a/.github/workflows/bump.yml +++ b/.github/workflows/bump.yml @@ -1,34 +1,79 @@ -name: Bump Version +name: Release - Bump Version on: push: - # Trigger unless only the wiki directory changed + branches: [ "master" ] paths-ignore: - "wiki/**" - - "**/**.md" + - "**/*.md" - ".github/workflows/**" - branches: [ "master" ] + workflow_dispatch: {} jobs: bump: if: "!startsWith(github.event.head_commit.message, 'bump:')" runs-on: ubuntu-latest - environment: bump - concurrency: bump permissions: - id-token: write contents: write + concurrency: bump + steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v6 with: - token: "${{ secrets.PERSONAL_ACCESS_TOKEN }}" fetch-depth: 0 - - uses: actions/setup-python@v5 + ssh-key: ${{ secrets.DEPLOY_KEY }} + persist-credentials: true + + - name: Setup Python + uses: actions/setup-python@v6 with: python-version: '3.12' + cache: 'pip' - - name: Bump version - id: cz - uses: commitizen-tools/commitizen-action@master + - name: Cache Commitizen + uses: actions/cache@v5 with: - github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + path: ~/.cache/pip + key: ${{ runner.os }}-pip-commitizen-${{ hashFiles('**/pyproject.toml') }} + restore-keys: | + ${{ runner.os }}-pip-commitizen- + + - name: Install Commitizen + run: pip install commitizen + + - name: Configure git identity + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + - name: Bump version and create tag + id: bump + run: | + # Check if there are commits to bump + if cz bump --yes --changelog --dry-run 2>&1 | grep -q "No commits found"; then + echo "No version bump needed - no conventional commits since last release" + echo "skip=true" >> $GITHUB_OUTPUT + exit 0 + fi + cz bump --yes --changelog + echo "version=$(cz version --project)" >> $GITHUB_OUTPUT + echo "skip=false" >> $GITHUB_OUTPUT + + - name: Push changes and tags + if: steps.bump.outputs.skip != 'true' + run: | + git push origin master + git push origin --tags + + - name: Create workflow summary + if: always() + run: | + echo "## Bump Summary" >> $GITHUB_STEP_SUMMARY + if [ "${{ steps.bump.outputs.skip }}" == "true" ]; then + echo "- **Status**: ⏭️ Skipped (no conventional commits)" >> $GITHUB_STEP_SUMMARY + else + echo "- **Status**: ✅ Success" >> $GITHUB_STEP_SUMMARY + echo "- **New Version**: ${{ steps.bump.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "- **Tag Created**: ${{ steps.bump.outputs.version }}" >> $GITHUB_STEP_SUMMARY + fi diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 6e2c61ddc2..4b6b43e587 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -47,11 +47,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -65,7 +65,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v3 + uses: github/codeql-action/autobuild@v4 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -78,4 +78,4 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 635f4b444c..275f9f1e36 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -1,4 +1,4 @@ -name: Docker Image CI +name: Build - Docker Image on: push: @@ -22,7 +22,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Publish to Registry uses: elgohr/Publish-Docker-Github-Action@v5 with: diff --git a/.github/workflows/ha_compatibility_test.yml b/.github/workflows/ha_compatibility_test.yml new file mode 100644 index 0000000000..2720dc86f0 --- /dev/null +++ b/.github/workflows/ha_compatibility_test.yml @@ -0,0 +1,238 @@ +name: PR - Home Assistant Compatibility Test + +on: + push: + branches: [ master, main ] + paths: + - 'custom_components/**' + - 'pyproject.toml' + pull_request: + branches: [ master, main ] + paths: + - 'custom_components/**' + - 'pyproject.toml' + schedule: + - cron: '0 6 * * 1' # Weekly on Monday at 6 AM UTC + +jobs: + generate-matrix: + name: Generate HA Version Matrix + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.get-versions.outputs.matrix }} + steps: + - name: Get HA versions from PyPI + id: get-versions + run: | + MATRIX=$(curl -s https://pypi.org/pypi/homeassistant/json | jq -c ' + .releases + | to_entries + # keep only x.y.z (skip betas/devs/post) + | map(select(.key | test("^[0-9]+\\.[0-9]+\\.[0-9]+$"))) + # group by major.minor, keep highest patch + | group_by(.key | (split(".")[:2] | join("."))) + | map(max_by(.key | (split(".")[2] | tonumber)) | .key) + # sort numerically and take latest 8 + | sort_by(split(".") | map(tonumber)) + | .[-8:] + # pick python version per HA series; adjust as needed + | map({ha_version: ., python_version: (if (split(".")[0] == "2025" and (split(".")[1]|tonumber) >= 2) then "3.13" else "3.12" end)}) + # also test latest dev on py 3.13 + | . + [{ha_version: "dev", python_version: "3.13"}] + | {include: .} + ') + echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT" + + test-ha-compatibility: + name: Test HA ${{ matrix.ha_version }} + runs-on: ubuntu-latest + needs: generate-matrix + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Determine Docker tag + id: docker-tag + run: | + if [ "${{ matrix.ha_version }}" = "dev" ]; then + echo "tag=dev" >> "$GITHUB_OUTPUT" + else + echo "tag=${{ matrix.ha_version }}" >> "$GITHUB_OUTPUT" + fi + + - name: Setup HA config directory + run: | + mkdir -p config/custom_components config/.storage + cp -r custom_components/uk_bin_collection config/custom_components/ + cat > config/configuration.yaml <<'YAML' + logger: + default: info + YAML + + # Create a config entry to trigger component setup + cat > config/.storage/core.config_entries <<'JSON' + { + "version": 1, + "minor_version": 1, + "key": "core.config_entries", + "data": { + "entries": [ + { + "entry_id": "test_uk_bin_collection", + "version": 3, + "domain": "uk_bin_collection", + "title": "Test Entry", + "data": { + "name": "Test Council", + "council": "GooglePublicCalendarCouncil", + "url": "https://calendar.google.com/calendar/ical/0d775884b4db6a7bae5204f06dae113c1a36e505b25991ebc27c6bd42edf5b5e%40group.calendar.google.com/public/basic.ics", + "timeout": 60, + "update_interval": 12, + "manual_refresh_only": true + }, + "options": {}, + "pref_disable_new_entities": false, + "pref_disable_polling": false, + "source": "user", + "unique_id": null, + "disabled_by": null + } + ] + } + } + JSON + + - name: Start Home Assistant in Docker + run: | + docker run -d \ + --name homeassistant \ + -v $(pwd)/config:/config \ + -e TZ=UTC \ + ghcr.io/home-assistant/home-assistant:${{ steps.docker-tag.outputs.tag }} + + echo "Waiting for container to start..." + sleep 5 + + - name: Wait for Home Assistant to boot + id: boot + run: | + set -euo pipefail + TIMEOUT=150 + SECS=0 + INIT_MARKER="Home Assistant initialized" + FAIL=0 + + echo "Waiting for HA to initialize..." + while (( SECS < TIMEOUT )); do + LOGS=$(docker logs homeassistant 2>&1) + if echo "$LOGS" | grep -q "$INIT_MARKER"; then + echo "✅ HA initialized successfully" + break + fi + sleep 1 + SECS=$((SECS+1)) + if (( SECS % 10 == 0 )); then + echo "Waiting... ${SECS}s" + fi + done + + # Check for dependency installation and component setup + LOGS=$(docker logs homeassistant 2>&1) + if echo "$LOGS" | grep -q "Attempting install of uk-bin-collection"; then + echo "✅ HA attempted to install uk-bin-collection dependency" + fi + + if echo "$LOGS" | grep -Eq "(ERROR|CRITICAL).*(uk_bin_collection|custom_components\.uk_bin_collection)"; then + echo "❌ Component has errors in logs:" + echo "$LOGS" | grep -E "(ERROR|CRITICAL).*(uk_bin_collection|custom_components\.uk_bin_collection)" || true + FAIL=1 + fi + + # Check timeout + if (( SECS >= TIMEOUT )) && ! echo "$LOGS" | grep -q "$INIT_MARKER"; then + echo "❌ HA did not finish booting within ${TIMEOUT}s" + FAIL=1 + fi + + # Expose pass/fail to later steps + echo "boot_failed=${FAIL}" >> "$GITHUB_OUTPUT" + exit ${FAIL} + + - name: Save HA logs to file + if: always() + run: | + docker logs homeassistant > home-assistant.log 2>&1 || true + + - name: Show HA logs + if: always() + run: | + echo "--- Last 80 log lines ---" + tail -n 80 home-assistant.log 2>/dev/null || docker logs homeassistant 2>&1 | tail -n 80 + + - name: Stop and remove container + if: always() + run: | + docker stop homeassistant || true + docker rm homeassistant || true + + - name: Upload HA log (always) + if: always() + uses: actions/upload-artifact@v6 + with: + name: ha-log-${{ matrix.ha_version }} + path: home-assistant.log + overwrite: true + + - name: Test manifest validation + id: manifest + run: | + python <<'PY' + import json, sys + with open('custom_components/uk_bin_collection/manifest.json') as f: + m = json.load(f) + required = ['domain', 'name', 'version', 'requirements'] + missing = [k for k in required if k not in m] + if missing: + print(f'❌ Missing required manifest fields: {missing}') + sys.exit(1) + print('✅ Manifest validation passed') + print(f'Component version: {m.get("version")}') + print(f'Requirements: {m.get("requirements")}') + PY + + - name: Create test result summary + if: always() + run: | + echo "## Boot Results for HA ${{ matrix.ha_version }} (Python ${{ matrix.python_version }})" >> "$GITHUB_STEP_SUMMARY" + if [ "${{ steps.boot.outputs.boot_failed }}" = "0" ] && [ "${{ steps.manifest.outcome }}" = "success" ]; then + echo "✅ **PASSED** – HA booted with the custom component present" >> "$GITHUB_STEP_SUMMARY" + else + echo "❌ **FAILED** – HA failed to boot cleanly" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "- boot step failed: \`${{ steps.boot.outputs.boot_failed }}\`" >> "$GITHUB_STEP_SUMMARY" + echo "- manifest step: \`${{ steps.manifest.outcome }}\`" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "See the uploaded **ha-log** artifact for details." >> "$GITHUB_STEP_SUMMARY" + fi + + + compatibility-report: + name: Generate Compatibility Report + runs-on: ubuntu-latest + needs: [generate-matrix, test-ha-compatibility] + if: always() + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Create compatibility report + run: | + echo "# Home Assistant Compatibility Report" > report.md + echo "" >> report.md + echo "Matrix tested: \`${{ needs.generate-matrix.outputs.matrix }}\`" >> report.md + echo "Last updated: $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> report.md + cat report.md >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/hacs_validation.yml b/.github/workflows/hacs_validation.yml index 2d7b2fc25d..060177fc0e 100644 --- a/.github/workflows/hacs_validation.yml +++ b/.github/workflows/hacs_validation.yml @@ -1,4 +1,4 @@ -name: Validate with hassfest +name: PR - Validate HACS on: push: @@ -11,8 +11,9 @@ jobs: name: HassFest Validation runs-on: "ubuntu-latest" steps: - - uses: "actions/checkout@v4" + - uses: "actions/checkout@v6" - uses: home-assistant/actions/hassfest@master + hacs: name: HACS Action Validation runs-on: "ubuntu-latest" @@ -21,3 +22,4 @@ jobs: uses: "hacs/action@main" with: category: "integration" + diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c219c96667..ddb01e4398 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,4 +1,4 @@ -name: Lint Commit Message +name: PR - Lint Commit Messages on: push: @@ -16,7 +16,7 @@ jobs: name: Lint Commit Messages runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: fetch-depth: 0 - run: "echo \"export default {extends: ['@commitlint/config-conventional'], rules: { 'subject-case': [0], 'body-max-line-length': [0], 'footer-max-line-length': [0] }}\" > commitlint.config.mjs" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e07bf3feab..844b747949 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: Publish Release +name: Release - Publish to PyPI on: push: @@ -8,41 +8,98 @@ on: jobs: release: runs-on: ubuntu-latest - environment: release permissions: - id-token: write contents: write + id-token: write steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup Python + uses: actions/setup-python@v6 with: python-version: '3.12' + cache: 'pip' - - name: Run image + - name: Install Poetry uses: abatilo/actions-poetry@v4.0.0 with: poetry-version: '1.8.4' - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install wheel twine - - - name: Install - run: make install + - name: Cache Poetry dependencies + uses: actions/cache@v5 + with: + path: ~/.cache/pypoetry + key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }} + restore-keys: | + ${{ runner.os }}-poetry- - name: Set release version run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - - name: Create release + - name: Verify version matches tag + run: | + POETRY_VERSION=$(poetry version -s) + if [ "$POETRY_VERSION" != "${{ env.RELEASE_VERSION }}" ]; then + echo "Error: Poetry version ($POETRY_VERSION) doesn't match tag (${{ env.RELEASE_VERSION }})" + exit 1 + fi + + - name: Build package + run: poetry build + + - name: Create GitHub release uses: ncipollo/release-action@v1 with: tag: ${{ env.RELEASE_VERSION }} generateReleaseNotes: true - prerelease: false - allowUpdates: true + artifacts: "dist/*" + token: ${{ secrets.GITHUB_TOKEN }} - - name: Build and publish package + - name: Publish to PyPI + uses: nick-fields/retry@v3 + with: + timeout_minutes: 5 + max_attempts: 3 + retry_wait_seconds: 30 + command: | + poetry config pypi-token.pypi "${{ secrets.PYPI_API_KEY }}" + poetry publish + + - name: Create workflow summary + if: always() run: | - poetry config pypi-token.pypi "${{ secrets.PYPI_API_KEY }}" - poetry publish --build + echo "## Release Summary" >> $GITHUB_STEP_SUMMARY + echo "- **Version**: ${{ env.RELEASE_VERSION }}" >> $GITHUB_STEP_SUMMARY + echo "- **Status**: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY + if [ "${{ job.status }}" == "success" ]; then + echo "- **PyPI**: https://pypi.org/project/uk-bin-collection/${{ env.RELEASE_VERSION }}/" >> $GITHUB_STEP_SUMMARY + echo "- **GitHub Release**: https://github.com/${{ github.repository }}/releases/tag/${{ env.RELEASE_VERSION }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "✅ Release published successfully!" >> $GITHUB_STEP_SUMMARY + else + echo "" >> $GITHUB_STEP_SUMMARY + echo "❌ Release failed - check logs above" >> $GITHUB_STEP_SUMMARY + fi + + docker: + needs: release + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_API_KEY }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: ./uk_bin_collection_api_server + push: true + tags: | + robbrad182/uk-bin-collection:${{ github.ref_name }} + robbrad182/uk-bin-collection:latest diff --git a/.github/workflows/rollback-release.yml b/.github/workflows/rollback-release.yml new file mode 100644 index 0000000000..82455b4c3c --- /dev/null +++ b/.github/workflows/rollback-release.yml @@ -0,0 +1,117 @@ +name: Release - Rollback + +on: + workflow_dispatch: + inputs: + version: + description: 'Version to rollback (e.g., 0.155.0)' + required: true + type: string + delete_pypi: + description: 'Also yank from PyPI? (cannot delete, only yank)' + required: false + type: boolean + default: false + +jobs: + rollback: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + ssh-key: ${{ secrets.DEPLOY_KEY }} + + - name: Validate version format + run: | + if ! [[ "${{ inputs.version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "❌ Invalid version format. Use X.Y.Z (e.g., 0.155.0)" + exit 1 + fi + echo "✅ Version format valid: ${{ inputs.version }}" + + - name: Check if release exists + id: check + run: | + if gh release view ${{ inputs.version }} > /dev/null 2>&1; then + echo "exists=true" >> $GITHUB_OUTPUT + echo "✅ Release ${{ inputs.version }} exists" + else + echo "exists=false" >> $GITHUB_OUTPUT + echo "⚠️ Release ${{ inputs.version }} not found" + fi + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Delete GitHub Release + if: steps.check.outputs.exists == 'true' + run: | + echo "🗑️ Deleting GitHub release ${{ inputs.version }}..." + gh release delete ${{ inputs.version }} --yes + echo "✅ GitHub release deleted" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Delete Git Tag + run: | + if git rev-parse ${{ inputs.version }} >/dev/null 2>&1; then + echo "🗑️ Deleting git tag ${{ inputs.version }}..." + git push origin :refs/tags/${{ inputs.version }} + echo "✅ Git tag deleted" + else + echo "⚠️ Tag ${{ inputs.version }} not found locally" + fi + + - name: Setup Python (if PyPI yank requested) + if: inputs.delete_pypi == true + uses: actions/setup-python@v6 + with: + python-version: '3.12' + + - name: Install Poetry (if PyPI yank requested) + if: inputs.delete_pypi == true + uses: abatilo/actions-poetry@v4.0.0 + with: + poetry-version: '1.8.4' + + - name: Yank from PyPI + if: inputs.delete_pypi == true + run: | + echo "⚠️ Yanking version ${{ inputs.version }} from PyPI..." + echo "Note: This marks the release as unsuitable for installation but doesn't delete it" + poetry config pypi-token.pypi "${{ secrets.PYPI_API_KEY }}" + # PyPI doesn't support yanking via poetry directly, need to use twine + pip install twine + # Note: You'll need to manually yank via PyPI web interface or use: + # twine upload --repository pypi --skip-existing dist/* + echo "⚠️ PyPI yanking must be done manually at: https://pypi.org/manage/project/uk-bin-collection/releases/" + echo "Go to the release and click 'Options' -> 'Yank release'" + + - name: Create workflow summary + if: always() + run: | + echo "## Rollback Summary" >> $GITHUB_STEP_SUMMARY + echo "- **Version**: ${{ inputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "- **GitHub Release**: ${{ steps.check.outputs.exists == 'true' && '✅ Deleted' || '⚠️ Not found' }}" >> $GITHUB_STEP_SUMMARY + echo "- **Git Tag**: Deleted from remote" >> $GITHUB_STEP_SUMMARY + if [ "${{ inputs.delete_pypi }}" == "true" ]; then + echo "- **PyPI**: ⚠️ Manual yank required" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Next Steps for PyPI" >> $GITHUB_STEP_SUMMARY + echo "1. Go to https://pypi.org/manage/project/uk-bin-collection/releases/" >> $GITHUB_STEP_SUMMARY + echo "2. Find version ${{ inputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "3. Click 'Options' -> 'Yank release'" >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ⚠️ Important Notes" >> $GITHUB_STEP_SUMMARY + echo "- The version bump commit still exists in git history" >> $GITHUB_STEP_SUMMARY + echo "- To fully rollback, you may need to revert the bump commit" >> $GITHUB_STEP_SUMMARY + echo "- Users who already installed this version will keep it" >> $GITHUB_STEP_SUMMARY + + - name: Notify completion + run: | + echo "✅ Rollback completed for version ${{ inputs.version }}" + echo "Check the summary tab for details" diff --git a/.github/workflows/validate-release-ready.yml b/.github/workflows/validate-release-ready.yml new file mode 100644 index 0000000000..e02d33f981 --- /dev/null +++ b/.github/workflows/validate-release-ready.yml @@ -0,0 +1,40 @@ +name: PR - Validate Release Ready + +on: + workflow_dispatch: + pull_request: + branches: [ "master" ] + types: [opened, synchronize, reopened] + +jobs: + validate: + name: Validate Release Prerequisites + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - uses: actions/setup-python@v6 + with: + python-version: '3.12' + cache: 'pip' + + - name: Cache Poetry + uses: actions/cache@v5 + with: + path: ~/.local/pipx + key: ${{ runner.os }}-pipx-poetry-1.8.4 + restore-keys: | + ${{ runner.os }}-pipx-poetry- + + - name: Install Poetry + run: pipx install poetry==1.8.4 + + - name: Validate pyproject.toml + run: poetry check + + - name: Check for conventional commits + uses: wagoid/commitlint-github-action@v6 + with: + configFile: commitlint.config.mjs diff --git a/.github/workflows/wiki.yml b/.github/workflows/wiki.yml index de68bc8a4f..93c38d646b 100644 --- a/.github/workflows/wiki.yml +++ b/.github/workflows/wiki.yml @@ -1,4 +1,4 @@ -name: Deploy Wiki +name: Deploy - Wiki on: push: @@ -22,8 +22,8 @@ jobs: runs-on: ubuntu-latest environment: wiki steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 with: python-version: '3.12' @@ -48,7 +48,7 @@ jobs: continue-on-error: true - name: Deploy Wiki Changes - uses: Andrew-Chen-Wang/github-wiki-action@v4 + uses: Andrew-Chen-Wang/github-wiki-action@v5 with: # Make sure WIKI_DIR ends with / as action uses rsync path: wiki/ diff --git a/.gitignore b/.gitignore index 193e15c91c..89fe81fb6c 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ !pytest.ini # Or these folders... +!docs !.github !*.png !.github/ISSUE_TEMPLATE @@ -41,5 +42,8 @@ __pycache__ !TO_BE_CONVERTED !.devcontainer -uk_bin_collection/.DS_Store -uk_bin_collection/uk_bin_collection/.DS_Store +uk_bin_collection/.DS_Store +uk_bin_collection/uk_bin_collection/.DS_Store +!scripts +!.kiro +ISSUE_RESOLUTION_PROGRESS.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 00288494fc..f695a4c62b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5263 @@ ======= +## 0.163.0 (2026-02-02) + +### Feat + +- #1686 GosportBoroughCouncil - Add new council using Supatrak API +- #1593 #1618 #1794 - Add Causeway Coast and Glens, Rossendale Borough, North Warwickshire to GooglePublicCalendarCouncil + +### Fix + +- #1831 HarboroughDistrictCouncil - use data instead of json, suppress SSL warnings, improve parsing +- #1831 HarboroughDistrictCouncil - add SSL bypass and better error handling for 502 errors +- #1836 LondonBoroughRedbridge - updated selectors for redesigned website + +## 0.162.7 (2026-02-02) + +### Fix + +- resolve issues #1776, #1780, #1782 - Camden, NE Derbyshire, Newport +- Broken councils +- remove URLs from translation strings for HACS compliance +- **CumberlandCouncil**: remove obsolete duplicate entries +- **AmberValleyBoroughCouncil**: filter invalid date 01/01/0001 +- Kingston parser for HTML format change with explicit error handling +- Kingston-upon-Thames website HTML format change +- UttlesfordDistrictCouncil use color names for bin types +- EastHertsCouncil handle empty NextDate values +- UttlesfordDistrictCouncil incorrect bin types due to wrong alt text +- compare dates without time component in UttlesfordDistrictCouncil +- UttlesfordDistrictCouncil hardcoded year 2024 +- Wyre Forest District Council +- #1835 - Wyre Forest District Council +- Babergh District Council +- #1783 - Babergh District Council +- Mid Suffolk District Council +- #1746 - Mid Suffolk District Council +- Waverley Borough Council +- #1834 - Waverley Borough Council +- London Borough Sutton +- #1830 - London Borough Sutton +- Bolton Council +- #1792 - Bolton Council +- Coventry City Council +- #1808 - Coventry City Council +- Slough Borough Council +- #1822 - Slough Borough Council +- Bromley Borough Council +- #1829 - Bromley Borough Council +- Burnley Borough Council +- #1820 - Burnley Borough Council + +### Refactor + +- add explicit datetime import in UttlesfordDistrictCouncil + +## 0.162.6 (2026-01-14) + +### Fix + +- FolkestoneandHytheDistrictCouncil.py +- CastlepointDistrictCouncil +- Folkestone and Hythe District Council +- Castlepoint District Council +- #1803 #1793 Castlepoint District Council +- Folkstone and Hythe District Council +- #1760 - Folkstone and Hythe District Council +- Newark and Sherwood District Council +- #1777 - fix: Newark and Sherwood District Council +- South Lanarkshire Council +- #1771 - South Lanarkshire Council +- Renfrewshire Council +- #1500 - Renfrewshire Council + +## 0.162.5 (2025-12-08) + +### Fix + +- West Oxfordshire +- West Oxfordshire +- Adur & Worthing (#1454), Hillingdon (#1680) + +## 0.162.4 (2025-12-08) + +### Fix + +- Cumberland Council + +## 0.162.3 (2025-12-08) + +### Fix + +- Islington, Worcester + +## 0.162.2 (2025-12-07) + +### Fix + +- Broken councils + +## 0.162.1 (2025-12-07) + +## 0.162.0 (2025-12-07) + +### Feat + +- Add support for Isle of Anglesey County Council +- replace Selenium with Cloud9 mobile API for NHDC bin collection data +- Adding Harlow Council +- #1639 Adding Harlow Council +- Adding Blackpool Council +- #1640 Adding Blackpool Council + +### Fix + +- add User-Agent header to KingsLynnandWestNorfolkBC scraper +- **southgloucestershirecouncil**: check none instead of empty string +- Treat missing response data as an error to prevent silent failure +- address latest CodeRabbit feedback +- address CodeRabbit feedback +- Fix input.json data +- fix UPRN param encoding for SouthamptonCityCouncil +- Replace loop variable for clarity in North Hertfordshire parsing logic +- Let requests handle query param encoding +- Address edge case in address splitting +- Handle edge case for date parsing validation +- Don't bail on invalid date format +- Add comment explaining where auth header came from +- Improve error handling for mobile API requests and JSON parsing +- Use constant for mobile API container count +- Improve error handling for mobile API JSON response +- Use named imports from common +- Add sorting key for bin collections using parsed datetime +- Improve error handling for collection date parsing +- Use `line.strip()` in list comp +- Update comment to match behaviour +- Amend list comprehension variable name to avoid shadowing +- Remove unused variable assignment +- Perform postcode/paon string manipulation after checking truthiness +- WiltshireCouncil.py +- Rushmoor Council +- #1724 - Rushmoor Council +- Wiltshire Council +- #1689 - Wiltshire Council +- Halton Borough Council +- #1209 Halton Borough Council +- Northumberland Council +- #1711 - Northumberland Council - Requires 12 digit UPRN +- South Lanarkshire Council +- #1712 - South Lanarkshire Council +- Argyll and Bute Council +- #1718 - Argyll and Bute Council +- Thurrock Council +- #1720 - Thurrock Council +- Mid Sussex +- #1721 Mid Sussex +- Chelmsford City Council +- #1707 +- #1706 - London Borough of Lambeth +- #1706 - London Borough of Lambeth +- Fife Council +- Armagh Banbridge Craigavon Council +- #1622 + +### Refactor + +- Adjust return payload aggregation logic + +## 0.161.0 (2025-11-08) + +### Feat + +- Dumfries and Galloway Council + +### Fix + +- Herefordshire Council +- Herefordshire Council +- Southampton City Council +- #1698 +- Newport City Council +- #1229 +- Middlesborough Council +- #1382 - Removed the need for Selenium +- Boston Borough Council +- #1690 +- Chelmsford City Council +- #1688 - BREAKING CHANGE +- Derby City Council +- #1676 +- London Borough of Hounslow +- #1683 +- Brighton & Hove +- #1685 - New URL +- Brighton & Hove +- #1685 - New URL +- Hart District Council +- #1625 +- London Borough of Harrow +- #1621 +- Wokingham Borough Council +- #1641 +- Norwich City Council +- #1653 +- Rochdale Council +- #1675 +fix: #1259 +- **tendring**: ignore stale 'Next collection' dates older than today +- **tendring**: restore headless=True default and silence unused lambda arg for lint +- **tendring**: use 'Next collection' column; fix imports/strings/waits; robust iframe/cookie handling +- **tendring**: read 'Next collection' column; harden cookie/iframe handling; normalise dd/MM/YYYY + +## 0.160.1 (2025-10-21) + +### Fix + +- test valley wrong dates +- Remove merge conflict +- remove merge conflict +- remove merge conflict message + +## 0.160.0 (2025-10-21) + +### Feat + +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant +- adding tests to ensure releases work with Home assistant + +## 0.159.3 (2025-10-20) + +### Fix + +- Broken dependancies + +## 0.159.2 (2025-10-19) + +### Fix + +- allow pillow 11.x to fix home assistant compatibility + +## 0.159.1 (2025-10-18) + +### Fix + +- Add null checks to prevent AttributeError when collection date text is not found. Introduces extract_collection_date() helper that safely extracts dates and returns None if parsing fails, allowing the scraper to gracefully skip missing collection types. + +## 0.159.0 (2025-10-18) + +### Feat + +- Modernize South Kesteven scraper with requests-based approach and OCR + +### Fix + +- **feedbank**: address improvements suggested in PR review +- Update NorthTynesideCouncil to reflect changes to website and extract schedule from the UPRN linked page + +## 0.158.1 (2025-10-18) + +### Fix + +- remove merge conflict annotations and delete old code +- click on the submit button instead of sending ENTER + +## 0.158.0 (2025-10-11) + +### Feat + +- workflow overhaul +- workflow overhaul + +## 0.157.0 (2025-10-11) + +### Feat + +- Create tag-on-merge.yml +- Update bump.yml +- fix bump.yml +- Update TorbayCouncil.py +- Update bump.yml +- fix release pipeline bump.yml +- fix Torbay + +### Fix + +- Update AberdeenCityCouncil.py +- Update TorbayCouncil.py +- Update TorbayCouncil.py +- Update TorbayCouncil.py +- Update URL for NewForestCouncil +- New URL and page for wheelie bins +- improve Mid Suffolk District Council holiday handling with dynamic bank holiday detection +- Oxford now rejects the "Requests" default user agent +- #1557 - Adding East Dunbartonshire +- #1557 - Adding East Dunbartonshire +- #1569 - Somerset Council +- #1569 - Somerset Council +- #1559 - Newport City Council +- #1559 - Newport City Council +- #1574 - Test Valley Borough Council +- #1574 - Test Valley Borough Council +- #1566 South Gloucestershire Council + +## 0.154.0 (2025-09-21) + +### Feat + +- handle changes to northumberland council website +- modify input for NorthumberlandCouncil to accept uprn instead of house number, and use new page structure + +### Fix + +- the cookie banner is not optional +- #1570 - Slough Borough Council +- #1570 - Slough Borough Council +- #1520 - Erewash Borough Council +- #1520 - Erewash Borough Council +- #1554 - Folkestone and Hythe District Council +- #1554 - Folkestone and Hythe District Council +- #1604 - West Berkshire Council +- #1604 - West Berkshire Council +- #1606 - Brighton and Hove City Council +- #1606 - Brighton and Hove City Council +- #1565 - BCP Council +- #1565 - BCP Council +- #1571 - Castle Point District Council +- #1571 - Castle Point District Council +- #1584 - NorthHertfordshireDistrictCouncil +- #1584 - NorthHertfordshireDistrictCouncil +- #1599 +- #1599 - Basingstoke Council +- #1587 +- #1587 - Hartlepool Borough Council +- #1588 +- #1588 Glasgow City Council +- #1591 +- #1591 Rushmoor Council + +## 0.153.0 (2025-09-02) + +### Feat + +- Change buckinghamshire council to get data from endpoint + +### Fix + +- 1573 Update Bolton council URL +- East Herts Council +- #1575 +- Runnymede Borough Council +- #1513 +- Wiltshire Council +- #1533 +- Staffordshire Moorlands District Council +- #1535 +- Ipswich Borough Council +- #1548 +- North East Lincs +- Hinckley and Bosworth Borough Council +- Nuneaton Bedworth Borough Council +- #1514 +- Lichfield District Council +- 1549 + +## 0.152.11 (2025-08-25) + +### Feat + +- fix releases process + +### Fix + +- date extraction in RochfordCouncil data parsing +- parsing error in BH selenium +- **hacs**: respect the headless option + +### Refactor + +- **hacs**: improve build_ukbcd_args with formatter functions + +## 0.152.10 (2025-08-04) + +### Fix + +- Gateshead and East Lothian +- Enfield and Broxbourne +- East Herts +- FermanaghOmaghDistrictCouncil +- Enfield and Broxbourne +- East Herts + +## 0.152.9 (2025-08-03) + +### Fix + +- Cotswald and coventry +- Fixing multiple broken councils +- multiple broken councils + +## 0.152.8 (2025-07-26) + +### Fix + +- Add headers to request for Swindon Borough Council +- Add headers to requests for Royal Borough of Greenwich Fixes #1496 by ensuring that the requests are not rejected due to lack of headers. +- **MidlothianCouncil**: add request headers to resolve 403 Forbidden + +## 0.152.7 (2025-07-01) + +### Fix + +- maidstone selenium fix + +## 0.152.6 (2025-06-18) + +### Fix + +- removed In Progress from date +- removed a degub print statement +- **RugbyBoroughCouncil**: Amended parsed date from full to abbreviated month date, may worked but jun and jul did not +- **RugbyBoroughCouncil**: Amended parsed date +- Reworked Cumberland Council to cater for postcode addition +- **OxfordCityCouncil**: Fixed Oxford City Council parsing dues to changes in output from the website + +## 0.152.5 (2025-06-07) + +### Fix + +- South Ribble and version pinning issues for input.json + +## 0.152.4 (2025-06-07) + +### Fix + +- **SouthRibble**: Corrected Date formatting issue +- **SouthRibble**: Resolved South Ribble without selenium + +## 0.152.3 (2025-06-04) + +### Fix + +- NorthHertfordshire selenium script +- Adur council +- Eastleigh date fix +- removed duplicates in BradfordMDC + +## 0.152.2 (2025-06-04) + +### Fix + +- Update Makefile +- Update CheshireEastCouncil.py +- Github action to handle branch name with parentheses + +## 0.152.1 (2025-05-15) + +### Fix + +- Update to fix North Somerset +- Glasgow SSL bypass +- more robust Northumberland +- updated Eastleigh input.json +- Eastleigh cloudflare fix +- converted collection datetimes into dates for BH parsing. +- Eastleigh cloudflare fix +- Eastleigh cloudflare fix +- added check_uprn to simplified councils +- simplified Swindon +- simplified East Devon +- simplified Dover +- Simplified Dartford +- simplified Cheshire East +- simplified Charnwood input.json +- improved Charnwood +- Adur Worthing fix +- Chorley simplification +- Bexley simplification +- added URL to Torbay script +- Guildford fixes +- reworked Maidstone +- maidstone input.json +- Croydon selenium version +- Stoke date-time fix + +## 0.152.0 (2025-05-02) + +### Feat + +- Added Fermanagh Omagh +- Added Twekesbury +- added Slough council +- Added Argus Council +- added Angus to input.json + +### Fix + +- Chichester now only requires postcode and house number +- Broadland now only requires postcode and house number +- Barking now only requires postcode and house number +- Brighton now only requires postcode and house number +- ensured all bins for this council +- added skip_get_url to hyndburn + +## 0.151.0 (2025-04-27) + +### Feat + +- version bump + +### Fix + +- more robust brent date handling +- input.json requires web_driver +- Rugby fix + +## 0.150.0 (2025-04-27) + +### Feat + +- added melton +- added pembrokeshire + +### Fix + +- added melton +- processed all bins for Moray + +## 0.148.6 (2025-04-27) + +## 0.148.5 (2025-04-27) + +### Fix + +- output check +- parsed bin info +- selenium navigation +- input.json changes + +## 0.148.4 (2025-04-27) + +### Fix + +- used canonical 'nice name' + +## 0.148.3 (2025-04-25) + +### Fix + +- working hyndburn +- hyndburn input.json + +## 0.148.2 (2025-04-24) + +### Fix + +- Update docker-compose.yml +- updated input.json +- cloudflare fix - switch to selenium method +- simplified blackburn + +## 0.148.1 (2025-04-22) + +### Fix + +- added bank holiday offsets. +- added bank holiday offsets. + +## 0.148.0 (2025-04-19) + +### Feat + +- adding Wrexham and #1046 Horsham councils + +### Fix + +- Argyll and Bute council #1053 + +## 0.147.2 (2025-04-18) + +### Fix + +- wait for element to be clickable + +## 0.147.1 (2025-04-18) + +### Fix + +- #1351 - moved geopandas to petry dev + +## 0.147.0 (2025-04-18) + +### Feat + +- add council tests results map + +## 0.146.2 (2025-04-18) + +### Fix + +- adding map checking and matching + +## 0.146.1 (2025-04-18) + +### Fix + +- more robust bank holiday handling + +## 0.146.0 (2025-04-18) + +### Feat + +- #1342 Adding Includes Trafford, Clackmannanshire, Havant, North Warwickshire, Newry Mourne and Down, East Dunbartonshire, Pendle, Torfaen, East Hampshire, Ribble Valley, Brentwood, Isle of Wight, Westmorland and Furness, Derry and Strabane, and Norwich. Google Cal support for PDF councils via ICS file + +### Fix + +- Black reformatting + +## 0.145.0 (2025-04-18) + +### Feat + +- Adding PDF councils + +## 0.144.4 (2025-04-18) + +### Fix + +- Bristol #1275 + +## 0.144.3 (2025-04-17) + +### Fix + +- better address for input.json +- bank holiday overrides +- more robust address searching +- simple parsing done +- Selenium navigation + +## 0.144.2 (2025-04-17) + +### Fix + +- knowsley +- knowsley +- knowsley +- knowsley +- KnowsleyMBCouncil.py +- #1220 adding Mid Ulster District Council + +## 0.144.1 (2025-04-17) + +### Fix + +- fix Sandwell garden waste collection date + +## 0.144.0 (2025-04-17) + +### Feat + +- added great yarmouth + +## 0.143.6 (2025-04-17) + +### Fix + +- Renfrewshire Council + +## 0.143.5 (2025-04-17) + +### Fix + +- Google Cal + +## 0.143.4 (2025-04-17) + +### Fix + +- Google Cal + +## 0.143.3 (2025-04-15) + +### Fix + +- #1301 Fix Leeds Council + +## 0.143.2 (2025-04-15) + +### Fix + +- #1301 Fix Leeds Council + +## 0.143.1 (2025-04-15) + +### Fix + +- Set the bin_type when different day + +## 0.143.0 (2025-04-13) + +### Fix + +- corrected url in input.json +- fixed input.json +- parsed Barking Dagenham collection information +- selenium navigation Barking + +## 0.142.0 (2025-04-13) + +### Feat + +- Added Stirling Council + +### Fix + +- typo in input.json + +## 0.141.4 (2025-04-13) + +### Fix + +- #1304 - sesnors goes to unknown if the data is blank from councils who are less reliable + +## 0.141.3 (2025-04-13) + +### Fix + +- Newham council + +## 0.141.2 (2025-04-13) + +### Fix + +- Newham council +- Newham council + +## 0.141.1 (2025-04-12) + +### Fix + +- missing finally block on selenium tests + +## 0.141.0 (2025-04-12) + +### Feat + +- #1185 Adding PeterboroughCity Council + +## 0.140.0 (2025-04-11) + +### Feat + +- Added Broadland District Council + +### Fix + +- cleanup of council file +- added Broadland to input.json + +## 0.139.0 (2025-04-07) + +### Feat + +- adding #1037 +- adding #1032 North Devon Count Council + +### Fix + +- #1296 Forest of dean +- 939 adding South Holland District Council - Lincolnshire UK + +## 0.138.1 (2025-04-05) + +### Fix + +- Walhtam forest council - revert previous changes + +## 0.138.0 (2025-04-05) + +### Feat + +- Adding Hastings Borough Council +- Adding Fylde Council + +### Fix + +- #1249 +- #1039 +fix: #1181 +fix: #1266 +fix: #1274 +- Gloucester City Council +- #1282 +- Mid Devon Council +- #1277 +fix: #1287 +- West Oxfordshire Council +- #1290 + +## 0.137.0 (2025-04-05) + +### Feat + +- #816 adding trafford council + +## 0.136.0 (2025-03-24) + +### Feat + +- Adding Southampton City Council +- Adding Cambridge City Council +- Adding Spelthorne Borough Council + +### Fix + +- #1057 +- #1264 +- #1270 +- Bexley Council +- #1256 +- HinckleyandBosworthBoroughCouncil +- #1207 +- Hackney Council +- #1230 +- Castlepoint District Council +- #1252 +- Canterbury City Council +- #1254 + +## 0.135.4 (2025-03-24) + +### Fix + +- parse scheduleCodeWorkflowIDs instead of scheduleCodeWorkflowID for Hackney Council + +## 0.135.3 (2025-02-23) + +## 0.135.2 (2025-02-19) + +### Fix + +- North Yorkshire - multiple bins on a day + +## 0.135.1 (2025-02-18) + +### Fix + +- devcontainer + +## 0.135.0 (2025-02-17) + +### Fix + +- #833 adding Middlesbrough and check script for Selenium +- Cotswold District Council +- #1238 +- Leeds City Council +- #1222 + +## 0.134.3 (2025-02-15) + +### Fix + +- Update input.json +- 1235 Councils missing Selenium in input.json + +## 0.134.2 (2025-02-15) + +### Fix + +- 1232 East herts missing Selenium url in input.json +- Derbyshire Dales District Council +- Conwy County Borough +- Sunderland City Council +- #1219 +- Tendring District Council +- #1221 + +## 0.134.1 (2025-02-11) + +### Fix + +- Cheltenham Borough Council +- #1061 + +## 0.134.0 (2025-02-07) + +### Feat + +- Ipswich Borough Council - trying different address +- Ipswich Borough Council - correcting param name in input.json +- Ipswich Borough Council - added input.json values and refactored code +- Ipswich Borough Council - initial implementation +- Adding Runnymede Borough Council +- Adding Cherwell District Council +- Adding Epsom and Ewell Borough Council +- Adding Redcar and Cleveland Council +- Adding Amber Valley Borough Council +- Adding Bolsover Council + +### Fix + +- #1214 +- #923 +- #895 +- #841 +- #903 +- #990 +- Torridge District Council +- #1204 +- Neath Port Talbot +- #1213 + +## 0.133.0 (2025-02-02) + +### Feat + +- adding manual refresh + +## 0.132.0 (2025-02-02) + +### Feat + +- adding manual refresh + +## 0.131.0 (2025-02-02) + +### Feat + +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding unit tests for the new manual refresh +- adding manual refresh control + +## 0.130.1 (2025-01-30) + +### Fix + +- slow councils + +## 0.130.0 (2025-01-29) + +### Feat + +- Add Herefordshire Council (closes: #1011) + +### Fix + +- Fix spacing in wiki name + +## 0.129.0 (2025-01-29) + +### Fix + +- input.json +- input.json + +## 0.128.6 (2025-01-29) + +### Fix + +- moving away from broken Allure reporting +- moving away from broken Allure reporting +- moving away from broken Allure reporting +- moving away from broken Allure reporting +- moving away from broken Allure reporting +- moving away from broken Allure reporting +- moving away from broken Allure reporting + +## 0.128.5 (2025-01-29) + +### Feat + +- Adding East Staffordshire Borough Council + +### Fix + +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update CheshireEastCouncil.py +- Adding East Lothian Council +- #1171 +- #1052 +fix: #1083 + +## 0.128.4 (2025-01-28) + +### Feat + +- Adding Boston Borough Council + +### Fix + +- Update CheshireEastCouncil.py +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update CheshireEastCouncil.py +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Leicester City Council +- #1178 +- Cardiff Council +- #1175 +- Newcastle City Council +- #1179 +- #1180 +- Midlothian Council +- #1192 - Adding Next Page support + +## 0.128.3 (2025-01-28) + +### Fix + +- Update CheshireEastCouncil.py +- Update behave_schedule.yml +- Update behave_pull_request.yml + +## 0.128.2 (2025-01-28) + +### Fix + +- Add communal recycling and communal rubbish +- Add garden waste to Merton Council + +## 0.128.1 (2025-01-28) + +### Fix + +- Update AberdeenshireCouncil.py +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml + +## 0.128.0 (2025-01-28) + +### Feat + +- implement Medway Council (#1021) + +### Fix + +- Forgot to include skip_get_url + +## 0.127.4 (2025-01-25) + +### Fix + +- NewForestCouncil + +## 0.127.3 (2025-01-16) + +### Fix + +- Swale Borough Council +- #1139 +- Vale of White Horse +- #1156 +- South Oxfordshire Council +- #1158 +- Surrey Heath Borough Council +- #1164 +- Carmarthenshire County Council +- #1167 +- Glasgow City Council +- #1166 + +## 0.127.2 (2025-01-13) + +### Fix + +- Update bin type to be the full string + +## 0.127.1 (2025-01-10) + +### Fix + +- Use visibility of list rather than existence +- Update Rushcliffe Borough Council input elements and flow +- Merton Council +- NewarkAndSherwoodDC +- Rushcliffe Borough Council +- Powys Council +- Staffordshire Moorlands District Council +- Stroud District Council +- Vale of Glamorgan Council +- West Oxfordshire District Council + +## 0.127.0 (2025-01-07) + +### Feat + +- Adding Oadby And Wigston Borough Council +- Add Gwynedd Council +- Adding Denbighshire Council +- Adding Dundee City Council +- Adding Brent Council +- Adding West Dunbartonshire Council +- Adding Cumberland Council + +### Fix + +- #929 +- Cornwall Council +- #1137 +- #1125 +- #1106 +- #1108 +- #1109 +- #1134 +- Northumberland Council +- #1082 +- #1110 +- Waltham Forest +- #1126 +- London Borough Sutton +- #1131 +- Kirklees Council +- #1129 - Breaking Change. UPRN required + +## 0.126.2 (2025-01-07) + +### Fix + +- **tests**: updates test case url for coventry city council +- **tests**: removes duplicate key for coventry city council +- updates coventry city council button text + +## 0.126.1 (2025-01-06) + +### Fix + +- behave_testing +- behave_testing + +## 0.126.0 (2025-01-04) + +### Fix + +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml + +## 0.125.2 (2025-01-04) + +### Fix + +- Update ArdsAndNorthDownCouncil.py +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update README.md to have links to Full and Partial Integration Test Reports +- Update behave_pull_request.yml +- Update README.md to have links to Full and Partial Integration Test Reports +- Swale Borough Council +- #1080 +(cherry picked from commit 6f580b39fb68b8079990221e050ae8dd6d2b7285) +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update ArdsAndNorthDownCouncil.py +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update README.md to have links to Full and Partial Integration Test Reports +- Update WestLindseyDistrictCouncil.py +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_schedule.yml + +## 0.125.1 (2025-01-04) + +### Fix + +- correctly handle year increment for January dates + +## 0.125.0 (2025-01-04) + +### Feat + +- Adding Redditch Borough Council +- Adding Blaenau Gwent County Borough Council +- Adding Wandsworth Council + +### Fix + +- #1068 +- #1098 +- Wiltshire Council +- #1094 +- Salford City Council +- #1097 +- #1078 +- Merton Council +- Swale Borough Council +- #1080 +- London Borough Sutton +- #1076 +- Update behave_schedule.yml +- Update bump.yml + +## 0.124.4 (2025-01-04) + +### Fix + +- Update behave_schedule.yml + +## 0.124.3 (2025-01-04) + +### Fix + +- allure reporting +- allure reporting +- allure reporting + +## 0.124.2 (2025-01-03) + +### Fix + +- Update behave.yml + +## 0.124.1 (2025-01-03) + +### Fix + +- avoid crashing on unexpected string value + +## 0.124.0 (2025-01-02) + +### Feat + +- Hart District Council + +## 0.123.2 (2024-12-19) + +### Fix + +- Update behave.yml + +## 0.123.1 (2024-12-18) + +### Feat + +- #1063 - rewrite Kirklees Council parser for new website +- #1067 - Add garden bin collections where available for Norwich City Council +- Adding Wandsworth Council + +### Fix + +- Update AberdeenCityCouncil.py +- Update behave.yml +- #1101 - Fix table parsing for Walsall Council +- Remove invalid escape sequence warnings from West Lindsey District Council +- #1073 - change method of generating bin types to avoid manual mapping for Rugby Borough Council +- add missing backticks to separate colour config and standard usage instructions +- #1078 +(cherry picked from commit 89d93666bb659010d1c130b98c1d81c6ff80cf7c) +- change date format to project default for Merton Council +- correct date logic for Swale Borough Council +- Merton Council +- London Borough Sutton +- #1076 +(cherry picked from commit 1eab20c9a57c9c4438ea343f374202bb2e9b98ca) +- Swale Borough Council +- #1080 +(cherry picked from commit 6f580b39fb68b8079990221e050ae8dd6d2b7285) +- correct date/year logic for West Lindsey District Council +- replace West Lindsey's input with working address +- #1089 - Correct shifted dates in Bromley Borough Council +- remove WDM import +- #1087 - Food waste date incorrect for West Berkshire Council + +## 0.123.0 (2024-12-17) + +## 0.122.0 (2024-12-04) + +### Feat + +- Adding Monmouthshire County Council +- Adding Hinckley and Bosworth Borough Council + +### Fix + +- Glasgow City Council +- Merton Council +- Blaby District Council +- Warwick District Council +- Blackburn Council +- Carmarthenshire County Council +- High Peak Council +- CarmarthenshireCountyCouncil + +## 0.121.1 (2024-12-03) + +### Fix + +- London Borough of Lewisham to have more reliable parsing of dates + +## 0.121.0 (2024-11-24) + +### Feat + +- Royal Borough of Greenwich +- Adding London Borough of Lewisham +- Adding Hackney Council +- Adding Sandwell Borough Council +- Adding Moray Council +- Adding Kings Lynn and West Norfolk Borough Council +- Adding Wyre Forest District Council +- Adding Folkstone and Hythe District Council +- Adding Cheltenham Borough Council +- Adding Thurrock Council + +### Fix + +- West Northamptonshire Council +- East Ayrshire Council +- Cotswold District Council + +## 0.120.0 (2024-11-20) + +### Feat + +- Adding Hartlepool Borough Council +- Adding Newcastle Under Lyme Council +- Adding London Borough of Havering +- Add Garden collection to EnvironmentFirst +- Adding Cumberland Council (Allerdale District) +- Adding North Hertfordshire District Council + +### Fix + +- #844 +- #778 +- #769 +- #1025 +- Mid Siffolk and Babergh Garden Collection Day +- #1026 +This will require the use of a DAY to be added to the UPRN field +- #1029 +- #1028 + +## 0.119.0 (2024-11-20) + +### Feat + +- Adding Braintree District Council +- Adding Burnley Borough Council +- Adding Exeter City Council +- Adding Edinburgh City Council + +### Fix + +- #699 +- #1015 +- #1017 +- #894 + +## 0.118.0 (2024-11-15) + +### Feat + +- Adding Aberdeen City Council +- Adding Wolverhampton City Council +- Adding Stevenage Borough Council +- Adding Thanet District Council +- Adding Copeland Borough Council +- Adding South Hams District Council + +### Fix + +- #1019 +- #966 +- #989 +- #1004 +- #1006 +- #1008 +- Rother District Council + +## 0.117.0 (2024-11-13) + +### Feat + +- Adding South Staffordshire District Council fix: #885 +- Adding Rother District Council + +### Fix + +- #1009 + +## 0.116.0 (2024-11-12) + +### Feat + +- Adding Ashfield District Council +- Adding Gravesham Borough Council +- Adding Argyll and Bute Council + +### Fix + +- CrawleyBoroughCouncil +- #1005 +- Adding Garden collection to Babergh and MidSuffolk Council +- #995 +- #579 +- #991 +- #692 +- CheshireWestAndChesterCouncil +- #993 +- Milton Keynes +- #702 +- Adding Babergh and Mid Suffolk District Councils +- #868 +fix: #919 +- Adding Derby City Council +- #987 + +## 0.115.0 (2024-11-11) + +### Feat + +- Adding Warrington Borough Council +- Adding Antrim And Newtonabbey Council +- Adding Hertsmere Borough Council +- Adding West Lancashire Borough Council +- Broxbourne Council + +### Fix + +- #695 +- #969 +- #776 +- #980 +- #982 +- Bradford MDC +- #984 + +## 0.114.6 (2024-11-09) + +### Fix + +- NBBC Date Fix + +## 0.114.5 (2024-11-08) + +### Fix + +- migration logging and debugging + +## 0.114.4 (2024-11-08) + +### Fix + +- migration not working +- migration not working + +## 0.114.3 (2024-11-08) + +## 0.114.2 (2024-11-08) + +## 0.114.1 (2024-11-08) + +### Fix + +- Update manifest.json + +## 0.114.0 (2024-11-07) + +### Feat + +- Nuneaton and Bedworth Borough Council + +## 0.113.0 (2024-11-07) + +## 0.112.1 (2024-11-07) + +## 0.112.0 (2024-11-06) + +### Feat + +- adding calendar for Bins in Custom Component + +### Fix + +- fix manifest in custom component +- #975 adding routine to handle migration error +- #975 adding routine to handle migration error +- #767 BREAKING CHANGE - READD your sensors / config + +## 0.111.0 (2024-11-06) + +### Fix + +- Add London Borough of Sutton +- #944 +- Add Mid Devon Council +- #945 +- Adding Oxford City Council +- #962 +- Tunbridge Wells / Lincoln +- #963 +- Glasgow City Council + +## 0.110.0 (2024-11-04) + +### Fix + +- Adding Blaby District Council +- #904 +- Adding Sefton Council +- #770 +- Adding Bromsgrove District Council +- #893 +- East Lindsey District Council +- #957 +- Adding Carmarthenshire County Council +- #892 +fix: #710 +- Adding East Ayrshire Council +- #955 + +## 0.109.2 (2024-11-03) + +### Fix + +- CC testing and add Chesterfield + +## 0.109.1 (2024-11-03) + +### Fix + +- CC testing and add Chesterfield +- CC testing and add Chesterfield + +## 0.109.0 (2024-11-02) + +### Feat + +- Adding Cotswold District Council +- Adding Breckland Council + +### Fix + +- St Helens Borough Council +- #753 +- NewarkAndSherwoodDC +- #941 +- #658 +- #656 + +## 0.108.2 (2024-11-01) + +### Fix + +- pytest-homeassistant-custom-component + +## 0.108.1 (2024-11-01) + +### Fix + +- Pydandic version +- Pydandic version + +## 0.108.0 (2024-11-01) + +### Feat + +- pytest fixes +- pytest fixes +- pytest fixes +- pytest fixes +- pytest fixes +- pytest fixes + +## 0.107.0 (2024-10-31) + +### Feat + +- Adding Powys Council +- Adding Worcester City Council +- Adding Ards and North Down Council +- Adding East Herts Council +- Adding Ashford Borough Council + +### Fix + +- WestOxfordshireDistrictCouncil +- South Norfolk Council +- ForestOfDeanDistrictCouncil +- Croydon Council +- South Kesteven District Council +- #647 +- #630 +- #623 +- #586 +- #578 +- #389 + +## 0.106.0 (2024-10-28) + +### Feat + +- Adding Stockton On Tees Council +- Adding Fife Council +- Adding Flintshire County Council + +### Fix + +- #930 +- #933 +- #750 + +## 0.105.1 (2024-10-24) + +### Fix + +- Refactor Midlothian Council scraper to use house number and postcode +- West Berkshire Council +- Southwark Council + +## 0.105.0 (2024-10-21) + +### Feat + +- Adding Teignbridge Council +- Adding Harborough District Council +- Adding Watford Borough Council +- Adding Coventry City Council +- pytest fixes +- pytest fixes +- pytest fixes +- pytest fixes +- pytest fixes +- Adding Powys Council +- Adding Worcester City Council +- Adding Ards and North Down Council +- Adding East Herts Council +- Adding Ashford Borough Council +- Adding Stockton On Tees Council +- Adding Fife Council +- Adding Flintshire County Council +- Adding Teignbridge Council +- Adding Harborough District Council +- Adding Watford Borough Council +- Adding Coventry City Council +- Python 3.12 only and CustomComp. Unit testing + +### Fix + +- #580 +- #888 +- #902 +- #607 +- CC testing and add Chesterfield +- CC testing and add Chesterfield +- CC testing and add Chesterfield +- pytest-homeassistant-custom-component +- Pydandic version +- Pydandic version +- WestOxfordshireDistrictCouncil +- South Norfolk Council +- ForestOfDeanDistrictCouncil +- Croydon Council +- South Kesteven District Council +- #647 +- #630 +- #623 +- #586 +- #578 +- #389 +- #930 +- #933 +- #750 +- Refactor Midlothian Council scraper to use house number and postcode +- West Berkshire Council +- Southwark Council +- #580 +- #888 +- #902 +- #607 + +## 0.104.0 (2024-10-20) + +### Feat + +- Adding Luton Borough Council +- Adding West Oxfordshire District Council +- Adding Aberdeenshire Council +- Adding Canterbury City Council +- Adding Swindon Borough Council + +### Fix + +- #697 +- #694 +- #659 +- #590 +- #900 + +## 0.103.0 (2024-10-20) + +### Feat + +- Adding RAW JSON Sensor + +### Fix + +- Black formatting +- Black formatting + +## 0.102.0 (2024-10-20) + +### Feat + +- Moving from Attributes to Sensors +- Moving from Attributes to Sensors + +## 0.101.0 (2024-10-20) + +### Feat + +- Add Midlothgian Council + +## 0.100.0 (2024-10-18) + +### Feat + +- Adding Dudley Council +- Adding South Ribble Council +- Plymouth Council +- Adding Norwich City Council + +### Fix + +- #744 +- #671 +- #566 +- #749 + +## 0.99.1 (2024-10-16) + +### Fix + +- #792 adding web_driver option to Wokingham Council + +## 0.99.0 (2024-10-16) + +### Feat + +- Adding Lincoln Council +- Adding Tunbridge Wells Council +- Adding Perth and Kinross Council + +### Fix + +- Update wiki +- #748 +- #598 +- #572 + +## 0.98.5 (2024-10-15) + +### Fix + +- Swale Borough Council +- HaltonBoroughCouncil +- Barnet Council +- WestBerkshireCouncil + +## 0.98.4 (2024-10-14) + +### Fix + +- West Suffolk Council +- Vale of White Horse Council +- Uttlesford District Council +- Neath Port Talbot Council +- Merton Council +- Manchester City Council +- Glasgow City Council +- BradfordMDC + +## 0.98.3 (2024-10-13) + +### Fix + +- EastRiding + +## 0.98.2 (2024-10-13) + +### Fix + +- MoleValley + +## 0.98.1 (2024-10-13) + +### Fix + +- Barnet and Bexley + +## 0.98.0 (2024-10-13) + +### Feat + +- Adding Wirral Council +- Adding Lichfield District Council +- Adding West Morland And Furness +- Adding Walsall Council +- Adding Armagh, Banbridge and Craigavon Council + +### Fix + +- #602 +- #830 +- #870 +- #873 +- #877 + +## 0.97.1 (2024-10-10) + +### Fix + +- NottinghamCityCouncil +- #875 + +## 0.97.0 (2024-10-10) + +### Feat + +- Adding Falkirk Council + +### Fix + +- #761 + +## 0.96.0 (2024-10-10) + +### Feat + +- Adding London Borough Harrow +- Adding North Ayrshire Council +- Adding Highland Council +- Add Elmbridge Borough Council +- Adding Southwark Council +- South Derbyshire District Council + +### Fix + +- #871 +- #869 +- #780 +- #845 +fix: #754 +- #835 +- #842 + +## 0.95.0 (2024-10-09) + +### Feat + +- Adding London Borough of Ealing + +## 0.94.0 (2024-10-09) + +### Feat + +- Adding London Borough of Lambeth +- Adding Dacorum Borough Council + +### Fix + +- Dacorum Borough Council +- East Devon DC + +## 0.93.0 (2024-10-08) + +### Feat + +- Update CheshireEastCouncil.py + +## 0.92.0 (2024-10-08) + +### Feat + +- Update CheshireEastCouncil.py +- Update README.md +- Adding Wokingham Borough Council +- Adding Winchester City Council +- Adding Basildon Council +- Adding Colchester City Council + +### Fix + +- RochfordCouncil +- Neath Port Talbot Council +- Buckinghamshire Council +- #639 +fix: #812 + +## 0.91.2 (2024-10-05) + +### Fix + +- Windsor and Maidenhead Council + +## 0.91.1 (2024-10-04) + +## 0.91.0 (2024-10-03) + +## 0.90.0 (2024-10-03) + +### Feat + +- Adding East Renfrewshire Council + +### Fix + +- Update DorsetCouncil.py +- #829 +- Update GatesheadCouncil.py +- #822 + +## 0.89.1 (2024-10-02) + +### Fix + +- High Peak have changed their cookie dialog Seems to be safe to ignore it now. + +## 0.89.0 (2024-09-27) + +### Feat + +- Update CheshireEastCouncil.py +- Update README.md + +### Fix + +- release to be non pre release + +## 0.88.0 (2024-09-16) + +### Feat + +- Add Ealing Council + +### Fix + +- Update README.md + +## 0.87.0 (2024-09-10) + +### Feat + +- Add IslingtonCouncil + +### Fix + +- #565 Gloucester city council driver + +## 0.86.1 (2024-09-09) + +### Fix + +- #773 Wakefield + +## 0.86.0 (2024-09-06) + +### Feat + +- added Rotherham Council + +## 0.85.7 (2024-09-05) + +### Fix + +- more unit tests +- more unit tests +- Chorley + +## 0.85.6 (2024-09-03) + +### Fix + +- #795 and add reconfigure to custom comp. + +## 0.85.5 (2024-09-03) + +## 0.85.4 (2024-09-03) + +### Fix + +- #795 and add reconfigure to custom comp. +- #795 Unit Test Coverage + +## 0.85.3 (2024-09-02) + +### Fix + +- #795 unit test coverage + +## 0.85.2 (2024-09-02) + +### Fix + +- 791 Glasgow URL change + +## 0.85.1 (2024-09-02) + +### Fix + +- 779 Add correct async wait to Home Assistant + +## 0.85.0 (2024-08-27) + +### Feat + +- support for enfield council + +## 0.84.2 (2024-08-27) + +### Fix + +- Re-work North Tyneside Council module for 2024 - some addresses do not have a garden collection +- Re-work North Tyneside Council module for 2024 + +## 0.84.1 (2024-08-08) + +### Fix + +- #771 Bolton bullet points on dates is now fixed + +## 0.84.0 (2024-07-31) + +## 0.83.0 (2024-07-07) + +### Feat + +- add has_numbers() function + +### Fix + +- update Gedling Borough Council parser to use alternative name key +- change Gedling to use new JSON data +- update instructions for Gedling +- update input.json to use UPRN parameter +- change DorsetCouncil.py to use API links provided in #756 +- explicit import of logging.config to stop error in Python 3.11 + +## 0.82.0 (2024-06-13) + +### Feat + +- adding dev container updates +- adding dev container updates +- refactoring main files +- adding ability to set local mode in HA custom comp. if users dont have a Selenium Server + +### Fix + +- MidSussex + +## 0.81.0 (2024-06-05) + +### Feat + +- Adding Wychavon District Council + +### Fix + +- IntTestWarnings +- IntTestWarnings + +## 0.80.0 (2024-06-02) + +### Feat + +- Adding Uttlesford District Council +- Adding Stafford Boro Council +- Adding Swansea Council +- Adding New Forest +- Adding Three Rivers +- Adding Three Rivers + +### Fix + +- ThreeRivers +- #425 Entities are not updated +- sessions to avoid deprecation +- Update docker-image.yml +- Update docker-image.yml + +## 0.79.1 (2024-05-29) + +### Fix + +- Change CSS class in search for collection types + +## 0.79.0 (2024-05-28) + +### Feat + +- Adding Dartford +- Adding South Kesteven District Council +- Adding ChichesterCouncil +- adding HounslowCouncil +- adding HounslowCouncil +- adding HounslowCouncil +- Epping Fix +- Adding Epping Forest District Council +- Update input.json +- Epping Forest District Council +- Adding Stroud District Council +- Add support for Tendring District Council +- #269 Adding Waltham Forest +- #269 Adding Waltham Forest +- Adding council creation script + +### Fix + +- Update Mole Valley URL + +## 0.78.0 (2024-05-26) + +### Feat + +- Add support for Fareham Borough Council + +## 0.77.0 (2024-05-26) + +### Feat + +- Add support for Bracknell Forest Council + +## 0.76.1 (2024-05-24) + +### Fix + +- Handle Barnet council cookies message + +## 0.76.0 (2024-05-24) + +### Feat + +- add bin colour support WestSuffolkCouncil style: black format WestSuffolkCouncil +- add bin colour support WestSuffolkCouncil style: black format WestSuffolkCouncil + +## 0.75.0 (2024-05-19) + +### Feat + +- #725 Add names to selenium test videos using "se:name" option in create webdriver function + +## 0.74.1 (2024-05-18) + +### Fix + +- #693 Cheshire West & Chester Council Sensor Bug +- #693 Cheshire West & Chester Council Sensor Bug + +## 0.74.0 (2024-05-17) + +### Feat + +- #722 Support Python 3.12 +- #722 Support Python 3.12 +- #722 Support Python 3.12 + +## 0.73.0 (2024-05-17) + +### Feat + +- #708 Adding HA to the dev container for debugging + +## 0.72.0 (2024-05-17) + +### Feat + +- #708 Adding HA to the dev container for debugging +- #708 Adding HA to the dev container for debugging +- #708 Adding HA to the dev container for debugging +- #708 Adding HA to the dev container for debugging +- #708 Adding HA to the dev container for debugging +- #708 Adding HA to the dev container for debugging +- #708 Adding HA to the dev container for debugging +- #708 Adding HA to the dev container for debugging + +## 0.71.0 (2024-05-17) + +### Feat + +- Update for West Suffolk Councils new website + +## 0.70.0 (2024-05-17) + +### Feat + +- #708 Dev Container +- Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 simplifying Selenium integration tests +- #708 simplifying Selenium integration tests +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Dev Container testing +- #708 - dev container changes +- #706 Adding Dev Container +- #706 Adding initial Dev Container + +## 0.69.7 (2024-05-17) + +### Fix + +- #713 BarnsleyMBCouncil.py + +## 0.69.6 (2024-05-16) + +### Fix + +- #709 Update DoverDistrictCouncil.py + +## 0.69.5 (2024-05-14) + +### Fix + +- #696 Small issue and Black formatting +- #696 Small issue and Black formatting +- #696 Small issue and Black formatting +- #696 Small issue and Black formatting +- #696 Small issue and Black formatting +- #696 Small issue and Black formatting +- #696 Small issue and Black formatting +- #696 Small issue and Black formatting +- #696 test coverage back to 100% + +## 0.69.4 (2024-05-09) + +### Fix + +- pass in required parameter into `create_webdriver` +- test runners for `MiltonKeynesCityCouncil` and `NorthEastLincs`. + +## 0.69.3 (2024-05-09) + +### Fix + +- fix AttributeError when no garden waste collection is available for properties using Huntingdon District Council +- add support for parsing "Today" / "Tomorrow" as date text for `BarnsleyMBCouncil` +- add support for parsing "Tomorrow" as date text for `LiverpoolCityCouncil` + +## 0.69.1 (2024-05-01) + +### Fix + +- Handling the "Website cookies enhance your user experience." button +- Handling the "Website cookies enhance your user experience." button + +## 0.69.0 (2024-04-28) + +### Feat + +- Adding Renfrewshire Council +- Adding Renfrewshire Council + +## 0.68.2 (2024-04-28) + +### Fix + +- Remove 'import Dumper' + +## 0.68.1 (2024-04-27) + +### Fix + +- input.json Bradford missing comma + +## 0.68.0 (2024-04-27) + +### Feat + +- Add support for West Berkshire Council +- add support for Knowsley Metropolitan Borough Council +- add support for Cheshire West and Chester Council +- add support for Cheshire West and Chester Council + +## 0.66.2 (2024-04-18) + +### Fix + +- Update HaringeyCouncil.py issue #670 + +## 0.66.1 (2024-04-15) + +### Fix + +- parse datetimes correctly and round to midnight + +## 0.66.0 (2024-04-15) + +## 0.65.2 (2024-04-15) + +### Fix + +- change address selection to fix errors selecting the user's PAON + +## 0.65.1 (2024-04-15) + +### Fix + +- add check for parsed string length to stop datetime parsing error + +## 0.65.0 (2024-04-13) + +### Feat + +- add Arun council +- add support for Sunderland City Council +- add support for Sunderland City Council + +## 0.64.3 (2024-03-25) + +### Fix + +- sort data and correct dictionary name (#609) + +## 0.64.2 (2024-03-24) + +## 0.64.1 (2024-03-24) + +### Fix + +- fix Kirklees address search (switch to house & postcode) +- fixes json + +## 0.64.0 (2024-03-23) + +### Feat + +- add Kirklees council + +### Fix + +- fixes json + +## 0.63.0 (2024-03-23) + +### Feat + +- Add Solihull Council (#513) +- Add Adur and Worthing Councils (#544) +- Add Dover District Council (#614) +- Add Rochford Council (#620) +- Add Tandridge District Council (#621) +- Add West Northamptonshire Council (#567) +- Add Hull City Council (#622) +- Add Wyre Council (#625) +- Add Telford and Wrekin Co-operative Council (#632) +- Add Mansfield District Council (#560) +- Add Bedford Borough Council (#552) + +### Fix + +- spacing on input.json +- realign input.json +- capitalize bin type text +- formatting on input.json +- incorrect collections +- update testing URL for Merton +- attempt to resolve invisible banner hiding postcode box +- resolve JSON schema exception for date formatting +- resolve JSON schema exception for date formatting +- accept cookies banner + +## 0.62.0 (2024-03-03) + +### Fix + +- Added missing .feature file entry to the test config for NewhamCouncil + +## 0.61.1 (2024-02-16) + +### Fix + +- code optimisations +- Fix date parsing in WestLindseyDistrictCouncil.py + +## 0.61.0 (2024-02-11) + +### Feat + +- Add Mole Valley District Council + +## 0.60.1 (2024-02-03) + +### Fix + +- Update input.json Closes #599 + +## 0.60.0 (2024-01-28) + +### Feat + +- Add Scraper for St Albans City and District Council + +## 0.59.1 (2024-01-25) + +### Fix + +- add wiki note for castlepoint +- update test data for castlepoint +- remove single line causing issues + +## 0.59.0 (2024-01-20) + +### Feat + +- Add NorthYorkshire to test feature file +- Add north yorkshire to test input +- Add Support for north yorkshire council + +### Fix + +- remove unused code + +## 0.58.8 (2024-01-19) + +### Fix + +- barnet no overrides + +## 0.58.7 (2024-01-18) + +### Fix + +- accidentally returned strings when needed date objects, refactor to handle this +- checking for future/past dates + +## 0.58.6 (2024-01-18) + +### Fix + +- correct date handling for North West Leicestershire + +## 0.58.5 (2024-01-15) + +### Fix + +- Don't call driver.quit where already handled by finally block + +## 0.58.4 (2024-01-15) + +### Fix + +- remove extra driver.quit to prevent errors + +## 0.58.3 (2024-01-15) + +### Feat + +- Added support for Newham Council's bin collections + +### Fix + +- Add a default value for user_agent to fix all councils using selenium and not specifying agent + +## 0.58.2 (2024-01-11) + +### Fix + +- use static values for bin types + +## 0.58.1 (2024-01-10) + +### Fix + +- Eastleigh Borough Council doesnt cope with "You haven't yet signed up for ..." +- Eastleigh Borough Council doesnt cope when Garden Waste service hasn't been signed up for, which gets the value "You haven't yet signed up for our garden waste collections. Find out more about our\xa0garden waste collection service" which results in ValueError: time data + +## 0.58.0 (2024-01-10) + +### Feat + +- Add Test Valley Borough Council + +## 0.57.0 (2024-01-09) + +### Feat + +- Add support for Chorley Council + +## 0.56.13 (2024-01-09) + +### Fix + +- update logic to account for council website change + +## 0.56.12 (2024-01-09) + +### Fix + +- duplicate driver.quit() calls causes error + +## 0.56.11 (2024-01-08) + +### Fix + +- Headless now working on custom comp Update sensor.py + +## 0.56.10 (2024-01-08) + +### Fix + +- headless mode in custom component + +## 0.56.9 (2024-01-08) + +### Fix + +- headless mode + +## 0.56.8 (2024-01-08) + +### Fix + +- headless in custom comp + +## 0.56.7 (2024-01-08) + +### Fix + +- headless options + +## 0.56.6 (2024-01-07) + +### Fix + +- modified Kingston-upon-Thames driver for greater reliability. + +## 0.56.5 (2024-01-07) + +### Fix + +- Update KingstonUponThamesCouncil.py + +## 0.56.4 (2024-01-07) + +### Fix + +- Update KingstonUponThamesCouncil.py + +## 0.56.3 (2024-01-07) + +### Fix + +- headless options +- #542 - Selenium Grid Sessions must be terminated cleanly +- #542 - Selenium Grid Sessions must be terminated cleanly + +## 0.56.2 (2024-01-07) + +### Fix + +- Update strings.json +- Update en.json +- Update config_flow.py + +## 0.56.1 (2024-01-07) + +### Fix + +- Update common.py + +## 0.156.0 (2025-10-11) + +### Feat + +- Create tag-on-merge.yml +- Update bump.yml +- fix bump.yml +- Update TorbayCouncil.py +- Update bump.yml +- fix release pipeline bump.yml +- fix Torbay + +### Fix + +- Update AberdeenCityCouncil.py +- Update TorbayCouncil.py +- Update TorbayCouncil.py +- Update TorbayCouncil.py +- Update URL for NewForestCouncil +- New URL and page for wheelie bins +- improve Mid Suffolk District Council holiday handling with dynamic bank holiday detection +- Oxford now rejects the "Requests" default user agent +- #1557 - Adding East Dunbartonshire +- #1557 - Adding East Dunbartonshire +- #1569 - Somerset Council +- #1569 - Somerset Council +- #1559 - Newport City Council +- #1559 - Newport City Council +- #1574 - Test Valley Borough Council +- #1574 - Test Valley Borough Council +- #1566 South Gloucestershire Council + +## 0.154.0 (2025-09-21) + +### Feat + +- handle changes to northumberland council website +- modify input for NorthumberlandCouncil to accept uprn instead of house number, and use new page structure + +### Fix + +- the cookie banner is not optional +- #1570 - Slough Borough Council +- #1570 - Slough Borough Council +- #1520 - Erewash Borough Council +- #1520 - Erewash Borough Council +- #1554 - Folkestone and Hythe District Council +- #1554 - Folkestone and Hythe District Council +- #1604 - West Berkshire Council +- #1604 - West Berkshire Council +- #1606 - Brighton and Hove City Council +- #1606 - Brighton and Hove City Council +- #1565 - BCP Council +- #1565 - BCP Council +- #1571 - Castle Point District Council +- #1571 - Castle Point District Council +- #1584 - NorthHertfordshireDistrictCouncil +- #1584 - NorthHertfordshireDistrictCouncil +- #1599 +- #1599 - Basingstoke Council +- #1587 +- #1587 - Hartlepool Borough Council +- #1588 +- #1588 Glasgow City Council +- #1591 +- #1591 Rushmoor Council + +## 0.153.0 (2025-09-02) + +### Feat + +- Change buckinghamshire council to get data from endpoint + +### Fix + +- 1573 Update Bolton council URL +- East Herts Council +- #1575 +- Runnymede Borough Council +- #1513 +- Wiltshire Council +- #1533 +- Staffordshire Moorlands District Council +- #1535 +- Ipswich Borough Council +- #1548 +- North East Lincs +- Hinckley and Bosworth Borough Council +- Nuneaton Bedworth Borough Council +- #1514 +- Lichfield District Council +- 1549 + +## 0.152.11 (2025-08-25) + +### Feat + +- fix releases process + +### Fix + +- date extraction in RochfordCouncil data parsing +- parsing error in BH selenium +- **hacs**: respect the headless option + +### Refactor + +- **hacs**: improve build_ukbcd_args with formatter functions + +## 0.152.10 (2025-08-04) + +### Fix + +- Gateshead and East Lothian +- Enfield and Broxbourne +- East Herts +- FermanaghOmaghDistrictCouncil +- Enfield and Broxbourne +- East Herts + +## 0.152.9 (2025-08-03) + +### Fix + +- Cotswald and coventry +- Fixing multiple broken councils +- multiple broken councils + +## 0.152.8 (2025-07-26) + +### Fix + +- Add headers to request for Swindon Borough Council +- Add headers to requests for Royal Borough of Greenwich Fixes #1496 by ensuring that the requests are not rejected due to lack of headers. +- **MidlothianCouncil**: add request headers to resolve 403 Forbidden + +## 0.152.7 (2025-07-01) + +### Fix + +- maidstone selenium fix + +## 0.152.6 (2025-06-18) + +### Fix + +- removed In Progress from date +- removed a degub print statement +- **RugbyBoroughCouncil**: Amended parsed date from full to abbreviated month date, may worked but jun and jul did not +- **RugbyBoroughCouncil**: Amended parsed date +- Reworked Cumberland Council to cater for postcode addition +- **OxfordCityCouncil**: Fixed Oxford City Council parsing dues to changes in output from the website + +## 0.152.5 (2025-06-07) + +### Fix + +- South Ribble and version pinning issues for input.json + +## 0.152.4 (2025-06-07) + +### Fix + +- **SouthRibble**: Corrected Date formatting issue +- **SouthRibble**: Resolved South Ribble without selenium + +## 0.152.3 (2025-06-04) + +### Fix + +- NorthHertfordshire selenium script +- Adur council +- Eastleigh date fix +- removed duplicates in BradfordMDC + +## 0.152.2 (2025-06-04) + +### Fix + +- Update Makefile +- Update CheshireEastCouncil.py +- Github action to handle branch name with parentheses + +## 0.152.1 (2025-05-15) + +### Fix + +- Update to fix North Somerset +- Glasgow SSL bypass +- more robust Northumberland +- updated Eastleigh input.json +- Eastleigh cloudflare fix +- converted collection datetimes into dates for BH parsing. +- Eastleigh cloudflare fix +- Eastleigh cloudflare fix +- added check_uprn to simplified councils +- simplified Swindon +- simplified East Devon +- simplified Dover +- Simplified Dartford +- simplified Cheshire East +- simplified Charnwood input.json +- improved Charnwood +- Adur Worthing fix +- Chorley simplification +- Bexley simplification +- added URL to Torbay script +- Guildford fixes +- reworked Maidstone +- maidstone input.json +- Croydon selenium version +- Stoke date-time fix + +## 0.152.0 (2025-05-02) + +### Feat + +- Added Fermanagh Omagh +- Added Twekesbury +- added Slough council +- Added Argus Council +- added Angus to input.json + +### Fix + +- Chichester now only requires postcode and house number +- Broadland now only requires postcode and house number +- Barking now only requires postcode and house number +- Brighton now only requires postcode and house number +- ensured all bins for this council +- added skip_get_url to hyndburn + +## 0.151.0 (2025-04-27) + +### Feat + +- version bump + +### Fix + +- more robust brent date handling +- input.json requires web_driver +- Rugby fix + +## 0.150.0 (2025-04-27) + +### Feat + +- added melton +- added pembrokeshire + +### Fix + +- added melton +- processed all bins for Moray + +## 0.148.6 (2025-04-27) + +## 0.148.5 (2025-04-27) + +### Fix + +- output check +- parsed bin info +- selenium navigation +- input.json changes + +## 0.148.4 (2025-04-27) + +### Fix + +- used canonical 'nice name' + +## 0.148.3 (2025-04-25) + +### Fix + +- working hyndburn +- hyndburn input.json + +## 0.148.2 (2025-04-24) + +### Fix + +- Update docker-compose.yml +- updated input.json +- cloudflare fix - switch to selenium method +- simplified blackburn + +## 0.148.1 (2025-04-22) + +### Fix + +- added bank holiday offsets. +- added bank holiday offsets. + +## 0.148.0 (2025-04-19) + +### Feat + +- adding Wrexham and #1046 Horsham councils + +### Fix + +- Argyll and Bute council #1053 + +## 0.147.2 (2025-04-18) + +### Fix + +- wait for element to be clickable + +## 0.147.1 (2025-04-18) + +### Fix + +- #1351 - moved geopandas to petry dev + +## 0.147.0 (2025-04-18) + +### Feat + +- add council tests results map + +## 0.146.2 (2025-04-18) + +### Fix + +- adding map checking and matching + +## 0.146.1 (2025-04-18) + +### Fix + +- more robust bank holiday handling + +## 0.146.0 (2025-04-18) + +### Feat + +- #1342 Adding Includes Trafford, Clackmannanshire, Havant, North Warwickshire, Newry Mourne and Down, East Dunbartonshire, Pendle, Torfaen, East Hampshire, Ribble Valley, Brentwood, Isle of Wight, Westmorland and Furness, Derry and Strabane, and Norwich. Google Cal support for PDF councils via ICS file + +### Fix + +- Black reformatting + +## 0.145.0 (2025-04-18) + +### Feat + +- Adding PDF councils + +## 0.144.4 (2025-04-18) + +### Fix + +- Bristol #1275 + +## 0.144.3 (2025-04-17) + +### Fix + +- better address for input.json +- bank holiday overrides +- more robust address searching +- simple parsing done +- Selenium navigation + +## 0.144.2 (2025-04-17) + +### Fix + +- knowsley +- knowsley +- knowsley +- knowsley +- KnowsleyMBCouncil.py +- #1220 adding Mid Ulster District Council + +## 0.144.1 (2025-04-17) + +### Fix + +- fix Sandwell garden waste collection date + +## 0.144.0 (2025-04-17) + +### Feat + +- added great yarmouth + +## 0.143.6 (2025-04-17) + +### Fix + +- Renfrewshire Council + +## 0.143.5 (2025-04-17) + +### Fix + +- Google Cal + +## 0.143.4 (2025-04-17) + +### Fix + +- Google Cal + +## 0.143.3 (2025-04-15) + +### Fix + +- #1301 Fix Leeds Council + +## 0.143.2 (2025-04-15) + +### Fix + +- #1301 Fix Leeds Council + +## 0.143.1 (2025-04-15) + +### Fix + +- Set the bin_type when different day + +## 0.143.0 (2025-04-13) + +### Fix + +- corrected url in input.json +- fixed input.json +- parsed Barking Dagenham collection information +- selenium navigation Barking + +## 0.142.0 (2025-04-13) + +### Feat + +- Added Stirling Council + +### Fix + +- typo in input.json + +## 0.141.4 (2025-04-13) + +### Fix + +- #1304 - sesnors goes to unknown if the data is blank from councils who are less reliable + +## 0.141.3 (2025-04-13) + +### Fix + +- Newham council + +## 0.141.2 (2025-04-13) + +### Fix + +- Newham council +- Newham council + +## 0.141.1 (2025-04-12) + +### Fix + +- missing finally block on selenium tests + +## 0.141.0 (2025-04-12) + +### Feat + +- #1185 Adding PeterboroughCity Council + +## 0.140.0 (2025-04-11) + +### Feat + +- Added Broadland District Council + +### Fix + +- cleanup of council file +- added Broadland to input.json + +## 0.139.0 (2025-04-07) + +### Feat + +- adding #1037 +- adding #1032 North Devon Count Council + +### Fix + +- #1296 Forest of dean +- 939 adding South Holland District Council - Lincolnshire UK + +## 0.138.1 (2025-04-05) + +### Fix + +- Walhtam forest council - revert previous changes + +## 0.138.0 (2025-04-05) + +### Feat + +- Adding Hastings Borough Council +- Adding Fylde Council + +### Fix + +- #1249 +- #1039 +fix: #1181 +fix: #1266 +fix: #1274 +- Gloucester City Council +- #1282 +- Mid Devon Council +- #1277 +fix: #1287 +- West Oxfordshire Council +- #1290 + +## 0.137.0 (2025-04-05) + +### Feat + +- #816 adding trafford council + +## 0.136.0 (2025-03-24) + +### Feat + +- Adding Southampton City Council +- Adding Cambridge City Council +- Adding Spelthorne Borough Council + +### Fix + +- #1057 +- #1264 +- #1270 +- Bexley Council +- #1256 +- HinckleyandBosworthBoroughCouncil +- #1207 +- Hackney Council +- #1230 +- Castlepoint District Council +- #1252 +- Canterbury City Council +- #1254 + +## 0.135.4 (2025-03-24) + +### Fix + +- parse scheduleCodeWorkflowIDs instead of scheduleCodeWorkflowID for Hackney Council + +## 0.135.3 (2025-02-23) + +## 0.135.2 (2025-02-19) + +### Fix + +- North Yorkshire - multiple bins on a day + +## 0.135.1 (2025-02-18) + +### Fix + +- devcontainer + +## 0.135.0 (2025-02-17) + +### Fix + +- #833 adding Middlesbrough and check script for Selenium +- Cotswold District Council +- #1238 +- Leeds City Council +- #1222 + +## 0.134.3 (2025-02-15) + +### Fix + +- Update input.json +- 1235 Councils missing Selenium in input.json + +## 0.134.2 (2025-02-15) + +### Fix + +- 1232 East herts missing Selenium url in input.json +- Derbyshire Dales District Council +- Conwy County Borough +- Sunderland City Council +- #1219 +- Tendring District Council +- #1221 + +## 0.134.1 (2025-02-11) + +### Fix + +- Cheltenham Borough Council +- #1061 + +## 0.134.0 (2025-02-07) + +### Feat + +- Ipswich Borough Council - trying different address +- Ipswich Borough Council - correcting param name in input.json +- Ipswich Borough Council - added input.json values and refactored code +- Ipswich Borough Council - initial implementation +- Adding Runnymede Borough Council +- Adding Cherwell District Council +- Adding Epsom and Ewell Borough Council +- Adding Redcar and Cleveland Council +- Adding Amber Valley Borough Council +- Adding Bolsover Council + +### Fix + +- #1214 +- #923 +- #895 +- #841 +- #903 +- #990 +- Torridge District Council +- #1204 +- Neath Port Talbot +- #1213 + +## 0.133.0 (2025-02-02) + +### Feat + +- adding manual refresh + +## 0.132.0 (2025-02-02) + +### Feat + +- adding manual refresh + +## 0.131.0 (2025-02-02) + +### Feat + +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding manual refresh +- adding unit tests for the new manual refresh +- adding manual refresh control + +## 0.130.1 (2025-01-30) + +### Fix + +- slow councils + +## 0.130.0 (2025-01-29) + +### Feat + +- Add Herefordshire Council (closes: #1011) + +### Fix + +- Fix spacing in wiki name + +## 0.129.0 (2025-01-29) + +### Fix + +- input.json +- input.json + +## 0.128.6 (2025-01-29) + +### Fix + +- moving away from broken Allure reporting +- moving away from broken Allure reporting +- moving away from broken Allure reporting +- moving away from broken Allure reporting +- moving away from broken Allure reporting +- moving away from broken Allure reporting +- moving away from broken Allure reporting + +## 0.128.5 (2025-01-29) + +### Feat + +- Adding East Staffordshire Borough Council + +### Fix + +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update CheshireEastCouncil.py +- Adding East Lothian Council +- #1171 +- #1052 +fix: #1083 + +## 0.128.4 (2025-01-28) + +### Feat + +- Adding Boston Borough Council + +### Fix + +- Update CheshireEastCouncil.py +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update CheshireEastCouncil.py +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Leicester City Council +- #1178 +- Cardiff Council +- #1175 +- Newcastle City Council +- #1179 +- #1180 +- Midlothian Council +- #1192 - Adding Next Page support + +## 0.128.3 (2025-01-28) + +### Fix + +- Update CheshireEastCouncil.py +- Update behave_schedule.yml +- Update behave_pull_request.yml + +## 0.128.2 (2025-01-28) + +### Fix + +- Add communal recycling and communal rubbish +- Add garden waste to Merton Council + +## 0.128.1 (2025-01-28) + +### Fix + +- Update AberdeenshireCouncil.py +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml + +## 0.128.0 (2025-01-28) + +### Feat + +- implement Medway Council (#1021) + +### Fix + +- Forgot to include skip_get_url + +## 0.127.4 (2025-01-25) + +### Fix + +- NewForestCouncil + +## 0.127.3 (2025-01-16) + +### Fix + +- Swale Borough Council +- #1139 +- Vale of White Horse +- #1156 +- South Oxfordshire Council +- #1158 +- Surrey Heath Borough Council +- #1164 +- Carmarthenshire County Council +- #1167 +- Glasgow City Council +- #1166 + +## 0.127.2 (2025-01-13) + +### Fix + +- Update bin type to be the full string + +## 0.127.1 (2025-01-10) + +### Fix + +- Use visibility of list rather than existence +- Update Rushcliffe Borough Council input elements and flow +- Merton Council +- NewarkAndSherwoodDC +- Rushcliffe Borough Council +- Powys Council +- Staffordshire Moorlands District Council +- Stroud District Council +- Vale of Glamorgan Council +- West Oxfordshire District Council + +## 0.127.0 (2025-01-07) + +### Feat + +- Adding Oadby And Wigston Borough Council +- Add Gwynedd Council +- Adding Denbighshire Council +- Adding Dundee City Council +- Adding Brent Council +- Adding West Dunbartonshire Council +- Adding Cumberland Council + +### Fix + +- #929 +- Cornwall Council +- #1137 +- #1125 +- #1106 +- #1108 +- #1109 +- #1134 +- Northumberland Council +- #1082 +- #1110 +- Waltham Forest +- #1126 +- London Borough Sutton +- #1131 +- Kirklees Council +- #1129 - Breaking Change. UPRN required + +## 0.126.2 (2025-01-07) + +### Fix + +- **tests**: updates test case url for coventry city council +- **tests**: removes duplicate key for coventry city council +- updates coventry city council button text + +## 0.126.1 (2025-01-06) + +### Fix + +- behave_testing +- behave_testing + +## 0.126.0 (2025-01-04) + +### Fix + +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml + +## 0.125.2 (2025-01-04) + +### Fix + +- Update ArdsAndNorthDownCouncil.py +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update README.md to have links to Full and Partial Integration Test Reports +- Update behave_pull_request.yml +- Update README.md to have links to Full and Partial Integration Test Reports +- Swale Borough Council +- #1080 +(cherry picked from commit 6f580b39fb68b8079990221e050ae8dd6d2b7285) +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update ArdsAndNorthDownCouncil.py +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update README.md to have links to Full and Partial Integration Test Reports +- Update WestLindseyDistrictCouncil.py +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_schedule.yml +- Update behave_pull_request.yml +- Update behave_pull_request.yml +- Update behave_schedule.yml +- Update behave_schedule.yml + +## 0.125.1 (2025-01-04) + +### Fix + +- correctly handle year increment for January dates + +## 0.125.0 (2025-01-04) + +### Feat + +- Adding Redditch Borough Council +- Adding Blaenau Gwent County Borough Council +- Adding Wandsworth Council + +### Fix + +- #1068 +- #1098 +- Wiltshire Council +- #1094 +- Salford City Council +- #1097 +- #1078 +- Merton Council +- Swale Borough Council +- #1080 +- London Borough Sutton +- #1076 +- Update behave_schedule.yml +- Update bump.yml + +## 0.124.4 (2025-01-04) + +### Fix + +- Update behave_schedule.yml + +## 0.124.3 (2025-01-04) + +### Fix + +- allure reporting +- allure reporting +- allure reporting + +## 0.124.2 (2025-01-03) + +### Fix + +- Update behave.yml + +## 0.124.1 (2025-01-03) + +### Fix + +- avoid crashing on unexpected string value + +## 0.124.0 (2025-01-02) + +### Feat + +- Hart District Council + +## 0.123.2 (2024-12-19) + +### Fix + +- Update behave.yml + +## 0.123.1 (2024-12-18) + +### Feat + +- #1063 - rewrite Kirklees Council parser for new website +- #1067 - Add garden bin collections where available for Norwich City Council +- Adding Wandsworth Council + +### Fix + +- Update AberdeenCityCouncil.py +- Update behave.yml +- #1101 - Fix table parsing for Walsall Council +- Remove invalid escape sequence warnings from West Lindsey District Council +- #1073 - change method of generating bin types to avoid manual mapping for Rugby Borough Council +- add missing backticks to separate colour config and standard usage instructions +- #1078 +(cherry picked from commit 89d93666bb659010d1c130b98c1d81c6ff80cf7c) +- change date format to project default for Merton Council +- correct date logic for Swale Borough Council +- Merton Council +- London Borough Sutton +- #1076 +(cherry picked from commit 1eab20c9a57c9c4438ea343f374202bb2e9b98ca) +- Swale Borough Council +- #1080 +(cherry picked from commit 6f580b39fb68b8079990221e050ae8dd6d2b7285) +- correct date/year logic for West Lindsey District Council +- replace West Lindsey's input with working address +- #1089 - Correct shifted dates in Bromley Borough Council +- remove WDM import +- #1087 - Food waste date incorrect for West Berkshire Council + +## 0.123.0 (2024-12-17) + +## 0.122.0 (2024-12-04) + +### Feat + +- Adding Monmouthshire County Council +- Adding Hinckley and Bosworth Borough Council + +### Fix + +- Glasgow City Council +- Merton Council +- Blaby District Council +- Warwick District Council +- Blackburn Council +- Carmarthenshire County Council +- High Peak Council +- CarmarthenshireCountyCouncil + +## 0.121.1 (2024-12-03) + +### Fix + +- London Borough of Lewisham to have more reliable parsing of dates + +## 0.121.0 (2024-11-24) + +### Feat + +- Royal Borough of Greenwich +- Adding London Borough of Lewisham +- Adding Hackney Council +- Adding Sandwell Borough Council +- Adding Moray Council +- Adding Kings Lynn and West Norfolk Borough Council +- Adding Wyre Forest District Council +- Adding Folkstone and Hythe District Council +- Adding Cheltenham Borough Council +- Adding Thurrock Council + +### Fix + +- West Northamptonshire Council +- East Ayrshire Council +- Cotswold District Council + +## 0.120.0 (2024-11-20) + +### Feat + +- Adding Hartlepool Borough Council +- Adding Newcastle Under Lyme Council +- Adding London Borough of Havering +- Add Garden collection to EnvironmentFirst +- Adding Cumberland Council (Allerdale District) +- Adding North Hertfordshire District Council + +### Fix + +- #844 +- #778 +- #769 +- #1025 +- Mid Siffolk and Babergh Garden Collection Day +- #1026 +This will require the use of a DAY to be added to the UPRN field +- #1029 +- #1028 + +## 0.119.0 (2024-11-20) + +### Feat + +- Adding Braintree District Council +- Adding Burnley Borough Council +- Adding Exeter City Council +- Adding Edinburgh City Council + +### Fix + +- #699 +- #1015 +- #1017 +- #894 + +## 0.118.0 (2024-11-15) + +### Feat + +- Adding Aberdeen City Council +- Adding Wolverhampton City Council +- Adding Stevenage Borough Council +- Adding Thanet District Council +- Adding Copeland Borough Council +- Adding South Hams District Council + +### Fix + +- #1019 +- #966 +- #989 +- #1004 +- #1006 +- #1008 +- Rother District Council + +## 0.117.0 (2024-11-13) + +### Feat + +- Adding South Staffordshire District Council fix: #885 +- Adding Rother District Council + +### Fix + +- #1009 + +## 0.116.0 (2024-11-12) + +### Feat + +- Adding Ashfield District Council +- Adding Gravesham Borough Council +- Adding Argyll and Bute Council + +### Fix + +- CrawleyBoroughCouncil +- #1005 +- Adding Garden collection to Babergh and MidSuffolk Council +- #995 +- #579 +- #991 +- #692 +- CheshireWestAndChesterCouncil +- #993 +- Milton Keynes +- #702 +- Adding Babergh and Mid Suffolk District Councils +- #868 +fix: #919 +- Adding Derby City Council +- #987 + +## 0.115.0 (2024-11-11) + +### Feat + +- Adding Warrington Borough Council +- Adding Antrim And Newtonabbey Council +- Adding Hertsmere Borough Council +- Adding West Lancashire Borough Council +- Broxbourne Council + +### Fix + +- #695 +- #969 +- #776 +- #980 +- #982 +- Bradford MDC +- #984 + +## 0.114.6 (2024-11-09) + +### Fix + +- NBBC Date Fix + +## 0.114.5 (2024-11-08) + +### Fix + +- migration logging and debugging + +## 0.114.4 (2024-11-08) + +### Fix + +- migration not working +- migration not working + +## 0.114.3 (2024-11-08) + +## 0.114.2 (2024-11-08) + +## 0.114.1 (2024-11-08) + +### Fix + +- Update manifest.json + +## 0.114.0 (2024-11-07) + +### Feat + +- Nuneaton and Bedworth Borough Council + +## 0.113.0 (2024-11-07) + +## 0.112.1 (2024-11-07) + +## 0.112.0 (2024-11-06) + +### Feat + +- adding calendar for Bins in Custom Component + +### Fix + +- fix manifest in custom component +- #975 adding routine to handle migration error +- #975 adding routine to handle migration error +- #767 BREAKING CHANGE - READD your sensors / config + +## 0.111.0 (2024-11-06) + +### Fix + +- Add London Borough of Sutton +- #944 +- Add Mid Devon Council +- #945 +- Adding Oxford City Council +- #962 +- Tunbridge Wells / Lincoln +- #963 +- Glasgow City Council + +## 0.110.0 (2024-11-04) + +### Fix + +- Adding Blaby District Council +- #904 +- Adding Sefton Council +- #770 +- Adding Bromsgrove District Council +- #893 +- East Lindsey District Council +- #957 +- Adding Carmarthenshire County Council +- #892 +fix: #710 +- Adding East Ayrshire Council +- #955 + +## 0.109.2 (2024-11-03) + +### Fix + +- CC testing and add Chesterfield + +## 0.109.1 (2024-11-03) + +### Fix + +- CC testing and add Chesterfield +- CC testing and add Chesterfield + +## 0.109.0 (2024-11-02) + +### Feat + +- Adding Cotswold District Council +- Adding Breckland Council + +### Fix + +- St Helens Borough Council +- #753 +- NewarkAndSherwoodDC +- #941 +- #658 +- #656 + +## 0.108.2 (2024-11-01) + +### Fix + +- pytest-homeassistant-custom-component + +## 0.108.1 (2024-11-01) + +### Fix + +- Pydandic version +- Pydandic version + +## 0.108.0 (2024-11-01) + +### Feat + +- pytest fixes +- pytest fixes +- pytest fixes +- pytest fixes +- pytest fixes +- pytest fixes + +## 0.107.0 (2024-10-31) + +### Feat + +- Adding Powys Council +- Adding Worcester City Council +- Adding Ards and North Down Council +- Adding East Herts Council +- Adding Ashford Borough Council + +### Fix + +- WestOxfordshireDistrictCouncil +- South Norfolk Council +- ForestOfDeanDistrictCouncil +- Croydon Council +- South Kesteven District Council +- #647 +- #630 +- #623 +- #586 +- #578 +- #389 + +## 0.106.0 (2024-10-28) + +### Feat + +- Adding Stockton On Tees Council +- Adding Fife Council +- Adding Flintshire County Council + +### Fix + +- #930 +- #933 +- #750 + +## 0.105.1 (2024-10-24) + +### Fix + +- Refactor Midlothian Council scraper to use house number and postcode +- West Berkshire Council +- Southwark Council + +## 0.105.0 (2024-10-21) + +### Feat + +- Adding Teignbridge Council +- Adding Harborough District Council +- Adding Watford Borough Council +- Adding Coventry City Council +- pytest fixes +- pytest fixes +- pytest fixes +- pytest fixes +- pytest fixes +- Adding Powys Council +- Adding Worcester City Council +- Adding Ards and North Down Council +- Adding East Herts Council +- Adding Ashford Borough Council +- Adding Stockton On Tees Council +- Adding Fife Council +- Adding Flintshire County Council +- Adding Teignbridge Council +- Adding Harborough District Council +- Adding Watford Borough Council +- Adding Coventry City Council +- Python 3.12 only and CustomComp. Unit testing + +### Fix + +- #580 +- #888 +- #902 +- #607 +- CC testing and add Chesterfield +- CC testing and add Chesterfield +- CC testing and add Chesterfield +- pytest-homeassistant-custom-component +- Pydandic version +- Pydandic version +- WestOxfordshireDistrictCouncil +- South Norfolk Council +- ForestOfDeanDistrictCouncil +- Croydon Council +- South Kesteven District Council +- #647 +- #630 +- #623 +- #586 +- #578 +- #389 +- #930 +- #933 +- #750 +- Refactor Midlothian Council scraper to use house number and postcode +- West Berkshire Council +- Southwark Council +- #580 +- #888 +- #902 +- #607 + +## 0.104.0 (2024-10-20) + +### Feat + +- Adding Luton Borough Council +- Adding West Oxfordshire District Council +- Adding Aberdeenshire Council +- Adding Canterbury City Council +- Adding Swindon Borough Council + +### Fix + +- #697 +- #694 +- #659 +- #590 +- #900 + +## 0.103.0 (2024-10-20) + +### Feat + +- Adding RAW JSON Sensor + +### Fix + +- Black formatting +- Black formatting + +## 0.102.0 (2024-10-20) + +### Feat + +- Moving from Attributes to Sensors +- Moving from Attributes to Sensors + +## 0.101.0 (2024-10-20) + +### Feat + +- Add Midlothgian Council + +## 0.100.0 (2024-10-18) + +### Feat + +- Adding Dudley Council +- Adding South Ribble Council +- Plymouth Council +- Adding Norwich City Council + +### Fix + +- #744 +- #671 +- #566 +- #749 + +## 0.99.1 (2024-10-16) + +### Fix + +- #792 adding web_driver option to Wokingham Council + +## 0.99.0 (2024-10-16) + +### Feat + +- Adding Lincoln Council +- Adding Tunbridge Wells Council +- Adding Perth and Kinross Council + +### Fix + +- Update wiki +- #748 +- #598 +- #572 + +## 0.98.5 (2024-10-15) + +### Fix + +- Swale Borough Council +- HaltonBoroughCouncil +- Barnet Council +- WestBerkshireCouncil + +## 0.98.4 (2024-10-14) + +### Fix + +- West Suffolk Council +- Vale of White Horse Council +- Uttlesford District Council +- Neath Port Talbot Council +- Merton Council +- Manchester City Council +- Glasgow City Council +- BradfordMDC + +## 0.98.3 (2024-10-13) + +### Fix + +- EastRiding + +## 0.98.2 (2024-10-13) + +### Fix + +- MoleValley + +## 0.98.1 (2024-10-13) + +### Fix + +- Barnet and Bexley + +## 0.98.0 (2024-10-13) + +### Feat + +- Adding Wirral Council +- Adding Lichfield District Council +- Adding West Morland And Furness +- Adding Walsall Council +- Adding Armagh, Banbridge and Craigavon Council + +### Fix + +- #602 +- #830 +- #870 +- #873 +- #877 + +## 0.97.1 (2024-10-10) + +### Fix + +- NottinghamCityCouncil +- #875 + +## 0.97.0 (2024-10-10) + +### Feat + +- Adding Falkirk Council + +### Fix + +- #761 + +## 0.96.0 (2024-10-10) + +### Feat + +- Adding London Borough Harrow +- Adding North Ayrshire Council +- Adding Highland Council +- Add Elmbridge Borough Council +- Adding Southwark Council +- South Derbyshire District Council + +### Fix + +- #871 +- #869 +- #780 +- #845 +fix: #754 +- #835 +- #842 + +## 0.95.0 (2024-10-09) + +### Feat + +- Adding London Borough of Ealing + +## 0.94.0 (2024-10-09) + +### Feat + +- Adding London Borough of Lambeth +- Adding Dacorum Borough Council + +### Fix + +- Dacorum Borough Council +- East Devon DC + +## 0.93.0 (2024-10-08) + +### Feat + +- Update CheshireEastCouncil.py + +## 0.92.0 (2024-10-08) + +### Feat + +- Update CheshireEastCouncil.py +- Update README.md +- Adding Wokingham Borough Council +- Adding Winchester City Council +- Adding Basildon Council +- Adding Colchester City Council + +### Fix + +- RochfordCouncil +- Neath Port Talbot Council +- Buckinghamshire Council +- #639 +fix: #812 + +## 0.91.2 (2024-10-05) + +### Fix + +- Windsor and Maidenhead Council + +## 0.91.1 (2024-10-04) + +## 0.91.0 (2024-10-03) + +## 0.90.0 (2024-10-03) + +### Feat + +- Adding East Renfrewshire Council + +### Fix + +- Update DorsetCouncil.py +- #829 +- Update GatesheadCouncil.py +- #822 + +## 0.89.1 (2024-10-02) + +### Fix + +- High Peak have changed their cookie dialog Seems to be safe to ignore it now. + +## 0.89.0 (2024-09-27) + +### Feat + +- Update CheshireEastCouncil.py +- Update README.md + +### Fix + +- release to be non pre release + +## 0.88.0 (2024-09-16) + +### Feat + +- Add Ealing Council + +### Fix + +- Update README.md + +## 0.87.0 (2024-09-10) + +### Feat + +- Add IslingtonCouncil + +### Fix + +- #565 Gloucester city council driver + +## 0.86.1 (2024-09-09) + +### Fix + +- #773 Wakefield + +## 0.86.0 (2024-09-06) + +### Feat + +- added Rotherham Council + +## 0.85.7 (2024-09-05) + +### Fix + +- more unit tests +- more unit tests +- Chorley + +## 0.85.6 (2024-09-03) + +### Fix + +- #795 and add reconfigure to custom comp. + +## 0.85.5 (2024-09-03) + +## 0.85.4 (2024-09-03) + +### Fix + +- #795 and add reconfigure to custom comp. +- #795 Unit Test Coverage + +## 0.85.3 (2024-09-02) + +### Fix + +- #795 unit test coverage + +## 0.85.2 (2024-09-02) + +### Fix + +- 791 Glasgow URL change + +## 0.85.1 (2024-09-02) + +### Fix + +- 779 Add correct async wait to Home Assistant + +## 0.85.0 (2024-08-27) + +### Feat + +- support for enfield council + +## 0.84.2 (2024-08-27) + +### Fix + +- Re-work North Tyneside Council module for 2024 - some addresses do not have a garden collection +- Re-work North Tyneside Council module for 2024 + +## 0.84.1 (2024-08-08) + +### Fix + +- #771 Bolton bullet points on dates is now fixed + +## 0.84.0 (2024-07-31) + +## 0.83.0 (2024-07-07) + +### Feat + +- add has_numbers() function + +### Fix + +- update Gedling Borough Council parser to use alternative name key +- change Gedling to use new JSON data +- update instructions for Gedling +- update input.json to use UPRN parameter +- change DorsetCouncil.py to use API links provided in #756 +- explicit import of logging.config to stop error in Python 3.11 + +## 0.82.0 (2024-06-13) + +### Feat + +- adding dev container updates +- adding dev container updates +- refactoring main files +- adding ability to set local mode in HA custom comp. if users dont have a Selenium Server + +### Fix + +- MidSussex + +## 0.81.0 (2024-06-05) + +### Feat + +- Adding Wychavon District Council + +### Fix + +- IntTestWarnings +- IntTestWarnings + +## 0.80.0 (2024-06-02) + +### Feat + +- Adding Uttlesford District Council +- Adding Stafford Boro Council +- Adding Swansea Council +- Adding New Forest +- Adding Three Rivers +- Adding Three Rivers + +### Fix + +- ThreeRivers +- #425 Entities are not updated +- sessions to avoid deprecation +- Update docker-image.yml +- Update docker-image.yml + +## 0.79.1 (2024-05-29) + +### Fix + +- Change CSS class in search for collection types + +## 0.79.0 (2024-05-28) + +### Feat + +- Adding Dartford +- Adding South Kesteven District Council +- Adding ChichesterCouncil +- adding HounslowCouncil +- adding HounslowCouncil +- adding HounslowCouncil +- Epping Fix +- Adding Epping Forest District Council +- Update input.json +- Epping Forest District Council +- Adding Stroud District Council +- Add support for Tendring District Council +- #269 Adding Waltham Forest +- #269 Adding Waltham Forest +- Adding council creation script + +### Fix + +- Update Mole Valley URL + +## 0.78.0 (2024-05-26) + +### Feat + +- Add support for Fareham Borough Council + +## 0.77.0 (2024-05-26) + +### Feat + +- Add support for Bracknell Forest Council + +## 0.76.1 (2024-05-24) + +### Fix + +- Handle Barnet council cookies message + +## 0.76.0 (2024-05-24) + +### Feat + +- add bin colour support WestSuffolkCouncil style: black format WestSuffolkCouncil +- add bin colour support WestSuffolkCouncil style: black format WestSuffolkCouncil + +## 0.75.0 (2024-05-19) + +### Feat + +- #725 Add names to selenium test videos using "se:name" option in create webdriver function + +## 0.74.1 (2024-05-18) + +### Fix + +- #693 Cheshire West & Chester Council Sensor Bug +- #693 Cheshire West & Chester Council Sensor Bug + +## 0.74.0 (2024-05-17) + +### Feat + +- #722 Support Python 3.12 +- #722 Support Python 3.12 +- #722 Support Python 3.12 + +## 0.73.0 (2024-05-17) + +### Feat + +- #708 Adding HA to the dev container for debugging + +## 0.72.0 (2024-05-17) + +### Feat + +- #708 Adding HA to the dev container for debugging +- #708 Adding HA to the dev container for debugging +- #708 Adding HA to the dev container for debugging +- #708 Adding HA to the dev container for debugging +- #708 Adding HA to the dev container for debugging +- #708 Adding HA to the dev container for debugging +- #708 Adding HA to the dev container for debugging +- #708 Adding HA to the dev container for debugging + +## 0.71.0 (2024-05-17) + +### Feat + +- Update for West Suffolk Councils new website + +## 0.70.0 (2024-05-17) + +### Feat + +- #708 Dev Container +- Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 Dev Container +- #708 simplifying Selenium integration tests +- #708 simplifying Selenium integration tests +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Test GH action seenium +- #708 Dev Container testing +- #708 - dev container changes +- #706 Adding Dev Container +- #706 Adding initial Dev Container + +## 0.69.7 (2024-05-17) + +### Fix + +- #713 BarnsleyMBCouncil.py + +## 0.69.6 (2024-05-16) + +### Fix + +- #709 Update DoverDistrictCouncil.py + +## 0.69.5 (2024-05-14) + +### Fix + +- #696 Small issue and Black formatting +- #696 Small issue and Black formatting +- #696 Small issue and Black formatting +- #696 Small issue and Black formatting +- #696 Small issue and Black formatting +- #696 Small issue and Black formatting +- #696 Small issue and Black formatting +- #696 Small issue and Black formatting +- #696 test coverage back to 100% + +## 0.69.4 (2024-05-09) + +### Fix + +- pass in required parameter into `create_webdriver` +- test runners for `MiltonKeynesCityCouncil` and `NorthEastLincs`. + +## 0.69.3 (2024-05-09) + +### Fix + +- fix AttributeError when no garden waste collection is available for properties using Huntingdon District Council +- add support for parsing "Today" / "Tomorrow" as date text for `BarnsleyMBCouncil` +- add support for parsing "Tomorrow" as date text for `LiverpoolCityCouncil` + +## 0.69.1 (2024-05-01) + +### Fix + +- Handling the "Website cookies enhance your user experience." button +- Handling the "Website cookies enhance your user experience." button + +## 0.69.0 (2024-04-28) + +### Feat + +- Adding Renfrewshire Council +- Adding Renfrewshire Council + +## 0.68.2 (2024-04-28) + +### Fix + +- Remove 'import Dumper' + +## 0.68.1 (2024-04-27) + +### Fix + +- input.json Bradford missing comma + +## 0.68.0 (2024-04-27) + +### Feat + +- Add support for West Berkshire Council +- add support for Knowsley Metropolitan Borough Council +- add support for Cheshire West and Chester Council +- add support for Cheshire West and Chester Council + +## 0.66.2 (2024-04-18) + +### Fix + +- Update HaringeyCouncil.py issue #670 + +## 0.66.1 (2024-04-15) + +### Fix + +- parse datetimes correctly and round to midnight + +## 0.66.0 (2024-04-15) + +## 0.65.2 (2024-04-15) + +### Fix + +- change address selection to fix errors selecting the user's PAON + +## 0.65.1 (2024-04-15) + +### Fix + +- add check for parsed string length to stop datetime parsing error + +## 0.65.0 (2024-04-13) + +### Feat + +- add Arun council +- add support for Sunderland City Council +- add support for Sunderland City Council + +## 0.64.3 (2024-03-25) + +### Fix + +- sort data and correct dictionary name (#609) + +## 0.64.2 (2024-03-24) + +## 0.64.1 (2024-03-24) + +### Fix + +- fix Kirklees address search (switch to house & postcode) +- fixes json + +## 0.64.0 (2024-03-23) + +### Feat + +- add Kirklees council + +### Fix + +- fixes json + +## 0.63.0 (2024-03-23) + +### Feat + +- Add Solihull Council (#513) +- Add Adur and Worthing Councils (#544) +- Add Dover District Council (#614) +- Add Rochford Council (#620) +- Add Tandridge District Council (#621) +- Add West Northamptonshire Council (#567) +- Add Hull City Council (#622) +- Add Wyre Council (#625) +- Add Telford and Wrekin Co-operative Council (#632) +- Add Mansfield District Council (#560) +- Add Bedford Borough Council (#552) + +### Fix + +- spacing on input.json +- realign input.json +- capitalize bin type text +- formatting on input.json +- incorrect collections +- update testing URL for Merton +- attempt to resolve invisible banner hiding postcode box +- resolve JSON schema exception for date formatting +- resolve JSON schema exception for date formatting +- accept cookies banner + +## 0.62.0 (2024-03-03) + +### Fix + +- Added missing .feature file entry to the test config for NewhamCouncil + +## 0.61.1 (2024-02-16) + +### Fix + +- code optimisations +- Fix date parsing in WestLindseyDistrictCouncil.py + +## 0.61.0 (2024-02-11) + +### Feat + +- Add Mole Valley District Council + +## 0.60.1 (2024-02-03) + +### Fix + +- Update input.json Closes #599 + +## 0.60.0 (2024-01-28) + +### Feat + +- Add Scraper for St Albans City and District Council + +## 0.59.1 (2024-01-25) + +### Fix + +- add wiki note for castlepoint +- update test data for castlepoint +- remove single line causing issues + +## 0.59.0 (2024-01-20) + +### Feat + +- Add NorthYorkshire to test feature file +- Add north yorkshire to test input +- Add Support for north yorkshire council + +### Fix + +- remove unused code + +## 0.58.8 (2024-01-19) + +### Fix + +- barnet no overrides + +## 0.58.7 (2024-01-18) + +### Fix + +- accidentally returned strings when needed date objects, refactor to handle this +- checking for future/past dates + +## 0.58.6 (2024-01-18) + +### Fix + +- correct date handling for North West Leicestershire + +## 0.58.5 (2024-01-15) + +### Fix + +- Don't call driver.quit where already handled by finally block + +## 0.58.4 (2024-01-15) + +### Fix + +- remove extra driver.quit to prevent errors + +## 0.58.3 (2024-01-15) + +### Feat + +- Added support for Newham Council's bin collections + +### Fix + +- Add a default value for user_agent to fix all councils using selenium and not specifying agent + +## 0.58.2 (2024-01-11) + +### Fix + +- use static values for bin types + +## 0.58.1 (2024-01-10) + +### Fix + +- Eastleigh Borough Council doesnt cope with "You haven't yet signed up for ..." +- Eastleigh Borough Council doesnt cope when Garden Waste service hasn't been signed up for, which gets the value "You haven't yet signed up for our garden waste collections. Find out more about our\xa0garden waste collection service" which results in ValueError: time data + +## 0.58.0 (2024-01-10) + +### Feat + +- Add Test Valley Borough Council + +## 0.57.0 (2024-01-09) + +### Feat + +- Add support for Chorley Council + +## 0.56.13 (2024-01-09) + +### Fix + +- update logic to account for council website change + +## 0.56.12 (2024-01-09) + +### Fix + +- duplicate driver.quit() calls causes error + +## 0.56.11 (2024-01-08) + +### Fix + +- Headless now working on custom comp Update sensor.py + +## 0.56.10 (2024-01-08) + +### Fix + +- headless mode in custom component + +## 0.56.9 (2024-01-08) + +### Fix + +- headless mode + +## 0.56.8 (2024-01-08) + +### Fix + +- headless in custom comp + +## 0.56.7 (2024-01-08) + +### Fix + +- headless options + +## 0.56.6 (2024-01-07) + +### Fix + +- modified Kingston-upon-Thames driver for greater reliability. + +## 0.56.5 (2024-01-07) + +### Fix + +- Update KingstonUponThamesCouncil.py + +## 0.56.4 (2024-01-07) + +### Fix + +- Update KingstonUponThamesCouncil.py + +## 0.56.3 (2024-01-07) + +### Fix + +- headless options +- #542 - Selenium Grid Sessions must be terminated cleanly +- #542 - Selenium Grid Sessions must be terminated cleanly + +## 0.56.2 (2024-01-07) + +### Fix + +- Update strings.json +- Update en.json +- Update config_flow.py + +## 0.56.1 (2024-01-07) + +### Fix + +- Update common.py + +## 0.56.0 (2024-01-07) + +### Feat + +- Update strings.json +- Update en.json +- Update config_flow.py +- adding headless control +- adding headless control +- adding headless control + +## 0.55.3 (2024-01-05) + +### Fix + +- Update lint.yml + +## 0.55.2 (2024-01-05) + +### Fix + +- Chelmsford + +## 0.55.1 (2024-01-05) + +### Fix + +- Update ChelmsfordCityCouncil.py +- Update ChelmsfordCityCouncil.py +- Update ChelmsfordCityCouncil.py + +## 0.155.0 (2025-10-11) + +### Feat + +- Create tag-on-merge.yml +- Update bump.yml +- fix bump.yml +- Update TorbayCouncil.py +- Update bump.yml +- fix release pipeline bump.yml +- fix Torbay +- fix releases process + +### Fix + +- Update AberdeenCityCouncil.py +- Update TorbayCouncil.py +- Update TorbayCouncil.py +- Update TorbayCouncil.py +- Update URL for NewForestCouncil +- New URL and page for wheelie bins +- improve Mid Suffolk District Council holiday handling with dynamic bank holiday detection +- Oxford now rejects the "Requests" default user agent +- #1557 - Adding East Dunbartonshire +- #1557 - Adding East Dunbartonshire +- #1569 - Somerset Council +- #1569 - Somerset Council +- #1559 - Newport City Council +- #1559 - Newport City Council +- #1574 - Test Valley Borough Council +- #1574 - Test Valley Borough Council +- #1566 South Gloucestershire Council + +## 0.154.0 (2025-09-21) + +### Feat + +- handle changes to northumberland council website +- modify input for NorthumberlandCouncil to accept uprn instead of house number, and use new page structure + +### Fix + +- the cookie banner is not optional +- #1570 - Slough Borough Council +- #1570 - Slough Borough Council +- #1520 - Erewash Borough Council +- #1520 - Erewash Borough Council +- #1554 - Folkestone and Hythe District Council +- #1554 - Folkestone and Hythe District Council +- #1604 - West Berkshire Council +- #1604 - West Berkshire Council +- #1606 - Brighton and Hove City Council +- #1606 - Brighton and Hove City Council +- #1565 - BCP Council +- #1565 - BCP Council +- #1571 - Castle Point District Council +- #1571 - Castle Point District Council +- #1584 - NorthHertfordshireDistrictCouncil +- #1584 - NorthHertfordshireDistrictCouncil +- #1599 +- #1599 - Basingstoke Council +- #1587 +- #1587 - Hartlepool Borough Council +- #1588 +- #1588 Glasgow City Council +- #1591 +- #1591 Rushmoor Council + +## 0.153.0 (2025-09-02) + +### Feat + +- Change buckinghamshire council to get data from endpoint + +### Fix + +- 1573 Update Bolton council URL +- East Herts Council +- #1575 +- Runnymede Borough Council +- #1513 +- Wiltshire Council +- #1533 +- Staffordshire Moorlands District Council +- #1535 +- Ipswich Borough Council +- #1548 +- North East Lincs +- Hinckley and Bosworth Borough Council +- Nuneaton Bedworth Borough Council +- #1514 +- Lichfield District Council +- 1549 + +## 0.152.11 (2025-08-25) + +### Fix + +- date extraction in RochfordCouncil data parsing +- parsing error in BH selenium +- **hacs**: respect the headless option + +### Refactor + +- **hacs**: improve build_ukbcd_args with formatter functions + +## 0.152.10 (2025-08-04) + +### Fix + +- Gateshead and East Lothian +- Enfield and Broxbourne +- East Herts +- FermanaghOmaghDistrictCouncil +- Enfield and Broxbourne +- East Herts + +## 0.152.9 (2025-08-03) + +### Fix + +- Cotswald and coventry +- Fixing multiple broken councils +- multiple broken councils + +## 0.152.8 (2025-07-26) + +### Fix + +- Add headers to request for Swindon Borough Council +- Add headers to requests for Royal Borough of Greenwich Fixes #1496 by ensuring that the requests are not rejected due to lack of headers. +- **MidlothianCouncil**: add request headers to resolve 403 Forbidden + +## 0.152.7 (2025-07-01) + +### Fix + +- maidstone selenium fix + +## 0.152.6 (2025-06-18) + +### Fix + +- removed In Progress from date +- removed a degub print statement +- **RugbyBoroughCouncil**: Amended parsed date from full to abbreviated month date, may worked but jun and jul did not +- **RugbyBoroughCouncil**: Amended parsed date +- Reworked Cumberland Council to cater for postcode addition +- **OxfordCityCouncil**: Fixed Oxford City Council parsing dues to changes in output from the website + +## 0.152.5 (2025-06-07) + +### Fix + +- South Ribble and version pinning issues for input.json + +## 0.152.4 (2025-06-07) + +### Fix + +- **SouthRibble**: Corrected Date formatting issue +- **SouthRibble**: Resolved South Ribble without selenium + +## 0.152.3 (2025-06-04) + +### Fix + +- NorthHertfordshire selenium script +- Adur council +- Eastleigh date fix +- removed duplicates in BradfordMDC + +## 0.152.2 (2025-06-04) + +### Fix + +- Update Makefile +- Update CheshireEastCouncil.py +- Github action to handle branch name with parentheses + +## 0.152.1 (2025-05-15) + +### Fix + +- Update to fix North Somerset +- Glasgow SSL bypass +- more robust Northumberland +- updated Eastleigh input.json +- Eastleigh cloudflare fix +- converted collection datetimes into dates for BH parsing. +- Eastleigh cloudflare fix +- Eastleigh cloudflare fix +- added check_uprn to simplified councils +- simplified Swindon +- simplified East Devon +- simplified Dover +- Simplified Dartford +- simplified Cheshire East +- simplified Charnwood input.json +- improved Charnwood +- Adur Worthing fix +- Chorley simplification +- Bexley simplification +- added URL to Torbay script +- Guildford fixes +- reworked Maidstone +- maidstone input.json +- Croydon selenium version +- Stoke date-time fix + ## 0.152.0 (2025-05-02) ### Feat diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md new file mode 100644 index 0000000000..ba32e51224 --- /dev/null +++ b/COMPATIBILITY.md @@ -0,0 +1,122 @@ +# Home Assistant Compatibility + +This document outlines the Home Assistant compatibility testing for the UK Bin Collection custom component. + +## Supported Versions + +The UK Bin Collection custom component is tested against the following Home Assistant versions: + +- **Minimum supported**: Home Assistant 2023.10.0 +- **Recommended**: Latest stable release +- **Development**: Latest dev builds (may have issues) + +## Automated Testing + +### GitHub Workflows + +1. **Home Assistant Compatibility Test** (`.github/workflows/ha_compatibility_test.yml`) + - Runs on every push to master/main + - Tests against multiple HA versions + - Validates component imports and manifest + - Runs weekly to catch breaking changes + +2. **HACS Validation** (`.github/workflows/hacs_validation.yml`) + - Includes HassFest validation + - HACS action validation + - Quick compatibility check + +### Manual Testing + +Run the compatibility checker locally: + +```bash +# From the project root directory +python scripts/check_ha_compatibility.py +``` + +This script will: +- ✅ Validate manifest.json structure +- ✅ Test component module imports +- ✅ Check Home Assistant version +- ✅ Verify dependencies are installed + +## Compatibility Matrix + +| Home Assistant Version | Status | Notes | +|------------------------|--------|-------| +| 2023.10.x | ✅ Supported | Minimum version | +| 2023.12.x | ✅ Supported | Stable | +| 2024.1.x | ✅ Supported | Stable | +| 2024.3.x | ✅ Supported | Stable | +| 2024.6.x | ✅ Supported | Stable | +| 2024.9.x | ✅ Supported | Stable | +| 2024.12.x | ✅ Supported | Latest stable | +| dev | ⚠️ Testing | May have breaking changes | + +## Breaking Changes + +### Home Assistant 2023.10.0 +- Minimum Python version: 3.12 +- Updated async patterns required + +### Future Considerations +- Monitor HA core API changes +- Update component when deprecated features are removed +- Test against beta releases before stable release + +## Troubleshooting + +### Common Issues + +1. **Import Errors** + - Ensure Home Assistant is properly installed + - Check Python version compatibility (≥3.12) + - Verify uk-bin-collection package is installed + +2. **Manifest Validation Failures** + - Check manifest.json syntax + - Ensure all required fields are present + - Verify version numbers match + +3. **Component Load Failures** + - Check Home Assistant logs + - Verify component files are in correct location + - Ensure dependencies are satisfied + +### Getting Help + +If you encounter compatibility issues: + +1. Check the [GitHub Issues](https://github.com/robbrad/UKBinCollectionData/issues) +2. Run the compatibility checker: `python scripts/check_ha_compatibility.py` +3. Post in the [Home Assistant Community Thread](https://community.home-assistant.io/t/bin-waste-collection/55451) +4. Create a new issue with: + - Home Assistant version + - Component version + - Error logs + - Compatibility check output + +## For Developers + +### Adding New HA Version Tests + +1. Update `.github/workflows/ha_compatibility_test.yml` +2. Add new version to the matrix +3. Test locally first: `python scripts/check_ha_compatibility.py` +4. Update compatibility matrix in this document + +### Testing Locally + +```bash +# Install specific HA version +pip install homeassistant==2024.12.0 + +# Install component in development mode +pip install -e . + +# Run compatibility check +python scripts/check_ha_compatibility.py + +# Run component tests +python -m pytest custom_components/uk_bin_collection/tests/ +``` \ No newline at end of file diff --git a/Makefile b/Makefile index 06e8792912..8bd03eb8ce 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ generate-test-map-test-results: poetry run python uk_bin_collection/tests/generate_map_test_results.py build/integration-test-results/junit.xml > build/integration-test-results/test_results.json parity-check: - poetry run python uk_bin_collection/tests/council_feature_input_parity.py $(repo) $(branch) + poetry run python uk_bin_collection/tests/council_feature_input_parity.py "$(repo)" "$(branch)" unit-tests: poetry run coverage erase diff --git a/README.md b/README.md index 472c4cc3a5..8e8506cb15 100644 --- a/README.md +++ b/README.md @@ -374,6 +374,184 @@ Open the map viewer in VS Code: ![Test Results Map](test_results_map.png) --- +## ICS Calendar Generation + +You can convert bin collection data to an ICS calendar file that can be imported into calendar applications like Google Calendar, Apple Calendar, Microsoft Outlook, etc. + +### Overview + +The `bin_to_ics.py` script allows you to: +- Convert JSON output from bin collection data into ICS calendar events +- Group multiple bin collections on the same day into a single event +- Create all-day events (default) or timed events +- Add optional reminders/alarms to events +- Customize the calendar name + +### Requirements + +- Python 3.6 or higher +- The `icalendar` package, which can be installed with: + ```bash + pip install icalendar + ``` + +### Basic Usage + +```bash +# Basic usage with stdin input and default output file (bin.ics) +python bin_to_ics.py < bin_data.json + +# Specify input and output files +python bin_to_ics.py -i bin_data.json -o my_calendar.ics + +# Custom calendar name +python bin_to_ics.py -i bin_data.json -o my_calendar.ics -n "My Bin Collections" +``` + +### Options + +``` +--input, -i Input JSON file (if not provided, read from stdin) +--output, -o Output ICS file (default: bin.ics) +--name, -n Calendar name (default: Bin Collections) +--alarms, -a Comma-separated list of alarm times before event (e.g., "1d,2h,30m") +--no-all-day Create timed events instead of all-day events +``` + +### Examples + +#### Adding Reminders (Alarms) + +Add reminders 1 day and 2 hours before each collection: + +```bash +python bin_to_ics.py -i bin_data.json -a "1d,2h" +``` + +The time format supports: +- Days: `1d`, `2day`, `3days` +- Hours: `1h`, `2hour`, `3hours` +- Minutes: `30m`, `45min`, `60mins`, `90minutes` + +#### Creating Timed Events + +By default, events are created as all-day events. To create timed events instead (default time: 7:00 AM): + +```bash +python bin_to_ics.py -i bin_data.json --no-all-day +``` + +### Integration with Bin Collection Data Retriever + +You can pipe the output from the bin collection data retriever directly to the ICS generator. The required parameters (postcode, house number, UPRN, etc.) depend on the specific council implementation - refer to the [Quickstart](#quickstart) section above or check the [project wiki](https://github.com/robbrad/UKBinCollectionData/wiki) for details about your council. + +```bash +python uk_bin_collection/uk_bin_collection/collect_data.py CouncilName "URL" [OPTIONS] | + python bin_to_ics.py [OPTIONS] +``` + +#### Complete Example for a Council + +```bash +python uk_bin_collection/uk_bin_collection/collect_data.py CouncilName \ + "council_url" \ + -p "YOUR_POSTCODE" \ + -n "YOUR_HOUSE_NUMBER" \ + -w "http://localhost:4444/wd/hub" | + python bin_to_ics.py \ + --name "My Bin Collections" \ + --output my_bins.ics \ + --alarms "1d,12h" +``` + +This will: +1. Fetch bin collection data for your address from your council's website +2. Convert it to an ICS file named "my_bins.ics" +3. Set the calendar name to "My Bin Collections" +4. Add reminders 1 day and 12 hours before each collection + +For postcode lookup and UPRN information, please check the [UPRN Finder](#uprn-finder) section above. + +### Using the Calendar + +You have two options for using the generated ICS file: + +#### 1. Importing the Calendar + +You can directly import the ICS file into your calendar application: + +- **Google Calendar**: Go to Settings > Import & export > Import +- **Apple Calendar**: File > Import +- **Microsoft Outlook**: File > Open & Export > Import/Export > Import an iCalendar (.ics) + +Note: Importing creates a static copy of the calendar events. If bin collection dates change, you'll need to re-import the calendar. + +#### 2. Subscribing to the Calendar + +If you host the ICS file on a publicly accessible web server, you can subscribe to it as an internet calendar: + +- **Google Calendar**: Go to "Other calendars" > "+" > "From URL" > Enter the URL of your hosted ICS file +- **Apple Calendar**: File > New Calendar Subscription > Enter the URL +- **Microsoft Outlook**: File > Account Settings > Internet Calendars > New > Enter the URL + +Benefits of subscribing: +- Calendar automatically updates when the source file changes +- No need to manually re-import when bin collection dates change +- Easily share the calendar with household members + +You can set up a cron job or scheduled task to regularly: +1. Retrieve the latest bin collection data +2. Generate a fresh ICS file +3. Publish it to a web-accessible location + +### Additional Examples and Use Cases + +#### Automation with Cron Jobs + +Create a weekly update script on a Linux/Mac system: + +```bash +#!/bin/bash +# File: update_bin_calendar.sh + +# Set variables +COUNCIL="YourCouncilName" +COUNCIL_URL="https://your-council-website.gov.uk/bins" +POSTCODE="YOUR_POSTCODE" +HOUSE_NUMBER="YOUR_HOUSE_NUMBER" +OUTPUT_DIR="/var/www/html/calendars" # Web-accessible directory +CALENDAR_NAME="Household Bins" + +# Ensure output directory exists +mkdir -p $OUTPUT_DIR + +# Run the collector and generate the calendar +cd /path/to/UKBinCollectionData && \ +python uk_bin_collection/uk_bin_collection/collect_data.py $COUNCIL "$COUNCIL_URL" \ + -p "$POSTCODE" -n "$HOUSE_NUMBER" | \ +python bin_to_ics.py --name "$CALENDAR_NAME" --output "$OUTPUT_DIR/bins.ics" --alarms "1d,6h" + +# Add timestamp to show last update time +echo "Calendar last updated: $(date)" > "$OUTPUT_DIR/last_update.txt" +``` + +Make the script executable: +```bash +chmod +x update_bin_calendar.sh +``` + +Add to crontab to run weekly (every Monday at 2 AM): +```bash +0 2 * * 1 /path/to/update_bin_calendar.sh +``` + +**Google Assistant/Alexa Integration** + +If you have your calendar connected to Google Calendar or Outlook, you can ask your smart assistant about upcoming bin collections: + +- "Hey Google, when is my next bin collection?" +- "Alexa, what's on my calendar tomorrow?" (will include bin collections) + ## Docker API Server We have created an API for this located under [uk_bin_collection_api_server](https://github.com/robbrad/UKBinCollectionData/uk_bin_collection_api_server) diff --git a/bin_to_ics.py b/bin_to_ics.py new file mode 100644 index 0000000000..5beca06213 --- /dev/null +++ b/bin_to_ics.py @@ -0,0 +1,280 @@ +#!/usr/bin/env python3 +""" +Script to convert UK Bin Collection Data to ICS calendar file. +Takes JSON output from the bin collection data retriever and creates calendar events +for each collection date. The events are saved to an ICS file that can be imported +into calendar applications. + +Features: +- Creates all-day events for bin collections by default +- Optional alarms/reminders before collection days +- Groups multiple bin collections on the same day into one event +""" + +import argparse +import datetime +import json +import os +import sys +from typing import Dict, List, Optional, Union + +try: + from icalendar import Calendar, Event, Alarm +except ImportError: + print("Error: Required package 'icalendar' not found.") + print("Please install it with: pip install icalendar") + sys.exit(1) + + +def parse_time_delta(time_str: str) -> datetime.timedelta: + """ + Parse a time string into a timedelta object. + + Formats supported: + - "1d" or "1day" or "1days" for days + - "2h" or "2hour" or "2hours" for hours + - "30m" or "30min" or "30mins" or "30minutes" for minutes + + Args: + time_str: String representing a time duration + + Returns: + timedelta object representing the duration + """ + time_str = time_str.lower().strip() + + # Handle days + if time_str.endswith('d') or time_str.endswith('day') or time_str.endswith('days'): + if time_str.endswith('days'): + value = int(time_str[:-4]) + elif time_str.endswith('day'): + value = int(time_str[:-3]) + else: + value = int(time_str[:-1]) + return datetime.timedelta(days=value) + + # Handle hours + elif time_str.endswith('h') or time_str.endswith('hour') or time_str.endswith('hours'): + if time_str.endswith('hours'): + value = int(time_str[:-5]) + elif time_str.endswith('hour'): + value = int(time_str[:-4]) + else: + value = int(time_str[:-1]) + return datetime.timedelta(hours=value) + + # Handle minutes + elif time_str.endswith('m') or time_str.endswith('min') or time_str.endswith('mins') or time_str.endswith('minutes'): + if time_str.endswith('minutes'): + value = int(time_str[:-7]) + elif time_str.endswith('mins'): + value = int(time_str[:-4]) + elif time_str.endswith('min'): + value = int(time_str[:-3]) + else: + value = int(time_str[:-1]) + return datetime.timedelta(minutes=value) + + # Default to hours if no unit specified + else: + try: + value = int(time_str) + return datetime.timedelta(hours=value) + except ValueError: + raise ValueError(f"Invalid time format: {time_str}. Use format like '1d', '2h', or '30m'.") + + +def create_bin_calendar( + bin_data: Dict, + calendar_name: str = "Bin Collections", + alarm_times: Optional[List[datetime.timedelta]] = None, + all_day: bool = True +) -> Calendar: + """ + Create a calendar from bin collection data. + + Args: + bin_data: Dictionary containing bin collection data + calendar_name: Name of the calendar + alarm_times: List of timedeltas for when reminders should trigger before the event + all_day: Whether the events should be all-day events + + Returns: + Calendar object with events for each bin collection + """ + cal = Calendar() + cal.add('prodid', '-//UK Bin Collection Data//bin_to_ics.py//EN') + cal.add('version', '2.0') + cal.add('name', calendar_name) + cal.add('x-wr-calname', calendar_name) + + # Process bin collection data + if 'bins' not in bin_data: + print("Error: Invalid bin data format. 'bins' key not found.") + sys.exit(1) + + # Group collections by date to combine bins collected on the same day + collections_by_date = {} + + for bin_info in bin_data['bins']: + if 'type' not in bin_info or 'collectionDate' not in bin_info: + continue + + bin_type = bin_info['type'] + collection_date_str = bin_info['collectionDate'] + + # Convert date string to datetime object + try: + # Expecting format DD/MM/YYYY + collection_date = datetime.datetime.strptime(collection_date_str, "%d/%m/%Y").date() + except ValueError: + print(f"Warning: Unable to parse date '{collection_date_str}'. Skipping.") + continue + + # Add to collections by date + if collection_date not in collections_by_date: + collections_by_date[collection_date] = [] + + collections_by_date[collection_date].append(bin_type) + + # Create events for each collection date + for collection_date, bin_types in collections_by_date.items(): + event = Event() + + # Join multiple bin types into one summary if needed + bin_types_str = ", ".join(bin_types) + + # Create event summary and description + summary = f"Bin Collection: {bin_types_str}" + description = f"Collection for: {bin_types_str}" + + # Add event details + event.add('summary', summary) + event.add('description', description) + + # Set the event as all-day if requested + if all_day: + event.add('dtstart', collection_date) + event.add('dtend', collection_date + datetime.timedelta(days=1)) + else: + # Default to 7am for non-all-day events + collection_datetime = datetime.datetime.combine( + collection_date, + datetime.time(7, 0, 0) + ) + event.add('dtstart', collection_datetime) + event.add('dtend', collection_datetime + datetime.timedelta(hours=1)) + + # Add alarms if specified + if alarm_times: + for alarm_time in alarm_times: + alarm = create_alarm(trigger_before=alarm_time) + event.add_component(alarm) + + # Generate a unique ID for the event + event_id = f"bin-collection-{collection_date.isoformat()}-{hash(bin_types_str) % 10000:04d}@ukbincollection" + event.add('uid', event_id) + + # Add the event to the calendar + cal.add_component(event) + + return cal + + +def create_alarm(trigger_before: datetime.timedelta) -> Alarm: + """ + Create an alarm component for calendar events. + + Args: + trigger_before: How long before the event to trigger the alarm + + Returns: + Alarm component + """ + alarm = Alarm() + alarm.add('action', 'DISPLAY') + alarm.add('description', 'Bin collection reminder') + alarm.add('trigger', -trigger_before) + + return alarm + + +def save_calendar(calendar: Calendar, output_file: str) -> None: + """ + Save a calendar to an ICS file. + + Args: + calendar: Calendar object to save + output_file: Path to save the calendar file + """ + with open(output_file, 'wb') as f: + f.write(calendar.to_ical()) + + print(f"Calendar saved to {output_file}") + + +def load_json_data(input_file: Optional[str] = None) -> Dict: + """ + Load bin collection data from JSON file or stdin. + + Args: + input_file: Path to JSON file (if None, read from stdin) + + Returns: + Dictionary containing bin collection data + """ + if input_file: + try: + with open(input_file, 'r') as f: + return json.load(f) + except (json.JSONDecodeError, FileNotFoundError) as e: + print(f"Error reading input file: {e}") + sys.exit(1) + else: + try: + return json.load(sys.stdin) + except json.JSONDecodeError as e: + print(f"Error parsing JSON from stdin: {e}") + sys.exit(1) + + +def main(): + parser = argparse.ArgumentParser(description='Convert UK Bin Collection Data to ICS calendar file.') + parser.add_argument('--input', '-i', help='Input JSON file (if not provided, read from stdin)') + parser.add_argument('--output', '-o', help='Output ICS file (default: bin.ics)', + default='bin.ics') + parser.add_argument('--name', '-n', help='Calendar name (default: Bin Collections)', + default='Bin Collections') + parser.add_argument('--alarms', '-a', help='Comma-separated list of alarm times before event (e.g., "1d,2h,30m")') + parser.add_argument('--no-all-day', action='store_true', help='Create timed events instead of all-day events') + + args = parser.parse_args() + + # Parse alarm times + alarm_times = None + if args.alarms: + alarm_times = [] + for alarm_str in args.alarms.split(','): + try: + alarm_times.append(parse_time_delta(alarm_str.strip())) + except ValueError as e: + print(f"Warning: {e}") + + # Load bin collection data + bin_data = load_json_data(args.input) + + # Create calendar + calendar = create_bin_calendar( + bin_data, + args.name, + alarm_times=alarm_times, + all_day=not args.no_all_day + ) + + # Save calendar to file + save_calendar(calendar, args.output) + + +if __name__ == '__main__': + main() + diff --git a/custom_components/uk_bin_collection/__init__.py b/custom_components/uk_bin_collection/__init__.py index a5273cdbc0..1aa52c4168 100644 --- a/custom_components/uk_bin_collection/__init__.py +++ b/custom_components/uk_bin_collection/__init__.py @@ -283,15 +283,28 @@ def build_ukbcd_args(config_data: dict) -> list: """Build the argument list for UKBinCollectionApp from config data.""" council = config_data.get("original_parser") or config_data.get("council", "") url = config_data.get("url", "") - args = [council, url] + # Per-key formatters: return a list of CLI args for that key + def _format_headless(v): + return ["--headless"] if v else ["--not-headless"] + + def _format_web_driver(v): + return [f"--web_driver={v.rstrip('/')}"] if v is not None else [] + + formatters = { + "headless": _format_headless, + "web_driver": _format_web_driver, + } + for key, value in config_data.items(): if key in EXCLUDED_ARG_KEYS: continue - if key == "web_driver" and value is not None: - value = value.rstrip("/") - args.append(f"--{key}={value}") + fmt = formatters.get(key) + if fmt: + args.extend(fmt(value)) + else: + args.append(f"--{key}={value}") return args @@ -400,6 +413,17 @@ def process_bin_data(data: dict) -> dict: ) continue + if ( + collection_date < current_date + and current_date.month == 12 + and collection_date.month == 1 + ): + collection_date = collection_date.replace(year=current_date.year + 1) + _LOGGER.debug( + f"{LOG_PREFIX} Corrected rollover year for '{bin_type}' to {collection_date}" + ) + + existing_date = next_collection_dates.get(bin_type) if collection_date >= current_date and ( not existing_date or collection_date < existing_date diff --git a/custom_components/uk_bin_collection/config_flow.py b/custom_components/uk_bin_collection/config_flow.py index 6035f4febc..e345a15d48 100644 --- a/custom_components/uk_bin_collection/config_flow.py +++ b/custom_components/uk_bin_collection/config_flow.py @@ -12,11 +12,10 @@ import collections # At the top with other imports -from .const import DOMAIN, LOG_PREFIX, SELENIUM_SERVER_URLS, BROWSER_BINARIES +from .const import DOMAIN, LOG_PREFIX, SELENIUM_SERVER_URLS, BROWSER_BINARIES, INPUT_JSON_URL _LOGGER = logging.getLogger(__name__) - class UkBinCollectionConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Handle a config flow for UkBinCollection.""" @@ -253,10 +252,9 @@ async def async_step_reconfigure_confirm( async def get_councils_json(self) -> Dict[str, Any]: """Fetch and return the supported councils data, including aliases and sorted alphabetically.""" - url = "https://raw.githubusercontent.com/robbrad/UKBinCollectionData/0.152.0/uk_bin_collection/tests/input.json" try: async with aiohttp.ClientSession() as session: - async with session.get(url) as response: + async with session.get(INPUT_JSON_URL) as response: response.raise_for_status() data_text = await response.text() original_data = json.loads(data_text) @@ -569,10 +567,9 @@ async def async_step_init(self, user_input=None): async def get_councils_json(self) -> Dict[str, Any]: """Fetch and return the supported councils data.""" - url = "https://raw.githubusercontent.com/robbrad/UKBinCollectionData/0.111.0/uk_bin_collection/tests/input.json" try: async with aiohttp.ClientSession() as session: - async with session.get(url) as response: + async with session.get(INPUT_JSON_URL) as response: response.raise_for_status() data_text = await response.text() return json.loads(data_text) diff --git a/custom_components/uk_bin_collection/const.py b/custom_components/uk_bin_collection/const.py index b51bb2a366..4c5273865e 100644 --- a/custom_components/uk_bin_collection/const.py +++ b/custom_components/uk_bin_collection/const.py @@ -4,6 +4,8 @@ from homeassistant.const import Platform +INPUT_JSON_URL = "https://raw.githubusercontent.com/robbrad/UKBinCollectionData/0.163.0/uk_bin_collection/tests/input.json" + DEFAULT_NAME = "UK Bin Collection Data" DOMAIN = "uk_bin_collection" @@ -29,7 +31,6 @@ "council", "url", "skip_get_url", - "headless", "local_browser", "timeout", "icon_color_mapping", diff --git a/custom_components/uk_bin_collection/manifest.json b/custom_components/uk_bin_collection/manifest.json index 976a21b459..ffd0337a97 100644 --- a/custom_components/uk_bin_collection/manifest.json +++ b/custom_components/uk_bin_collection/manifest.json @@ -9,7 +9,7 @@ "integration_type": "service", "iot_class": "cloud_polling", "issue_tracker": "https://github.com/robbrad/UKBinCollectionData/issues", - "requirements": ["uk-bin-collection>=0.152.0"], - "version": "0.152.0", + "requirements": ["uk-bin-collection>=0.163.0"], + "version": "0.163.0", "zeroconf": [] } diff --git a/custom_components/uk_bin_collection/strings.json b/custom_components/uk_bin_collection/strings.json index 31f2dfaabe..5431c9e8db 100644 --- a/custom_components/uk_bin_collection/strings.json +++ b/custom_components/uk_bin_collection/strings.json @@ -8,9 +8,9 @@ "name": "Location name", "council": "Council", "manual_refresh_only":"Automatically refresh the sensor", - "icon_color_mapping": "JSON to map Bin Type for Colour and Icon see: https://github.com/robbrad/UKBinCollectionData" + "icon_color_mapping": "JSON to map Bin Type for Colour and Icon (see documentation)" }, - "description": "Please see [here](https://github.com/robbrad/UKBinCollectionData#requesting-your-council) if your council isn't listed" + "description": "Please see the documentation if your council isn't listed" }, "council": { "title": "Provide council details", @@ -27,7 +27,7 @@ "local_browser": "Don't run on remote Selenium server, use local install of Chrome instead", "submit": "Submit" }, - "description": "Please refer to your council's [wiki](https://github.com/robbrad/UKBinCollectionData/wiki/Councils) entry for details on what to enter.\n{selenium_message}" + "description": "Please refer to your council's wiki entry for details on what to enter.\n{selenium_message}" }, "reconfigure_confirm": { "title": "Update council details", @@ -43,17 +43,17 @@ "headless": "Run Selenium in headless mode (recommended)", "local_browser": "Don't run on remote Selenium server, use local install of Chrome instead", "manual_refresh_only":"Automatically refresh the sensor", - "icon_color_mapping": "JSON to map Bin Type for Colour and Icon see: https://github.com/robbrad/UKBinCollectionData", + "icon_color_mapping": "JSON to map Bin Type for Colour and Icon (see documentation)", "submit": "Submit" }, - "description": "Please refer to your council's [wiki](https://github.com/robbrad/UKBinCollectionData/wiki/Councils) entry for details on what to enter." + "description": "Please refer to your council's wiki entry for details on what to enter." } }, "error": { "name": "Please enter a location name", "council": "Please select a council", - "selenium_unavailable": "❌ Selenium server is not accessible. Please ensure it is running at http://localhost:4444 or http://selenium:4444. [Setup Guide](https://example.com/selenium-setup)", - "chromium_not_found": "❌ Chromium browser is not installed. Please install Chromium or Google Chrome. [Installation Guide](https://example.com/chromium-install)" + "selenium_unavailable": "Selenium server is not accessible. Please ensure it is running at localhost:4444 or selenium:4444", + "chromium_not_found": "Chromium browser is not installed. Please install Chromium or Google Chrome" } } } diff --git a/custom_components/uk_bin_collection/translations/en.json b/custom_components/uk_bin_collection/translations/en.json index 31f2dfaabe..5431c9e8db 100644 --- a/custom_components/uk_bin_collection/translations/en.json +++ b/custom_components/uk_bin_collection/translations/en.json @@ -8,9 +8,9 @@ "name": "Location name", "council": "Council", "manual_refresh_only":"Automatically refresh the sensor", - "icon_color_mapping": "JSON to map Bin Type for Colour and Icon see: https://github.com/robbrad/UKBinCollectionData" + "icon_color_mapping": "JSON to map Bin Type for Colour and Icon (see documentation)" }, - "description": "Please see [here](https://github.com/robbrad/UKBinCollectionData#requesting-your-council) if your council isn't listed" + "description": "Please see the documentation if your council isn't listed" }, "council": { "title": "Provide council details", @@ -27,7 +27,7 @@ "local_browser": "Don't run on remote Selenium server, use local install of Chrome instead", "submit": "Submit" }, - "description": "Please refer to your council's [wiki](https://github.com/robbrad/UKBinCollectionData/wiki/Councils) entry for details on what to enter.\n{selenium_message}" + "description": "Please refer to your council's wiki entry for details on what to enter.\n{selenium_message}" }, "reconfigure_confirm": { "title": "Update council details", @@ -43,17 +43,17 @@ "headless": "Run Selenium in headless mode (recommended)", "local_browser": "Don't run on remote Selenium server, use local install of Chrome instead", "manual_refresh_only":"Automatically refresh the sensor", - "icon_color_mapping": "JSON to map Bin Type for Colour and Icon see: https://github.com/robbrad/UKBinCollectionData", + "icon_color_mapping": "JSON to map Bin Type for Colour and Icon (see documentation)", "submit": "Submit" }, - "description": "Please refer to your council's [wiki](https://github.com/robbrad/UKBinCollectionData/wiki/Councils) entry for details on what to enter." + "description": "Please refer to your council's wiki entry for details on what to enter." } }, "error": { "name": "Please enter a location name", "council": "Please select a council", - "selenium_unavailable": "❌ Selenium server is not accessible. Please ensure it is running at http://localhost:4444 or http://selenium:4444. [Setup Guide](https://example.com/selenium-setup)", - "chromium_not_found": "❌ Chromium browser is not installed. Please install Chromium or Google Chrome. [Installation Guide](https://example.com/chromium-install)" + "selenium_unavailable": "Selenium server is not accessible. Please ensure it is running at localhost:4444 or selenium:4444", + "chromium_not_found": "Chromium browser is not installed. Please install Chromium or Google Chrome" } } } diff --git a/docs/RELEASE-SETUP-SUMMARY.md b/docs/RELEASE-SETUP-SUMMARY.md new file mode 100644 index 0000000000..0ccabd2c14 --- /dev/null +++ b/docs/RELEASE-SETUP-SUMMARY.md @@ -0,0 +1,136 @@ +# Release Workflow Setup Summary + +## What You Need to Do + +Your release workflow has been updated to use a GitHub App for secure, automated releases. Here's what you need to do to get it working: + +### 1. Create GitHub App (5 minutes) + +Follow the detailed guide: [GitHub App Setup Guide](./github-app-setup.md) + +**Quick steps:** +1. Go to https://github.com/settings/apps/new +2. Fill in: + - Name: `UKBinCollection Release Bot` (or similar unique name) + - Homepage: `https://github.com/robbrad/UKBinCollectionData` + - Uncheck "Webhook Active" + - Permissions: **Contents** = Read and write +3. Click "Create GitHub App" +4. Click "Install App" → Select your repository +5. Generate a private key (downloads a `.pem` file) + +### 2. Add Secrets to Repository (2 minutes) + +Go to: https://github.com/robbrad/UKBinCollectionData/settings/secrets/actions + +Add two secrets: + +**APP_ID** +- Value: The App ID shown at top of app settings (e.g., `123456`) + +**APP_PRIVATE_KEY** +- Value: Entire contents of the `.pem` file +- Include the `-----BEGIN RSA PRIVATE KEY-----` and `-----END RSA PRIVATE KEY-----` lines + +### 3. Test It (5 minutes) + +1. Create a test branch: + ```bash + git checkout -b test/release-workflow + ``` + +2. Make a small change with a conventional commit: + ```bash + echo "# Test" >> README.md + git add README.md + git commit -m "fix: test release workflow" + git push origin test/release-workflow + ``` + +3. Create and merge a PR on GitHub + +4. Watch the workflows run: + - Bump workflow should run and create a tag + - Release workflow should publish to PyPI + +5. Verify: + - Check https://github.com/robbrad/UKBinCollectionData/releases + - Check https://pypi.org/project/uk-bin-collection/ + +## What Changed + +### Workflows Updated +- ✅ `.github/workflows/bump.yml` - Now uses GitHub App token +- ✅ `.github/workflows/release.yml` - Cleaned up +- ✅ `.github/workflows/validate-release-ready.yml` - Simplified + +### Documentation Updated +- ✅ `docs/release-workflow.md` - Main documentation +- ✅ `docs/release-workflow-setup-checklist.md` - Setup checklist +- ✅ `docs/release-quick-reference.md` - Quick reference +- ✅ `docs/github-app-setup.md` - **NEW** - Detailed GitHub App guide +- ✅ `docs/release-workflow-migration.md` - Migration guide + +### Configuration Updated +- ✅ `pyproject.toml` - Enhanced Commitizen config + +## How It Works Now + +``` +1. Developer creates PR with conventional commits (feat:, fix:, etc.) +2. CI validates commits and runs tests +3. PR gets merged to master +4. Bump workflow automatically: + - Analyzes commits with Commitizen + - Updates version in all files + - Updates CHANGELOG.md + - Creates commit and tag + - Pushes to master (using GitHub App to bypass protection) +5. Release workflow automatically: + - Builds package + - Publishes to PyPI + - Creates GitHub release +``` + +**Everything is automated after merge!** + +## Benefits + +✅ **More secure** - GitHub App instead of personal token +✅ **No expiration** - Tokens auto-refresh +✅ **Fully automated** - No manual steps after PR merge +✅ **Version syncing** - Commitizen handles all version files +✅ **Better changelog** - Auto-generated from commits +✅ **Simpler** - Fewer secrets to manage + +## Troubleshooting + +### Bump workflow fails with "Bad credentials" +- Check that `APP_PRIVATE_KEY` includes the full key with BEGIN/END lines +- Verify no extra spaces or line breaks were added + +### Bump workflow fails with "Resource not accessible" +- Verify the GitHub App has "Contents: Read and write" permission +- Check that the app is installed on the repository + +### Release didn't trigger +- Check if the tag was created (look at bump workflow logs) +- Verify the tag follows the format `X.Y.Z` (no `v` prefix) + +## Need Help? + +- 📖 [Full Documentation](./release-workflow.md) +- 🔧 [GitHub App Setup Guide](./github-app-setup.md) +- ✅ [Setup Checklist](./release-workflow-setup-checklist.md) +- ⚡ [Quick Reference](./release-quick-reference.md) + +## Next Steps + +1. ✅ Complete the GitHub App setup +2. ✅ Add the secrets to your repository +3. ✅ Test with a small PR +4. ✅ Monitor the first few releases +5. ✅ Remove old `PERSONAL_ACCESS_TOKEN` if you had one +6. ✅ Update team documentation + +That's it! Your release workflow is now simplified and more secure. diff --git a/docs/deploy-key-setup.md b/docs/deploy-key-setup.md new file mode 100644 index 0000000000..01044df00a --- /dev/null +++ b/docs/deploy-key-setup.md @@ -0,0 +1,115 @@ +# Deploy Key Setup Guide + +Since the GitHub App bypass feature isn't available on your plan, we'll use a deploy key instead. This works on all GitHub plans and can bypass branch protection. + +## Step 1: Generate SSH Key Pair + +On your local machine (Windows), open PowerShell and run: + +```powershell +ssh-keygen -t ed25519 -C "github-actions-deploy-key" -f ukbcd-deploy-key -N "" +``` + +This creates two files: +- `ukbcd-deploy-key` (private key) +- `ukbcd-deploy-key.pub` (public key) + +## Step 2: Add Public Key to Repository + +1. Go to: https://github.com/robbrad/UKBinCollectionData/settings/keys + +2. Click **"Add deploy key"** + +3. Fill in: + - **Title**: `Release Workflow Deploy Key` + - **Key**: Paste the contents of `ukbcd-deploy-key.pub` + - **✅ Allow write access** - IMPORTANT: Check this box! + +4. Click **"Add key"** + +## Step 3: Add Private Key as Secret + +1. Go to: https://github.com/robbrad/UKBinCollectionData/settings/secrets/actions + +2. Click **"New repository secret"** + +3. Fill in: + - **Name**: `DEPLOY_KEY` + - **Value**: Paste the entire contents of `ukbcd-deploy-key` (the private key, not .pub) + +4. Click **"Add secret"** + +## Step 4: Update Branch Protection + +Deploy keys with write access can bypass branch protection automatically, but you need to ensure: + +1. Go to: https://github.com/robbrad/UKBinCollectionData/settings/branch_protection_rules + +2. Edit your master branch rule + +3. Make sure **"Do not allow bypassing the above settings"** is UNCHECKED + - Or if you see **"Include administrators"**, UNCHECK it + +4. Save changes + +## Step 5: Clean Up + +After adding the keys to GitHub, delete the local key files: + +```powershell +Remove-Item ukbcd-deploy-key +Remove-Item ukbcd-deploy-key.pub +``` + +## Step 6: Remove Old Secrets (Optional) + +Since we're not using the GitHub App anymore, you can remove: +- `APP_ID` +- `APP_PRIVATE_KEY` + +Or keep them for future use. + +## Test It + +1. Create a test PR with a conventional commit +2. Merge it +3. Watch the bump workflow run +4. It should now successfully push to master + +## How It Works + +- Deploy keys with write access can push to protected branches +- The SSH key authenticates the workflow +- No need for GitHub App or PAT +- Works on all GitHub plans (Free, Pro, Team, Enterprise) + +## Troubleshooting + +### "Permission denied (publickey)" +- Check that `DEPLOY_KEY` secret contains the private key (not the .pub file) +- Verify the deploy key is added to the repository with write access + +### Still getting "Protected branch update failed" +- Ensure "Allow write access" is checked on the deploy key +- Uncheck "Do not allow bypassing the above settings" in branch protection + +### "Host key verification failed" +- This shouldn't happen with GitHub, but if it does, the workflow will handle it automatically + +## Security Notes + +✅ Deploy key only has access to this one repository +✅ Can be revoked anytime from repository settings +✅ More secure than personal access tokens +✅ Doesn't expire + +## Alternative: Personal Access Token + +If deploy keys don't work, you can use a PAT: + +1. Create token at: https://github.com/settings/tokens/new +2. Select scope: `repo` +3. Add as secret: `PERSONAL_ACCESS_TOKEN` +4. Update workflow to use `token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}` + +But deploy keys are preferred for single-repository automation. diff --git a/docs/example_council.md b/docs/example_council.md new file mode 100644 index 0000000000..0dbae58dca --- /dev/null +++ b/docs/example_council.md @@ -0,0 +1,62 @@ +# Example Council Implementation + +This document shows how to implement a council class using the new utilities. + +## Basic Structure + +```python +from uk_bin_collection.uk_bin_collection.utils.retry import retry +from uk_bin_collection.uk_bin_collection.utils.cache import cached +from uk_bin_collection.uk_bin_collection.utils.http_client import get as http_get +from uk_bin_collection.uk_bin_collection.utils.logger import get_logger + +# Get a logger for this module +logger = get_logger(__name__) + +class ExampleCouncil: + """Example council implementation using the new utilities.""" + + # Required class variables + postcode_required = True + paon_required = True + + def __init__(self, url): + self.url = url + self.postcode = None + self.paon = None + + @cached(ttl=3600) # Cache for 1 hour + @retry(tries=3, delay=1, backoff=2) + def get_data(self): + """Get bin collection data for this council.""" + logger.info(f"Fetching data for postcode {self.postcode}") + + # Construct the URL with parameters + params = { + "postcode": self.postcode, + "house_number": self.paon + } + + # Make the request with automatic retry + response = http_get(self.url, params=params) + + # Process the response + # ... + + # Return the data in the standard format + return [ + { + "type": "General Waste", + "date": "01/01/2023" + }, + { + "type": "Recycling", + "date": "08/01/2023" + } + ] +``` + +## Complete Example + +For a complete example, see the updated council class template: +`/workspaces/UKBinCollectionData/uk_bin_collection/uk_bin_collection/councils/council_class_template/councilclasstemplate.py` \ No newline at end of file diff --git a/docs/github-app-setup.md b/docs/github-app-setup.md new file mode 100644 index 0000000000..0dda37cee5 --- /dev/null +++ b/docs/github-app-setup.md @@ -0,0 +1,173 @@ +# GitHub App Setup Guide + +This guide walks you through creating and configuring a GitHub App to allow the release workflow to bypass branch protection rules. + +## Why Use a GitHub App? + +✅ **More secure** - Fine-grained permissions, not tied to a user account +✅ **No expiration** - Tokens are automatically refreshed +✅ **Better audit trail** - Shows as the app, not a personal account +✅ **Team-friendly** - Won't break if someone leaves the team +✅ **Built-in bypass** - Can push to protected branches + +## Step-by-Step Setup + +### Step 1: Create the GitHub App + +1. **Navigate to GitHub App settings:** + - Personal account: https://github.com/settings/apps/new + - Organization: https://github.com/organizations/YOUR_ORG/settings/apps/new + +2. **Fill in the basic information:** + - **GitHub App name**: `UKBinCollection Release Bot` (must be globally unique) + - If taken, try: `UKBinCollection-Release-Bot-YourUsername` + - **Homepage URL**: `https://github.com/robbrad/UKBinCollectionData` + - **Description** (optional): `Automated release workflow for UK Bin Collection Data` + +3. **Configure webhook:** + - **Uncheck** "Active" under "Webhook" + - We don't need webhooks for this use case + +4. **Set repository permissions:** + - **Contents**: `Read and write` ✅ (Required - to push commits and tags) + - **Metadata**: `Read-only` (Automatically selected) + - **Pull requests**: `Read and write` (Optional - for future features) + +5. **Where can this GitHub App be installed?** + - Select: **"Only on this account"** + +6. **Click "Create GitHub App"** + +### Step 2: Install the App + +1. After creation, you'll see the app settings page +2. Click **"Install App"** in the left sidebar +3. Click **"Install"** next to your account/organization name +4. Choose installation scope: + - Select **"Only select repositories"** + - Check `UKBinCollectionData` +5. Click **"Install"** + +### Step 3: Generate Private Key + +1. Go back to the app settings page (Settings → Developer settings → GitHub Apps → Your App) +2. Scroll down to the **"Private keys"** section +3. Click **"Generate a private key"** +4. A `.pem` file will download automatically +5. **Save this file securely** - you'll need it in the next step + +### Step 4: Get Your App Credentials + +You need two pieces of information: + +#### App ID +- Found at the top of your app settings page +- Example: `123456` +- Copy this number + +#### Private Key +- Open the downloaded `.pem` file in a text editor +- Copy the **entire contents**, including: + ``` + -----BEGIN RSA PRIVATE KEY----- + [long string of characters] + -----END RSA PRIVATE KEY----- + ``` + +### Step 5: Add Secrets to Repository + +1. Go to your repository: https://github.com/robbrad/UKBinCollectionData +2. Navigate to: **Settings → Secrets and variables → Actions** +3. Click **"New repository secret"** + +#### Add APP_ID Secret +- **Name**: `APP_ID` +- **Value**: Your App ID (e.g., `123456`) +- Click "Add secret" + +#### Add APP_PRIVATE_KEY Secret +- **Name**: `APP_PRIVATE_KEY` +- **Value**: Paste the entire contents of the `.pem` file +- **Important**: Include the `-----BEGIN RSA PRIVATE KEY-----` and `-----END RSA PRIVATE KEY-----` lines +- Click "Add secret" + +### Step 6: Verify Setup + +1. The workflow is already configured to use these secrets +2. Test by merging a PR with a conventional commit message +3. Check the bump workflow logs to verify it runs successfully + +## Troubleshooting + +### "Bad credentials" error +- **Cause**: Private key not copied correctly +- **Solution**: Re-copy the entire `.pem` file contents, including BEGIN/END lines + +### "Resource not accessible by integration" error +- **Cause**: App doesn't have correct permissions +- **Solution**: + 1. Go to app settings + 2. Check "Contents" permission is set to "Read and write" + 3. Reinstall the app if needed + +### "App not installed" error +- **Cause**: App not installed on the repository +- **Solution**: Go to https://github.com/settings/installations and install it + +### Workflow still fails with permission error +- **Cause**: Secrets not set correctly +- **Solution**: + 1. Verify `APP_ID` is just the number (no quotes) + 2. Verify `APP_PRIVATE_KEY` includes the full key with headers + 3. Check for extra spaces or line breaks + +## Security Best Practices + +✅ **Never commit** the `.pem` file to your repository +✅ **Store the `.pem` file** securely (password manager or secure vault) +✅ **Rotate keys** if compromised (generate new private key) +✅ **Review app permissions** periodically +✅ **Monitor app activity** in audit logs + +## Managing the App + +### View App Activity +- Go to: Settings → Developer settings → GitHub Apps → Your App +- Click "Advanced" tab to see delivery logs + +### Regenerate Private Key +1. Go to app settings +2. Scroll to "Private keys" +3. Click "Generate a private key" +4. Update the `APP_PRIVATE_KEY` secret in your repository + +### Uninstall/Reinstall +- Go to: https://github.com/settings/installations +- Click "Configure" next to your app +- Adjust repository access or uninstall + +## Alternative: Using a Personal Access Token + +If you prefer not to use a GitHub App, you can use a Personal Access Token instead: + +1. Create a token at: https://github.com/settings/tokens/new +2. Select scope: `repo` (Full control of private repositories) +3. Add as secret: `BUMP_TOKEN` +4. Update workflow to use `${{ secrets.BUMP_TOKEN }}` instead of the app token + +However, GitHub Apps are recommended for production use. + +## Next Steps + +Once setup is complete: +1. ✅ Test the workflow with a small PR +2. ✅ Monitor the first few releases +3. ✅ Document the app for your team +4. ✅ Set up monitoring/alerts for workflow failures + +## Support + +If you encounter issues: +- Check the [troubleshooting section](#troubleshooting) above +- Review workflow logs in GitHub Actions +- See the [main workflow documentation](./release-workflow.md) diff --git a/docs/github-app-troubleshooting.md b/docs/github-app-troubleshooting.md new file mode 100644 index 0000000000..614da98a76 --- /dev/null +++ b/docs/github-app-troubleshooting.md @@ -0,0 +1,146 @@ +# GitHub App Troubleshooting - Branch Protection + +## Problem: "Protected branch update failed" + +If you're getting this error, the GitHub App isn't properly configured to bypass branch protection. + +## Solution Steps + +### Step 1: Verify App Installation + +1. Go to: https://github.com/settings/installations +2. Find your app (e.g., "UKBinCollection Release Bot") +3. Click "Configure" +4. Verify it's installed on `UKBinCollectionData` repository +5. Check that it has "Contents: Read and write" permission + +### Step 2: Configure Branch Protection + +Go to: https://github.com/robbrad/UKBinCollectionData/settings/branches + +Click "Edit" on your `master` branch protection rule. + +#### Option A: Allow App to Bypass (Recommended) + +Scroll to **"Allow specified actors to bypass required pull requests"**: +- Click "Add" +- Search for your app name +- Select it +- Click "Save changes" + +#### Option B: If App Doesn't Appear in Search + +The app might not show up in the bypass list. Instead: + +1. Temporarily disable "Require a pull request before merging" +2. Test the workflow +3. Re-enable after confirming it works + +OR + +1. Under "Restrict who can push to matching branches": + - Enable it + - Add your GitHub App + - This allows the app to push directly + +### Step 3: Verify App Permissions + +Go to your app settings: https://github.com/settings/apps + +1. Click on your app +2. Verify permissions: + - **Contents**: Read and write ✅ + - **Metadata**: Read-only ✅ +3. If permissions are wrong, update them +4. Go to https://github.com/settings/installations +5. Click "Configure" on your app +6. Click "Update" to refresh permissions + +### Step 4: Check Secrets + +Verify secrets are set correctly: + +1. Go to: https://github.com/robbrad/UKBinCollectionData/settings/secrets/actions +2. Verify `APP_ID` exists +3. Verify `APP_PRIVATE_KEY` exists +4. The private key should include: + ``` + -----BEGIN RSA PRIVATE KEY----- + [key content] + -----END RSA PRIVATE KEY----- + ``` + +### Step 5: Test the Workflow + +Create a test PR and merge it to see if it works. + +## Alternative: Temporary Workaround + +If you need to release immediately while fixing the app setup: + +### Manual Release + +```bash +# 1. Pull latest +git checkout master +git pull + +# 2. Bump version +cz bump --yes --changelog + +# 3. Push (you'll need to temporarily disable branch protection) +git push origin master --follow-tags +``` + +### Or Use Personal Access Token Temporarily + +Update `.github/workflows/bump.yml`: + +```yaml +- name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} +``` + +Then: +1. Create a PAT at: https://github.com/settings/tokens/new +2. Select scope: `repo` +3. Add as secret: `PERSONAL_ACCESS_TOKEN` +4. This will work until you fix the app setup + +## Common Issues + +### "Bad credentials" +- Private key not copied correctly +- Missing BEGIN/END lines +- Extra spaces or line breaks + +### "Resource not accessible by integration" +- App doesn't have correct permissions +- App not installed on repository +- Need to update app permissions + +### "App not found" +- APP_ID is incorrect +- App was deleted or renamed + +## Still Not Working? + +If none of the above works, you have two options: + +### Option 1: Use Personal Access Token (Quick Fix) +See "Alternative: Temporary Workaround" above + +### Option 2: Remove Branch Protection for Automation +1. Create a separate branch protection rule +2. Exclude `github-actions[bot]` from restrictions +3. This allows the workflow to push + +## Need More Help? + +Check the workflow logs for the exact error message and search for it in: +- GitHub Actions documentation +- GitHub App documentation +- Stack Overflow diff --git a/docs/manual-tag-fix.md b/docs/manual-tag-fix.md new file mode 100644 index 0000000000..b8941febcb --- /dev/null +++ b/docs/manual-tag-fix.md @@ -0,0 +1,40 @@ +# Manual Tag Fix for Version 0.155.0 + +Since the tag wasn't pushed, you need to manually create and push it to trigger the release. + +## Steps: + +1. **Pull the latest changes:** + ```bash + git checkout master + git pull + ``` + +2. **Create the annotated tag:** + ```bash + git tag -a 0.155.0 -m "Release 0.155.0" + ``` + +3. **Push the tag:** + ```bash + git push origin 0.155.0 + ``` + +4. **Verify:** + - Check tags: https://github.com/robbrad/UKBinCollectionData/tags + - Watch the release workflow: https://github.com/robbrad/UKBinCollectionData/actions + +## What Was Fixed + +1. **bump.yml** - Changed from `--follow-tags` to separate push commands +2. **pyproject.toml** - Added `annotated_tag = true` to Commitizen config + +## Future Releases + +The next merge will automatically: +1. Create annotated tag +2. Push commit and tag separately +3. Trigger release workflow +4. Publish to PyPI + +No manual intervention needed! diff --git a/docs/release-quick-reference.md b/docs/release-quick-reference.md new file mode 100644 index 0000000000..f501e82826 --- /dev/null +++ b/docs/release-quick-reference.md @@ -0,0 +1,95 @@ +# Release Workflow Quick Reference + +## Commit Message Cheat Sheet + +| Type | Version Bump | Example | +|------|--------------|---------| +| `feat:` | Minor (0.152.0 → 0.153.0) | `feat(councils): add Leeds support` | +| `fix:` | Patch (0.152.0 → 0.152.1) | `fix(selenium): handle timeout` | +| `feat!:` or `BREAKING CHANGE:` | Major (0.152.0 → 1.0.0) | `feat!: change API format` | +| `docs:` | None | `docs: update README` | +| `style:` | None | `style: format code` | +| `refactor:` | None | `refactor: simplify parser` | +| `test:` | None | `test: add unit tests` | +| `chore:` | None | `chore: update dependencies` | + +## Workflow Stages + +``` +PR → Tests → Merge → Bump (auto) → Tag (auto) → Release (auto) → PyPI (auto) +``` + +Everything after merge is fully automated! + +## How It Works + +1. **Developer**: Create PR with conventional commits +2. **CI**: Validates commits and runs tests +3. **Merge**: PR merged to master +4. **Commitizen**: Analyzes commits, bumps version, updates CHANGELOG +5. **Git**: Creates tag and pushes +6. **Release**: Publishes to PyPI and GitHub + +## Common Commands + +```bash +# Check current version +poetry version -s + +# Validate before PR +make pre-build + +# Run tests locally +make unit-tests +make integration-tests + +# Check commit messages +git log --oneline + +# Manual bump (if needed) +cz bump --yes --changelog +git push origin master --follow-tags +``` + +## Troubleshooting + +| Problem | Solution | +|---------|----------| +| Version bump didn't happen | Check commit message format (must use `feat:` or `fix:`) | +| Release didn't trigger | Check if tag was created in bump workflow logs | +| PyPI publish failed | Verify `PYPI_API_KEY` secret is set | +| Permission error | Verify `APP_ID` and `APP_PRIVATE_KEY` secrets are set | +| Version files out of sync | Commitizen handles this automatically | + +## Required Secrets + +- `APP_ID` - GitHub App ID (for protected branches) +- `APP_PRIVATE_KEY` - GitHub App private key +- `PYPI_API_KEY` - For PyPI publishing +- `CODECOV_TOKEN` - For test coverage (optional) + +**Note:** Uses GitHub App for secure, non-expiring authentication + +## Workflow Files + +- `behave_pull_request.yml` - PR tests +- `lint.yml` - Commit message validation +- `validate-release-ready.yml` - Pre-merge checks +- `bump.yml` - Automated version bumping and tagging +- `release.yml` - Publishing to PyPI and GitHub + +## Version Files (Auto-Synced) + +Commitizen automatically updates: +- `pyproject.toml` +- `custom_components/uk_bin_collection/manifest.json` +- `custom_components/uk_bin_collection/const.py` +- `CHANGELOG.md` + +## Quick Links + +- [Full Documentation](./release-workflow.md) +- [Setup Checklist](./release-workflow-setup-checklist.md) +- [Conventional Commits](https://www.conventionalcommits.org/) +- [Semantic Versioning](https://semver.org/) +- [Commitizen](https://commitizen-tools.github.io/commitizen/) diff --git a/docs/release-workflow-branch-protection.md b/docs/release-workflow-branch-protection.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/release-workflow-diagram.md b/docs/release-workflow-diagram.md new file mode 100644 index 0000000000..29f5dfa3fc --- /dev/null +++ b/docs/release-workflow-diagram.md @@ -0,0 +1,181 @@ +# Release Workflow Diagram + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ PULL REQUEST STAGE │ +└─────────────────────────────────────────────────────────────────────────────┘ + + Developer creates PR → master + ↓ + ┌───────────────────────────────────────────────────────────┐ + │ Automated Checks Run in Parallel: │ + │ │ + │ ✓ behave_pull_request.yml │ + │ - Unit tests (Python 3.12) │ + │ - Integration tests (changed councils only) │ + │ - Parity check (councils/input.json/features) │ + │ │ + │ ✓ lint.yml │ + │ - Validate conventional commit messages │ + │ │ + │ ✓ validate-release-ready.yml │ + │ - Check version file consistency │ + │ - Validate pyproject.toml │ + │ - Verify commitizen config │ + │ │ + │ ✓ hacs_validation.yml │ + │ - Validate Home Assistant integration │ + │ │ + │ ✓ codeql-analysis.yml │ + │ - Security scanning │ + └───────────────────────────────────────────────────────────┘ + ↓ + All checks pass? → YES → Ready to merge + ↓ NO + Fix issues and push updates + + +┌─────────────────────────────────────────────────────────────────────────────┐ +│ MERGE TO MASTER STAGE │ +└─────────────────────────────────────────────────────────────────────────────┘ + + PR merged to master + ↓ + ┌───────────────────────────────────────────────────────────┐ + │ bump.yml workflow triggers │ + │ │ + │ 1. Commitizen analyzes commits since last tag │ + │ - feat: → minor bump (0.152.0 → 0.153.0) │ + │ - fix: → patch bump (0.152.0 → 0.152.1) │ + │ - BREAKING CHANGE → major bump (0.152.0 → 1.0.0) │ + │ │ + │ 2. Updates version in: │ + │ - pyproject.toml │ + │ - manifest.json │ + │ - const.py │ + │ │ + │ 3. Creates commit: "bump: version X.Y.Z" │ + │ │ + │ 4. Creates git tag: X.Y.Z │ + │ │ + │ 5. Pushes commit and tag to master │ + └───────────────────────────────────────────────────────────┘ + ↓ + Tag pushed → Triggers release workflow + + +┌─────────────────────────────────────────────────────────────────────────────┐ +│ RELEASE STAGE │ +└─────────────────────────────────────────────────────────────────────────────┘ + + Tag X.Y.Z pushed + ↓ + ┌───────────────────────────────────────────────────────────┐ + │ release.yml workflow triggers │ + │ │ + │ 1. Checkout tagged commit │ + │ │ + │ 2. Install Poetry and dependencies │ + │ │ + │ 3. Verify version matches tag │ + │ (Poetry version == Git tag) │ + │ │ + │ 4. Build Python package │ + │ poetry build → creates dist/*.whl and dist/*.tar.gz │ + │ │ + │ 5. Create GitHub Release │ + │ - Auto-generated release notes │ + │ - Attach build artifacts │ + │ │ + │ 6. Publish to PyPI │ + │ poetry publish → uploads to pypi.org │ + └───────────────────────────────────────────────────────────┘ + ↓ + ┌───────────────────────────────────────────────────────────┐ + │ Release Complete! ✓ │ + │ │ + │ - GitHub Release: github.com/robbrad/.../releases │ + │ - PyPI Package: pypi.org/project/uk-bin-collection │ + │ - HACS Update: Available to Home Assistant users │ + └───────────────────────────────────────────────────────────┘ + + +┌─────────────────────────────────────────────────────────────────────────────┐ +│ COMMIT MESSAGE EXAMPLES │ +└─────────────────────────────────────────────────────────────────────────────┘ + +feat(councils): add Birmingham City Council support +→ Minor version bump (0.152.0 → 0.153.0) + +fix(selenium): handle connection timeout errors +→ Patch version bump (0.152.0 → 0.152.1) + +feat(api)!: change date format to ISO 8601 + +BREAKING CHANGE: API responses now use ISO 8601 dates +→ Major version bump (0.152.0 → 1.0.0) + +docs: update README with new council instructions +→ No version bump (documentation only) + + +┌─────────────────────────────────────────────────────────────────────────────┐ +│ TROUBLESHOOTING FLOW │ +└─────────────────────────────────────────────────────────────────────────────┘ + +Issue: Version bump didn't happen + ↓ +Check: Are commits using conventional format? + ↓ NO → Fix commit messages and force push + ↓ YES +Check: Is PERSONAL_ACCESS_TOKEN set? + ↓ NO → Add secret in repo settings + ↓ YES +Check: Bump workflow logs for errors + ↓ +Manual fix: Run commitizen locally + +───────────────────────────────────────────── + +Issue: Release didn't publish + ↓ +Check: Was tag created by bump workflow? + ↓ NO → Check bump workflow logs + ↓ YES +Check: Is PYPI_API_KEY valid? + ↓ NO → Update secret in repo settings + ↓ YES +Check: Release workflow logs for errors + ↓ +Manual fix: Run poetry publish locally + + +┌─────────────────────────────────────────────────────────────────────────────┐ +│ WORKFLOW DEPENDENCIES │ +└─────────────────────────────────────────────────────────────────────────────┘ + +Secrets Required: +├── PERSONAL_ACCESS_TOKEN (for bump workflow) +│ └── Needs: repo write access +│ +├── PYPI_API_KEY (for release workflow) +│ └── Needs: PyPI project upload permissions +│ +└── CODECOV_TOKEN (for test coverage) + └── Needs: Codecov project access + +Environments: +├── bump (requires approval) +└── release (requires approval) + +Configuration Files: +├── pyproject.toml +│ ├── [tool.poetry] version +│ └── [tool.commitizen] config +│ +├── custom_components/uk_bin_collection/manifest.json +│ └── version field +│ +└── custom_components/uk_bin_collection/const.py + └── INPUT_JSON_URL (includes version) +``` diff --git a/docs/release-workflow-fixes.md b/docs/release-workflow-fixes.md new file mode 100644 index 0000000000..238ed485c7 --- /dev/null +++ b/docs/release-workflow-fixes.md @@ -0,0 +1,201 @@ +# Release Workflow Fixes Applied + +## Summary +Fixed the release workflow to ensure proper version bumping and release publishing from PR merge to master. + +## Issues Identified + +1. **Bump workflow wasn't explicitly pushing tags** + - Commitizen action needed `push: true` parameter + - No confirmation output of version bump + +2. **Release workflow lacked validation** + - No verification that Poetry version matches git tag + - Could publish mismatched versions + +3. **Missing pre-merge validation** + - No check that version files are in sync before merge + - Could lead to failed releases + +4. **Inconsistent Poetry installation** + - Some workflows used `abatilo/actions-poetry` + - Others used `pipx install poetry` + +## Changes Made + +### 1. Updated `.github/workflows/bump.yml` +**Changes:** +- Added explicit Poetry installation for consistency +- Added `push: true` to commitizen action to ensure tags are pushed +- Added version output for debugging + +**Why:** Ensures tags are created and pushed, triggering the release workflow + +### 2. Updated `.github/workflows/release.yml` +**Changes:** +- Added `fetch-depth: 0` to checkout for full git history +- Renamed "Run image" step to "Install Poetry" for clarity +- Added version verification step to ensure Poetry version matches tag +- Split build and publish into separate steps +- Added build artifacts to GitHub release + +**Why:** Prevents publishing mismatched versions and improves reliability + +### 3. Created `.github/workflows/validate-release-ready.yml` +**New workflow that:** +- Validates `pyproject.toml` syntax +- Checks version consistency across files +- Validates commitizen configuration +- Runs on every PR + +**Why:** Catches version sync issues before merge, preventing failed releases + +### 4. Created `docs/release-workflow.md` +**Comprehensive documentation covering:** +- Complete workflow stages (PR → Merge → Release) +- Commit message format and examples +- Version numbering strategy +- Troubleshooting guide +- Manual release procedure +- Required secrets and environments + +**Why:** Provides clear guidance for contributors and maintainers + +### 5. Created `docs/release-workflow-diagram.md` +**Visual documentation showing:** +- ASCII flow diagrams for each stage +- Parallel workflow execution +- Decision points and error handling +- Commit message examples with version impacts +- Troubleshooting flows +- Dependency tree + +**Why:** Makes the workflow easy to understand at a glance + +## Complete Workflow Flow + +``` +1. Developer creates PR + ↓ +2. Automated tests run (behave, lint, validate) + ↓ +3. PR approved and merged to master + ↓ +4. bump.yml triggers: + - Analyzes commits + - Bumps version in all files + - Creates commit "bump: version X.Y.Z" + - Creates and pushes tag X.Y.Z + ↓ +5. release.yml triggers (on tag push): + - Verifies version matches tag + - Builds package + - Creates GitHub release + - Publishes to PyPI + ↓ +6. Release complete! +``` + +## Testing the Workflow + +### Test 1: Version Validation +```bash +# Should pass if versions are in sync +poetry check +jq -r '.version' custom_components/uk_bin_collection/manifest.json +poetry version -s +``` + +### Test 2: Commit Message Format +```bash +# Valid examples: +git commit -m "feat(councils): add new council" +git commit -m "fix(selenium): handle timeout" +git commit -m "docs: update README" + +# Invalid examples (will fail lint): +git commit -m "added new feature" +git commit -m "Fixed bug" +``` + +### Test 3: Manual Version Bump (if needed) +```bash +# Bump version +poetry version patch # or minor/major + +# Update manifest +# Edit custom_components/uk_bin_collection/manifest.json + +# Commit and tag +git add . +git commit -m "bump: version X.Y.Z" +git tag X.Y.Z +git push origin master --tags +``` + +## Required Secrets + +Ensure these are set in GitHub repository settings: + +1. **PERSONAL_ACCESS_TOKEN** + - Settings → Secrets → Actions + - Needs: `repo` scope + - Used by: bump.yml + +2. **PYPI_API_KEY** + - Settings → Secrets → Actions + - Get from: pypi.org account settings + - Used by: release.yml + +3. **CODECOV_TOKEN** + - Settings → Secrets → Actions + - Get from: codecov.io project settings + - Used by: test workflows + +## Verification Checklist + +After merging these changes: + +- [ ] Verify `PERSONAL_ACCESS_TOKEN` secret is set +- [ ] Verify `PYPI_API_KEY` secret is set +- [ ] Verify `CODECOV_TOKEN` secret is set +- [ ] Check bump and release environments exist +- [ ] Test with a small PR using conventional commits +- [ ] Monitor bump workflow creates tag +- [ ] Monitor release workflow publishes to PyPI +- [ ] Verify GitHub release is created +- [ ] Check PyPI package is available + +## Rollback Plan + +If issues occur: + +1. **Disable automatic bumping:** + - Add `[skip ci]` to commit messages + - Or temporarily disable bump.yml workflow + +2. **Manual release:** + - Follow manual release procedure in docs/release-workflow.md + - Use `poetry version` and `poetry publish` directly + +3. **Revert workflow changes:** + - Git revert the workflow file changes + - Return to previous manual process + +## Next Steps + +1. Merge these workflow fixes to master +2. Test with a small feature PR +3. Monitor the complete flow +4. Update team documentation if needed +5. Consider adding release notifications (Slack, Discord, etc.) + +## Additional Improvements (Future) + +Consider adding: +- Slack/Discord notifications on release +- Automated changelog generation +- Release candidate (RC) workflow for testing +- Automated rollback on failed releases +- Release metrics and monitoring +- Pre-release testing environment diff --git a/docs/release-workflow-migration.md b/docs/release-workflow-migration.md new file mode 100644 index 0000000000..1929c79b60 --- /dev/null +++ b/docs/release-workflow-migration.md @@ -0,0 +1,177 @@ +# Release Workflow Migration Guide + +## Overview + +The release workflow has been simplified to use Commitizen and GITHUB_TOKEN, eliminating complexity and manual steps. + +## What Changed + +### Before (Complex) +- Bump workflow created PRs for version bumps +- Required PERSONAL_ACCESS_TOKEN secret +- Manual PR review and merge for version bumps +- Separate environments with approvals +- Manual version file syncing +- Multiple validation steps + +### After (Simplified) +- Bump workflow directly commits and tags on master +- Uses built-in GITHUB_TOKEN +- Fully automated after PR merge +- No environment approvals needed +- Commitizen auto-syncs all version files +- Streamlined validation + +## Key Improvements + +### 1. Removed PERSONAL_ACCESS_TOKEN Requirement +- **Before**: Required creating and managing a personal access token +- **After**: Uses built-in `GITHUB_TOKEN` with proper permissions +- **Benefit**: One less secret to manage and rotate + +### 2. Eliminated Bump PRs +- **Before**: Bump workflow created a PR that needed manual merge +- **After**: Bump workflow directly commits to master after PR merge +- **Benefit**: Faster releases, no manual intervention + +### 3. Automatic Version Syncing +- **Before**: Manual checks to ensure version files stayed in sync +- **After**: Commitizen automatically updates all configured files +- **Benefit**: No version mismatch errors + +### 4. Simplified Configuration +- **Before**: Complex environment setup with approvals +- **After**: Simple workflow permissions +- **Benefit**: Easier to set up and maintain + +### 5. Better CHANGELOG Management +- **Before**: Manual or semi-automated changelog updates +- **After**: Commitizen automatically generates changelog from commits +- **Benefit**: Consistent, automated changelog + +## Migration Steps + +### 1. Set Up GitHub App +Follow the [GitHub App Setup Guide](./github-app-setup.md) to: +- Create a GitHub App +- Install it on your repository +- Generate a private key +- Add `APP_ID` and `APP_PRIVATE_KEY` secrets + +### 2. Update Secrets +```bash +# Add (new requirements) ++ APP_ID ++ APP_PRIVATE_KEY + +# Keep (still required) +- PYPI_API_KEY +- CODECOV_TOKEN (optional) + +# Remove (no longer needed) +- PERSONAL_ACCESS_TOKEN (if you had one) +``` + +### 3. Update Workflow Permissions +Ensure Settings → Actions → General → Workflow permissions: +- Select "Read and write permissions" +- Enable "Allow GitHub Actions to create and approve pull requests" + +### 4. Remove Environments (Optional) +The `bump` and `release` environments are no longer required, but can be kept if you want manual approval gates. + +### 5. Update pyproject.toml +Ensure Commitizen configuration includes: +```toml +[tool.commitizen] +name = "cz_conventional_commits" +version_provider = "poetry" +version_scheme = "semver" +major_version_zero = true +tag_format = "$version" +update_changelog_on_bump = true +version_files = [ + "custom_components/uk_bin_collection/manifest.json:version", + "custom_components/uk_bin_collection/manifest.json:requirements", + "custom_components/uk_bin_collection/const.py:INPUT_JSON_URL" +] +``` + +### 6. Test the New Workflow +1. Create a test branch with a conventional commit +2. Open and merge a PR +3. Watch the automated bump and release workflows +4. Verify the release appears on PyPI and GitHub + +## Workflow Comparison + +### Old Workflow +``` +PR → Tests → Merge → Bump Workflow → Bump PR → Manual Review → Merge Bump PR → Tag → Release +``` + +### New Workflow +``` +PR → Tests → Merge → Bump (auto) → Tag (auto) → Release (auto) +``` + +## File Changes + +### Modified Files +- `.github/workflows/bump.yml` - Simplified to direct commit/tag +- `.github/workflows/release.yml` - Cleaned up and uses GITHUB_TOKEN +- `.github/workflows/validate-release-ready.yml` - Removed version sync checks +- `pyproject.toml` - Enhanced Commitizen configuration +- `docs/release-workflow.md` - Updated documentation +- `docs/release-workflow-setup-checklist.md` - Simplified checklist +- `docs/release-quick-reference.md` - Updated quick reference + +### New Files +- `docs/release-workflow-migration.md` - This file + +## Rollback Plan + +If you need to rollback to the old workflow: + +1. Revert the workflow files: + ```bash + git revert + ``` + +2. Re-add PERSONAL_ACCESS_TOKEN secret + +3. Recreate bump and release environments + +## Benefits Summary + +✅ Fewer secrets to manage +✅ Faster release process +✅ No manual intervention needed +✅ Automatic version syncing +✅ Better changelog generation +✅ Simpler configuration +✅ Easier to understand and maintain + +## Support + +If you encounter issues: +1. Check workflow logs in GitHub Actions +2. Review `docs/release-workflow.md` +3. Verify GITHUB_TOKEN permissions +4. Ensure conventional commits are used +5. Check Commitizen configuration + +## Next Steps + +1. Review the updated documentation +2. Test the new workflow with a small change +3. Monitor the first few automated releases +4. Update team documentation and training +5. Remove old PERSONAL_ACCESS_TOKEN secret + +## Questions? + +See the full documentation: +- [Release Workflow](./release-workflow.md) +- [Setup Checklist](./release-workflow-setup-checklist.md) +- [Quick Reference](./release-quick-reference.md) diff --git a/docs/release-workflow-setup-checklist.md b/docs/release-workflow-setup-checklist.md new file mode 100644 index 0000000000..51dd7bee7b --- /dev/null +++ b/docs/release-workflow-setup-checklist.md @@ -0,0 +1,247 @@ +# Release Workflow Setup Checklist + +Use this checklist to verify your simplified release workflow is properly configured. + +## GitHub Repository Settings + +### GitHub App Setup (for protected branches) +- [ ] Create a GitHub App + - Go to: https://github.com/settings/apps/new + - Name: `UKBinCollection Release Bot` (must be unique) + - Homepage URL: `https://github.com/robbrad/UKBinCollectionData` + - Uncheck "Active" under Webhook + - Repository permissions: + - **Contents**: Read and write + - **Metadata**: Read-only (auto-selected) + - Where can this be installed: "Only on this account" + - Click "Create GitHub App" + +- [ ] Install the app on your repository + - Click "Install App" in left sidebar + - Click "Install" next to your account + - Select "Only select repositories" + - Choose `UKBinCollectionData` + - Click "Install" + +- [ ] Generate and save credentials + - In app settings, scroll to "Private keys" + - Click "Generate a private key" + - Save the downloaded `.pem` file securely + - Note your **App ID** (shown at top of settings page) + +### Secrets Configuration +- [ ] `APP_ID` is set + - Path: Settings → Secrets and variables → Actions → Repository secrets + - Value: Your GitHub App ID (e.g., `123456`) + +- [ ] `APP_PRIVATE_KEY` is set + - Path: Settings → Secrets and variables → Actions → Repository secrets + - Value: Entire contents of the `.pem` file + - Include the `-----BEGIN RSA PRIVATE KEY-----` and `-----END RSA PRIVATE KEY-----` lines + +- [ ] `PYPI_API_KEY` is set + - Path: Settings → Secrets and variables → Actions → Repository secrets + - Get from: https://pypi.org/manage/account/token/ + - Scope: Project-specific or account-wide + - Test: Should allow publishing packages + +- [ ] `CODECOV_TOKEN` is set (optional) + - Path: Settings → Secrets and variables → Actions → Repository secrets + - Get from: https://codecov.io/gh/robbrad/UKBinCollectionData/settings + - Test: Should allow uploading coverage reports + +### Branch Protection Rules +- [ ] `master` branch is protected + - Path: Settings → Branches → Add rule + - Branch name pattern: `master` + - Recommended settings: + - [x] Require a pull request before merging + - [x] Require status checks to pass before merging + - [x] Require branches to be up to date before merging + +### Actions Permissions +- [ ] Workflows have write permissions + - Path: Settings → Actions → General → Workflow permissions + - Select: "Read and write permissions" + - [x] Allow GitHub Actions to create and approve pull requests + +## Local Configuration + +### pyproject.toml +- [ ] Version is set correctly + ```toml + [tool.poetry] + version = "X.Y.Z" + ``` + +- [ ] Commitizen is configured + ```toml + [tool.commitizen] + name = "cz_conventional_commits" + version_provider = "poetry" + version_scheme = "semver" + major_version_zero = true + tag_format = "$version" + update_changelog_on_bump = true + version_files = [ + "custom_components/uk_bin_collection/manifest.json:version", + "custom_components/uk_bin_collection/manifest.json:requirements", + "custom_components/uk_bin_collection/const.py:INPUT_JSON_URL" + ] + ``` + +## Workflow Files + +### Required Workflows +- [ ] `.github/workflows/behave_pull_request.yml` exists +- [ ] `.github/workflows/lint.yml` exists +- [ ] `.github/workflows/validate-release-ready.yml` exists +- [ ] `.github/workflows/bump.yml` exists (simplified) +- [ ] `.github/workflows/release.yml` exists +- [ ] `.github/workflows/hacs_validation.yml` exists + +### Workflow Configuration +- [ ] `bump.yml` uses `GITHUB_TOKEN` + ```yaml + token: ${{ secrets.GITHUB_TOKEN }} + ``` + +- [ ] `bump.yml` runs `cz bump --yes --changelog` + ```yaml + - name: Bump version and create tag + run: cz bump --yes --changelog + ``` + +- [ ] `release.yml` uses `PYPI_API_KEY` + ```yaml + poetry config pypi-token.pypi "${{ secrets.PYPI_API_KEY }}" + ``` + +## Testing + +### Pre-Merge Testing +- [ ] Create a test branch + ```bash + git checkout -b test/release-workflow + ``` + +- [ ] Make a small change with conventional commit + ```bash + echo "# Test" >> README.md + git add README.md + git commit -m "fix: test release workflow" + ``` + +- [ ] Push and create PR + ```bash + git push origin test/release-workflow + # Create PR on GitHub + ``` + +- [ ] Verify workflows run: + - [ ] `behave_pull_request.yml` runs + - [ ] `lint.yml` runs + - [ ] `validate-release-ready.yml` runs + - [ ] All checks pass + +### Post-Merge Testing +- [ ] Merge the test PR +- [ ] Verify `bump.yml` runs automatically +- [ ] Check workflow logs: + - [ ] Commitizen analyzed commits + - [ ] Version was bumped in all files + - [ ] CHANGELOG.md was updated + - [ ] Commit was created with message `bump: version X.Y.Z` + - [ ] Tag was created and pushed + - [ ] No errors in logs + +- [ ] Verify `release.yml` runs automatically +- [ ] Check workflow logs: + - [ ] Version verification passed + - [ ] Package was built + - [ ] GitHub release was created + - [ ] PyPI publish succeeded + +### Verification +- [ ] Check GitHub releases page + - URL: https://github.com/robbrad/UKBinCollectionData/releases + - Latest release should be visible + - Release notes should be auto-generated + - Build artifacts should be attached + +- [ ] Check PyPI package page + - URL: https://pypi.org/project/uk-bin-collection/ + - Latest version should be available + - Package should be installable: + ```bash + pip install uk-bin-collection==X.Y.Z + ``` + +- [ ] Check version files are synced + ```bash + # All should show the same version + poetry version -s + jq -r '.version' custom_components/uk_bin_collection/manifest.json + grep INPUT_JSON_URL custom_components/uk_bin_collection/const.py + ``` + +## Rollback Plan + +If something goes wrong: + +### Delete Bad Release +```bash +# Delete tag locally +git tag -d X.Y.Z + +# Delete tag remotely +git push origin :refs/tags/X.Y.Z + +# Delete GitHub release manually on GitHub +``` + +### Manual Release +```bash +# Bump version with Commitizen +cz bump --yes --changelog + +# Push changes and tags +git push origin master --follow-tags + +# Or manually build and publish +poetry build +poetry publish +``` + +## Maintenance + +### Regular Checks +- [ ] Quarterly: Verify PYPI_API_KEY hasn't expired +- [ ] Quarterly: Update workflow actions to latest versions +- [ ] Quarterly: Review and update documentation + +### Action Updates +Check for updates to GitHub Actions: +- `actions/checkout@v5` → Check for newer version +- `actions/setup-python@v6` → Check for newer version +- `abatilo/actions-poetry@v4.0.0` → Check for newer version +- `ncipollo/release-action@v1` → Check for newer version + +## Support + +If you encounter issues: + +1. Check workflow logs in GitHub Actions tab +2. Review documentation in `docs/release-workflow.md` +3. Verify GITHUB_TOKEN has write permissions +4. Ensure conventional commits are used +5. Check Commitizen configuration in pyproject.toml + +## Sign-Off + +- [ ] All checklist items completed +- [ ] Test release successful +- [ ] Documentation reviewed + +**Completed by:** _______________ +**Date:** _______________ diff --git a/docs/release-workflow.md b/docs/release-workflow.md new file mode 100644 index 0000000000..728008dccf --- /dev/null +++ b/docs/release-workflow.md @@ -0,0 +1,202 @@ +# Release Workflow Documentation + +## Overview +This document describes the complete release workflow from pull request to published release. + +## Workflow Stages + +### 1. Pull Request Stage +**Triggers:** When a PR is opened/updated targeting `master` branch + +**Workflows that run:** +- `behave_pull_request.yml` - Runs tests on changed councils +- `lint.yml` - Validates commit messages follow conventional commits +- `validate-release-ready.yml` - Validates pyproject.toml and commit messages +- `hacs_validation.yml` - Validates Home Assistant integration + +**What happens:** +- Unit tests run on Python 3.12 +- Integration tests run only for changed council files +- Parity check ensures councils, input.json, and feature files are in sync +- Commit messages are validated against conventional commits format +- pyproject.toml is validated + +**Requirements to merge:** +- All tests must pass +- Commit messages must follow conventional commits format +- Code must pass linting + +### 2. Merge to Master Stage +**Triggers:** When PR is merged to `master` branch + +**Workflow that runs:** +- `bump.yml` - Automatically bumps version and creates release + +**What happens:** +1. Commitizen analyzes commit messages since last tag +2. Determines version bump type (major/minor/patch) based on conventional commits: + - `feat:` → minor version bump + - `fix:` → patch version bump + - `BREAKING CHANGE:` → major version bump +3. Updates version in all configured files: + - `pyproject.toml` + - `custom_components/uk_bin_collection/manifest.json` + - `custom_components/uk_bin_collection/const.py` +4. Updates CHANGELOG.md +5. Creates a commit with message `bump: version X.Y.Z` +6. Creates and pushes a git tag `X.Y.Z` +7. Pushes the commit and tag to master + +**Note:** The bump workflow is skipped if the commit message starts with `bump:` to prevent infinite loops. + +### 3. Release Stage +**Triggers:** When a tag is pushed (automatically by bump workflow) + +**Workflow that runs:** +- `release.yml` - Publishes the release + +**What happens:** +1. Checks out the tagged commit +2. Verifies the Poetry version matches the git tag +3. Builds the Python package with Poetry +4. Creates a GitHub release with auto-generated release notes +5. Publishes the package to PyPI +6. Attaches build artifacts to the GitHub release + +## Commit Message Format + +Follow [Conventional Commits](https://www.conventionalcommits.org/) format: + +``` +(): + + + +