This is an automated email from the ASF dual-hosted git repository.
sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
The following commit(s) were added to refs/heads/main by this push:
new 48cdb79 Unify the release file viewing mechanisms
48cdb79 is described below
commit 48cdb7961e0b435a11430537de0423fac0fc350e
Author: Sean B. Palmer <[email protected]>
AuthorDate: Sun Nov 16 16:27:34 2025 +0000
Unify the release file viewing mechanisms
---
atr/construct.py | 4 +-
atr/get/candidate.py | 73 --------
atr/get/draft.py | 33 ----
atr/get/file.py | 220 ++++++++++++++++++++++---
atr/get/finish.py | 4 +-
atr/get/preview.py | 178 --------------------
atr/get/projects.py | 13 +-
atr/get/release.py | 57 -------
atr/post/announce.py | 2 +-
atr/templates/check-selected-release-info.html | 2 +-
atr/templates/phase-view.html | 136 ---------------
atr/templates/releases-finished.html | 2 +-
12 files changed, 205 insertions(+), 519 deletions(-)
diff --git a/atr/construct.py b/atr/construct.py
index 2ed558e..78dd112 100644
--- a/atr/construct.py
+++ b/atr/construct.py
@@ -66,9 +66,9 @@ async def announce_release_body(body: str, options:
AnnounceReleaseOptions) -> s
raise RuntimeError(f"Release {options.project_name}
{options.version_name} has no committee")
committee = release.committee
- routes_release_view = get.release.view # type: ignore[has-type]
+ routes_file_selected = get.file.selected
download_path = util.as_url(
- routes_release_view, project_name=options.project_name,
version_name=options.version_name
+ routes_file_selected, project_name=options.project_name,
version_name=options.version_name
)
# TODO: This download_url should probably be for the proxy download
directory, not the ATR view
download_url = f"https://{host}{download_path}"
diff --git a/atr/get/candidate.py b/atr/get/candidate.py
index dcce63c..d57f756 100644
--- a/atr/get/candidate.py
+++ b/atr/get/candidate.py
@@ -16,76 +16,3 @@
# under the License.
"""candidate.py"""
-
-import asfquart.base as base
-
-import atr.blueprints.get as get
-import atr.db as db
-import atr.log as log
-import atr.models.sql as sql
-import atr.template as template
-import atr.util as util
-import atr.web as web
-
-
[email protected]("/candidate/view/<project_name>/<version_name>")
-async def view(session: web.Committer, project_name: str, version_name: str)
-> web.WerkzeugResponse | str:
- """View all the files in the rsync upload directory for a release."""
- await session.check_access(project_name)
-
- # Check that the release exists
- async with db.session() as data:
- release = await data.release(name=sql.release_name(project_name,
version_name), _project=True).demand(
- base.ASFQuartException("Release does not exist", errorcode=404)
- )
-
- # Convert async generator to list
- file_stats = [
- stat
- async for stat in util.content_list(
- util.get_unfinished_dir(), project_name, version_name,
release.unwrap_revision_number
- )
- ]
- # Sort the files by FileStat.path
- file_stats.sort(key=lambda fs: fs.path)
- log.debug(f"File stats: {file_stats}")
-
- return await template.render(
- # TODO: Move to somewhere appropriate
- "phase-view.html",
- file_stats=file_stats,
- release=release,
- format_datetime=util.format_datetime,
- format_file_size=util.format_file_size,
- format_permissions=util.format_permissions,
- phase="release candidate",
- phase_key="candidate",
- )
-
-
[email protected]("/candidate/view/<project_name>/<version_name>/<path:file_path>")
-async def view_path(
- session: web.Committer, project_name: str, version_name: str, file_path:
str
-) -> web.WerkzeugResponse | str:
- """View the content of a specific file in the release candidate."""
- await session.check_access(project_name)
-
- release = await session.release(project_name, version_name,
phase=sql.ReleasePhase.RELEASE_CANDIDATE)
- _max_view_size = 1 * 1024 * 1024
- full_path = util.release_directory(release) / file_path
- content_listing = await util.archive_listing(full_path)
- content, is_text, is_truncated, error_message = await
util.read_file_for_viewer(full_path, _max_view_size)
- return await template.render(
- "file-selected-path.html",
- release=release,
- project_name=project_name,
- version_name=version_name,
- file_path=file_path,
- content=content,
- is_text=is_text,
- is_truncated=is_truncated,
- error_message=error_message,
- format_file_size=util.format_file_size,
- phase_key="candidate",
- content_listing=content_listing,
- )
diff --git a/atr/get/draft.py b/atr/get/draft.py
index daa028a..2383972 100644
--- a/atr/get/draft.py
+++ b/atr/get/draft.py
@@ -62,36 +62,3 @@ async def tools(session: web.Committer, project_name: str,
version_name: str, fi
format_file_size=util.format_file_size,
empty_form=await forms.Empty.create_form(),
)
-
-
-# TODO: Should we deprecate this and ensure compose covers it all?
-# If we did that, we'd lose the exhaustive use of the abstraction
[email protected]("/draft/view/<project_name>/<version_name>")
-async def view(session: web.Committer, project_name: str, version_name: str)
-> web.WerkzeugResponse | str:
- """View all the files in the rsync upload directory for a release."""
- await session.check_access(project_name)
-
- release = await session.release(project_name, version_name)
-
- # Convert async generator to list
- revision_number = release.latest_revision_number
- file_stats = []
- if revision_number is not None:
- file_stats = [
- stat
- async for stat in util.content_list(util.get_unfinished_dir(),
project_name, version_name, revision_number)
- ]
- # Sort the files by FileStat.path
- file_stats.sort(key=lambda fs: fs.path)
-
- return await template.render(
- # TODO: Move to somewhere appropriate
- "phase-view.html",
- file_stats=file_stats,
- release=release,
- format_datetime=util.format_datetime,
- format_file_size=util.format_file_size,
- format_permissions=util.format_permissions,
- phase="release candidate draft",
- phase_key="draft",
- )
diff --git a/atr/get/file.py b/atr/get/file.py
index c8ccd79..fcbc758 100644
--- a/atr/get/file.py
+++ b/atr/get/file.py
@@ -15,44 +15,210 @@
# specific language governing permissions and limitations
# under the License.
+from typing import Literal
import atr.blueprints.get as get
+import atr.get.compose as compose
+import atr.get.finish as finish
+import atr.get.vote as vote
+import atr.htm as htm
+import atr.models.sql as sql
+import atr.shared.distribution as distribution
import atr.template as template
import atr.util as util
import atr.web as web
+type Phase = Literal["COMPOSE", "VOTE", "FINISH"]
[email protected]("/file/<project_name>/<version_name>/<path:file_path>")
-async def selected_path(
- session: web.Committer, project_name: str, version_name: str, file_path:
str
-) -> web.WerkzeugResponse | str:
- """View the content of a specific file in the release candidate draft."""
- # TODO: Make this independent of the release phase
+
[email protected]("/file/<project_name>/<version_name>")
+async def selected(session: web.Committer, project_name: str, version_name:
str) -> str:
+ """View all the files in a release (any phase)."""
await session.check_access(project_name)
- release = await session.release(project_name, version_name)
+ release = await session.release(project_name, version_name, phase=None)
- # Limit to 256 KiB
- _max_view_size = 256 * 1024
- full_path = util.release_directory(release) / file_path
+ revision_number = release.latest_revision_number
+ file_stats = []
+ if revision_number is not None:
+ if release.phase == sql.ReleasePhase.RELEASE:
+ file_stats = [stat async for stat in
util.content_list(util.get_finished_dir(), project_name, version_name)]
+ else:
+ file_stats = [
+ stat
+ async for stat in util.content_list(
+ util.get_unfinished_dir(), project_name, version_name,
revision_number
+ )
+ ]
+ file_stats.sort(key=lambda fs: fs.path)
- # Attempt to get an archive listing
- # This will be None if the file is not an archive
- content_listing = await util.archive_listing(full_path)
+ block = htm.Block()
+
+ nav_info = _get_navigation_info(release)
+ if nav_info:
+ back_url, back_label, phase_label = nav_info
+ distribution.html_nav(block, back_url, back_label, phase_label)
+
+ block.h1["Files in ", htm.strong[release.project.short_display_name], " ",
htm.em[release.version]]
+
+ block.div(".card.mb-4")[
+
htm.div(".card-header.d-flex.justify-content-between.align-items-center")[
+ htm.h3(".mb-0")["Release information"]
+ ],
+ htm.div(".card-body")[
+ htm.div(".row")[
+ htm.div(".col-md-6")[
+ htm.p[htm.strong["Project:"], " ",
release.project.display_name],
+ htm.p[htm.strong["Label:"], " ", release.name],
+ ],
+ htm.div(".col-md-6")[htm.p[htm.strong["Created:"], " ",
release.created.strftime("%Y-%m-%d %H:%M:%S")]],
+ ]
+ ],
+ ]
+
+ files_card = htm.Block(htm.div, classes=".card.mb-4")
+
files_card.div(".card-header.d-flex.justify-content-between.align-items-center")[htm.h3(".mb-0")["Files"]]
+
+ if file_stats:
+ tbody = htm.Block(htm.tbody)
+ for stat in file_stats:
+ if stat.is_file:
+ file_url = util.as_url(
+ selected_path,
+ project_name=release.project.name,
+ version_name=release.version,
+ file_path=stat.path,
+ )
+ file_link = htm.a(href=file_url)[stat.path]
+ else:
+ file_link = htm.strong[stat.path + "/"]
+
+ tbody.tr[
+ htm.td[util.format_permissions(stat.permissions)],
+ htm.td[file_link],
+ htm.td[util.format_file_size(stat.size) if stat.is_file else
"-"],
+ htm.td[util.format_datetime(stat.modified)],
+ ]
+
+ files_card.div(".card-body")[
+ htm.div(".table-responsive")[
+ htm.table(".table.table-striped.table-hover")[
+ htm.thead[
+ htm.tr[
+ htm.th["Permissions"],
+ htm.th["File path"],
+ htm.th["Size"],
+ htm.th["Modified"],
+ ]
+ ],
+ tbody.collect(),
+ ]
+ ]
+ ]
+ else:
+ phase_name = _phase_display_name(release.phase)
+ files_card.div(".card-body")[htm.div(".alert.alert-info")[f"This
{phase_name} does not have any files."]]
+
+ block.append(files_card.collect())
+
+ return await template.blank(f"Files in {release.short_display_name}",
content=block.collect())
+
+
[email protected]("/file/<project_name>/<version_name>/<path:file_path>")
+async def selected_path(session: web.Committer, project_name: str,
version_name: str, file_path: str) -> str:
+ """View the content of a specific file in a release (any phase)."""
+ await session.check_access(project_name)
+ release = await session.release(project_name, version_name, phase=None)
+ _max_view_size = 512 * 1024
+ full_path = util.release_directory(release) / file_path
+ content_listing = await util.archive_listing(full_path)
content, is_text, is_truncated, error_message = await
util.read_file_for_viewer(full_path, _max_view_size)
- return await template.render(
- "file-selected-path.html",
- release=release,
- project_name=project_name,
- version_name=version_name,
- file_path=file_path,
- content=content,
- is_text=is_text,
- is_truncated=is_truncated,
- error_message=error_message,
- content_listing=content_listing,
- format_file_size=util.format_file_size,
- phase_key="draft",
- max_view_size=util.format_file_size(_max_view_size),
+
+ block = htm.Block()
+
+ back_url = util.as_url(selected, project_name=release.project.name,
version_name=release.version)
+ phase_name = _phase_display_name(release.phase)
+ block.a(href=back_url, class_="atr-back-link")[f"← Back to {phase_name}
files"]
+
+ block.div(".p-3.mt-4.mb-4.bg-light.border.rounded")[
+ htm.h2(".mt-0")[f"Viewing file: {file_path}"],
+ htm.p(".mb-0")[htm.strong["Release:"], " ", release.name],
+ ]
+
+ if content_listing:
+ items = [htm.li(".list-group-item.py-1.px-3.small")[item] for item in
content_listing]
+ block.div(".card.mb-3")[
+ htm.div(".card-header")[htm.h3(".mb-0")[f"Archive contents
({len(content_listing)})"]],
+
htm.div(".card-body.p-0")[htm.ul(".list-group.list-group-flush")[*items]],
+ ]
+
+ if error_message:
+ block.div(".alert.alert-danger")[error_message]
+ elif content is not None:
+ if content_listing:
+ details_block = htm.Block(htm.details, classes=".mb-3")
+ details_block.summary(".mb-2")["View raw file content"]
+ _render_file_content(details_block, content, is_text,
is_truncated, _max_view_size)
+ block.append(details_block.collect())
+ else:
+ _render_file_content(block, content, is_text, is_truncated,
_max_view_size)
+ else:
+ block.div(".alert.alert-secondary")["No content available for this
file."]
+
+ return await template.blank(
+ f"View
{release.project.short_display_name}/{release.version}/{file_path}",
content=block.collect()
)
+
+
+def _render_file_content(block: htm.Block, content: str, is_text: bool,
is_truncated: bool, max_view_size: int) -> None:
+ card = htm.Block(htm.div, classes=".card.mb-4")
+ card.div(".card-header")[htm.h3(".mb-0")["File content" + (" (Hexdump)" if
not is_text else "")]]
+
+ if is_text:
+
card.div(".card-body.p-0")[htm.pre(".bg-light.p-4.rounded-bottom.mb-0.text-break")[content]]
+ else:
+
card.div(".card-body.p-0")[htm.pre(".bg-light.p-4.rounded-bottom.mb-0.text-break")[htm.code[content]]]
+
+ if is_truncated:
+ card.div(".card-footer.text-muted.small")[
+ f"Note: File content truncated to the first
{util.format_file_size(max_view_size)}."
+ ]
+
+ block.append(card.collect())
+
+
+def _get_navigation_info(release: sql.Release) -> tuple[str, str, Phase] |
None:
+ """Get back URL, back label, and phase label based on release phase."""
+ if release.phase == sql.ReleasePhase.RELEASE_CANDIDATE_DRAFT:
+ return (
+ util.as_url(compose.selected, project_name=release.project.name,
version_name=release.version),
+ f"Compose {release.short_display_name}",
+ "COMPOSE",
+ )
+ elif release.phase == sql.ReleasePhase.RELEASE_CANDIDATE:
+ return (
+ util.as_url(vote.selected, project_name=release.project.name,
version_name=release.version),
+ f"Vote on {release.short_display_name}",
+ "VOTE",
+ )
+ elif release.phase == sql.ReleasePhase.RELEASE_PREVIEW:
+ return (
+ util.as_url(finish.selected, project_name=release.project.name,
version_name=release.version),
+ f"Finish {release.short_display_name}",
+ "FINISH",
+ )
+ return None
+
+
+def _phase_display_name(phase: sql.ReleasePhase) -> str:
+ """Get a display name for the phase."""
+ if phase == sql.ReleasePhase.RELEASE_CANDIDATE_DRAFT:
+ return "draft"
+ elif phase == sql.ReleasePhase.RELEASE_CANDIDATE:
+ return "candidate"
+ elif phase == sql.ReleasePhase.RELEASE_PREVIEW:
+ return "preview"
+ elif phase == sql.ReleasePhase.RELEASE:
+ return "release"
+ return "release"
diff --git a/atr/get/finish.py b/atr/get/finish.py
index 3033b5e..dfc03ad 100644
--- a/atr/get/finish.py
+++ b/atr/get/finish.py
@@ -35,7 +35,7 @@ import atr.form as form
import atr.get.announce as announce
import atr.get.distribution as distribution
import atr.get.download as download
-import atr.get.preview as preview
+import atr.get.file as file
import atr.get.revisions as revisions
import atr.get.root as root
import atr.htm as htm
@@ -412,7 +412,7 @@ def _render_release_card(release: sql.Release) ->
htm.Element:
".btn.btn-secondary.me-2",
title=f"Show files for {release.name}",
href=util.as_url(
- preview.view,
+ file.selected,
project_name=release.project.name,
version_name=release.version,
),
diff --git a/atr/get/preview.py b/atr/get/preview.py
index ed423ca..13a8339 100644
--- a/atr/get/preview.py
+++ b/atr/get/preview.py
@@ -14,181 +14,3 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-
-import atr.blueprints.get as get
-import atr.get.finish as finish
-import atr.htm as htm
-import atr.models.sql as sql
-import atr.shared as shared
-import atr.template as template
-import atr.util as util
-import atr.web as web
-
-
[email protected]("/preview/view/<project_name>/<version_name>")
-async def view(session: web.Committer, project_name: str, version_name: str)
-> str:
- """View all the files in the rsync upload directory for a release."""
- await session.check_access(project_name)
-
- release = await session.release(project_name, version_name,
phase=sql.ReleasePhase.RELEASE_PREVIEW)
-
- # Convert async generator to list
- # There must be a revision on a preview
- file_stats = [
- stat
- async for stat in util.content_list(
- util.get_unfinished_dir(), project_name, version_name,
release.unwrap_revision_number
- )
- ]
- # Sort the files by FileStat.path
- file_stats.sort(key=lambda fs: fs.path)
-
- block = htm.Block()
-
- shared.distribution.html_nav(
- block,
- util.as_url(finish.selected, project_name=release.project.name,
version_name=release.version),
- f"Finish {release.short_display_name}",
- "FINISH",
- )
-
- block.h1[
- "Files in ",
- htm.strong[release.project.short_display_name],
- " ",
- htm.em[release.version],
- ]
-
- block.div(".card.mb-4")[
-
htm.div(".card-header.d-flex.justify-content-between.align-items-center")[
- htm.h3(".mb-0")["Release information"]
- ],
- htm.div(".card-body")[
- htm.div(".row")[
- htm.div(".col-md-6")[
- htm.p[htm.strong["Project:"], " ",
release.project.display_name],
- htm.p[htm.strong["Label:"], " ", release.name],
- ],
- htm.div(".col-md-6")[
- htm.p[htm.strong["Created:"], " ",
release.created.strftime("%Y-%m-%d %H:%M:%S")],
- ],
- ]
- ],
- ]
-
- files_card = htm.Block(htm.div, classes=".card.mb-4")
-
files_card.div(".card-header.d-flex.justify-content-between.align-items-center")[htm.h3(".mb-0")["Files"]]
-
- if file_stats:
- tbody = htm.Block(htm.tbody)
- for stat in file_stats:
- if stat.is_file:
- file_url = util.as_url(
- view_path,
- project_name=release.project.name,
- version_name=release.version,
- file_path=stat.path,
- )
- file_link = htm.a(href=file_url)[stat.path]
- else:
- file_link = htm.strong[stat.path + "/"]
-
- tbody.tr[
- htm.td[util.format_permissions(stat.permissions)],
- htm.td[file_link],
- htm.td[util.format_file_size(stat.size) if stat.is_file else
"-"],
- htm.td[util.format_datetime(stat.modified)],
- ]
-
- files_card.div(".card-body")[
- htm.div(".table-responsive")[
- htm.table(".table.table-striped.table-hover")[
- htm.thead[
- htm.tr[
- htm.th["Permissions"],
- htm.th["File path"],
- htm.th["Size"],
- htm.th["Modified"],
- ]
- ],
- tbody.collect(),
- ]
- ]
- ]
- else:
- files_card.div(".card-body")[htm.div(".alert.alert-info")["This
release preview does not have any files."]]
-
- block.append(files_card.collect())
-
- return await template.blank(
- f"Files in {release.short_display_name}",
- content=block.collect(),
- )
-
-
[email protected]("/preview/view/<project_name>/<version_name>/<path:file_path>")
-async def view_path(session: web.Committer, project_name: str, version_name:
str, file_path: str) -> str:
- """View the content of a specific file in the release preview."""
- await session.check_access(project_name)
-
- release = await session.release(project_name, version_name,
phase=sql.ReleasePhase.RELEASE_PREVIEW)
- _max_view_size = 1 * 1024 * 1024
- full_path = util.release_directory(release) / file_path
- content_listing = await util.archive_listing(full_path)
- content, is_text, is_truncated, error_message = await
util.read_file_for_viewer(full_path, _max_view_size)
-
- block = htm.Block()
-
- back_url = util.as_url(
- view,
- project_name=release.project.name,
- version_name=release.version,
- )
- block.a(href=back_url, class_="atr-back-link")["← Back to preview"]
-
- block.div(".p-3.mt-4.mb-4.bg-light.border.rounded")[
- htm.h2(".mt-0")[f"Viewing file: {file_path}"],
- htm.p(".mb-0")[htm.strong["Release:"], " ", release.name],
- ]
-
- if content_listing:
- items = [htm.li(".list-group-item.py-1.px-3.small")[item] for item in
content_listing]
- block.div(".card.mb-3")[
- htm.div(".card-header")[htm.h3(".mb-0")[f"Archive contents
({len(content_listing)})"]],
-
htm.div(".card-body.p-0")[htm.ul(".list-group.list-group-flush")[*items]],
- ]
-
- if error_message:
- block.div(".alert.alert-danger")[error_message]
- elif content is not None:
- if content_listing:
- details_block = htm.Block(htm.details, classes=".mb-3")
- details_block.summary(".mb-2")["View raw file content"]
- _render_file_content(details_block, content, is_text,
is_truncated, _max_view_size)
- block.append(details_block.collect())
- else:
- _render_file_content(block, content, is_text, is_truncated,
_max_view_size)
- else:
- block.div(".alert.alert-secondary")["No content available for this
file."]
-
- return await template.blank(
- f"View
{release.project.short_display_name}/{release.version}/{file_path}",
- content=block.collect(),
- )
-
-
-def _render_file_content(block: htm.Block, content: str, is_text: bool,
is_truncated: bool, max_view_size: int) -> None:
- card = htm.Block(htm.div, classes=".card.mb-4")
- card.div(".card-header")[htm.h3(".mb-0")["File content" + (" (Hexdump)" if
not is_text else "")]]
-
- if is_text:
-
card.div(".card-body.p-0")[htm.pre(".bg-light.p-4.rounded-bottom.mb-0.text-break")[content]]
- else:
-
card.div(".card-body.p-0")[htm.pre(".bg-light.p-4.rounded-bottom.mb-0.text-break")[htm.code[content]]]
-
- if is_truncated:
- card.div(".card-footer.text-muted.small")[
- f"Note: File content truncated to the first
{util.format_file_size(max_view_size)}."
- ]
-
- block.append(card.collect())
diff --git a/atr/get/projects.py b/atr/get/projects.py
index 9d72441..aa4a15e 100644
--- a/atr/get/projects.py
+++ b/atr/get/projects.py
@@ -28,9 +28,7 @@ import atr.db.interaction as interaction
import atr.form as form
import atr.forms as forms
import atr.get.committees as committees
-import atr.get.draft as draft
-import atr.get.preview as preview
-import atr.get.release as release
+import atr.get.file as file
import atr.get.start as start
import atr.htm as htm
import atr.models.sql as sql
@@ -41,7 +39,6 @@ import atr.template as template
import atr.user as user
import atr.util as util
import atr.web as web
-from atr.get import candidate
@get.committer("/project/add/<committee_name>")
@@ -449,7 +446,7 @@ async def _render_releases_sections(
draft_buttons.append(
htm.a(
".btn.btn-sm.btn-outline-secondary.py-2.px-3",
- href=util.as_url(draft.view, project_name=project.name,
version_name=drf.version),
+ href=util.as_url(file.selected, project_name=project.name,
version_name=drf.version),
title=f"View draft {project.name} {drf.version}",
)[
f"{project.name} {drf.version} ",
@@ -466,7 +463,7 @@ async def _render_releases_sections(
candidate_buttons.append(
htm.a(
".btn.btn-sm.btn-outline-info.py-2.px-3",
- href=util.as_url(candidate.view,
project_name=project.name, version_name=cnd.version),
+ href=util.as_url(file.selected, project_name=project.name,
version_name=cnd.version),
title=f"View candidate {project.name} {cnd.version}",
)[
f"{project.name} {cnd.version} ",
@@ -483,7 +480,7 @@ async def _render_releases_sections(
preview_buttons.append(
htm.a(
".btn.btn-sm.btn-outline-warning.py-2.px-3",
- href=util.as_url(preview.view, project_name=project.name,
version_name=prv.version),
+ href=util.as_url(file.selected, project_name=project.name,
version_name=prv.version),
title=f"View preview {project.name} {prv.version}",
)[
f"{project.name} {prv.version} ",
@@ -500,7 +497,7 @@ async def _render_releases_sections(
release_buttons.append(
htm.a(
".btn.btn-sm.btn-outline-success.py-2.px-3",
- href=util.as_url(release.view, project_name=project.name,
version_name=rel.version),
+ href=util.as_url(file.selected, project_name=project.name,
version_name=rel.version),
title=f"View release {project.name} {rel.version}",
)[
f"{project.name} {rel.version} ",
diff --git a/atr/get/release.py b/atr/get/release.py
index 4c17f9c..10a7061 100644
--- a/atr/get/release.py
+++ b/atr/get/release.py
@@ -90,60 +90,3 @@ async def select(session: web.Committer, project_name: str)
-> str:
return await template.render(
"release-select.html", project=project, releases=releases,
format_datetime=util.format_datetime
)
-
-
[email protected]("/release/view/<project_name>/<version_name>")
-async def view(session: web.Committer | None, project_name: str, version_name:
str) -> web.WerkzeugResponse | str:
- """View all the files in the rsync upload directory for a release."""
- async with db.session() as data:
- release_name = sql.release_name(project_name, version_name)
- release = await data.release(name=release_name, _project=True).demand(
- base.ASFQuartException(f"Release {version_name} not found",
errorcode=404)
- )
-
- # Convert async generator to list
- file_stats = [stat async for stat in
util.content_list(util.get_finished_dir(), project_name, version_name)]
- # Sort the files by FileStat.path
- file_stats.sort(key=lambda fs: fs.path)
-
- return await template.render(
- # TODO: Move to somewhere appropriate
- "phase-view.html",
- file_stats=file_stats,
- release=release,
- format_datetime=util.format_datetime,
- format_file_size=util.format_file_size,
- format_permissions=util.format_permissions,
- phase="release",
- phase_key="release",
- )
-
-
[email protected]("/release/view/<project_name>/<version_name>/<path:file_path>")
-async def view_path(
- session: web.Committer | None, project_name: str, version_name: str,
file_path: str
-) -> web.WerkzeugResponse | str:
- """View the content of a specific file in the final release."""
- async with db.session() as data:
- release_name = sql.release_name(project_name, version_name)
- release = await data.release(name=release_name, _project=True).demand(
- base.ASFQuartException(f"Release {version_name} not found",
errorcode=404)
- )
- _max_view_size = 1 * 1024 * 1024
- full_path = util.release_directory(release) / file_path
- content_listing = await util.archive_listing(full_path)
- content, is_text, is_truncated, error_message = await
util.read_file_for_viewer(full_path, _max_view_size)
- return await template.render(
- "file-selected-path.html",
- release=release,
- project_name=project_name,
- version_name=version_name,
- file_path=file_path,
- content=content,
- is_text=is_text,
- is_truncated=is_truncated,
- error_message=error_message,
- format_file_size=util.format_file_size,
- phase_key="release",
- content_listing=content_listing,
- )
diff --git a/atr/post/announce.py b/atr/post/announce.py
index 873799b..56d2417 100644
--- a/atr/post/announce.py
+++ b/atr/post/announce.py
@@ -78,7 +78,7 @@ async def selected(
get.announce.selected, error=str(e), project_name=project_name,
version_name=version_name
)
- routes_release_finished = get.release.finished # type: ignore[has-type]
+ routes_release_finished = get.release.finished
return await session.redirect(
routes_release_finished,
success="Preview successfully announced",
diff --git a/atr/templates/check-selected-release-info.html
b/atr/templates/check-selected-release-info.html
index 127f5c2..4fd99fc 100644
--- a/atr/templates/check-selected-release-info.html
+++ b/atr/templates/check-selected-release-info.html
@@ -79,7 +79,7 @@
{% elif phase == "release_candidate" %}
<a href="{{ as_url(get.download.all_selected,
project_name=release.project.name, version_name=release.version) }}"
class="btn btn-primary"><i class="bi bi-download me-1"></i>
Download files</a>
- <a href="{{ as_url(get.candidate.view,
project_name=release.project.name, version_name=release.version) }}"
+ <a href="{{ as_url(get.file.selected,
project_name=release.project.name, version_name=release.version) }}"
class="btn btn-secondary"><i class="bi bi-eye me-1"></i> View
files</a>
{% if can_resolve and release.vote_manual %}
<a href="{{ as_url(get.manual.resolve_selected,
project_name=release.project.name, version_name=release.version) }}"
diff --git a/atr/templates/phase-view.html b/atr/templates/phase-view.html
deleted file mode 100644
index 946a676..0000000
--- a/atr/templates/phase-view.html
+++ /dev/null
@@ -1,136 +0,0 @@
-{% extends "layouts/base.html" %}
-
-{% block title %}
- Files in {{ release.short_display_name }} ~ ATR
-{% endblock title %}
-
-{% block description %}
- View the files in the {{ release.short_display_name }} release.
-{% endblock description %}
-
-{% block content %}
- <p class="d-flex justify-content-between align-items-center">
- {# TODO: Use mappings.py #}
- {% if phase_key == "draft" %}
- <a href="{{ as_url(get.compose.selected,
project_name=release.project.name, version_name=release.version) }}"
- class="atr-back-link">← Back to Compose {{ release.short_display_name
}}</a>
- <span>
- <strong class="atr-phase-one atr-phase-symbol">①</strong>
- <span class="atr-phase-one atr-phase-label">COMPOSE</span>
- <span class="atr-phase-arrow">→</span>
- <span class="atr-phase-symbol-other">②</span>
- <span class="atr-phase-arrow">→</span>
- <span class="atr-phase-symbol-other">③</span>
- </span>
- {% elif phase_key == "candidate" %}
- <a href="{{ as_url(get.vote.selected, project_name=release.project.name,
version_name=release.version) }}"
- class="atr-back-link">← Back to Vote for {{
release.short_display_name }}</a>
- <span>
- <span class="atr-phase-symbol-other">①</span>
- <span class="atr-phase-arrow">→</span>
- <strong class="atr-phase-two atr-phase-symbol">②</strong>
- <span class="atr-phase-two atr-phase-label">VOTE</span>
- <span class="atr-phase-arrow">→</span>
- <span class="atr-phase-symbol-other">③</span>
- </span>
- {% elif phase_key == "preview" %}
- <a href="{{ as_url(get.finish.selected,
project_name=release.project.name, version_name=release.version) }}"
- class="atr-back-link">← Back to Finish {{ release.short_display_name
}}</a>
- <span>
- <span class="atr-phase-symbol-other">①</span>
- <span class="atr-phase-arrow">→</span>
- <span class="atr-phase-symbol-other">②</span>
- <span class="atr-phase-arrow">→</span>
- <strong class="atr-phase-three atr-phase-symbol">③</strong>
- <span class="atr-phase-three atr-phase-label">FINISH</span>
- </span>
- {% else %}
- <a href="{{ as_url(get.release.releases) }}" class="atr-back-link">←
Back to Releases</a>
- {% endif %}
- </p>
-
- <h1>
- Files in <strong>{{ release.project.short_display_name }}</strong> <em>{{
release.version }}</em>
- </h1>
-
- <div class="card mb-4">
- <div class="card-header d-flex justify-content-between align-items-center">
- <h5 class="mb-0">Release information</h5>
- </div>
- <div class="card-body">
- <div class="row">
- <div class="col-md-6">
- <p>
- <strong>Project:</strong> {{ release.project.display_name }}
- </p>
- <p>
- <strong>Label:</strong> {{ release.name }}
- </p>
- </div>
- <div class="col-md-6">
- <p>
- <strong>Created:</strong> {{ release.created.strftime("%Y-%m-%d
%H:%M:%S") }}
- </p>
- </div>
- </div>
- </div>
- </div>
-
- <div class="card mb-4">
- <div class="card-header d-flex justify-content-between align-items-center">
- <h5 class="mb-0">Files</h5>
- </div>
- <div class="card-body">
- {% if file_stats|length > 0 %}
- <div class="table-responsive">
- <table class="table table-striped table-hover">
- <thead>
- <tr>
- <th>Permissions</th>
- <th>File path</th>
- <th>Size</th>
- <th>Modified</th>
- </tr>
- </thead>
- <tbody>
- {% for stat in file_stats %}
- <tr>
- <td>{{ format_permissions(stat.permissions) }}</td>
- <td>
- {% if stat.is_file %}
- {% if phase_key == "draft" %}
- {% set file_url = as_url(get.file.selected_path,
project_name=release.project.name, version_name=release.version,
file_path=stat.path) %}
- {% elif phase_key == "candidate" %}
- {% set file_url = as_url(get.candidate.view_path,
project_name=release.project.name, version_name=release.version,
file_path=stat.path) %}
- {% elif phase_key == "preview" %}
- {% set file_url = as_url(get.preview.view_path,
project_name=release.project.name, version_name=release.version,
file_path=stat.path) %}
- {% elif phase_key == "release" %}
- {% set file_url = as_url(get.release.view_path,
project_name=release.project.name, version_name=release.version,
file_path=stat.path) %}
- {% else %}
- {# TODO: Should probably disable the link here #}
- {% set file_url = "#" %}
- {% endif %}
- <a href="{{ file_url }}">{{ stat.path }}</a>
- {% else %}
- <strong>{{ stat.path }}/</strong>
- {% endif %}
- </td>
- <td>
- {% if stat.is_file %}
- {{ format_file_size(stat.size) }}
- {% else %}
- -
- {% endif %}
- </td>
- <td>{{ format_datetime(stat.modified) }}</td>
- </tr>
- {% endfor %}
- </tbody>
- </table>
- </div>
- {% else %}
- <div class="alert alert-info">This {{ phase }} does not have any
files.</div>
- {% endif %}
- </div>
- </div>
-{% endblock content %}
diff --git a/atr/templates/releases-finished.html
b/atr/templates/releases-finished.html
index 7d9d456..bc63ca5 100644
--- a/atr/templates/releases-finished.html
+++ b/atr/templates/releases-finished.html
@@ -29,7 +29,7 @@
class="btn btn-outline-primary w-100 mb-2">
<i class="bi bi-download me-1"></i> Download files
</a>
- <a href="{{ as_url(get.release.view,
project_name=release.project.name, version_name=release.version) }}"
+ <a href="{{ as_url(get.file.selected,
project_name=release.project.name, version_name=release.version) }}"
class="btn btn-outline-secondary w-100">
<i class="bi bi-folder2-open me-1"></i> View files
</a>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]