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-release.git
The following commit(s) were added to refs/heads/main by this push:
new be5a846 Migrate more distribution code to the storage interface
be5a846 is described below
commit be5a8462ccdd6502a09e2c227c72e3cf6d3660cb
Author: Sean B. Palmer <[email protected]>
AuthorDate: Mon Sep 8 15:57:56 2025 +0100
Migrate more distribution code to the storage interface
---
atr/models/distribution.py | 12 ++++-
atr/routes/distribution.py | 100 ++++++++---------------------------
atr/storage/writers/distributions.py | 44 +++++++++++++--
3 files changed, 72 insertions(+), 84 deletions(-)
diff --git a/atr/models/distribution.py b/atr/models/distribution.py
index 1a5e6e4..2c54216 100644
--- a/atr/models/distribution.py
+++ b/atr/models/distribution.py
@@ -15,10 +15,11 @@
# specific language governing permissions and limitations
# under the License.
+import datetime
+
import pydantic
-import atr.models.schema as schema
-import atr.models.sql as sql
+from . import basic, schema, sql
class ArtifactHubAvailableVersion(schema.Lax):
@@ -116,3 +117,10 @@ class Data(schema.Lax):
@classmethod
def empty_to_none(cls, v):
return None if v is None or (isinstance(v, str) and v.strip() == "")
else v
+
+
+class Metadata(schema.Strict):
+ api_url: str
+ result: basic.JSON
+ upload_date: datetime.datetime
+ web_url: str | None
diff --git a/atr/routes/distribution.py b/atr/routes/distribution.py
index 201f76a..4280cdb 100644
--- a/atr/routes/distribution.py
+++ b/atr/routes/distribution.py
@@ -463,61 +463,35 @@ async def _record_form_page(
async def _record_form_process_page(fpv: FormProjectVersion, /, staging: bool
= False) -> str:
dd = distribution.Data.model_validate(fpv.form.data)
- resolved = await _release_validated_and_committee_and_template(fpv, dd,
staging)
- if isinstance(resolved, htpy.Element):
- return await _record_form_page(fpv, extra_content=resolved,
staging=staging)
- release, committee, template_url = resolved
- api_url = template_url.format(
- owner_namespace=dd.owner_namespace,
- package=dd.package,
- version=dd.version,
+ release, committee = await _release_validated_and_committee(
+ fpv.project,
+ fpv.version,
+ staging=staging,
)
- api_oc = await _json_from_distribution_platform(api_url, dd.platform,
dd.version)
-
- block = htm.Block()
# In case of error, show an alert
- def _alert(not_found: str, action: str) -> htpy.Element:
+ async def _alert(message: str) -> str:
div = htm.Block(htpy.div(".alert.alert-danger"))
- div.p[
- f"The {not_found} was not found in ",
- htpy.a(href=api_url)["the distribution platform API"],
- f". Please {action}.",
- ]
- return div.collect()
+ div.p[message]
+ collected = div.collect()
+ return await _record_form_page(fpv, extra_content=collected,
staging=staging)
+
+ async with
storage.write_as_committee_member(committee_name=committee.name) as w:
+ try:
+ dist, added, metadata = await
w.distributions.add_distribution_from_data(
+ release=release,
+ staging=staging,
+ dd=dd,
+ )
+ except storage.AccessError as e:
+ return await _alert(str(e))
+
+ block = htm.Block()
# Distribution submitted
block.h1["Distribution recorded"]
- match api_oc:
- case outcome.Result(result):
- pass
- case outcome.Error():
- alert = _alert("package and version", "check the package name and
version")
- return await _record_form_page(fpv, extra_content=alert,
staging=staging)
- # We leak result, usefully, from this scope
-
- # This must come after the api_oc match, as it uses the result
- upload_date = _distribution_upload_date(dd.platform, result, dd.version)
- if upload_date is None:
- # TODO: Add a link to an issue tracker
- alert = _alert("upload date", "report this bug to ASF Tooling")
- return await _record_form_page(fpv, extra_content=alert,
staging=staging)
-
- web_url = _distribution_web_url(dd.platform, result, dd.version)
- async with
storage.write_as_committee_member(committee_name=committee.name) as w:
- dist, added = await w.distributions.add_distribution(
- release_name=release.name,
- platform=dd.platform,
- owner_namespace=dd.owner_namespace,
- package=dd.package,
- version=dd.version,
- staging=staging,
- upload_date=upload_date,
- api_url=api_url,
- web_url=web_url,
- )
- ### Record
+ ## Record
block.h2["Record"]
if added:
block.p["The distribution was recorded successfully."]
@@ -552,13 +526,13 @@ async def _record_form_process_page(fpv:
FormProjectVersion, /, staging: bool =
### API URL
block.h3["API URL"]
- block.pre(".mb-3")[api_url]
+ block.pre(".mb-3")[metadata.api_url]
### API response
block.h3["API response"]
block.details[
htpy.summary["Show full API response"],
- htpy.pre(".atr-pre-wrap.mb-3")[json.dumps(result, indent=2)],
+ htpy.pre(".atr-pre-wrap.mb-3")[json.dumps(metadata.result,
indent=2)],
]
return await template.blank("Distribution submitted",
content=block.collect())
@@ -601,31 +575,3 @@ async def _release_validated(
# if release.project.status != sql.ProjectStatus.ACTIVE:
# raise RuntimeError(f"Project {project} is not active")
return release
-
-
-async def _release_validated_and_committee_and_template(
- fpv: FormProjectVersion,
- dd: distribution.Data,
- staging: bool | None = None,
-) -> tuple[sql.Release, sql.Committee, str] | htpy.Element:
- release, committee = await _release_validated_and_committee(
- fpv.project,
- fpv.version,
- staging=staging,
- )
- if staging is False:
- return release, committee, dd.platform.value.template_url
-
- supported = {sql.DistributionPlatform.ARTIFACT_HUB,
sql.DistributionPlatform.PYPI}
- if dd.platform not in supported:
- div = htm.Block(htpy.div(".alert.alert-danger"))
- div.p["Staging is currently supported only for ArtifactHub and PyPI."]
- return div.collect()
-
- template_url = dd.platform.value.template_staging_url
- if template_url is None:
- div = htm.Block(htpy.div(".alert.alert-danger"))
- div.p["This platform does not provide a staging API endpoint."]
- return div.collect()
-
- return release, committee, template_url
diff --git a/atr/storage/writers/distributions.py
b/atr/storage/writers/distributions.py
index 7e1b1e4..4bc778f 100644
--- a/atr/storage/writers/distributions.py
+++ b/atr/storage/writers/distributions.py
@@ -142,12 +142,46 @@ class CommitteeMember(CommitteeParticipant):
raise e
return distribution, True
- async def add_distribution_from_url(
+ async def add_distribution_from_data(
self,
- api_url: str,
- platform: sql.DistributionPlatform,
- version: str,
- ) -> tuple[sql.Distribution, bool]: ...
+ release: sql.Release,
+ staging: bool,
+ dd: distribution.Data,
+ ) -> tuple[sql.Distribution, bool, distribution.Metadata]:
+ template_url = await self.__template_url(dd, staging)
+ api_url = template_url.format(
+ owner_namespace=dd.owner_namespace,
+ package=dd.package,
+ version=dd.version,
+ )
+ api_oc = await self.__json_from_distribution_platform(api_url,
dd.platform, dd.version)
+ match api_oc:
+ case outcome.Result(result):
+ pass
+ case outcome.Error():
+ raise storage.AccessError("Failed to get API response from
distribution platform")
+ upload_date = self.__distribution_upload_date(dd.platform, result,
dd.version)
+ if upload_date is None:
+ raise storage.AccessError("Failed to get upload date from
distribution platform")
+ web_url = self.__distribution_web_url(dd.platform, result, dd.version)
+ metadata = distribution.Metadata(
+ api_url=api_url,
+ result=result,
+ upload_date=upload_date,
+ web_url=web_url,
+ )
+ dist, added = await self.add_distribution(
+ release_name=release.name,
+ platform=dd.platform,
+ owner_namespace=dd.owner_namespace,
+ package=dd.package,
+ version=dd.version,
+ staging=staging,
+ upload_date=upload_date,
+ api_url=api_url,
+ web_url=web_url,
+ )
+ return dist, added, metadata
def __distribution_upload_date( # noqa: C901
self,
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]