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 ee33438 Set project name dynamically based on committee metadata
ee33438 is described below
commit ee334383f8bc0373036cfd73b7f91a850e16a162
Author: Sean B. Palmer <[email protected]>
AuthorDate: Fri May 30 16:42:34 2025 +0100
Set project name dynamically based on committee metadata
---
atr/blueprints/admin/admin.py | 24 +++++++++++++++----
.../admin/templates/cleanup-incubating-names.html | 25 ++++++++++++++++++++
atr/db/__init__.py | 9 +++-----
atr/db/models.py | 9 ++++----
atr/routes/__init__.py | 2 +-
atr/routes/projects.py | 3 +--
atr/routes/resolve.py | 13 -----------
atr/templates/index-committer.html | 2 +-
atr/templates/project-select.html | 2 +-
migrations/versions/0006_2025.05.30_9672a901.py | 27 ++++++++++++++++++++++
10 files changed, 83 insertions(+), 33 deletions(-)
diff --git a/atr/blueprints/admin/admin.py b/atr/blueprints/admin/admin.py
index 743c4d3..65be76f 100644
--- a/atr/blueprints/admin/admin.py
+++ b/atr/blueprints/admin/admin.py
@@ -326,6 +326,24 @@ async def admin_performance() -> str:
return await template.render("performance.html", stats=sorted_summary)
[email protected]("/cleanup-incubating-names", methods=["GET", "POST"])
+async def admin_cleanup_incubating_names() -> str | response.Response:
+ form = await util.EmptyForm.create_form()
+ if await form.validate_on_submit():
+ updated_count = 0
+ async with db.session() as data:
+ async with data.begin():
+ projects = await data.project().all()
+ for project_model in projects:
+ if project_model.full_name and
project_model.full_name.endswith(" (Incubating)"):
+ project_model.full_name =
project_model.full_name.removesuffix(" (Incubating)")
+ data.add(project_model)
+ updated_count += 1
+ await quart.flash(f"Successfully removed ' (Incubating)' from
{updated_count} project full_names.", "success")
+ return
quart.redirect(quart.url_for("admin.admin_cleanup_incubating_names"))
+ return await template.render("cleanup-incubating-names.html", form=form)
+
+
@admin.BLUEPRINT.route("/projects/update", methods=["GET", "POST"])
async def admin_projects_update() -> str | response.Response |
tuple[Mapping[str, Any], int]:
"""Update projects from remote data."""
@@ -556,9 +574,7 @@ async def _update_committees() -> tuple[int, int]: # noqa:
C901
podling = await data.project(name=podling_name).get()
if not podling:
# Create the associated podling project
- podling = models.Project(
- name=podling_name, full_name=podling_data.name,
committee=ppmc, is_podling=True
- )
+ podling = models.Project(name=podling_name,
full_name=podling_data.name, committee=ppmc)
data.add(podling)
added_count += 1
else:
@@ -594,7 +610,7 @@ async def _update_committees() -> tuple[int, int]: # noqa:
C901
project_model = await data.project(name=project_name).get()
if not project_model:
- project_model = models.Project(name=project_name,
committee=pmc, is_podling=pmc.is_podling)
+ project_model = models.Project(name=project_name,
committee=pmc)
data.add(project_model)
added_count += 1
else:
diff --git a/atr/blueprints/admin/templates/cleanup-incubating-names.html
b/atr/blueprints/admin/templates/cleanup-incubating-names.html
new file mode 100644
index 0000000..03853a9
--- /dev/null
+++ b/atr/blueprints/admin/templates/cleanup-incubating-names.html
@@ -0,0 +1,25 @@
+{% extends "layouts/base-admin.html" %}
+
+{% block title %}Cleanup incubating project names ~ ATR admin{% endblock %}
+
+{% block content %}
+ <h1 class="mb-4">Cleanup incubating project names</h1>
+ <p>
+ This action will remove the " (Incubating)" suffix from the full
name of all projects where it is present.
+ This is a one time operation to help standardise project names in
the database.
+ </p>
+
+ <div class="card shadow-sm mb-4">
+ <div class="card-body">
+ <h5 class="card-title">Confirm cleanup</h5>
+ <p class="card-text">
+ Press the button below to proceed with removing the "
(Incubating)" suffix from project full names.
+ This change will be applied to the database immediately.
+ </p>
+ <form method="post" action="{{
url_for('admin.admin_cleanup_incubating_names') }}">
+ {{ form.csrf_token }}
+ <button type="submit" class="btn btn-danger">Cleanup project
names</button>
+ </form>
+ </div>
+ </div>
+{% endblock %}
diff --git a/atr/db/__init__.py b/atr/db/__init__.py
index 5d31707..a50fcf2 100644
--- a/atr/db/__init__.py
+++ b/atr/db/__init__.py
@@ -270,10 +270,9 @@ class Session(sqlalchemy.ext.asyncio.AsyncSession):
self,
name: Opt[str] = NOT_SET,
full_name: Opt[str] = NOT_SET,
- is_podling: Opt[bool] = NOT_SET,
committee_name: Opt[str] = NOT_SET,
release_policy_id: Opt[int] = NOT_SET,
- _committee: bool = False,
+ _committee: bool = True,
_releases: bool = False,
_distribution_channels: bool = False,
_super_project: bool = False,
@@ -286,8 +285,6 @@ class Session(sqlalchemy.ext.asyncio.AsyncSession):
query = query.where(models.Project.name == name)
if is_defined(full_name):
query = query.where(models.Project.full_name == full_name)
- if is_defined(is_podling):
- query = query.where(models.Project.is_podling == is_podling)
if is_defined(committee_name):
query = query.where(models.Project.committee_name ==
committee_name)
if is_defined(release_policy_id):
@@ -359,9 +356,9 @@ class Session(sqlalchemy.ext.asyncio.AsyncSession):
release_policy_id: Opt[int] = NOT_SET,
votes: Opt[list[models.VoteEntry]] = NOT_SET,
latest_revision_number: Opt[str | None] = NOT_SET,
- _project: bool = False,
+ _project: bool = True,
+ _committee: bool = True,
_release_policy: bool = False,
- _committee: bool = False,
_tasks: bool = False,
_revisions: bool = False,
) -> Query[models.Release]:
diff --git a/atr/db/models.py b/atr/db/models.py
index 037eed5..88b4e00 100644
--- a/atr/db/models.py
+++ b/atr/db/models.py
@@ -170,11 +170,7 @@ class Project(sqlmodel.SQLModel, table=True):
# We always include "Apache" in the full_name
full_name: str | None = sqlmodel.Field(default=None)
- # True if this a podling project
- # TODO: We should have this on Committee too, or instead
- is_podling: bool = sqlmodel.Field(default=False)
is_retired: bool = sqlmodel.Field(default=False)
-
super_project_name: str | None = sqlmodel.Field(default=None,
foreign_key="project.name")
# NOTE: Neither "Project" | None nor "Project | None" works
super_project: Optional["Project"] = sqlmodel.Relationship()
@@ -207,7 +203,10 @@ class Project(sqlmodel.SQLModel, table=True):
@property
def display_name(self) -> str:
"""Get the display name for the Project."""
- return self.full_name or self.name
+ base = self.full_name or self.name
+ if self.committee and self.committee.is_podling:
+ return f"{base} (Incubating)"
+ return base
@property
def short_display_name(self) -> str:
diff --git a/atr/routes/__init__.py b/atr/routes/__init__.py
index d9ba242..9276eac 100644
--- a/atr/routes/__init__.py
+++ b/atr/routes/__init__.py
@@ -213,7 +213,7 @@ class CommitterSession:
phase: models.ReleasePhase | db.NotSet | None = db.NOT_SET,
latest_revision_number: str | db.NotSet | None = db.NOT_SET,
data: db.Session | None = None,
- with_committee: bool = False,
+ with_committee: bool = True,
with_project: bool = True,
with_tasks: bool = False,
with_revisions: bool = False,
diff --git a/atr/routes/projects.py b/atr/routes/projects.py
index debdf19..237c3cd 100644
--- a/atr/routes/projects.py
+++ b/atr/routes/projects.py
@@ -425,7 +425,7 @@ async def _project_add(form: AddFormProtocol, asf_id: str)
-> response.Response:
# Construct the new full name
# We ensure that parenthesised suffixes like "(Incubating)" are
preserved
- base_name = base_project.full_name or base_project.name
+ base_name = base_project.display_name
match = re.match(r"^(.*?) *(\(.*\))?$", base_name)
if match:
main_part = match.group(1).strip()
@@ -448,7 +448,6 @@ async def _project_add(form: AddFormProtocol, asf_id: str)
-> response.Response:
project = models.Project(
name=new_project_label,
full_name=new_project_full_name,
- is_podling=base_project.is_podling,
is_retired=base_project.is_retired,
super_project_name=base_project.name,
description=base_project.description,
diff --git a/atr/routes/resolve.py b/atr/routes/resolve.py
index 7a7e72b..54f1125 100644
--- a/atr/routes/resolve.py
+++ b/atr/routes/resolve.py
@@ -163,19 +163,6 @@ def task_mid_get(latest_vote_task: models.Task) -> str |
None:
return task_mid
-def _format_artifact_name(project_name: str, version: str, is_podling: bool =
False) -> str:
- """Format an artifact name according to Apache naming conventions.
-
- For regular projects: apache-${project}-${version}
- For podlings: apache-${project}-incubating-${version}
- """
- # TODO: Format this better based on committee and project
- # Must depend on whether project is a subproject or not
- if is_podling:
- return f"apache-{project_name}-incubating-{version}"
- return f"apache-{project_name}-{version}"
-
-
async def _send_resolution(
session: routes.CommitterSession,
release: models.Release,
diff --git a/atr/templates/index-committer.html
b/atr/templates/index-committer.html
index 6d8c6b2..6e7dff1 100644
--- a/atr/templates/index-committer.html
+++ b/atr/templates/index-committer.html
@@ -67,7 +67,7 @@
<div class="mb-5" id="project-{{ project_id }}">
<h2 class="border-bottom border-secondary pb-2 mb-3">
{{ display_name_cleaned }}
- {% if project.is_podling or project.name.startswith("incubator-") %}
+ {% if project.committee.is_podling or
project.name.startswith("incubator-") %}
<span class="text-muted fw-normal fs-5">(Incubating)</span>
<img src="{{ url_for('static',
filename='svg/apache_incubator.svg') }}"
alt=""
diff --git a/atr/templates/project-select.html
b/atr/templates/project-select.html
index e401c38..63abb38 100644
--- a/atr/templates/project-select.html
+++ b/atr/templates/project-select.html
@@ -20,7 +20,7 @@
<h3 class="card-title fs-5 mb-2">{{ project.display_name
}}</h3>
<h4 class="card-subtitle mb-2 text-muted fs-6">{{ project.name
}}</h4>
<p>
- {% if project.is_podling or
project.name.startswith("incubator-") %}
+ {% if project.committee.is_podling or
project.name.startswith("incubator-") %}
<img
src="https://incubator.apache.org/images/SVG/apache_incubator.svg"
alt="" />
{% else %}
diff --git a/migrations/versions/0006_2025.05.30_9672a901.py
b/migrations/versions/0006_2025.05.30_9672a901.py
new file mode 100644
index 0000000..39fccee
--- /dev/null
+++ b/migrations/versions/0006_2025.05.30_9672a901.py
@@ -0,0 +1,27 @@
+"""Remove Project.is_podling
+
+Revision ID: 0006_2025.05.30_9672a901
+Revises: 0005_2025.05.29_49f92935
+Create Date: 2025-05-30 15:22:08.113248+00:00
+"""
+
+from collections.abc import Sequence
+
+import sqlalchemy as sa
+from alembic import op
+
+# Revision identifiers, used by Alembic
+revision: str = "0006_2025.05.30_9672a901"
+down_revision: str | None = "0005_2025.05.29_49f92935"
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
+
+
+def upgrade() -> None:
+ with op.batch_alter_table("project", schema=None) as batch_op:
+ batch_op.drop_column("is_podling")
+
+
+def downgrade() -> None:
+ with op.batch_alter_table("project", schema=None) as batch_op:
+ batch_op.add_column(sa.Column("is_podling", sa.BOOLEAN(),
nullable=False))
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]