Skip to content

Refactor get_storage_path* functions#12906

Merged
stsewd merged 6 commits intomainfrom
refactor-get-storage-paths
Apr 9, 2026
Merged

Refactor get_storage_path* functions#12906
stsewd merged 6 commits intomainfrom
refactor-get-storage-paths

Conversation

@stsewd
Copy link
Copy Markdown
Member

@stsewd stsewd commented Mar 31, 2026

We were using Project.get_storage_path, which required to manually pass attributes from a version. Most of the time we already have a version object in place, so I "moved" the method to the Version class. The old method was also used to get file of a downloadable media type, I moved this to another method. Version.get_storage_path also accepts a filename, so we don't need to join the paths manually everytime we want to get the storage path from a file.

We also were setting a version_type attribute to force all storage calls to be external/internal, but we should make sure the version we are getting the file from matches the external domain it's served from, this check is already done by the unresolver. We also have tests for this already.

Project.get_storage_paths wasn't returning the paths used by PR previews, we were missing deleting those from storage when the project was deleted.

Ref #12899
Closes #10220

@read-the-docs-community
Copy link
Copy Markdown

read-the-docs-community bot commented Mar 31, 2026

Documentation build overview

📚 dev | 🛠️ Build #32081754 | 📁 Comparing 83411de against latest (b21b706)

  🔍 Preview build  

No files changed.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors storage path generation by moving responsibility from Project.get_storage_path(...) to new Version.get_storage_path(...) / Version.get_download_storage_path(...), and updates multiple call sites accordingly (including removing the proxito version_type override behavior).

Changes:

  • Remove Project.get_storage_path(...) and extend Project.get_storage_paths() to include external-version prefixes.
  • Add Version.get_storage_path(...) and Version.get_download_storage_path(...), and migrate storage path usage across build/search/embed/proxito code.
  • Update unit tests to use the new Version-based storage path APIs.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
readthedocs/search/parsers.py Use Version.get_storage_path for HTML page reads during indexing.
readthedocs/rtd_tests/tests/test_project.py Update storage-path tests to target Version methods and downloadable artifacts API.
readthedocs/proxito/views/serve.py Remove version_type forcing and switch custom 404 storage path building to Version.get_storage_path.
readthedocs/proxito/views/mixins.py Replace project-level storage path building with Version-based storage paths.
readthedocs/projects/tasks/search.py Use Version.get_storage_path as the root for walking HTML files.
readthedocs/projects/tasks/builds.py Use Version.get_storage_path for artifact sync and cleanup destinations.
readthedocs/projects/models.py Remove Project.get_storage_path and adjust get_storage_paths to include external prefixes.
readthedocs/filetreediff/init.py Use Version.get_storage_path for manifest read/write paths.
readthedocs/embed/v3/views.py Use Version.get_storage_path to read embedded content from storage.
readthedocs/builds/models.py Introduce Version.get_storage_path / get_download_storage_path implementations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@stsewd
Copy link
Copy Markdown
Member Author

stsewd commented Apr 1, 2026

@copilot make sure we have tests that cover the cases where a user tries to serve resources from internal versions from an external domain and the other way around as well. Check the same for downloads.

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 1, 2026

@copilot make sure we have tests that cover the cases where a user tries to serve resources from internal versions from an external domain and the other way around as well. Check the same for download...

The cross-domain tests were already present, but there was a critical bug: two methods in TestDocServingBackends shared the name test_download_files_from_external_version (lines 632 and 666). Python silently overwrites the first with the second, so the test covering "external version downloaded from main domain → 404" was dead code and never ran.

Fixed in commit 83411de:

  • Renamed the dead test to test_download_external_version_on_main_domain (external version slug on main domain → 404)
  • Renamed the misleadingly named test_download_files_from_external_version_from_main_domain to test_download_internal_version_on_external_domain (it was testing an internal version slug from an external domain, not the other way around)

All 4 cross-domain scenarios now have active, clearly-named tests:

  • Serve: test_serve_external_version_on_main_domain and test_serve_non_external_version_on_external_domain
  • Download: test_download_external_version_on_main_domain and test_download_internal_version_on_external_domain

@stsewd stsewd marked this pull request as ready for review April 1, 2026 22:06
@stsewd stsewd requested a review from a team as a code owner April 1, 2026 22:06
@stsewd stsewd requested a review from humitos April 1, 2026 22:06
@github-project-automation github-project-automation bot moved this to Planned in 📍Roadmap Apr 8, 2026
@stsewd stsewd moved this from Planned to Needs review in 📍Roadmap Apr 8, 2026
Copy link
Copy Markdown
Contributor

@agjohnson agjohnson left a comment

Choose a reason for hiding this comment

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

This looks great, the pattern is much nicer this way. I'm guessing the AWS policy code can use these pretty easily now as well.

# depth against serving the wrong version.
if unresolved_domain.is_from_external_domain:
self.version_type = EXTERNAL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How are these chunks able to be removed? I wasn't able to figure this out looking over this, I didn't see where we moved the logic to test the unresolved_domain.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The unresolver already makes sure that only external versions are resolved when working on an external domain.

manager = EXTERNAL if external_version_slug else INTERNAL
version = project.versions(manager=manager).filter(slug=version_slug).first()

We also have tests in place to verify this behavior #12906 (comment)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah gotcha, thanks. Yeah figured it was well tested, I just wasn't seeing it

@stsewd stsewd merged commit 79422ed into main Apr 9, 2026
10 checks passed
@stsewd stsewd deleted the refactor-get-storage-paths branch April 9, 2026 15:10
@github-project-automation github-project-automation bot moved this from Needs review to Done in 📍Roadmap Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Proxito: remove version_type

4 participants