Skip to content

packOptions.filesIncluded is silently ignored for any path under a dot-prefixed directory #1855

Description

@radu-mocanu

What happens

packOptions.filesIncluded accepts a relative path so a file in a subdirectory can be added to the package. Any path under a dot-prefixed directory is dropped instead, and nothing reports it. The same applies to a dotfile named explicitly.

The spec describes filesIncluded as "Specific files to always include" (packOptions), and uipath pack exits successfully, so there is no signal that part of the configuration was ignored.

Reproduction

import os, tempfile
from uipath._cli._utils._project_files import files_to_include
from uipath._cli.models.uipath_json_schema import PackOptions

root = tempfile.mkdtemp()
os.makedirs(f"{root}/.config/assets/demo")
os.makedirs(f"{root}/plain")
open(f"{root}/.config/assets/demo/ASSET.md", "w").write("x")
open(f"{root}/plain/ASSET.md", "w").write("x")          # control, same shape without the dot
open(f"{root}/.python-version", "w").write("3.11")
open(f"{root}/pyproject.toml", "w").write("[project]")

opts = PackOptions(**{"filesIncluded": [
    ".config/assets/demo/ASSET.md",
    ".python-version",
    "plain/ASSET.md",
]})

included, skipped = files_to_include(opts, root, include_uv_lock=False)
print("included:", sorted(f.relative_path for f in included))
print("skipped :", skipped)

Output:

included: ['plain/ASSET.md', 'pyproject.toml']
skipped : []

plain/ASSET.md is honoured. .config/assets/demo/ASSET.md and .python-version are not, and skipped is empty.

Cause

Two unconditional filters run before the inclusion rules are evaluated.

_project_files.py:471 drops dot-prefixed directories from dirs[:], so os.walk never descends into them. Line 497 skips dot-prefixed files with a bare continue.

The per-file inclusion check that would honour the configuration is lines 514 to 520, and it already supports a path match for subdirectories. It is simply unreachable for these paths.

Because both filters continue rather than appending to skipped_files, the omission does not surface anywhere, including in the caller that reports skipped files.

Why it matters

Tooling configuration and assets conventionally live in a dot-prefixed directory. A project that needs such a directory inside its package has no way to express that: directoriesExcluded has no directoriesIncluded counterpart, and the documented per-file escape hatch does not work there.

The available workaround is to keep the content under a non-dot directory and copy it into place at runtime, which means the package layout no longer matches the source layout and the copy step has to be reimplemented per project.

Suggested fix

Any of these would resolve it, in rough order of smallest change:

  1. Honour an explicit filesIncluded entry regardless of a dot prefix. Descend into a dot-prefixed directory only when some filesIncluded entry has it as a path prefix, which keeps the current pruning fast for .git, .venv and similar. Apply the same to the dotfile filter at line 497. This matches the word "always" already in the spec.
  2. Add directoriesIncluded to packOptions as the counterpart to directoriesExcluded.

Independent of which is chosen, appending to skipped_files at both filters would turn a silent omission into something a caller can report.

Environment

  • uipath 2.14.2, resolved from PyPI
  • Python 3.14, macOS
  • Line numbers above are against main

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions