Skip to content

envoy.code.check: per-entry changelog filename and content validation (PR 4)#4502

Draft
Copilot wants to merge 2 commits into
mainfrom
copilot/featureper-entry-filename-validation
Draft

envoy.code.check: per-entry changelog filename and content validation (PR 4)#4502
Copilot wants to merge 2 commits into
mainfrom
copilot/featureper-entry-filename-validation

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 11, 2026

Adds validation for the per-entry changelog layout (changelogs/current/<section>/<area>__<slug>.rst) to envoy.code.check. Only runs on the current changelog; historical <version>.yaml files are unaffected.

New methods on AChangelogChangesChecker

  • check_entry_filename(path) — validates in order: section name ∈ self.sections, extension is .rst, stem contains exactly one __, both area and slug are non-empty
  • check_entry_content(path) — rejects empty or whitespace-only files
  • check_entry_files(paths) — runs both checks over a list of paths, returns all errors as a tuple (for executor dispatch)

Wired into AChangelogStatus

  • entry_dir property — resolves the per-entry directory via changelog_path(version).with_suffix(""); returns None for non-current changelogs
  • check_entry_files() — globs */*.rst under entry_dir, dispatches checker.check_entry_files via project.execute
  • errors — extended to await self.check_entry_files() alongside existing checks

Interface

IChangelogChangesChecker gains the three new abstract methods so mypy remains clean.

Constants

# TODO: Replace with imports from envoy.base.utils once PR 2 lands
ENTRY_SEPARATOR = "__"
CHANGELOG_ENTRY_GLOB = "*/*.rst"

Tests

14 new test functions in test_abstract_changelog.py covering all filename/content validation paths; test_changelogstatus_errors updated to include check_entry_files. abstract/changelog.py remains at 100% coverage.

Original prompt

Toolshed PR 4 — Per-entry filename and section validation in envoy.code.check

This is the fourth PR in the implementation plan for per-entry changelog layout support (see issue #4498, plan at plans/per-entry-changelog-4498.md, investigation PR #4499). It can be developed in parallel with PRs 1–3; it lives in a different package (envoy.code.check) and only depends on the relaxed typing from PR 1 and the constants introduced in PR 2.

Background

Envoy is migrating from a single monolithic changelogs/current.yaml to a per-entry layout:

changelogs/current/<section>/<area>__<slug>.rst

Validation rules:

  • <section>: must be a key in changelogs/sections.yaml (the existing self.sections set on the checker already provides this).
  • <area>: must not contain __. May contain - and _.
  • <slug>: must not contain __. May contain - and _.
  • Separator: exactly one __ between area and slug.
  • File extension: .rst.
  • File contents: pure RST, non-empty (whitespace-only also rejected).

The checker should surface clear, actionable errors when these rules are violated.

Required changes

Primary file: py/envoy.code.check/envoy/code/check/abstract/changelog.py

1. Add check_entry_filename to AChangelogChangesChecker

Around the existing check_entry() (lines ~40–58) and check_section() (lines ~60–73), add:

def check_entry_filename(self, path: pathlib.Path) -> str | None:
    ...

Behaviour — return None on success, or a single human-readable error string describing the first failure found:

  1. Section validity: path.parent.name must be in self.sections (the existing set sourced from sections.yaml). If not, return an error naming the file and the invalid section, and listing valid sections (or hinting at the source of truth).
  2. Extension: path.suffix must be .rst. If not, return an error.
  3. Separator count: path.stem must contain exactly one __. If zero or more than one, return an error naming the file and explaining the <area>__<slug> rule.
  4. Area/slug non-empty: after area, slug = path.stem.split("__", 1), both area and slug must be non-empty. If either is empty, return an error.
  5. (Optional, document if added) reject leading/trailing whitespace in the filename or other obviously malformed names — but keep the rules minimal and aligned with the issue spec.

Use the existing constants from envoy.base.utils if/when PR 2 lands them (ENTRY_SEPARATOR, CHANGELOG_ENTRY_GLOB, CHANGELOG_CURRENT_DIR_PATH). If PR 2 hasn't merged yet, define local constants matching those names/values and add a TODO comment to swap to the imports once PR 2 lands. Do not import from a not-yet-existing module path; prefer a small local fallback.

2. Add a content non-emptiness check

Either:

  • Extend check_entry() (lines ~40–58) so it also flags empty / whitespace-only RST bodies for per-entry files, or
  • Add a sibling check_entry_content(self, path: pathlib.Path) -> str | None that returns an error if the file is empty or whitespace-only.

Pick whichever fits the existing style of the class better. Either way, an empty .rst entry must produce an error.

3. Wire the new checks into AChangelogStatus / AChangelogCheck

  • AChangelogStatus (lines ~99–232) orchestrates per-version/date/section checks. Add iteration over the per-entry files of the current changelog (the per-entry directory) so that check_entry_filename and the content non-emptiness check run on every *.rst under changelogs/current/<section>/.
  • AChangelogCheck (lines ~235–267) iterates over all changelogs. Make sure the new checks are surfaced via the same error-collection mechanism the existing checks use (look at how check_entry/check_section results are collected and reported — match that pattern exactly so CI output stays consistent).
  • Per-entry checks should run only on the current changelog (the one that uses the per-entry layout). Historical <version>.yaml files must not be touched — they continue to be validated by the existing checks.

4. Treat duplicate_current and is_pending correctly with the slim current.yaml

The plan flags these as open considerations, but the safe behaviour for this PR is:

  • duplicate_current (lines ~132–137): currently checks self.project.changelogs.changelog_path(self.version).exists(). With the per-entry layout, the slim current.yaml still exists alongside the directory, so the existing check should still work without modification. If you find it would now produce a false positive, leave the logic as-is and add a TODO comment referencing the plan's open question; do not change behaviour as part of this PR.
  • is_pending check (lines ~250–254 of envoy.base.utils/.../changelog.py): out of scope for this PR — leave it alone.

Tests

Add unit tests in py/envoy.code.check/tests/test_abstract_changelog.py covering:

  • Valid filename in a ...

This pull request was created from Copilot chat.

@netlify
Copy link
Copy Markdown

netlify Bot commented May 11, 2026

Deploy Preview for nifty-bassi-e26446 ready!

Name Link
🔨 Latest commit 254b4df
🔍 Latest deploy log https://app.netlify.com/projects/nifty-bassi-e26446/deploys/6a0206872f4531000880e157
😎 Deploy Preview https://deploy-preview-4502--nifty-bassi-e26446.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copilot AI changed the title [WIP] Add filename and section validation for per-entry changelog layout envoy.code.check: per-entry changelog filename and content validation (PR 4) May 11, 2026
Copilot finished work on behalf of phlax May 11, 2026 16:43
Copilot AI requested a review from phlax May 11, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants