diff --git a/.vale/styles/Readability/LICENSE b/.vale/styles/Readability/LICENSE new file mode 100644 index 0000000..b61c4e1 --- /dev/null +++ b/.vale/styles/Readability/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Joseph Kato + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/.vale/styles/Readability/Polysyllables.yml b/.vale/styles/Readability/Polysyllables.yml new file mode 100644 index 0000000..8803397 --- /dev/null +++ b/.vale/styles/Readability/Polysyllables.yml @@ -0,0 +1,38 @@ +# The words behind a SMOG or Gunning fog score: each one of three or more +# syllables. The scores say a paragraph reads hard; this says which words +# made it so. Syllables are counted by vowel groups, with the silent e and +# the -ed and -es endings taken off, which agrees with the scores' count on +# nearly every word and errs on the long side for the rest. +# +# A suggestion, since a paragraph can carry a few. Turn it on while bringing +# a score down, and off again after. See issue 8. +extends: script +message: "'%s' has three or more syllables. It counts toward the SMOG and Gunning fog scores." +link: https://en.wikipedia.org/wiki/SMOG +level: suggestion +scope: paragraph +script: | + text := import("text") + + matches := [] + for m in text.re_find(`[A-Za-z]+(?:'[A-Za-z]+)?`, scope, -1) { + w := text.to_lower(m[0].text) + if len(w) < 5 { + continue + } + groups := text.re_find(`[aeiouy]+`, w, -1) + n := groups == undefined ? 0 : len(groups) + if text.has_suffix(w, "e") && !text.has_suffix(w, "le") && !text.has_suffix(w, "ee") { + n-- + } + if text.has_suffix(w, "ed") && !text.re_match(`[td]ed$`, w) { + n-- + } + if text.has_suffix(w, "es") && !text.re_match(`[sxz]es$|[cs]hes$`, w) { + n-- + } + if n >= 3 { + matches = append(matches, {begin: m[0].begin, end: m[0].end}) + } + } + diff --git a/.vale/styles/Readability/meta.json b/.vale/styles/Readability/meta.json index 0ff71c3..832469e 100644 --- a/.vale/styles/Readability/meta.json +++ b/.vale/styles/Readability/meta.json @@ -1,4 +1,7 @@ { - "feed": "https://github.com/errata-ai/Readability/releases.atom", - "vale_version": ">=2.13.0" -} \ No newline at end of file + "feed": "https://github.com/vale-cli/readability/releases.atom", + "vale_version": ">=2.13.0", + "license_files": [ + "LICENSE" + ] +} diff --git a/docs/specs/DEVX-178.md b/docs/specs/DEVX-178.md new file mode 100644 index 0000000..f62ef23 --- /dev/null +++ b/docs/specs/DEVX-178.md @@ -0,0 +1,38 @@ +# DEVX-178: PLAYBOOK_ROLE_MAP entry for deploy-controller playbook + +## Problem + +OBL-INFRA-655 adds the `deploy-controller.yml` playbook in the infra repo to the infra +repo (drives the new `deploy_controller` role). The infra molecule +coverage guard (`test_every_playbook_is_mapped`) requires every playbook +under `ansible/playbooks/` to appear in `PLAYBOOK_ROLE_MAP`. Without the +entry, the guard fails and unmapped playbooks fail open to all testable +roles — correct but wasteful. + +## Approach + +REQ-1: Add a `deploy-controller.yml` → `['deploy_controller']` entry +to `PLAYBOOK_ROLE_MAP` in `src/devx/molecule/molecule_changed.py` so +changes to the playbook select the `deploy_controller` molecule scenario. + +## Test Plan + +- Existing `test_molecule_changed.py` mapping tests cover new entries + generically; add an explicit assertion that the deploy-controller + playbook maps to `deploy_controller`. +- `make pytest-cov` (100% gate), `make lint-all`. + +## Deploy Plan + +Merge → devx release publishes automatically → infra dep-PR bumps the +pin; the mapping takes effect on the next infra CI run. + +## Rollback Plan + +Revert the squash commit; infra playbook falls back to fail-open all-role +selection (safe, slower). + +## Acceptance Criteria + +- [x] REQ-1: the deploy-controller playbook key maps to `["deploy_controller"]` in `PLAYBOOK_ROLE_MAP`. +- [x] Unit test pins the mapping; 100% coverage maintained. diff --git a/src/devx/molecule/molecule_changed.py b/src/devx/molecule/molecule_changed.py index 663d78f..6918014 100644 --- a/src/devx/molecule/molecule_changed.py +++ b/src/devx/molecule/molecule_changed.py @@ -47,6 +47,7 @@ def role_to_target(role: str) -> str: PLAYBOOK_ROLE_MAP: dict[str, list[str]] = { "ansible/playbooks/deploy-observability.yml": ["observability", "docker_base", "zitadel", "crowdsec"], "ansible/playbooks/deploy-customer.yml": ["app_container", "docker_base", "app_hardening"], + "ansible/playbooks/deploy-controller.yml": ["deploy_controller"], "ansible/playbooks/prepare-vms.yml": ["docker_base", "app_hardening", "storage", "disk_cleanup", "crowdsec"], "ansible/playbooks/restore.yml": ["restore"], "ansible/playbooks/upgrade-postgres.yml": ["app_container"], diff --git a/tests/unit/test_molecule_changed.py b/tests/unit/test_molecule_changed.py index 6a69442..d9e98cc 100644 --- a/tests/unit/test_molecule_changed.py +++ b/tests/unit/test_molecule_changed.py @@ -13,6 +13,7 @@ import pytest from click.testing import CliRunner from devx.molecule.molecule_changed import ( + PLAYBOOK_ROLE_MAP, detect_changed_roles, get_changed_files, main, @@ -52,6 +53,14 @@ def test_detect_playbook_change(roles_dir: Path): assert roles == {"observability", "docker_base"} +def test_detect_deploy_controller_playbook(roles_dir: Path): + """The deploy-controller playbook maps to the deploy_controller role.""" + assert PLAYBOOK_ROLE_MAP["ansible/playbooks/deploy-controller.yml"] == ["deploy_controller"] + (roles_dir / "deploy_controller" / "molecule" / "default").mkdir(parents=True) + roles = detect_changed_roles(["ansible/playbooks/deploy-controller.yml"], roles_dir) + assert roles == {"deploy_controller"} + + def test_detect_shared_infra_triggers_all(roles_dir: Path): """ansible.cfg change triggers all testable roles only.""" roles = detect_changed_roles(["ansible/ansible.cfg"], roles_dir)