Skip to content

WIP: Add v4 remote-module ingestion (two-phase, per-commit hooks)#6204

Draft
hjmjohnson wants to merge 15 commits intoInsightSoftwareConsortium:mainfrom
hjmjohnson:ingest-strategy-v4
Draft

WIP: Add v4 remote-module ingestion (two-phase, per-commit hooks)#6204
hjmjohnson wants to merge 15 commits intoInsightSoftwareConsortium:mainfrom
hjmjohnson:ingest-strategy-v4

Conversation

@hjmjohnson
Copy link
Copy Markdown
Member

@hjmjohnson hjmjohnson commented May 4, 2026

This PR is a WIP because each new remote module adds minor new elements that need to be addressed.

PROMPT: Use the ~/src/ITK-ingest-v4/Utilities/Maintenance/RemoteModuleIngest tooling  to ingest the remote module on the latest upstream/main branch for <<MODULE_NAME>>

Adds a v4 remote-module ingestion pipeline that splits the v3 single-driver flow into two independent phases — Phase A is fully local and reversible; Phase B publishes to upstream only after the Phase A PR has merged on ITK main. Each historical commit is individually re-formatted (clang-format / black / gersemi / trailing-ws / EOF / line-ending) and retroactively conformed to ITK ghostflow rules (subject ≤78 chars, blank line after subject, exec-bit cleared on text files), so every historical commit independently passes ITK's CI gates after the merge.

