asf-tooling commented on issue #921:
URL:
https://github.com/apache/tooling-trusted-releases/issues/921#issuecomment-4410014102
<!-- gofannon-issue-triage-bot v2 -->
**Automated triage** — analyzed at `main@2da7807a`
**Type:** `discussion` • **Classification:** `no_action` •
**Confidence:** `medium`
**Application domain(s):** `project_committee_management`,
`web_api_infrastructure`, `shared_infrastructure`
### Summary
This issue requests defining a unified YAML/JSON format for
exporting/importing project metadata, cycles, and policy settings as a single
document, enabling a programmatic API for bulk project configuration (issue
#139). The underlying data models already exist (Project, ProjectCycle,
ReleasePolicy) and partial APIs exist (PolicyGetResults, PolicyUpdateArgs,
ProjectGetResults), but there is no unified schema combining all three into a
single interchange format. No prior discussion has occurred, so a format design
decision is needed before implementation.
### Where this lives in the code today
#### `atr/models/api.py` — `PolicyGetResults` (lines 295-316)
_currently does this_
Existing API response model for policy data - partial coverage of what the
unified format would include.
```python
class PolicyGetResults(schema.Strict):
endpoint: Literal["/policy/get"] = schema.alias("endpoint")
project_key: safe.ProjectKey
policy_announce_release_subject: str
policy_announce_release_template: str
policy_binary_artifact_paths: list[str]
policy_github_compose_workflow_path: list[str]
policy_github_finish_workflow_path: list[str]
policy_github_repository_branch: str
policy_github_repository_name: str
policy_github_vote_workflow_path: list[str]
policy_license_check_mode: sql.LicenseCheckMode
policy_mailto_addresses: list[str]
policy_manual_vote: bool
policy_min_hours: int
policy_vote_mode: sql.VoteMode = schema.example(sql.VoteMode.EMAIL)
policy_preserve_download_files: bool
policy_release_checklist: str
policy_source_artifact_paths: list[str]
policy_start_vote_subject: str
policy_start_vote_template: str
policy_vote_comment_template: str
```
#### `atr/models/api.py` — `ProjectGetResults` (lines 290-292)
_currently does this_
Existing API response model for project metadata - another partial component
of the unified format.
```python
class ProjectGetResults(schema.Strict):
endpoint: Literal["/project/get"] = schema.alias("endpoint")
project: sql.Project
```
#### `atr/models/api.py` — `PolicyUpdateArgs` (lines 319-342)
_currently does this_
Existing API request model for updating policy - the POST counterpart for
policy settings.
```python
class PolicyUpdateArgs(schema.Strict):
project: safe.ProjectKey = schema.example("example")
announce_release_subject: str | None = None
announce_release_template: str | None = None
binary_artifact_paths: list[str] | None = None
file_tag_mappings: dict[str, list[str]] | None = None
github_compose_workflow_path: list[str] | None = None
github_finish_workflow_path: list[str] | None = None
github_repository_branch: str | None = None
github_repository_name: str | None = None
github_vote_workflow_path: list[str] | None = None
license_check_mode: sql.LicenseCheckMode | None = None
mailto_addresses: list[pydantic.EmailStr] | None = None
manual_vote: bool | None = None
min_hours: int | None = None
preserve_download_files: bool | None = None
release_checklist: str | None = None
source_artifact_paths: list[str] | None = None
source_excludes_lightweight: list[str] | None = None
source_excludes_rat: list[str] | None = None
start_vote_subject: str | None = None
start_vote_template: str | None = None
vote_comment_template: str | None = None
vote_mode: sql.VoteMode | None = None
```
#### `atr/models/sql.py` — `Project` (lines 714-726)
_extension point_
Project model with version-scheme metadata fields from issue #912 - would be
serialized as part of the unified format.
```python
class Project(sqlmodel.SQLModel, table=True):
key: str = sqlmodel.Field(primary_key=True, unique=True,
**example("example"))
name: str | None = sqlmodel.Field(default=None, **example("Apache
Example"))
status: ProjectStatus = sqlmodel.Field(default=ProjectStatus.ACTIVE,
**example(ProjectStatus.ACTIVE))
super_project_key: str | None = sqlmodel.Field(default=None,
foreign_key="project.key")
super_project: Optional["Project"] = sqlmodel.Relationship()
description: str | None = sqlmodel.Field(default=None,
**example("Example is a simple example project"))
category: str | None = sqlmodel.Field(default=None,
**example("data,storage"))
programming_languages: str | None = sqlmodel.Field(default=None,
**example("c,python"))
version_method: VersionMethod =
sqlmodel.Field(default=VersionMethod.SIMPLE, **example(VersionMethod.SIMPLE))
version_pattern: str | None = sqlmodel.Field(default=None,
**example(r"^\d+\.\d+\.\d+$"))
cycle_match: str | None = sqlmodel.Field(default=None,
**example(r"^(\d+)\.\d+\.\d+$"))
branch_template: str | None = sqlmodel.Field(default=None,
**example("release-{cycle}"))
```
#### `atr/db/__init__.py` — `Session.project_cycle` (lines 432-447)
_extension point_
Query builder for ProjectCycle - the data source for cycle information that
would be included in the unified format.
```python
def project_cycle(
self,
cycle_key: Opt[str] = NOT_SET,
project_key: Opt[str] = NOT_SET,
cycle: Opt[str] = NOT_SET,
_project: bool = False,
_releases: bool = False,
) -> Query[sql.ProjectCycle]:
query = sqlmodel.select(sql.ProjectCycle)
if is_defined(cycle_key):
query = query.where(sql.ProjectCycle.cycle_key == cycle_key)
if is_defined(project_key):
query = query.where(sql.ProjectCycle.project_key == project_key)
if is_defined(cycle):
query = query.where(sql.ProjectCycle.cycle == cycle)
```
#### `migrations/versions/0074_2026.05.04_0d6e9554.py` — `upgrade` (lines
22-35)
_currently does this_
Migration for issue #912 that added versioning and cycle metadata to the
project model - infrastructure the unified format would expose.
```python
def upgrade() -> None:
# project: add version-scheme metadata. Existing rows default to
"simple".
with op.batch_alter_table("project", schema=None) as batch_op:
batch_op.add_column(
sa.Column(
"version_method",
sa.Enum("SIMPLE", "SEMVER", "CALVER", name="versionmethod"),
nullable=False,
server_default="SIMPLE",
)
)
batch_op.add_column(sa.Column("version_pattern", sa.String(),
nullable=True))
batch_op.add_column(sa.Column("cycle_match", sa.String(),
nullable=True))
batch_op.add_column(sa.Column("branch_template", sa.String(),
nullable=True))
```
### Where new code would go
- `atr/models/api.py` — after symbol PolicyUpdateResults
New Pydantic models for a unified project configuration schema (e.g.,
ProjectConfigGetResults, ProjectConfigUpdateArgs) that combines metadata,
cycles, and policy into a single document.
- `atr/api/__init__.py` — new endpoints
New API endpoint handlers for GET /project/config and POST /project/config
that serialize/deserialize the unified format.
### Proposed approach
This issue requires a design decision before implementation. The unified
format should combine three currently separate concerns into a single document:
(1) project metadata (name, status, description, categories, languages, version
method/pattern), (2) cycle definitions (cycle_key, lifecycle dates, LTS flag),
and (3) policy settings (vote config, trusted publishing, license checks,
templates). The existing partial APIs (PolicyGetResults, PolicyUpdateArgs,
ProjectGetResults) show the shape of the data but are spread across multiple
endpoints.
Once the format is agreed upon (likely as a new Pydantic schema in
atr/models/api.py), implementation would involve: creating a GET endpoint that
assembles the full document from Project + ProjectCycle + ReleasePolicy, and a
POST/PUT endpoint that can apply a full or partial configuration document to
update all three models atomically. YAML support could be added via a
content-type negotiation layer or a separate serialization step. This would
enable issue #139 (likely programmatic/declarative project setup).
### Open questions
- What is the scope of issue #139 that this format is meant to enable? (Bulk
project bootstrap? Declarative config-as-code?)
- Should the format be YAML-primary or JSON-primary with YAML as an
alternative serialization?
- Should the unified format be a single flat document or nested sections
(metadata/cycles/policy)?
- Should cycle definitions be inline in the project document or referenced
separately?
- Should the format support partial updates (like PolicyUpdateArgs with
nullable fields) or require full documents?
- What authorization level is needed for the new endpoint - committee member
only, or should participants also read?
- Is there an existing design document or RFC template where this format
should be proposed?
_The agent reviewed this issue and is not proposing patches in this run.
Review the existing-code citations and open questions above before deciding
next steps._
### Files examined
- `atr/models/sql.py`
- `atr/models/api.py`
- `atr/db/__init__.py`
- `migrations/versions/0074_2026.05.04_0d6e9554.py`
- `migrations/versions/0076_2026.05.06_e5fa9b30.py`
- `atr/storage/__init__.py`
- `atr/shared/projects.py`
- `atr/docs/database.md`
---
*Draft from a triage agent. A human reviewer should validate before merging
any change. The agent did not run tests or verify diffs apply.*
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]