Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b841a5e
feat: implement catalog workflow automation (issues #22, #23, #24)
ChristopherJHart Oct 28, 2025
10d2be2
refactor: use catalog_destined per-issue instead of global CLI flag
ChristopherJHart Oct 28, 2025
fa36308
fix: update default catalog repository to Testing-as-Code/tac-catalog
ChristopherJHart Oct 28, 2025
8ec7f14
refactor: extract OS from Test Tags instead of filename parsing
ChristopherJHart Oct 28, 2025
eda2d24
refactor: simplify regex pattern for OS tag extraction
ChristopherJHart Oct 28, 2025
7d3dfd2
fix: add console script entry point for CLI
ChristopherJHart Oct 28, 2025
c00c35a
fix: use non-recursive glob to avoid backup files in test_cases_dir
ChristopherJHart Oct 28, 2025
95a0f9c
refactor: separate catalog PR workflow from issues workflow
ChristopherJHart Oct 28, 2025
b7db17f
fix: remove double slash in catalog repo URL
ChristopherJHart Oct 30, 2025
48e29e8
feat: use conventional branch naming for catalog PRs
ChristopherJHart Oct 30, 2025
dfd519a
refactor: include OS name in catalog branch naming
ChristopherJHart Oct 30, 2025
993afcb
feat: add tracking issue creation for catalog PRs
ChristopherJHart Nov 7, 2025
ff12796
fix: strip OS tags from test case titles in CLI commands
ChristopherJHart Nov 7, 2025
f486113
feat: suggest project branch name based on catalog branch
ChristopherJHart Nov 7, 2025
e5222ae
refactor: use fenced code blocks for copyable commands
ChristopherJHart Nov 7, 2025
2d333eb
fix: prevent data loss when test case not found in source file
ChristopherJHart Nov 13, 2025
fb37bf4
fix: add defensive check to prevent wiping files with empty test_cases
ChristopherJHart Nov 13, 2025
85b0322
fix: use atomic file writes to prevent data loss from truncation
ChristopherJHart Nov 13, 2025
436a5ca
fix: handle large files (>1MB) in fetch-files command
ChristopherJHart Nov 13, 2025
2f2f022
Revert "fix: add defensive check to prevent wiping files with empty t…
ChristopherJHart Nov 13, 2025
3332dc6
feat: add test requirement section to catalog tracking issues
ChristopherJHart Nov 14, 2025
f72d9af
fix: improve YAML formatting in test requirement section
ChristopherJHart Nov 14, 2025
9d5fd87
Merge remote-tracking branch 'origin/master' into feature/catalog-wor…
ChristopherJHart Dec 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion github_ops_manager/configuration/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,43 @@ def process_issues_cli(
create_prs: Annotated[bool, Option(envvar="CREATE_PRS", help="Create PRs for issues.")] = False,
debug: Annotated[bool, Option(envvar="DEBUG", help="Enable debug mode.")] = False,
testing_as_code_workflow: Annotated[bool, Option(envvar="TESTING_AS_CODE_WORKFLOW", help="Enable Testing as Code workflow.")] = False,
catalog_repo: Annotated[
str,
Option(
envvar="CATALOG_REPO",
help="Catalog repository name (owner/repo) for catalog-destined test cases. Used when test cases have catalog_destined=true.",
),
] = "Testing-as-Code/tac-catalog",
test_cases_dir: Annotated[
Path,
Option(
envvar="TEST_CASES_DIR",
help="Directory containing test_cases.yaml files for catalog PR metadata writeback. Used when test cases have catalog_destined=true.",
),
] = Path("workspace/test_cases/"),
create_tracking_issues: Annotated[
bool,
Option(
envvar="CREATE_TRACKING_ISSUES",
help="Create tracking issues in project repo for catalog PRs and parameter learning tasks.",
),
] = False,
tracking_issue_labels: Annotated[
str | None,
Option(
envvar="TRACKING_ISSUE_LABELS",
help="Comma-separated list of labels to apply to tracking issues (e.g., 'parameter-learning,catalog-pr').",
),
] = None,
) -> None:
"""Processes issues in a GitHub repository."""
"""Processes issues in a GitHub repository.

Automatically detects catalog-destined test cases (catalog_destined=true) and creates
PRs against the catalog repository with proper directory structure and metadata writeback.
Non-catalog test cases are processed normally against the project repository.

Optionally creates tracking issues for catalog PRs to track parameter learning tasks.
"""
repo: str = ctx.obj["repo"]
github_api_url: str = ctx.obj["github_api_url"]
github_pat_token: str = ctx.obj["github_pat_token"]
Expand All @@ -229,6 +264,11 @@ def process_issues_cli(
if testing_as_code_workflow is True:
typer.echo("Testing as Code workflow is enabled - any Pull Requests created will have an augmented body")

# Parse tracking issue labels from comma-separated string
parsed_labels = None
if tracking_issue_labels:
parsed_labels = [label.strip() for label in tracking_issue_labels.split(",") if label.strip()]

# Run the workflow
result = asyncio.run(
run_process_issues_workflow(
Expand All @@ -241,6 +281,10 @@ def process_issues_cli(
github_api_url=github_api_url,
yaml_path=yaml_path,
testing_as_code_workflow=testing_as_code_workflow,
catalog_repo=catalog_repo,
test_cases_dir=test_cases_dir,
create_tracking_issues=create_tracking_issues,
tracking_issue_labels=parsed_labels,
)
)
if result.errors:
Expand Down
25 changes: 24 additions & 1 deletion github_ops_manager/github/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -473,13 +473,36 @@ async def list_files_in_pull_request(self, pull_number: int) -> list[Any]:
return response.parsed_data

async def get_file_content_from_pull_request(self, file_path: str, branch: str) -> str:
"""Get the content of a file from a specific branch (typically the PR's head branch)."""
"""Get the content of a file from a specific branch (typically the PR's head branch).

Handles both small files (inline base64 content) and large files (> 1MB, via download_url).
"""
response = await self.client.rest.repos.async_get_content(
owner=self.owner,
repo=self.repo_name,
path=file_path,
ref=branch,
)

# For large files (> 1MB), GitHub API returns content as None and provides download_url
if response.parsed_data.content is None or response.parsed_data.content == "":
download_url = getattr(response.parsed_data, "download_url", None)
if download_url:
logger.info(
"File too large for inline content, using download_url",
file_path=file_path,
download_url=download_url,
)
# Use httpx to download the raw file content
import httpx

async with httpx.AsyncClient() as client:
download_response = await client.get(download_url)
download_response.raise_for_status()
return download_response.text
else:
raise ValueError(f"File content is empty and no download_url provided for {file_path}")

return base64.b64decode(response.parsed_data.content).decode("utf-8")

# Release/Tag Operations
Expand Down
Loading