feat(extensions): support .extensionignore to exclude files during install#1781
feat(extensions): support .extensionignore to exclude files during install#1781Rubiss wants to merge 2 commits intogithub:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds .extensionignore support to the extension installation pipeline, letting extension authors exclude development-only files (tests, CI configs, docs source, build artifacts) from being copied when users run specify extension add. The feature is analogous to .gitignore and is integrated into ExtensionManager.install_from_directory() via a new _load_extensionignore() static method.
Changes:
- Added
_load_extensionignore()static method toExtensionManagerand wired it intoinstall_from_directory()viashutil.copytree(ignore=…) - Added 6 new test cases in
TestExtensionIgnorecovering all documented scenarios - Added documentation section in
EXTENSION-DEVELOPMENT-GUIDE.mdand bumped version to 0.1.14
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/extensions.py |
New _load_extensionignore() static method; integrates ignore function into install_from_directory(); adds Callable/Set and fnmatch imports |
tests/test_extensions.py |
6 new tests in TestExtensionIgnore class covering all pattern-matching scenarios |
extensions/EXTENSION-DEVELOPMENT-GUIDE.md |
New "Excluding Files with .extensionignore" section with format description, example, and pattern table |
CHANGELOG.md |
New 0.1.14 entry documenting the feature |
pyproject.toml |
Version bump from 0.1.13 to 0.1.14 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
0a00c97 to
5245079
Compare
5245079 to
868d608
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
mnriem
left a comment
There was a problem hiding this comment.
I will approve, but consider the things below
-
fnmatch≠.gitignoresemantics (documentation bug)
The docs and PR description claim "similar to.gitignoresyntax," butfnmatch.fnmatch()treats*as matching any character including path separators. In.gitignore,*does not cross directory boundaries. The documentation table saysdocs/*.draft.mdmatches "Draft markdown files insidedocs/", butfnmatchwould also matchdocs/sub/api.draft.md. This needs to either:- Switch to
pathlib.PurePath.match()orfnmatchwith per-segment matching to get proper gitignore-like behavior, or - Remove all
.gitignorecomparisons from the docs and clearly document that*matches across directories.
- Switch to
-
No support for negation (
!) or**patterns
Not a blocker since these aren't claimed, but the.gitignoreanalogy sets expectations. At minimum, the docs should state what's not supported. -
Missing edge-case tests:
- Pattern with
..(e.g.,../sibling/) — should be a no-op or explicitly rejected - Absolute path patterns (e.g.,
/etc/passwd) — verify they don't match anything - Empty
.extensionignorefile (no patterns, just the file itself) - Patterns with Windows-style backslashes
- Pattern with
-
Minor: forward-slash normalization is one-directional
The code doesrel_path_fwd = rel_path.replace("\\", "/")but doesn't normalize the patterns themselves. A user on Windows writingdocs\internal\draft.mdin their.extensionignorewould get inconsistent behavior.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
No need to approve yet, these seem like all valid concerns that I will address. Thanks for the feedback. Personally, I think it should work consistently like .gitignore does since generally people are very familiar with the concept. |
…stall Add .extensionignore support so extension authors can exclude files and folders from being copied when users run 'specify extension add'. The file uses glob-style patterns (one per line), supports comments (#), blank lines, trailing-slash directory patterns, and relative path matching. The .extensionignore file itself is always excluded from the copy. - Add _load_extensionignore() to ExtensionManager - Integrate ignore function into shutil.copytree in install_from_directory - Document .extensionignore in EXTENSION-DEVELOPMENT-GUIDE.md - Add 6 tests covering all pattern matching scenarios - Bump version to 0.1.14
868d608 to
bcc8f30
Compare
…re matching Replace fnmatch with pathspec.GitIgnoreSpec to get proper .gitignore semantics where * does not cross directory boundaries. This addresses review feedback on github#1781. Changes: - Switch from fnmatch to pathspec>=0.12.0 (GitIgnoreSpec.from_lines) - Normalize backslashes in patterns for cross-platform compatibility - Distinguish directories from files for trailing-slash patterns - Update docs to accurately describe supported pattern semantics - Add edge-case tests: .., absolute paths, empty file, backslashes, * vs ** boundary behavior, and ! negation - Move changelog entry to [Unreleased] section
Thanks for the feedback. I have updated .extensionignore implementation to match familiar .gitignore patterns with a callout of what is not supported. Let me know what you think. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…re matching Replace fnmatch with pathspec.GitIgnoreSpec to get proper .gitignore semantics where * does not cross directory boundaries. This addresses review feedback on github#1781. Changes: - Switch from fnmatch to pathspec>=0.12.0 (GitIgnoreSpec.from_lines) - Normalize backslashes in patterns for cross-platform compatibility - Distinguish directories from files for trailing-slash patterns - Update docs to accurately describe supported pattern semantics - Add edge-case tests: .., absolute paths, empty file, backslashes, * vs ** boundary behavior, and ! negation - Move changelog entry to [Unreleased] section
13c25bc to
cdb4a0c
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
Adds
.extensionignoresupport so extension authors can exclude files and folders from being copied when users runspecify extension add.Problem
Extension authors often have development-only files (tests, CI configs, documentation source, build artifacts) that shouldn't be copied into the user's project when installing an extension. There was no mechanism to exclude these files.
Solution
Extension authors can now create a
.extensionignorefile in their extension root. The file uses.gitignore-compatible patterns (one per line), powered by thepathspeclibrary:Features
.gitignore-compatible pattern matching viapathspec.GitIgnoreSpec*matches anything except/;**matches zero or more directories?matches any single character except//on directory patterns restricts matching to directories only/(other than trailing) are anchored to the extension root!negates a previously excluded pattern (re-includes a file)#) and blank lines are ignored.extensionignorefile itself is always excluded from the copyChanges
_load_extensionignore()static method and integrated it intoinstall_from_directory()viashutil.copytree(ignore=...).extensionignoreformat, example patterns, and a pattern-matching reference tableTestExtensionIgnorecovering all pattern matching scenariospathspec>=0.12.0dependency[Unreleased]entry for this featureTesting
All 152 passing tests continue to pass (4 pre-existing failures in
test_cursor_frontmatter.pyare unrelated — bash/WSL not available on Windows). New tests cover:.extensionignore→ all files copied (baseline)tests/,.github/)*.pyc) across nested directories.extensionignoreitself never copied..traversal patterns are a no-op (security).extensionignorefile*does not cross directory boundaries**crosses directory boundaries!negation re-includes previously excluded filesAI Disclosure
This PR was authored with GitHub Copilot assistance.