WIP — opening for design feedback. Validated end-to-end on Cuberille (PR #6205): ghostflow now reports a single, unavoidable error (the upstream root commit). All other categories (long subjects, conflict markers in .orig, exec-bit on CMakeLists.txt, two-line subjects) are eliminated.

Why two phases (motivation)

In v3 (ingest-remote-module.sh) the script orchestrated upstream archival as a bonus step at the end of the ingest. Re-running the ingest after a CI failure risked re-touching the upstream remote, and the upstream-archival step was a manual checklist (per feedback_ingest_archive_readme.md) — easy to forget steps.

v4 splits these into two independent phases:

Phase Script Local-clone fate Upstream side-effects
A — Ingestion ingest-module-v4.sh Throwaway None (no pushes to upstream remote)
B — Upstream archival archive-remote-module.sh Fresh clone Pushes one removal commit + promotes MIGRATION_README.md to README.md + flips archived=true

The phases share one persistent artifact: the whitelist at Utilities/Maintenance/RemoteModuleIngest/whitelists/<Module>.list. Every other piece of state is reproducible.

The central correctness property: upstream is never touched until ITK has accepted the migration.

Per-commit hook + ghostflow coverage

sanitize-history.py walks every commit on the rewritten ingestion branch via git_filter_repo's blob_callback + commit_callback. Because blob_callback is filename-blind by design (blobs stream before commits), the filter mirrors ITK's pre-commit excludes via content sniffing. For typical module ingests, the upstream whitelist has already pruned ThirdParty/, Data/, build/, and pixi/ paths, so the exclude set narrows to a handful of content-detectable extensions.

ITK pre-commit hook v4 coverage
clang-format (.c .cc .cxx .h .hxx) Sniff: #include, #pragma, namespace itk, template <, ... in first 8K bytes
black (.py) Sniff: shebang or top-level import/from/def/class
gersemi (.cmake .wrap CMakeLists.txt) Sniff: cmake_minimum_required, project(, add_library(, ITK macros (itk_module_*, itk_add_test, itk_wrap_*)
trailing-whitespace Universal text fixer (every text-classified blob)
end-of-file-fixer Universal text fixer
mixed-line-ending (CRLF→LF) Universal text fixer
check-shebang-scripts-are-executable Not implemented — post-merge gate catches it
ITK ghostflow rule v4 coverage
Subject line ≤ 78 chars truncate_subject_to_body() — excess moves to commit body, preferring word-break
Subject followed by blank line ensure_blank_line_after_subject() — inserts \n if missing
No leftover merge-conflict markers Deny-pass strips *.orig, *.rej, *.BACKUP.*, *.LOCAL.*, *.REMOTE.*, *.BASE.* from all history
No exec-bit on text files commit_callback walks file_changes and clears mode 100755 → 100644 for known text extensions
No CI scaffolding under module subtree Deny-pass strips Dockerfile*, .github/*, .travis.yml, azure-pipelines*, circle.yml, .gitlab-ci.yml, appveyor.yml, pyproject.toml, setup.py, etc.
Root commit Unfixable — every upstream remote module has one; surfaces as the single remaining ghostflow error
Heuristic commit-prefix mapping

When a historical commit subject does not start with a recognized ITK prefix (BUG:/COMP:/DOC:/ENH:/PERF:/STYLE:/WIP:), sanitize-history.py auto-prepends one based on the table below. Every decision is logged with <sha> <chosen-prefix> <original-subject> so the operator can audit before merge.

Subject contains... Prefix
fix, bug, crash, segfault, leak, regression, corrupt, deadlock BUG:
cmake, compil, warning, build, ci / ci:, clang , gcc, msvc COMP:
doc, readme, comment, license, sphinx, doxygen DOC:
style, whitespace, format, rename, lint, clean up, reorder STYLE:
perf, optim, speed, faster, efficien PERF:
anything else ENH: (default)

These rules are conservative — when in doubt, default to ENH:. Misclassifications get caught by the operator reading the sidecar log.

Smoke-test 1: IOMeshSTL (--dry-run)
Phase A — Ingestion (LOCAL, throwaway)
  Module:        IOMeshSTL
  DestGroup:     IO

After filter-repo: 91 commits, 24 merges
sanitize-history complete:
  commits walked:        97
  prefix auto-prepended: 42
  blobs scanned:         149
  blobs reformatted:     108
  by-kind sniff:         cxx=106 py=0 cmake=28 text=9 skip=6

Final rewritten history:
  Commits:  143 -> 89
  Merges:   44 -> 24
Verifying every commit subject has a valid ITK prefix...
  OK: every commit has a valid prefix.

Topology preserved (44→24 merges; non-zero, no linearization).

Smoke-test 2: Cuberille (real ingest, PR #6205) — proves ghostflow conformance

PR #6205 stacks on this PR and is the first real consumer. Ghostflow on PR #6205 reports exactly one error:

Errors:
  - commit 49774c0545... not allowed; it is a root commit.

That's the only remaining failure mode — the upstream module's genesis commit. All four other ghostflow categories that originally fired on Cuberille (long subjects on 6 commits, conflict markers in .h.orig on commit d23f9207, exec-bit on CMakeLists.txt in the root commit, two-line subject on 6127d75f41) are gone after this PR's hardening landed.

Sanitize-history.py counters from the Cuberille run that demonstrate the hardening is doing real work:

  prefix auto-prepended: 36
  subjects truncated:    5
  blank lines inserted:  33
  exec-bits cleared:     1
  blobs scanned:         147
  blobs reformatted:     94
  by-kind sniff:         cxx=102 py=1 cmake=28 text=5 skip=11

Build + 25/25 Cuberille tests pass locally.

Files added
  • Utilities/Maintenance/RemoteModuleIngest/INGESTION_STRATEGY_v4.md — design document
  • Utilities/Maintenance/RemoteModuleIngest/ingest-module-v4.sh — Phase A driver
  • Utilities/Maintenance/RemoteModuleIngest/archive-remote-module.sh — Phase B driver
  • Utilities/Maintenance/RemoteModuleIngest/sanitize-history.pygit_filter_repo callback driver
  • Utilities/Maintenance/RemoteModuleIngest/whitelists/IOMeshSTL.list — first concrete whitelist (smoke-test target)

The v3 scripts (ingest-remote-module.sh, normalize-ingest-commits.py, etc.) are intentionally retained in tree until v4 has been used for two successful ingests.

Open questions for reviewers
  1. Gersemi version drift. Local install is 0.24.0; ITK pre-commit pins 0.19.3. Confirmed in practice on Cuberille: the post-merge pre-commit run --all-files gate catches one CMake file per ingest where the two versions disagree, fixed via a STYLE: follow-up commit. Acceptable, or should v4 verify version match before running?

  2. Subject truncation can fall mid-word when a long word starts before offset 40 (e.g. STYLE: Merge pull request #21 from jhlegarreta/ImproveCuberilleImageToMeshFilt lost the erStyle suffix). The full original subject is preserved in the body, but the visible subject is uglier. Reviewer preference for raising the word-break minimum, or accept ghostflow-clean-but-cosmetically-truncated?

  3. check-shebang-scripts-are-executable is currently deferred. Acceptable post-merge gate, or worth adding now?

Splits the v3 single-driver flow into two independent phases so the
upstream-archival publish step never runs on a working tree that
filter-repo has rewritten:

  - Phase A (ingest-module-v4.sh): local, throwaway clone; rewrites
    history into Modules/<Group>/<Module>; never touches the upstream
    remote.

  - Phase B (archive-remote-module.sh): fresh shallow clone; pushes
    one removal commit + promotes MIGRATION_README.md to README.md;
    flips archived=true.  Gated on the Phase A PR being merged.

The shared sanitize-history.py walks the rewritten branch and applies
the same hooks ITK's .pre-commit-config.yaml enforces:

  - clang-format on every C/C++ blob (content sniff)
  - black on every Python blob (content sniff)
  - gersemi on every CMake blob using ITK's .gersemi.config
  - trailing-whitespace, end-of-file-fixer, mixed-line-ending on
    every text-classified blob
  - VTK / SVG / hash-content sidecar files are skipped intact
  - Every commit subject without an ITK prefix gets one heuristically
    auto-prepended; decisions are logged for operator audit

filter-repo's blob_callback is filename-blind by design, so excludes
are approximated via content sniffing.  IOMeshSTL whitelist is the
first concrete example; smoke-tested via --dry-run successfully
(143->89 commits, 44->24 merges preserved, 108/149 blobs reformatted).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots area:Python wrapping Python bindings for a class labels May 4, 2026
The whitelist admits whole directories (test/, wrapping/, ...) but
some upstream remote modules place CI / packaging scaffolding inside
those (e.g. test/Docker/, .github/, azure-pipelines/).  Without a
deny-pass after the whitelist filter, those leak into ITK history.

Mirrors v3's --invert-paths --path-glob pass; discovered missing on
the first Cuberille v4 ingest (test/Docker/{Dockerfile,build,run,test}.sh
leaked).
@@ -0,0 +1,25 @@
# IOMeshSTL — files that migrate into ITK at Modules/IO/MeshSTL/
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there reason this list is kept per remote?

@@ -0,0 +1,539 @@
#!/usr/bin/env python3
"""sanitize-history.py — Apply ITK formatting and commit-prefix conventions
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like "sanitize history" script already exists somewhere.

hjmjohnson added 2 commits May 4, 2026 14:05
Fixes the four classes of ghostflow errors that surfaced on the first
Cuberille v4 ingest (PR InsightSoftwareConsortium#6205) — the only allowable remaining error
should be the unavoidable upstream root commit.

  - Strip *.orig / *.rej / *.BACKUP.* / *.LOCAL.* / *.REMOTE.* /
    *.BASE.* merge-conflict-artifact files from history (catches
    leftover-conflict-marker errors like the .h.orig on Cuberille).
  - sanitize-history.py: cap every commit subject at 78 chars (ghostflow
    / kw-commit-msg rule); excess words move into the body.
  - sanitize-history.py: insert a blank line between subject and body
    when the original commit message lacked one (two-line subject error).
  - sanitize-history.py: clear the executable bit (mode 100755 -> 100644)
    on text-file extensions so root-commit "executable permissions but
    file does not look executable" stops firing.
Many ITK remote modules' itk-module.cmake reads
  file(READ "${MY_CURRENT_DIR}/README.rst" DOCUMENTATION)
to populate the CMake DESCRIPTION variable from the upstream README.

The v4 whitelist intentionally excludes the upstream README (the
operator ships a new README.md as part of the ingest PR), so without
this rewrite every commit's CMakeLists fails to configure post-ingest
until the operator manually patches itk-module.cmake.

sanitize-history.py now rewrites the file(READ ... README.rst ...)
reference to README.md as part of the cmake-blob transform, so every
historical commit on the rewritten branch is independently buildable.

Surfaced on the IOMeshSTL ingest (PR following PR InsightSoftwareConsortium#6204).
hjmjohnson added 4 commits May 5, 2026 05:51
…terns

Add a 'Known artifacts at PR-review time' section to capture two
things future ingest operators need to expect but that v3/v4 do not
fix automatically:

  - The single ghostflow-check-main 'root commit not allowed' error
    that every Mode-A merge produces.  Maintainers override at merge.
    Calling it out keeps operators from chasing a non-fix.

  - A short table of code-level patterns Greptile has flagged
    post-ingest on multiple modules (IOMeshSTL InsightSoftwareConsortium#6206, RLEImage InsightSoftwareConsortium#6208):
    signed-vs-unsigned size types, missing override, dead return after
    itkExceptionMacro, stray test args, external-friend declarations,
    GetBuffer-const correctness, and allocator-init invariants.

The table is the durable channel for cross-ingest review knowledge —
extend it as new recurring patterns surface.
ExternalData stores resolved fetched content as .ExternalData_<algo>_<hash>
files alongside the .cid / .md5 sidecars they correspond to.  These
are local fetch cache, not source — ExternalData regenerates them on
demand at consumer-time.  Upstream remote modules sometimes commit
them inadvertently from a CTest run inside their working tree (e.g.
ITKIOMeshSTL had four such files in test/Baseline/, flagged by
@dzenanz on PR InsightSoftwareConsortium#6206).

Add **/.ExternalData_* to the scaffolding deny-pass so they never
enter ITK history.
Upstream remote modules wrap their top-level CMakeLists.txt in

    if(NOT ITK_SOURCE_DIR)
      find_package(ITK REQUIRED)
      list(APPEND CMAKE_MODULE_PATH ${ITK_CMAKE_DIR})
      include(ITKModuleExternal)
    else()
      itk_module_impl()
    endif()

so the same file works both as a fetched remote module and as a
stand-alone CMake project.  In an in-tree ingested module
ITK_SOURCE_DIR is always defined, so the if-branch is dead code;
@dzenanz flagged it on PR InsightSoftwareConsortium#6206 (IOMeshSTL).

Add patch_standalone_build_guard() that detects the idiom (allowing
2- or 4-space indent variants) and replaces it with a bare
itk_module_impl() before gersemi formatting runs.  Track count via
sanitizer.standalone_guard_patches and print it in the run summary.
The 'Greptile post-ingest patterns' table mixed mechanical artifacts
(strippable in Phase A) with semantic concerns (require human
judgment).  Split into two sections so the operator's checklist
shrinks as the sanitizer learns more rules.

Promote .ExternalData_* and the standalone-build CMake guard to the
auto-sanitized table now that the previous two commits handle them.
hjmjohnson added 4 commits May 5, 2026 08:45
Upstream remote modules typically begin their top-level CMakeLists.txt
with their own cmake_minimum_required(VERSION X.Y.Z) declaration, often
3.10.2 or earlier.  ITK's top-level CMakeLists pins a higher minimum,
so the per-module line is redundant and frequently *lower* than ITK's
floor.  @dzenanz flagged it on every ingest with the comment 'Version
behind, not needed.' — most recently on PR InsightSoftwareConsortium#6215 (IOFDF).

Add patch_drop_cmake_minimum_required() that detects the idiom and
removes the matching line via a multiline regex.  Track count via
sanitizer.cmake_min_required_drops and print it in the run summary.
Apply alongside patch_standalone_build_guard() in the cmake-blob
branch of blob_callback.
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 5, 2026
….txt

In-tree, ITK's top-level CMakeLists pins the CMake minimum, so the
per-module declaration is dead code.  Pre-emptive cleanup matching the
v4 ingest-pipeline rule codified in PR InsightSoftwareConsortium#6204
(sanitize-history.py:patch_drop_cmake_minimum_required).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 5, 2026
…mage

In-tree, ITK_SOURCE_DIR is always defined and ITK's top-level
CMakeLists pins the CMake minimum version.  The per-module
cmake_minimum_required line and if(NOT ITK_SOURCE_DIR) ... else()
itk_module_impl() endif() guard are dead code.  Pre-emptive cleanup
matching the v4 ingest-pipeline rules codified in PR InsightSoftwareConsortium#6204
(sanitize-history.py:patch_drop_cmake_minimum_required and
:patch_standalone_build_guard).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 5, 2026
In-tree, ITK's top-level CMakeLists pins the CMake minimum, so the
per-module declaration is dead code.  Matches the v4 ingest-pipeline
rule in PR InsightSoftwareConsortium#6204 (sanitize-history.py:patch_drop_cmake_minimum_required).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 5, 2026
In-tree, ITK's top-level CMakeLists pins the CMake minimum, so the
per-module declaration is dead code.  Matches the v4 ingest-pipeline
rule in PR InsightSoftwareConsortium#6204 (sanitize-history.py:patch_drop_cmake_minimum_required).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 5, 2026
…shMZ3

In-tree, ITK_SOURCE_DIR is always defined and ITK's top-level
CMakeLists pins the CMake minimum version.  The per-module
cmake_minimum_required line and if(NOT ITK_SOURCE_DIR) ... else()
itk_module_impl() endif() guard are dead code.  The 'set(ITK_DIR
${CMAKE_BINARY_DIR})' line that was inside the in-tree else branch
is preserved (now unconditional) since it actually had effect during
the in-tree build path.  Matches the v4 ingest-pipeline rules in
PR InsightSoftwareConsortium#6204 (sanitize-history.py:patch_drop_cmake_minimum_required and
:patch_standalone_build_guard).
@hjmjohnson hjmjohnson added this to the ITK 6.0 Release Candidate 1 milestone May 5, 2026
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 5, 2026
…shMZ3

In-tree, ITK_SOURCE_DIR is always defined and ITK's top-level
CMakeLists pins the CMake minimum version.  The per-module
cmake_minimum_required line and if(NOT ITK_SOURCE_DIR) ... else()
itk_module_impl() endif() guard are dead code.  The 'set(ITK_DIR
${CMAKE_BINARY_DIR})' line that was inside the in-tree else branch
is preserved (now unconditional) since it actually had effect during
the in-tree build path.  Matches the v4 ingest-pipeline rules in
PR InsightSoftwareConsortium#6204 (sanitize-history.py:patch_drop_cmake_minimum_required and
:patch_standalone_build_guard).
hjmjohnson added a commit that referenced this pull request May 5, 2026
Four already-merged remote-module ingests still carry their
upstream-original boilerplate at the top of their module CMakeLists:

  - cmake_minimum_required(VERSION X.Y.Z) — redundant; ITK's top-level
    CMakeLists pins a higher minimum.
  - if(NOT ITK_SOURCE_DIR) ... find_package(ITK) ... else()
    itk_module_impl() endif() — dead code in-tree because
    ITK_SOURCE_DIR is always defined.

Strip both from:

  Modules/Filtering/AnisotropicDiffusionLBR
  Modules/Filtering/Cuberille
  Modules/Filtering/LabelErodeDilate
  Modules/Registration/Montage

Lines that had effect inside the in-tree else() branch
(set(ITK_DIR ${CMAKE_BINARY_DIR}) on AnisotropicDiffusionLBR and
Montage) are preserved unconditionally.

The other four merged ingests (GenericLabelInterpolator, MGHIO,
FastBilateral, MeshNoise) were already cleaned up during their
respective ingest PRs.

Matches the v4 ingest-pipeline rules now codified in PR #6204
(sanitize-history.py:patch_drop_cmake_minimum_required and
:patch_standalone_build_guard); future ingests will not introduce
this idiom.
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 5, 2026
…mage

In-tree, ITK_SOURCE_DIR is always defined and ITK's top-level
CMakeLists pins the CMake minimum version.  The per-module
cmake_minimum_required line and if(NOT ITK_SOURCE_DIR) ... else()
itk_module_impl() endif() guard are dead code.  Pre-emptive cleanup
matching the v4 ingest-pipeline rules codified in PR InsightSoftwareConsortium#6204
(sanitize-history.py:patch_drop_cmake_minimum_required and
:patch_standalone_build_guard).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 5, 2026
…mage

