Skip to content

docs: Add release notes for 3.6.9#91

Open
tomerqodo wants to merge 3 commits into
qodo_combined_100_qodo_grep_sentry_1_base_docs_add_release_notes_for_369_pr251from
qodo_combined_100_qodo_grep_sentry_1_head_docs_add_release_notes_for_369_pr251
Open

docs: Add release notes for 3.6.9#91
tomerqodo wants to merge 3 commits into
qodo_combined_100_qodo_grep_sentry_1_base_docs_add_release_notes_for_369_pr251from
qodo_combined_100_qodo_grep_sentry_1_head_docs_add_release_notes_for_369_pr251

Conversation

@tomerqodo
Copy link
Copy Markdown

Benchmark PR from qodo-benchmark#251

devin-ai-integration Bot and others added 3 commits December 31, 2025 21:58
Co-Authored-By: alex.s@prefect.io <ajstreed1@gmail.com>
Co-Authored-By: alex.s@prefect.io <ajstreed1@gmail.com>
@qodo-code-review
Copy link
Copy Markdown

Code Review by Qodo (Alpha)

🐞 Bugs (3) 📘 Rule Violations (1) 📎 Requirement Gaps (0) 💡 Suggestions (0)

Grey Divider


Action Required

1. `cachetools` mismatch across pyprojects 📘 Rule Violation
Description
• The root pyproject.toml updates the client dependency constraint for cachetools to <8.0, but
  the corresponding entry in client/pyproject.toml remains <7.0.
• This violates the requirement to keep client-side dependencies consistent across both pyproject
  files and can lead to mismatched builds or runtime behavior between the main project and the client
  package.

reliability

Code

pyproject.toml[46]

+    "cachetools>=5.3,<8.0",
Evidence
Compliance ID 10 requires any client dependency update in the root pyproject.toml to be mirrored
in client/pyproject.toml. The root file updates cachetools to <8.0, but the client file still
pins it to <7.0, creating an inconsistency.

AGENTS.md
pyproject.toml[42-47]
client/pyproject.toml[26-32]

Agent Prompt
## Issue description
The root `pyproject.toml` updates the client dependency constraint for `cachetools` to `&lt;8.0`, but `client/pyproject.toml` still constrains `cachetools` to `&lt;7.0`. This violates the repo requirement that client dependency updates be applied to both pyproject files.

## Issue Context
The root dependency list explicitly notes that changes must be mirrored in `client/pyproject.toml` to prevent mismatched client builds.

## Fix Focus Areas
- pyproject.toml[42-47]
- client/pyproject.toml[26-32]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. git_clone returns absolute path 🐞 Bug
Description
agit_clone/git_clone now return directory as an absolute path (Path.cwd()/…) instead of
  the previously returned relative directory name.
• Existing step tests assert the output is the relative directory ("repo"), so this is a breaking
  change to the step output contract.
• Absolute temp paths are also less usable for step-output templating because they vary by runtime
  environment.

correctness

Code

src/prefect/deployments/steps/pull.py[100]

+    return dict(directory=str(storage.destination))
Evidence
The pull step now returns str(storage.destination) (a path under Path.cwd()), while tests and
step behavior expect a relative directory name "repo".

src/prefect/deployments/steps/pull.py[88-101]
tests/deployment/test_steps.py[735-807]

Agent Prompt
## Issue description
`agit_clone` and `git_clone` changed their returned `directory` value from a relative directory (e.g. `repo`) to an absolute path (e.g. `/tmp/.../repo`). This breaks existing tests and makes step outputs non-portable for templating.

## Issue Context
The `GitRepository.destination` path is computed under a storage base path (defaulting to `Path.cwd()`); step outputs are used downstream (and in tests) as stable relative paths.

## Fix Focus Areas
- src/prefect/deployments/steps/pull.py[88-101]
- src/prefect/deployments/steps/pull.py[209-224]

## Suggested fix
- Restore relative return semantics:
 - Prefer `directory = str(storage.destination.relative_to(Path.cwd()))`
 - If `relative_to` raises (edge cases), fall back to `os.path.relpath(storage.destination, Path.cwd())` or finally the absolute path.
- Keep `pull_from_remote_storage` behavior unchanged (it already returns relative).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Async get_directory dereferences symlinks 🐞 Bug
Description
LocalFileSystem.aget_directory now calls shutil.copytree(..., symlinks=False), which
  dereferences symlinks (copies targets) instead of preserving links.
• This diverges from the sync implementation (get_directory uses symlinks=True) and from the
  documented/announced behavior to preserve symlinks.
• Following symlinks can unexpectedly pull in content outside the intended directory (and can expand
  large trees), making async vs sync behavior inconsistent.

security

Code

src/prefect/filesystems.py[R162-164]

        copytree(
-            from_path, local_path, dirs_exist_ok=True, ignore=ignore_func, symlinks=True
+            from_path, local_path, dirs_exist_ok=True, ignore=ignore_func, symlinks=False
        )
Evidence
The async implementation changed to symlinks=False while the sync implementation remains
symlinks=True. Repo release notes state symlinks should be preserved, and other repository copying
code/tests explicitly validate symlink preservation.

src/prefect/filesystems.py[130-165]
src/prefect/filesystems.py[167-210]
docs/v3/release-notes/oss/version-3-6.mdx[19-23]
src/integrations/prefect-github/tests/test_repository.py[210-236]

Agent Prompt
## Issue description
`LocalFileSystem.aget_directory` switched to `shutil.copytree(..., symlinks=False)` which dereferences symlinks. This conflicts with the sync implementation (`symlinks=True`) and the documented expectation to preserve symlinks.

## Issue Context
`LocalFileSystem.get_directory` is decorated with `@async_dispatch(aget_directory)` and will use `aget_directory` when called from async contexts, so this impacts common runtime paths.

## Fix Focus Areas
- src/prefect/filesystems.py[130-165]
- src/prefect/filesystems.py[167-210]

## Suggested fix
- Change async `copytree(... symlinks=False)` to `symlinks=True` to preserve symlinks.
- Consider adding/adjusting tests for LocalFileSystem symlink handling in async context to prevent regressions.
- Ensure both implementations use the same symlink behavior.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation Recommended

4. to_pull_step forces clone name 🐞 Bug
Description
GitRepository.to_pull_step() now always emits clone_directory_name, even when the name is just
  the auto-inferred default.
• This prevents the pull step from using its documented inference behavior (“if not provided, infer
  from repository URL and branch”) and breaks existing tests that expect omission when using defaults.
• The implementation currently cannot distinguish between an explicitly provided name and an
  inferred default, so the current fix likely overshoots and changes generated prefect.yaml
  semantics.

correctness

Code

src/prefect/runner/storage.py[R503-507]

            "prefect.deployments.steps.git_clone": {
                "repository": self._url,
                "branch": self._branch,
+                "clone_directory_name": self._name,
            }
Evidence
GitRepository.__init__ overwrites _name with name or default_name, losing whether the name was
user-specified. to_pull_step now always outputs clone_directory_name, contradicting docs/tests
that expect omission when using inferred defaults.

src/prefect/runner/storage.py[178-189]
src/prefect/runner/storage.py[501-508]
src/prefect/deployments/steps/pull.py[70-74]
tests/runner/test_storage.py[962-980]

Agent Prompt
## Issue description
`GitRepository.to_pull_step()` always includes `clone_directory_name`, even when the name is just the inferred default. This contradicts the documented behavior of `git_clone` (infer name when not provided) and breaks tests expecting omission for default names.

## Issue Context
`GitRepository.__init__` currently sets `self._name = name or default_name`, losing whether `name` was explicitly passed. Fixing “name preservation” should not require always emitting `clone_directory_name` for inferred defaults.

## Fix Focus Areas
- src/prefect/runner/storage.py[149-190]
- src/prefect/runner/storage.py[501-544]

## Suggested fix
- Add an internal flag, e.g. `self._name_was_provided = name is not None`.
- Keep `self._name = name or default_name` for destination computation.
- In `to_pull_step`, include `clone_directory_name` only when `self._name_was_provided` is True (or equivalently retain the previous “omit when equals default_name” behavior).
- Update/restore the existing tests in `tests/runner/test_storage.py` accordingly (they currently assert omission for default names).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread pyproject.toml
"anyio>=4.4.0,<5.0.0",
"asgi-lifespan>=1.0,<3.0",
"cachetools>=5.3,<7.0",
"cachetools>=5.3,<8.0",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action Required

1. cachetools mismatch across pyprojects 📘 Rule Violation

• The root pyproject.toml updates the client dependency constraint for cachetools to <8.0, but
  the corresponding entry in client/pyproject.toml remains <7.0.
• This violates the requirement to keep client-side dependencies consistent across both pyproject
  files and can lead to mismatched builds or runtime behavior between the main project and the client
  package.
Agent Prompt
## Issue description
The root `pyproject.toml` updates the client dependency constraint for `cachetools` to `<8.0`, but `client/pyproject.toml` still constrains `cachetools` to `<7.0`. This violates the repo requirement that client dependency updates be applied to both pyproject files.

## Issue Context
The root dependency list explicitly notes that changes must be mirrored in `client/pyproject.toml` to prevent mismatched client builds.

## Fix Focus Areas
- pyproject.toml[42-47]
- client/pyproject.toml[26-32]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

await _pull_git_repository_with_retries(storage)

return dict(directory=str(storage.destination.relative_to(Path.cwd())))
return dict(directory=str(storage.destination))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action Required

2. Git_clone returns absolute path 🐞 Bug

agit_clone/git_clone now return directory as an absolute path (Path.cwd()/…) instead of
  the previously returned relative directory name.
• Existing step tests assert the output is the relative directory ("repo"), so this is a breaking
  change to the step output contract.
• Absolute temp paths are also less usable for step-output templating because they vary by runtime
  environment.
Agent Prompt
## Issue description
`agit_clone` and `git_clone` changed their returned `directory` value from a relative directory (e.g. `repo`) to an absolute path (e.g. `/tmp/.../repo`). This breaks existing tests and makes step outputs non-portable for templating.

## Issue Context
The `GitRepository.destination` path is computed under a storage base path (defaulting to `Path.cwd()`); step outputs are used downstream (and in tests) as stable relative paths.

## Fix Focus Areas
- src/prefect/deployments/steps/pull.py[88-101]
- src/prefect/deployments/steps/pull.py[209-224]

## Suggested fix
- Restore relative return semantics:
  - Prefer `directory = str(storage.destination.relative_to(Path.cwd()))`
  - If `relative_to` raises (edge cases), fall back to `os.path.relpath(storage.destination, Path.cwd())` or finally the absolute path.
- Keep `pull_from_remote_storage` behavior unchanged (it already returns relative).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines 162 to 164
copytree(
from_path, local_path, dirs_exist_ok=True, ignore=ignore_func, symlinks=True
from_path, local_path, dirs_exist_ok=True, ignore=ignore_func, symlinks=False
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action Required

3. Async get_directory dereferences symlinks 🐞 Bug

LocalFileSystem.aget_directory now calls shutil.copytree(..., symlinks=False), which
  dereferences symlinks (copies targets) instead of preserving links.
• This diverges from the sync implementation (get_directory uses symlinks=True) and from the
  documented/announced behavior to preserve symlinks.
• Following symlinks can unexpectedly pull in content outside the intended directory (and can expand
  large trees), making async vs sync behavior inconsistent.
Agent Prompt
## Issue description
`LocalFileSystem.aget_directory` switched to `shutil.copytree(..., symlinks=False)` which dereferences symlinks. This conflicts with the sync implementation (`symlinks=True`) and the documented expectation to preserve symlinks.

## Issue Context
`LocalFileSystem.get_directory` is decorated with `@async_dispatch(aget_directory)` and will use `aget_directory` when called from async contexts, so this impacts common runtime paths.

## Fix Focus Areas
- src/prefect/filesystems.py[130-165]
- src/prefect/filesystems.py[167-210]

## Suggested fix
- Change async `copytree(... symlinks=False)` to `symlinks=True` to preserve symlinks.
- Consider adding/adjusting tests for LocalFileSystem symlink handling in async context to prevent regressions.
- Ensure both implementations use the same symlink behavior.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines 503 to 507
"prefect.deployments.steps.git_clone": {
"repository": self._url,
"branch": self._branch,
"clone_directory_name": self._name,
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation Recommended

4. To_pull_step forces clone name 🐞 Bug

GitRepository.to_pull_step() now always emits clone_directory_name, even when the name is just
  the auto-inferred default.
• This prevents the pull step from using its documented inference behavior (“if not provided, infer
  from repository URL and branch”) and breaks existing tests that expect omission when using defaults.
• The implementation currently cannot distinguish between an explicitly provided name and an
  inferred default, so the current fix likely overshoots and changes generated prefect.yaml
  semantics.
Agent Prompt
## Issue description
`GitRepository.to_pull_step()` always includes `clone_directory_name`, even when the name is just the inferred default. This contradicts the documented behavior of `git_clone` (infer name when not provided) and breaks tests expecting omission for default names.

## Issue Context
`GitRepository.__init__` currently sets `self._name = name or default_name`, losing whether `name` was explicitly passed. Fixing “name preservation” should not require always emitting `clone_directory_name` for inferred defaults.

## Fix Focus Areas
- src/prefect/runner/storage.py[149-190]
- src/prefect/runner/storage.py[501-544]

## Suggested fix
- Add an internal flag, e.g. `self._name_was_provided = name is not None`.
- Keep `self._name = name or default_name` for destination computation.
- In `to_pull_step`, include `clone_directory_name` only when `self._name_was_provided` is True (or equivalently retain the previous “omit when equals default_name” behavior).
- Update/restore the existing tests in `tests/runner/test_storage.py` accordingly (they currently assert omission for default names).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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.

1 participant