From ee0c3a5ab34d50156bea86a3943b66752a8f3a3e Mon Sep 17 00:00:00 2001 From: Robert Bradley Date: Fri, 17 May 2024 18:23:04 +0000 Subject: [PATCH 1/8] feat: #708 Adding HA to the dev container for debugging --- .devcontainer/docker-compose.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 6f9061fb95..c479d83ff0 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -13,6 +13,21 @@ services: - selenium-hub command: sleep infinity + homeassistant: + container_name: homeassistant + image: "ghcr.io/home-assistant/home-assistant:stable" + volumes: + - .ha_config:/config:rw + - ../custom_components:/config/custom_components + - /etc/localtime:/etc/localtime:ro + - /run/dbus:/run/dbus:ro + restart: unless-stopped + privileged: true + networks: + - devnet + ports: + - "8124:8123/tcp" + chrome: image: selenium/node-chrome:4.20.0-20240505 shm_size: 2gb From 7ddba47cf0e2ed8e2ed50eeb3d31ce61009941e0 Mon Sep 17 00:00:00 2001 From: Robert Bradley Date: Fri, 17 May 2024 18:27:42 +0000 Subject: [PATCH 2/8] feat: #708 Adding HA to the dev container for debugging --- uk_bin_collection/tests/input.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index 7d8b0ef4cd..f59b6e4d80 100644 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -1029,7 +1029,7 @@ "uprn": "10009739960", "skip_get_url": true, "url": "https://maps.westsuffolk.gov.uk/MyWestSuffolk.aspx", - "wiki_name": "West Suffolk Council", + "wiki_name": "West Suffolk Council" }, "WiganBoroughCouncil": { "postcode": "WN24UQ", From c0c0e6cdba00d912fc93abc6f24cc4daf08942c1 Mon Sep 17 00:00:00 2001 From: Robert Bradley Date: Fri, 17 May 2024 18:28:38 +0000 Subject: [PATCH 3/8] feat: #708 Adding HA to the dev container for debugging --- .../step_defs/step_helpers/file_handler.py | 16 ++++-- .../tests/step_defs/test_validate_council.py | 57 +++++++------------ 2 files changed, 31 insertions(+), 42 deletions(-) diff --git a/uk_bin_collection/tests/step_defs/step_helpers/file_handler.py b/uk_bin_collection/tests/step_defs/step_helpers/file_handler.py index a07d8d107a..e826562992 100644 --- a/uk_bin_collection/tests/step_defs/step_helpers/file_handler.py +++ b/uk_bin_collection/tests/step_defs/step_helpers/file_handler.py @@ -2,6 +2,7 @@ import logging from jsonschema import validate, ValidationError from pathlib import Path +from typing import Any, Dict logging.basicConfig(level=logging.INFO, format="%(levelname)s - %(message)s") @@ -10,27 +11,30 @@ BASE_PATH = current_file_path.parent.parent.parent.parent / "tests" -def load_json_file(file_name, encoding="utf-8"): +def load_json_file(file_name: str) -> Dict[str, Any]: file_path = BASE_PATH / file_name try: - with open(file_path, "r", encoding=encoding) as f: + with open(file_path, "r") as f: data = json.load(f) logging.info(f"{file_name} file successfully loaded") return data except UnicodeDecodeError as e: - logging.error(f"Failed to load {file_name} with encoding {encoding}: {e}") + logging.error(f"Failed to load {file_name}: {e}") + raise + except json.JSONDecodeError as e: + logging.error(f"Failed to parse JSON in {file_name}: {e}") raise -def validate_json(json_str): +def validate_json(json_str: str) -> Dict[str, Any]: try: return json.loads(json_str) - except ValueError as err: + except json.JSONDecodeError as err: logging.error(f"JSON validation error: {err}") raise -def validate_json_schema(json_str, schema): +def validate_json_schema(json_str: str, schema: Dict[str, Any]) -> bool: json_data = validate_json(json_str) try: validate(instance=json_data, schema=schema) diff --git a/uk_bin_collection/tests/step_defs/test_validate_council.py b/uk_bin_collection/tests/step_defs/test_validate_council.py index b444c708b4..6ca5fad130 100644 --- a/uk_bin_collection/tests/step_defs/test_validate_council.py +++ b/uk_bin_collection/tests/step_defs/test_validate_council.py @@ -1,6 +1,8 @@ import logging -import pytest import traceback +from typing import Any, Generator, Callable + +import pytest from pytest_bdd import scenario, given, when, then, parsers from functools import wraps @@ -9,49 +11,40 @@ logging.basicConfig(level=logging.INFO, format="%(levelname)s - %(message)s") - @scenario("../features/validate_council_outputs.feature", "Validate Council Output") -def test_scenario_outline(): +def test_scenario_outline() -> None: pass - -def handle_test_errors(func): +def handle_test_errors(func: Callable[..., Any]) -> Callable[..., Any]: @wraps(func) - def wrapper(*args, **kwargs): + def wrapper(*args: Any, **kwargs: Any) -> Any: try: return func(*args, **kwargs) except Exception as e: logging.error(f"Error in test '{func.__name__}': {e}") logging.error(traceback.format_exc()) raise e - return wrapper - @pytest.fixture @handle_test_errors -def context(): - class Context(object): - pass +def context() -> Generator[Any, None, None]: + class Context: + metadata: dict[str, Any] + council: str + parse_result: Any return Context() - @handle_test_errors @given(parsers.parse("the council: {council_name}")) -def get_council_step(context, council_name): +def get_council_step(context: Any, council_name: str) -> None: council_input_data = file_handler.load_json_file("input.json") context.metadata = council_input_data[council_name] -# When we scrape the data from using and the is set. - @handle_test_errors -@when( - parsers.parse( - "we scrape the data from {council}" - ) -) -def scrape_step(context, council, headless_mode, local_browser, selenium_url): +@when(parsers.parse("we scrape the data from {council}")) +def scrape_step(context: Any, council: str, headless_mode: str, local_browser: str, selenium_url: str) -> None: context.council = council args = [council, context.metadata["url"]] @@ -69,34 +62,26 @@ def scrape_step(context, council, headless_mode, local_browser, selenium_url): usrn = context.metadata["usrn"] args.append(f"-us={usrn}") if headless_mode == "True": - args.append(f"--headless") + args.append("--headless") else: - args.append(f"--not-headless") - # TODO we should somehow run this test with and without this argument passed - # TODO I do think this would make the testing of the councils a lot longer and cause a double hit from us + args.append("--not-headless") - # At the moment the feature file is set to local execution of the selenium so no url will be set - # And it the behave test will execute locally if local_browser == "False": args.append(f"-w={selenium_url}") if "skip_get_url" in context.metadata: - args.append(f"-s") + args.append("-s") CollectData = collect_data.UKBinCollectionApp() CollectData.set_args(args) context.parse_result = CollectData.run() - @handle_test_errors @then("the result is valid json") -def validate_json_step(context): +def validate_json_step(context: Any) -> None: assert file_handler.validate_json(context.parse_result), "Invalid JSON output" - @handle_test_errors @then("the output should validate against the schema") -def validate_output_step(context): - council_schema = file_handler.load_json_file(f"output.schema") - assert file_handler.validate_json_schema( - context.parse_result, council_schema - ), "Schema validation failed" +def validate_output_step(context: Any) -> None: + council_schema = file_handler.load_json_file("output.schema") + assert file_handler.validate_json_schema(context.parse_result, council_schema), "Schema validation failed" From fd05d780df0d00b656cd4c7298b88ef4ee51e3f9 Mon Sep 17 00:00:00 2001 From: Robert Bradley Date: Fri, 17 May 2024 18:34:47 +0000 Subject: [PATCH 4/8] feat: #708 Adding HA to the dev container for debugging --- .github/workflows/behave.yml | 180 +++++++++++++++++------------------ 1 file changed, 88 insertions(+), 92 deletions(-) diff --git a/.github/workflows/behave.yml b/.github/workflows/behave.yml index 16902c4592..d241735810 100644 --- a/.github/workflows/behave.yml +++ b/.github/workflows/behave.yml @@ -7,7 +7,6 @@ on: paths-ignore: - "wiki/**" - "**/**.md" - - "**.md" - "uk_bin_collection_api_server/**" branches: [ "master" ] pull_request: @@ -15,9 +14,7 @@ on: paths-ignore: - "wiki/**" - "**/**.md" - - "**.md" - "uk_bin_collection_api_server/**" - # The branches below must be a subset of the branches above branches: [ "master" ] schedule: - cron: '0 0 * * *' @@ -34,113 +31,112 @@ jobs: selenium: image: selenium/standalone-chrome:latest options: --shm-size=2gb --name selenium --hostname selenium - ports: + ports: - 4444:4444 steps: - - uses: actions/checkout@v4 - - - name: Install poetry - run: pipx install poetry==${{ matrix.poetry-version }} - - - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - cache: 'poetry' - - - name: Install - run: make install - - - name: Get all councils files that have changed - id: changed-council-files - uses: tj-actions/changed-files@v44 - with: - files: | - uk_bin_collection/uk_bin_collection/councils/**.py - - - name: Get all councils - env: - ALL_CHANGED_FILES: ${{ steps.changed-council-files.outputs.all_changed_files }} - run: | - IFS=' ' read -ra FILES <<< "$ALL_CHANGED_FILES" - COUNCIL_TESTS="" - for file in "${FILES[@]}"; do - FILENAME=$(basename "$file" .py) - if [ -z "$COUNCIL_TESTS" ]; then - COUNCIL_TESTS="$FILENAME" - else - COUNCIL_TESTS="$COUNCIL_TESTS or $FILENAME" - fi - done - echo "COUNCIL_TESTS=${COUNCIL_TESTS}" >> $GITHUB_ENV - - - - name: run integration-tests - env: - HEADLESS: True - run: make matrix=${{ matrix.python-version }} councils="${{ env.COUNCIL_TESTS }}" integration-tests - continue-on-error: true - - - name: run unit-tests - run: make unit-tests - continue-on-error: true - - - name: Upload Test Coverage to Codecov - uses: codecov/codecov-action@v4 - with: - gcov_ignore: uk_bin_collection/tests/** - - - name: Get Allure history - uses: actions/checkout@v4 - if: github.ref == 'refs/heads/master' - continue-on-error: true - with: - ref: gh-pages - path: gh-pages - - - name: Allure Report action from marketplace - uses: simple-elf/allure-report-action@master - if: github.ref == 'refs/heads/master' - #id: allure-report - with: - allure_results: build/${{ matrix.python-version }}/allure-results - #gh_pages: gh-pages - #allure_report: allure-report - subfolder: ${{ matrix.python-version }} - allure_history: allure-history - keep_reports: 20 - - - name: Tar Report - if: github.ref == 'refs/heads/master' - run: tar -cvf allure_history_${{ matrix.python-version }}.tar allure-history/${{ matrix.python-version }} - - name: upload artifact - uses: actions/upload-artifact@v4 - if: github.ref == 'refs/heads/master' - with: - name: allure_history_${{ matrix.python-version }} - path: allure_history_${{ matrix.python-version }}.tar + - uses: actions/checkout@v4 + + - name: Install poetry + run: pipx install poetry==${{ matrix.poetry-version }} + + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: 'poetry' + + - name: Install + run: make install + + - name: Lint JSON + run: jq empty uk_bin_collection/uk_bin_collection/tests/input.json + + - name: Get all councils files that have changed + id: changed-council-files + uses: tj-actions/changed-files@v44 + with: + files: | + uk_bin_collection/uk_bin_collection/councils/**.py + + - name: Get all councils + env: + ALL_CHANGED_FILES: ${{ steps.changed-council-files.outputs.all_changed_files }} + run: | + IFS=' ' read -ra FILES <<< "$ALL_CHANGED_FILES" + COUNCIL_TESTS="" + for file in "${FILES[@]}"; do + FILENAME=$(basename "$file" .py) + if [ -z "$COUNCIL_TESTS" ]; then + COUNCIL_TESTS="$FILENAME" + else + COUNCIL_TESTS="$COUNCIL_TESTS or $FILENAME" + fi + done + echo "COUNCIL_TESTS=${COUNCIL_TESTS}" >> $GITHUB_ENV + + - name: Run integration tests + env: + HEADLESS: True + run: make matrix=${{ matrix.python-version }} councils="${{ env.COUNCIL_TESTS }}" integration-tests + continue-on-error: true + + - name: Run unit tests + run: make unit-tests + continue-on-error: true + + - name: Upload test coverage to Codecov + uses: codecov/codecov-action@v4 + with: + gcov_ignore: uk_bin_collection/tests/** + + - name: Get Allure history + uses: actions/checkout@v4 + if: github.ref == 'refs/heads/master' + continue-on-error: true + with: + ref: gh-pages + path: gh-pages + + - name: Allure report action from marketplace + uses: simple-elf/allure-report-action@master + if: github.ref == 'refs/heads/master' + with: + allure_results: build/${{ matrix.python-version }}/allure-results + subfolder: ${{ matrix.python-version }} + allure_history: allure-history + keep_reports: 20 + + - name: Tar report + if: github.ref == 'refs/heads/master' + run: tar -cvf allure_history_${{ matrix.python-version }}.tar allure-history/${{ matrix.python-version }} + + - name: Upload artifact + uses: actions/upload-artifact@v4 + if: github.ref == 'refs/heads/master' + with: + name: allure_history_${{ matrix.python-version }} + path: allure_history_${{ matrix.python-version }}.tar deploy: runs-on: ubuntu-latest needs: build if: github.ref == 'refs/heads/master' steps: - - uses: actions/download-artifact@v4 - name: Download 3.10 Artifacts + name: Download 3.10 artifacts with: name: allure_history_3.10 path: allure-history/tars - + - uses: actions/download-artifact@v4 - name: Download 3.11 Artifacts + name: Download 3.11 artifacts with: name: allure_history_3.11 path: allure-history/tars - - - name: Untar Reports + + - name: Untar reports run: for i in allure-history/tars/*.tar; do tar -xvf "$i" allure-history ;done - - name: Remove Tar Reports + - name: Remove tar reports run: rm -rf allure-history/tars - name: Display structure of downloaded files From a1d4552ad243fa10141425d81ea58d65d43cbec0 Mon Sep 17 00:00:00 2001 From: Robert Bradley Date: Fri, 17 May 2024 18:36:55 +0000 Subject: [PATCH 5/8] feat: #708 Adding HA to the dev container for debugging --- .github/workflows/behave.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/behave.yml b/.github/workflows/behave.yml index d241735810..78388f85b6 100644 --- a/.github/workflows/behave.yml +++ b/.github/workflows/behave.yml @@ -48,7 +48,7 @@ jobs: run: make install - name: Lint JSON - run: jq empty uk_bin_collection/uk_bin_collection/tests/input.json + run: jq empty uk_bin_collection/tests/input.json - name: Get all councils files that have changed id: changed-council-files From afc3556727af8680508271511794833360b0a946 Mon Sep 17 00:00:00 2001 From: Robert Bradley Date: Fri, 17 May 2024 18:49:12 +0000 Subject: [PATCH 6/8] feat: #708 Adding HA to the dev container for debugging --- .github/workflows/behave.yml | 3 + Makefile | 3 + poetry.lock | 20 ++++- pyproject.toml | 3 +- .../tests/council_feature_input_parity.py | 73 +++++++++++++++++++ 5 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 uk_bin_collection/tests/council_feature_input_parity.py diff --git a/.github/workflows/behave.yml b/.github/workflows/behave.yml index 78388f85b6..f612387829 100644 --- a/.github/workflows/behave.yml +++ b/.github/workflows/behave.yml @@ -50,6 +50,9 @@ jobs: - name: Lint JSON run: jq empty uk_bin_collection/tests/input.json + - name: Check Parity of Councils / input.json / Feature file + run: make parity-check branch="${{ github.event.pull_request.head.ref }}" + - name: Get all councils files that have changed id: changed-council-files uses: tj-actions/changed-files@v44 diff --git a/Makefile b/Makefile index ee6868339a..0bb06c22af 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,9 @@ integration-tests: ## runs tests for the project poetry run pytest uk_bin_collection/tests/step_defs/ -k "$(councils)" -n logical --alluredir=build/$(matrix)/allure-results; \ fi +parity-check: + poetry run uk_bin_collection/tests/council_feature_input_parity.py $(branch) + unit-tests: poetry run coverage erase poetry run coverage run --append --omit "*/tests/*" -m pytest uk_bin_collection/tests --ignore=uk_bin_collection/tests/step_defs/ diff --git a/poetry.lock b/poetry.lock index a407ad9527..9f4b3121f3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "allure-pytest-bdd" @@ -1104,8 +1104,8 @@ astroid = ">=3.0.1,<=3.1.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, ] isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.8" @@ -1450,6 +1450,20 @@ files = [ {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, ] +[[package]] +name = "tabulate" +version = "0.9.0" +description = "Pretty-print tabular data" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, + {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, +] + +[package.extras] +widechars = ["wcwidth"] + [[package]] name = "tomli" version = "2.0.1" @@ -1583,4 +1597,4 @@ h11 = ">=0.9.0,<1" [metadata] lock-version = "2.0" python-versions = ">=3.10" -content-hash = "e1abe58852910d4037fee6f9c0c1d5a6e93c87a48c19d1ab81b99c73013cd84b" +content-hash = "3257949d8921063e745be866c2f7217c57f2825d2823bae1143469f944b19815" diff --git a/pyproject.toml b/pyproject.toml index e45945be3f..5c90417f33 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ pytest-bdd = "*" allure-pytest-bdd = "*" pytest-xdist = {extras = ["psutil"], version = "*"} pyhamcrest = "*" - +tabulate = "^0.9.0" [tool.poetry.scripts] uk_bin_collection = "uk_bin_collection.uk_bin_collection.collect_data:run" @@ -58,6 +58,7 @@ selenium = "*" lxml = "*" urllib3 = "*" webdriver-manager = "^4.0.1" +tabulate = "^0.9.0" [tool.commitizen] major_version_zero = true diff --git a/uk_bin_collection/tests/council_feature_input_parity.py b/uk_bin_collection/tests/council_feature_input_parity.py new file mode 100644 index 0000000000..45f583d389 --- /dev/null +++ b/uk_bin_collection/tests/council_feature_input_parity.py @@ -0,0 +1,73 @@ +import json +import re +import requests +import sys +from tabulate import tabulate + +def get_councils_from_files(branch): + url = f"https://api.github.com/repos/robbrad/UKBinCollectionData/contents/uk_bin_collection/uk_bin_collection/councils?ref={branch}" + response = requests.get(url) + data = response.json() + return [item['name'].replace('.py', '') for item in data if item['name'].endswith('.py')] + +def get_councils_from_json(branch): + url = f"https://raw.githubusercontent.com/robbrad/UKBinCollectionData/{branch}/uk_bin_collection/tests/input.json" + response = requests.get(url) + data = json.loads(response.text) + return list(data.keys()) + +def get_councils_from_features(branch): + url = f"https://raw.githubusercontent.com/robbrad/UKBinCollectionData/{branch}/uk_bin_collection/tests/features/validate_council_outputs.feature" + response = requests.get(url) + content = response.text + return re.findall(r'Examples:\s+(\w+)', content) + +def compare_councils(councils1, councils2, councils3): + set1 = set(councils1) + set2 = set(councils2) + set3 = set(councils3) + all_councils = set1 | set2 | set3 + all_council_data = {} + for council in all_councils: + in_files = council in set1 + in_json = council in set2 + in_features = council in set3 + discrepancies_count = [in_files, in_json, in_features].count(False) + all_council_data[council] = { + 'in_files': in_files, + 'in_json': in_json, + 'in_features': in_features, + 'discrepancies_count': discrepancies_count + } + return all_council_data + +def main(branch): + # Execute and print the comparison + file_councils = get_councils_from_files(branch) + json_councils = get_councils_from_json(branch) + feature_councils = get_councils_from_features(branch) + + all_councils_data = compare_councils(file_councils, json_councils, feature_councils) + + # Create a list of lists for tabulate, sort by discrepancies count and then by name + table_data = [] + headers = ["Council Name", "In Files", "In JSON", "In Features", "Discrepancies"] + for council, presence in sorted(all_councils_data.items(), key=lambda x: (x[1]['discrepancies_count'], x[0])): + row = [ + council, + "✔" if presence['in_files'] else "✘", + "✔" if presence['in_json'] else "✘", + "✔" if presence['in_features'] else "✘", + presence['discrepancies_count'] + ] + table_data.append(row) + + # Print the table using tabulate + print(tabulate(table_data, headers=headers, tablefmt='grid')) + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage: python script.py ") + sys.exit(1) + branch = sys.argv[1] + main(branch) From 899fad1e9522daf3903e0196ee1b443d30fb086d Mon Sep 17 00:00:00 2001 From: Robert Bradley Date: Fri, 17 May 2024 18:53:55 +0000 Subject: [PATCH 7/8] feat: #708 Adding HA to the dev container for debugging --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0bb06c22af..12d67ae7f6 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ integration-tests: ## runs tests for the project fi parity-check: - poetry run uk_bin_collection/tests/council_feature_input_parity.py $(branch) + poetry run python uk_bin_collection/tests/council_feature_input_parity.py $(branch) unit-tests: poetry run coverage erase From 3531611696cdba26c5d34fcb11433afe663d042e Mon Sep 17 00:00:00 2001 From: Robert Bradley Date: Fri, 17 May 2024 18:56:11 +0000 Subject: [PATCH 8/8] feat: #708 Adding HA to the dev container for debugging --- .../tests/council_feature_input_parity.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/uk_bin_collection/tests/council_feature_input_parity.py b/uk_bin_collection/tests/council_feature_input_parity.py index 45f583d389..0ae1118990 100644 --- a/uk_bin_collection/tests/council_feature_input_parity.py +++ b/uk_bin_collection/tests/council_feature_input_parity.py @@ -28,6 +28,7 @@ def compare_councils(councils1, councils2, councils3): set3 = set(councils3) all_councils = set1 | set2 | set3 all_council_data = {} + discrepancies_found = False for council in all_councils: in_files = council in set1 in_json = council in set2 @@ -39,7 +40,9 @@ def compare_councils(councils1, councils2, councils3): 'in_features': in_features, 'discrepancies_count': discrepancies_count } - return all_council_data + if discrepancies_count > 0: + discrepancies_found = True + return all_council_data, discrepancies_found def main(branch): # Execute and print the comparison @@ -47,7 +50,7 @@ def main(branch): json_councils = get_councils_from_json(branch) feature_councils = get_councils_from_features(branch) - all_councils_data = compare_councils(file_councils, json_councils, feature_councils) + all_councils_data, discrepancies_found = compare_councils(file_councils, json_councils, feature_councils) # Create a list of lists for tabulate, sort by discrepancies count and then by name table_data = [] @@ -65,6 +68,12 @@ def main(branch): # Print the table using tabulate print(tabulate(table_data, headers=headers, tablefmt='grid')) + if discrepancies_found: + print("Discrepancies found! Failing the workflow.") + sys.exit(1) + else: + print("No discrepancies found. Workflow successful.") + if __name__ == "__main__": if len(sys.argv) != 2: print("Usage: python script.py ")