In-tree, ITK_SOURCE_DIR is always defined and ITK's top-level
CMakeLists pins the CMake minimum version.  The per-module
cmake_minimum_required line and if(NOT ITK_SOURCE_DIR) ... else()
itk_module_impl() endif() guard are dead code.  Pre-emptive cleanup
matching the v4 ingest-pipeline rules codified in PR InsightSoftwareConsortium#6204
(sanitize-history.py:patch_drop_cmake_minimum_required and
:patch_standalone_build_guard).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 5, 2026
In-tree, ITK's top-level CMakeLists pins the CMake minimum, so the
per-module declaration is dead code.  Matches the v4 ingest-pipeline
rule in PR InsightSoftwareConsortium#6204 (sanitize-history.py:patch_drop_cmake_minimum_required).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 6, 2026
In-tree, ITK's top-level CMakeLists pins the CMake minimum, so the
per-module declaration is dead code.  Matches the v4 ingest-pipeline
rule in PR InsightSoftwareConsortium#6204 (sanitize-history.py:patch_drop_cmake_minimum_required).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 6, 2026
Four already-merged remote-module ingests still carry their
upstream-original boilerplate at the top of their module CMakeLists:

  - cmake_minimum_required(VERSION X.Y.Z) — redundant; ITK's top-level
    CMakeLists pins a higher minimum.
  - if(NOT ITK_SOURCE_DIR) ... find_package(ITK) ... else()
    itk_module_impl() endif() — dead code in-tree because
    ITK_SOURCE_DIR is always defined.

Strip both from:

  Modules/Filtering/AnisotropicDiffusionLBR
  Modules/Filtering/Cuberille
  Modules/Filtering/LabelErodeDilate
  Modules/Registration/Montage

Lines that had effect inside the in-tree else() branch
(set(ITK_DIR ${CMAKE_BINARY_DIR}) on AnisotropicDiffusionLBR and
Montage) are preserved unconditionally.

The other four merged ingests (GenericLabelInterpolator, MGHIO,
FastBilateral, MeshNoise) were already cleaned up during their
respective ingest PRs.

Matches the v4 ingest-pipeline rules now codified in PR InsightSoftwareConsortium#6204
(sanitize-history.py:patch_drop_cmake_minimum_required and
:patch_standalone_build_guard); future ingests will not introduce
this idiom.
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 6, 2026
….txt

In-tree, ITK's top-level CMakeLists pins the CMake minimum, so the
per-module declaration is dead code.  Pre-emptive cleanup matching the
v4 ingest-pipeline rule codified in PR InsightSoftwareConsortium#6204
(sanitize-history.py:patch_drop_cmake_minimum_required).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 6, 2026
…shMZ3

In-tree, ITK_SOURCE_DIR is always defined and ITK's top-level
CMakeLists pins the CMake minimum version.  The per-module
cmake_minimum_required line and if(NOT ITK_SOURCE_DIR) ... else()
itk_module_impl() endif() guard are dead code.  The 'set(ITK_DIR
${CMAKE_BINARY_DIR})' line that was inside the in-tree else branch
is preserved (now unconditional) since it actually had effect during
the in-tree build path.  Matches the v4 ingest-pipeline rules in
PR InsightSoftwareConsortium#6204 (sanitize-history.py:patch_drop_cmake_minimum_required and
:patch_standalone_build_guard).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 6, 2026
…mage

In-tree, ITK_SOURCE_DIR is always defined and ITK's top-level
CMakeLists pins the CMake minimum version.  The per-module
cmake_minimum_required line and if(NOT ITK_SOURCE_DIR) ... else()
itk_module_impl() endif() guard are dead code.  Pre-emptive cleanup
matching the v4 ingest-pipeline rules codified in PR InsightSoftwareConsortium#6204
(sanitize-history.py:patch_drop_cmake_minimum_required and
:patch_standalone_build_guard).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 6, 2026
In-tree, ITK's top-level CMakeLists pins the CMake minimum, so the
per-module declaration is dead code.  Matches the v4 ingest-pipeline
rule in PR InsightSoftwareConsortium#6204 (sanitize-history.py:patch_drop_cmake_minimum_required).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 6, 2026
In-tree, ITK's top-level CMakeLists pins the CMake minimum, so the
per-module declaration is dead code.  Matches the v4 ingest-pipeline
rule in PR InsightSoftwareConsortium#6204 (sanitize-history.py:patch_drop_cmake_minimum_required).
…cmake

Archival README.md files contain semicolons and bracket characters.
CMake's foreach(arg \${ARGN}) splits on semicolons, so reading them
into a DESCRIPTION argument produces CMake (dev) configure warnings
for every module ingested via v4 (observed: RLEImage, SplitComponents,
IOFDF, IOMeshMZ3, IOMeshSTL).

Add patch_dynamic_description() to sanitize-history.py to strip the
get_filename_component/file(READ README.md) preamble and replace
DESCRIPTION "\${DOCUMENTATION}" with a static one-liner during history
rewrite.  Document the pattern in INGESTION_STRATEGY_v4.md.
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 7, 2026
Many ITK remote modules' itk-module.cmake reads
  file(READ "${MY_CURRENT_DIR}/README.rst" DOCUMENTATION)
to populate the CMake DESCRIPTION variable from the upstream README.

The v4 whitelist intentionally excludes the upstream README (the
operator ships a new README.md as part of the ingest PR), so without
this rewrite every commit's CMakeLists fails to configure post-ingest
until the operator manually patches itk-module.cmake.

sanitize-history.py now rewrites the file(READ ... README.rst ...)
reference to README.md as part of the cmake-blob transform, so every
historical commit on the rewritten branch is independently buildable.

Surfaced on the IOMeshSTL ingest (PR following PR InsightSoftwareConsortium#6204).
Copy link
Copy Markdown
Member

@dzenanz dzenanz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is all in the maintenance directory, I believe we can accept it without really reviewing it.

hjmjohnson added a commit that referenced this pull request May 7, 2026
…shFilter

ENH: Ingest ITKSubdivisionQuadEdgeMeshFilter into Modules/Filtering (v4, stacks on #6204)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Python wrapping Python bindings for a class type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants