mirror of
https://github.com/PlaneQuery/OpenAirframes.git
synced 2026-09-23 22:30:43 +02:00
OpenAirframes 1.0
This commit is contained in:
@@ -21,12 +21,14 @@ import urllib.request
|
||||
import urllib.error
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from .schema import extract_json_from_issue_body, extract_contributor_name_from_issue_body, parse_and_validate
|
||||
from .schema import extract_json_from_issue_body, extract_contributor_name_from_issue_body, parse_and_validate, load_schema, SCHEMAS_DIR
|
||||
from .contributor import (
|
||||
generate_contributor_uuid,
|
||||
generate_submission_filename,
|
||||
compute_content_hash,
|
||||
)
|
||||
from .update_schema import generate_updated_schema, check_for_new_tags, get_existing_tag_definitions
|
||||
from .read_community_data import build_tag_type_registry
|
||||
|
||||
|
||||
def github_api_request(
|
||||
@@ -54,7 +56,11 @@ def github_api_request(
|
||||
|
||||
try:
|
||||
with urllib.request.urlopen(req) as response:
|
||||
return json.loads(response.read())
|
||||
response_body = response.read()
|
||||
# DELETE requests return empty body (204 No Content)
|
||||
if not response_body:
|
||||
return {}
|
||||
return json.loads(response_body)
|
||||
except urllib.error.HTTPError as e:
|
||||
error_body = e.read().decode() if e.fp else ""
|
||||
print(f"GitHub API error: {e.code} {e.reason}: {error_body}", file=sys.stderr)
|
||||
@@ -94,14 +100,30 @@ def create_branch(branch_name: str, sha: str) -> None:
|
||||
raise
|
||||
|
||||
|
||||
def get_file_sha(path: str, branch: str) -> str | None:
|
||||
"""Get the SHA of an existing file, or None if it doesn't exist."""
|
||||
try:
|
||||
response = github_api_request("GET", f"/contents/{path}?ref={branch}")
|
||||
return response.get("sha")
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def create_or_update_file(path: str, content: str, message: str, branch: str) -> None:
|
||||
"""Create or update a file in the repository."""
|
||||
content_b64 = base64.b64encode(content.encode()).decode()
|
||||
github_api_request("PUT", f"/contents/{path}", {
|
||||
payload = {
|
||||
"message": message,
|
||||
"content": content_b64,
|
||||
"branch": branch,
|
||||
})
|
||||
}
|
||||
|
||||
# If file exists, we need to include its SHA to update it
|
||||
sha = get_file_sha(path, branch)
|
||||
if sha:
|
||||
payload["sha"] = sha
|
||||
|
||||
github_api_request("PUT", f"/contents/{path}", payload)
|
||||
|
||||
|
||||
def create_pull_request(title: str, head: str, base: str, body: str) -> dict:
|
||||
@@ -144,21 +166,19 @@ def process_submission(
|
||||
return False
|
||||
|
||||
data, errors = parse_and_validate(json_str)
|
||||
if errors:
|
||||
error_list = "\n".join(f"- {e}" for e in errors)
|
||||
if errors or data is None:
|
||||
error_list = "\n".join(f"- {e}" for e in errors) if errors else "Unknown error"
|
||||
add_issue_comment(issue_number, f"❌ **Validation Failed**\n\n{error_list}")
|
||||
return False
|
||||
|
||||
# Normalize to list
|
||||
submissions = data if isinstance(data, list) else [data]
|
||||
submissions: list[dict] = data if isinstance(data, list) else [data]
|
||||
|
||||
# Generate contributor UUID from GitHub ID
|
||||
contributor_uuid = generate_contributor_uuid(author_id)
|
||||
|
||||
# Extract contributor name from issue form (or default to GitHub username)
|
||||
# Extract contributor name from issue form (None means user opted out of attribution)
|
||||
contributor_name = extract_contributor_name_from_issue_body(issue_body)
|
||||
if not contributor_name:
|
||||
contributor_name = f"@{author_username}"
|
||||
|
||||
# Add metadata to each submission
|
||||
now = datetime.now(timezone.utc)
|
||||
@@ -167,14 +187,15 @@ def process_submission(
|
||||
|
||||
for submission in submissions:
|
||||
submission["contributor_uuid"] = contributor_uuid
|
||||
submission["contributor_name"] = contributor_name
|
||||
if contributor_name:
|
||||
submission["contributor_name"] = contributor_name
|
||||
submission["creation_timestamp"] = timestamp_str
|
||||
|
||||
# Generate unique filename
|
||||
content_json = json.dumps(submissions, indent=2, sort_keys=True)
|
||||
content_hash = compute_content_hash(content_json)
|
||||
filename = generate_submission_filename(author_username, date_str, content_hash)
|
||||
file_path = f"community/{filename}"
|
||||
file_path = f"community/{date_str}/{filename}"
|
||||
|
||||
# Create branch
|
||||
branch_name = f"community-submission-{issue_number}"
|
||||
@@ -185,14 +206,53 @@ def process_submission(
|
||||
commit_message = f"Add community submission from @{author_username} (closes #{issue_number})"
|
||||
create_or_update_file(file_path, content_json, commit_message, branch_name)
|
||||
|
||||
# Update schema with any new tags (modifies v1 in place)
|
||||
schema_updated = False
|
||||
new_tags = []
|
||||
try:
|
||||
# Build tag registry from new submissions
|
||||
tag_registry = build_tag_type_registry(submissions)
|
||||
|
||||
# Get current schema and merge existing tags
|
||||
current_schema = load_schema()
|
||||
existing_tags = get_existing_tag_definitions(current_schema)
|
||||
|
||||
# Merge existing tags into registry
|
||||
for tag_name, tag_def in existing_tags.items():
|
||||
if tag_name not in tag_registry:
|
||||
tag_type = tag_def.get("type", "string")
|
||||
tag_registry[tag_name] = tag_type
|
||||
|
||||
# Check for new tags
|
||||
new_tags = check_for_new_tags(tag_registry, current_schema)
|
||||
|
||||
if new_tags:
|
||||
# Generate updated schema
|
||||
updated_schema = generate_updated_schema(current_schema, tag_registry)
|
||||
schema_json = json.dumps(updated_schema, indent=2) + "\n"
|
||||
|
||||
create_or_update_file(
|
||||
"schemas/community_submission.v1.schema.json",
|
||||
schema_json,
|
||||
f"Update schema with new tags: {', '.join(new_tags)}",
|
||||
branch_name
|
||||
)
|
||||
schema_updated = True
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not update schema: {e}", file=sys.stderr)
|
||||
|
||||
# Create PR
|
||||
schema_note = ""
|
||||
if schema_updated:
|
||||
schema_note = f"\n**Schema Updated:** Added new tags: `{', '.join(new_tags)}`\n"
|
||||
|
||||
pr_body = f"""## Community Submission
|
||||
|
||||
Adds {len(submissions)} submission(s) from @{author_username}.
|
||||
|
||||
**File:** `{file_path}`
|
||||
**Contributor UUID:** `{contributor_uuid}`
|
||||
|
||||
{schema_note}
|
||||
Closes #{issue_number}
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user