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 92f62f0 Place incubator KEYS in the correct location in downloads
92f62f0 is described below
commit 92f62f0fbc745315f83d6c365f7dbfddd1134914
Author: Sean B. Palmer <[email protected]>
AuthorDate: Wed Jun 18 14:20:17 2025 +0100
Place incubator KEYS in the correct location in downloads
---
atr/blueprints/admin/admin.py | 7 ++++++-
atr/construct.py | 12 +++++++++---
atr/db/interaction.py | 2 ++
atr/routes/draft.py | 1 +
atr/routes/keys.py | 23 +++++++++++++++++------
atr/tasks/__init__.py | 2 ++
atr/tasks/vote.py | 1 +
7 files changed, 38 insertions(+), 10 deletions(-)
diff --git a/atr/blueprints/admin/admin.py b/atr/blueprints/admin/admin.py
index 62f2c82..7225fcd 100644
--- a/atr/blueprints/admin/admin.py
+++ b/atr/blueprints/admin/admin.py
@@ -754,11 +754,12 @@ def _project_status(
async def _regenerate_keys_all() -> tuple[int, list[str]]:
okay = 0
failures = []
+ downloads_dir = util.get_downloads_dir()
async with db.session() as data:
committees = await data.committee().all()
for committee in committees:
try:
- error_msg = await keys.autogenerate_keys_file(committee.name,
caller_data=data)
+ error_msg = await keys.autogenerate_keys_file(committee.name,
committee.is_podling, caller_data=data)
except Exception as e:
failures.append(f"Caller error regenerating KEYS file for
committee {committee.name}: {e!s}")
continue
@@ -766,6 +767,10 @@ async def _regenerate_keys_all() -> tuple[int, list[str]]:
failures.append(error_msg)
else:
okay += 1
+ if committee.is_podling:
+ if await aiofiles.os.path.isdir(downloads_dir /
committee.name):
+ # Accidental top level directory, so remove it
+ await aiofiles.os.rmdir(downloads_dir / committee.name)
return okay, failures
diff --git a/atr/construct.py b/atr/construct.py
index 1184ea8..17a7313 100644
--- a/atr/construct.py
+++ b/atr/construct.py
@@ -39,6 +39,7 @@ class StartVoteOptions:
asfuid: str
fullname: str
committee_name: str
+ is_podling: bool
project_name: str
version_name: str
vote_duration: int
@@ -111,9 +112,14 @@ async def start_vote_body(body: str, options:
StartVoteOptions) -> str:
project_short_display_name = release.project.short_display_name if
release.project else options.project_name
keys_file = None
- keys_file_path = util.get_finished_dir() / options.committee_name / "KEYS"
- if await aiofiles.os.path.isfile(keys_file_path):
- keys_file = f"https://{host}/downloads/{options.committee_name}/KEYS"
+ if options.is_podling:
+ keys_file_path = util.get_downloads_dir() / "incubator" /
options.committee_name / "KEYS"
+ if await aiofiles.os.path.isfile(keys_file_path):
+ keys_file =
f"https://{host}/downloads/incubator/{options.committee_name}/KEYS"
+ else:
+ keys_file_path = util.get_downloads_dir() / options.committee_name /
"KEYS"
+ if await aiofiles.os.path.isfile(keys_file_path):
+ keys_file =
f"https://{host}/downloads/{options.committee_name}/KEYS"
checklist_content = ""
async with db.session() as data:
diff --git a/atr/db/interaction.py b/atr/db/interaction.py
index e4a4e1a..32ae0ee 100644
--- a/atr/db/interaction.py
+++ b/atr/db/interaction.py
@@ -356,6 +356,8 @@ def _key_latest_self_signature(key: dict) ->
datetime.datetime | None:
async def _key_user_add_validate_key_properties(public_key: str) -> list[dict]:
"""Validate GPG key string, import it, and return its properties and
fingerprint."""
+ # import atr.gpgpatch as gpgpatch
+ # gnupg = gpgpatch.patch_gnupg()
import gnupg
def _sig_with_timestamp(self, args):
diff --git a/atr/routes/draft.py b/atr/routes/draft.py
index dab5af5..1e92f25 100644
--- a/atr/routes/draft.py
+++ b/atr/routes/draft.py
@@ -502,6 +502,7 @@ async def vote_preview(
asfuid=asfuid,
fullname=session.fullname,
committee_name=release.committee.display_name,
+ is_podling=release.committee.is_podling,
project_name=project_name,
version_name=version_name,
vote_duration=vote_duration,
diff --git a/atr/routes/keys.py b/atr/routes/keys.py
index d097f65..adf03ca 100644
--- a/atr/routes/keys.py
+++ b/atr/routes/keys.py
@@ -130,6 +130,7 @@ async def add(session: routes.CommitterSession) -> str:
project_list = session.committees + session.projects
user_committees = await data.committee(name_in=project_list).all()
+ committee_is_podling = {c.name: c.is_podling for c in user_committees}
committee_choices = [(c.name, c.display_name or c.name) for c in
user_committees]
class AddGpgKeyForm(util.QuartFormTyped):
@@ -171,7 +172,8 @@ async def add(session: routes.CommitterSession) -> str:
if key_info:
await quart.flash(f"GPG key {key_info.get('fingerprint',
'')} added successfully.", "success")
for committee_name in selected_committees_data:
- await autogenerate_keys_file(committee_name)
+ is_podling = committee_is_podling[committee_name]
+ await autogenerate_keys_file(committee_name,
is_podling)
if not added_keys:
await quart.flash("No keys were added.", "error")
# Clear form data on success by creating a new empty form instance
@@ -194,7 +196,9 @@ async def add(session: routes.CommitterSession) -> str:
)
-async def autogenerate_keys_file(committee_name: str, caller_data: db.Session
| None = None) -> str | None:
+async def autogenerate_keys_file(
+ committee_name: str, is_podling: bool, caller_data: db.Session | None =
None
+) -> str | None:
base_downloads_dir = util.get_downloads_dir()
if caller_data is None:
@@ -204,7 +208,10 @@ async def autogenerate_keys_file(committee_name: str,
caller_data: db.Session |
async with manager as data:
full_keys_file_content = await _keys_formatter(committee_name, data)
- committee_keys_dir = base_downloads_dir / committee_name
+ if is_podling:
+ committee_keys_dir = base_downloads_dir / "incubator" /
committee_name
+ else:
+ committee_keys_dir = base_downloads_dir / committee_name
committee_keys_path = committee_keys_dir / "KEYS"
error_msg = await _write_keys_file(
committee_keys_dir=committee_keys_dir,
@@ -235,7 +242,7 @@ async def delete(session: routes.CommitterSession) ->
response.Response:
# Delete the GPG key
await data.delete(key)
for committee in key.committees:
- await autogenerate_keys_file(committee.name,
caller_data=data)
+ await autogenerate_keys_file(committee.name,
committee.is_podling, caller_data=data)
return await session.redirect(keys, success="GPG key deleted
successfully")
# If not a GPG key, try to get an SSH key
@@ -281,7 +288,7 @@ async def import_selected_revision(
)
except interaction.InteractionError as e:
return await session.redirect(compose.selected, error=str(e))
- await autogenerate_keys_file(release.committee.name)
+ await autogenerate_keys_file(release.committee.name,
release.committee.is_podling)
message = f"Uploaded {success_count} keys,"
if error_count > 0:
message += f" failed to upload {error_count} keys for {',
'.join(submitted_committees)}"
@@ -435,7 +442,11 @@ async def update_committee_keys(session:
routes.CommitterSession, committee_name
if committee_name not in (session.committees + session.projects):
quart.abort(403, description=f"You are not authorised to update the
KEYS file for {committee_name}")
- error_msg = await autogenerate_keys_file(committee_name)
+ async with db.session() as data:
+ committee = await data.committee(name=committee_name).demand(
+ base.ASFQuartException(f"Committee {committee_name} not found",
errorcode=404)
+ )
+ error_msg = await autogenerate_keys_file(committee_name,
committee.is_podling, caller_data=data)
if error_msg:
await quart.flash(error_msg, "error")
diff --git a/atr/tasks/__init__.py b/atr/tasks/__init__.py
index cb2f41e..0fde156 100644
--- a/atr/tasks/__init__.py
+++ b/atr/tasks/__init__.py
@@ -88,6 +88,8 @@ async def draft_checks(
def ensure_session(caller_data: db.Session | None) -> db.Session |
contextlib.nullcontext[db.Session]:
+ # TODO: Move to interaction.py
+ # This pattern is also used in routes/keys.py
if caller_data is None:
return db.session()
return contextlib.nullcontext(caller_data)
diff --git a/atr/tasks/vote.py b/atr/tasks/vote.py
index 218f38b..d651003 100644
--- a/atr/tasks/vote.py
+++ b/atr/tasks/vote.py
@@ -116,6 +116,7 @@ async def _initiate_core_logic(args: Initiate) -> dict[str,
Any]:
asfuid=args.initiator_id,
fullname=args.initiator_fullname,
committee_name=release.committee.display_name,
+ is_podling=release.committee.is_podling,
project_name=release.project.name,
version_name=release.version,
vote_duration=args.vote_duration,
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]