This project aims to create a flexible and robust Python tool, github-ops-manager, designed to automate common GitHub workflows based on declarative configuration files, primarily YAML. It stems from internal tooling but is intended to be a standalone, reusable tool for broader use cases on both GitHub.com and GitHub Enterprise Server (GHES).
The overarching goal is to provide a modular and configurable command-line interface (CLI) application that can:
- Read structured data (initially from YAML files) describing desired states or actions in a GitHub repository.
- Interact with the GitHub API to enact those states/actions, authenticating either via a GitHub App (recommended) or a Personal Access Token (PAT).
- (Forward Sync): Synchronize YAML definitions to GitHub issues (create or update).
- (Reverse Sync / Import): Optionally, read existing GitHub issues from a repository and export them to a structured YAML file format compatible with this tool.
- Extensible functionality: Optionally handle associated artifacts (like generated code files), commit them to unique branches, and create corresponding Pull Requests linked to the issues.
- Be highly configurable and flexible, especially regarding the structure of the input YAML files, allowing different teams or projects to adapt it to their needs.
- Be decoupled from any specific application logic (like the original Quicksilver tool), focusing solely on GitHub operations driven by configuration.
This README serves as a guide for the development of this tool, targeting a developer implementing the core features.
The github-ops-manager tool must fulfill the following core requirements:
-
Configuration & Authentication:
- Load GitHub connection details securely, prioritizing GitHub App credentials over Personal Access Tokens (PATs).
- Supported Authentication Methods:
- GitHub App (Preferred):
- GitHub App ID (e.g.,
GITHUB_APP_IDenv var). - GitHub App Private Key (e.g., path via
GITHUB_PRIVATE_KEY_PATHenv var or the key content itself viaGITHUB_PRIVATE_KEYenv var). - GitHub App Installation ID (e.g.,
GITHUB_INSTALLATION_IDenv var - specifies which installation to act as). The tool should ideally include logic to find the installation ID for a target repo/org if not provided directly.
- GitHub App ID (e.g.,
- Personal Access Token (Fallback):
- GitHub PAT (e.g.,
GITHUB_TOKENenv var).
- GitHub PAT (e.g.,
- GitHub App (Preferred):
- Target GitHub Base URL (e.g.,
GITHUB_BASE_URLenv var). Defaults tohttps://api.github.com. Crucial for GHES. - Target Repository URL or
owner/reposlug (specified via CLI argument). - The tool must detect which set of credentials are provided (checking for App credentials first) and initialize the GitHub client (
githubkit) accordingly. If neither is configured, provide a clear error. - Allow configuration of tool behavior (e.g., default branch, YAML parsing strategies) potentially via a config file (
pyproject.tomlor dedicated file).
1.A. GitHub App Configuration (If using App Auth):
- The GitHub App used by the tool must be registered on GitHub (or the target GHES instance).
- It needs to be configured with the appropriate permissions. Likely required permissions:
- Repository Permissions:
Contents: Read & Write,Issues: Read & Write,Metadata: Read-only,Pull requests: Read & Write,Administration: Read-only(check if needed). - Organization Permissions:
Members: Read-only(potentially).
- Repository Permissions:
- Note: Select the minimum required permissions for security.
1.B. GitHub App Installation (If using App Auth):
- The GitHub App must be installed on the target organization or specific repositories where the
github-ops-managertool needs to operate.
-
Input Processing (YAML Focus):
- Accept one or more paths to input YAML files via CLI arguments.
- Robustly parse the YAML files. Handle potential syntax errors gracefully using
PyYAMLorruamel.yaml. - Flexibility: Design the parser to accommodate variations in YAML structure.
- Define a default expected schema for issues (e.g., a list under an
issues:key, with each item havingtitle,body,labels, etc.). Use Pydantic models internally for validation after mapping. - Provide a mechanism (e.g., configuration file section, CLI arguments) for users to map their YAML fields to the tool's internal representation if their structure differs significantly (e.g.,
my_issue_title -> title,tags -> labels). - Document the default expected schema(s) clearly in the tool's documentation or
--helpoutput.
- Define a default expected schema for issues (e.g., a list under an
-
GitHub Issue Management (Forward Sync: YAML -> GitHub):
- Authenticate and connect to the target GitHub repository using the configured method (App or PAT) via
githubkit. - Iterate through the items parsed from the input YAML(s).
- For each item representing an issue:
- Check if an issue with a matching identifier (e.g., the
title) already exists. - Create: If no matching issue exists, create a new GitHub issue using details mapped from the YAML (e.g.,
title,body,labels,assignees,milestone). - Update: If a matching issue does exist (and update functionality is enabled via CLI flag), update its attributes (e.g., body, labels, assignees, milestone, state) to match the YAML definition.
- Render the issue body content. Support simple templating if the YAML provides a template path or inline template string.
- Log actions clearly (e.g., "Created issue #123 using App Auth", "Updated labels for issue #45 using PAT Auth").
- Check if an issue with a matching identifier (e.g., the
- Authenticate and connect to the target GitHub repository using the configured method (App or PAT) via
-
GitHub File & PR Management (Extension):
- Optionally (e.g., triggered by a CLI flag
--create-prsand corresponding YAML data), handle file artifacts associated with an issue item. - For each item with associated files:
- Create a unique, descriptively named branch originating from the repository's default branch (e.g.,
feature/123-issue-title-slug). - Commit the specified file(s) with provided content to this new branch.
- Create a Pull Request targeting the repository's default branch.
- The PR title/body must reference and link to the corresponding GitHub issue (e.g., "Closes #123").
- Apply relevant labels to the PR.
- Log actions clearly.
- Create a unique, descriptively named branch originating from the repository's default branch (e.g.,
- Optionally (e.g., triggered by a CLI flag
-
GitHub Issue Export (Reverse Sync: GitHub -> YAML):
- (New Requirement): Provide functionality to read existing issues from a target repository and export them into a structured YAML file.
- Input: Target repository, optional filters (e.g.,
--label "bug",--state "open",--since "YYYY-MM-DD"). - Process:
- Fetch issues from the target repository using specified filters via
githubkit. - For each fetched issue, extract key fields:
number,title,body(as raw markdown),labels(as a list of names),assignees(list of logins),milestone(title),state,created_at,updated_at. Consider optionally including comments. - Structure the extracted data for each issue in a format consistent with the tool's expected input YAML schema (Requirement #2).
- Fetch issues from the target repository using specified filters via
- Output: Generate a YAML file (path specified via CLI, e.g.,
--output-file exported_issues.yaml) containing the list of structured issue data.
-
Modularity & Design:
- Structure the codebase logically into distinct modules (e.g.,
cli,config,auth,githubinteractions,processing,schemas). - Employ object-oriented principles where appropriate.
- Prioritize clear, readable, and maintainable "Pythonic" code with extensive type hinting.
- Structure the codebase logically into distinct modules (e.g.,
-
Error Handling & Resilience:
- Implement robust error handling for API errors (auth failures, rate limits, not found, validation errors), file system errors, YAML parsing errors, and configuration errors.
- Provide informative error messages indicating the context (e.g., which auth method was used, which YAML file/item failed).
- Leverage
githubkit's error handling and implement appropriate retry logic, especially for rate limits.
-
Command-Line Interface (CLI):
- Develop a user-friendly CLI using
TyperorClick. - Required arguments: Input YAML file path(s), target repository (
owner/repo). - Optional arguments/flags:
--create-prs,--update-existing,--config-file, potentially arguments for YAML field mapping overrides,--verbose/--quiet. - The CLI should clearly indicate which authentication method is being used based on detected credentials.
- Develop a user-friendly CLI using
-
Testing:
- Implement comprehensive unit tests covering different logic paths, including both App and PAT authentication flows (using mocking).
- Implement integration tests against a mock GitHub API or a dedicated test repository.
-
Documentation:
- Maintain this
README.mdwith clear instructions for both authentication methods, configuration details, GHES usage, and examples. - Include docstrings for public modules, classes, and functions.
- Provide example YAML input files and example configuration snippets.
- Maintain this
To ensure a high-quality, maintainable, and consistent codebase, this project should adhere to standard Python best practices, leveraging a central utils package (github_ops_manager/utils/) for shared components inspired by the reference files provided:
-
Configuration Management (
utils/config.py):- Utilize Pydantic's
BaseSettingsto define and load application configuration (like API settings, feature flags, default paths) in a type-safe manner. - Support loading configuration from environment variables and
.envfiles. - Organize settings into logical classes (e.g.,
GitHubSettings,AppSettings).
- Utilize Pydantic's
-
Constants (
utils/constants.py):- Define shared, immutable values (like default filenames, mapping dictionaries, regex patterns, API endpoints fragments) in a dedicated
constants.pymodule to avoid magic strings/numbers and improve maintainability.
- Define shared, immutable values (like default filenames, mapping dictionaries, regex patterns, API endpoints fragments) in a dedicated
-
Type Hinting (
utils/typings.py):- Use Python's type hinting features (
typingmodule) extensively throughout the codebase for clarity and static analysis benefits. - Define shared custom types, such as
TypedDictfor specific data structures orEnumfor controlled vocabularies (like issue labels or states), intypings.py.
- Use Python's type hinting features (
-
Custom Exceptions (
utils/exceptions.py):- Define a hierarchy of custom exception classes, potentially inheriting from a base
GitHubOpsManagerError, inexceptions.py. This allows for more specific error handling and categorization (e.g.,ConfigurationError,GitHubApiError,YamlProcessingError).
- Define a hierarchy of custom exception classes, potentially inheriting from a base
-
Structured Logging (
utils/logging.py):- Implement structured logging using libraries like
structlogwrapping the standardloggingmodule. - Configure logging centrally to include timestamps, log levels, logger names, and potentially contextual information.
- Support configurable log levels (e.g., INFO, DEBUG) via environment variables or CLI flags.
- Allow JSON output for easier parsing by log collectors, in addition to console-friendly formats.
- Consider silencing overly verbose logs from third-party libraries (like
httpx,githubkititself if needed) at the WARNING level.
- Implement structured logging using libraries like
-
Helper Functions (
utils/helpers.py):- Place general-purpose, reusable utility functions (e.g., file system operations, string manipulation, ID generation, date handling) that don't belong to a more specific module into
helpers.py.
- Place general-purpose, reusable utility functions (e.g., file system operations, string manipulation, ID generation, date handling) that don't belong to a more specific module into
Adhering to these practices will contribute significantly to the project's long-term health and ease of collaboration.
- GitHub Interaction:
githubkit- Modern, typed, supports both GitHub App and PAT authentication. - CLI Framework:
TyperorClick- For building the command-line interface. - YAML Parsing:
PyYAMLorruamel.yaml-ruamel.yamlis preferred if comment/order preservation is needed. - Data Validation/Schemas:
Pydantic- For configuration and internal data model validation. - Environment/Package Mgmt:
uv- For environment and dependency management. - Environment Variables (Optional):
python-dotenv- Useful for loading credentials from a.envfile during local development.
A proposed structure focusing on modularity:
github-ops-manager/
├── .github/
│ └── workflows/
│ └── ci.yml # Linting, testing, build pipeline
├── .venv/ # Virtual environment (created by uv)
├── config_examples/
│ └── issues_default.yaml # Example YAML for the default issue schema
│ └── config.toml # Example tool configuration (optional)
├── github_ops_manager/ # Main Python package source
│ ├── __init__.py
│ ├── auth.py # Logic to detect/handle App vs PAT auth
│ ├── cli.py # CLI definition (Typer/Click app) - Add 'export-issues' command here
│ ├── config.py # Loading config (URLs, settings - reads auth from env/dotenv)
│ ├── github/ # Module for GitHub API interactions via githubkit
│ │ ├── __init__.py
│ │ ├── client.py # Authenticated githubkit client setup (accepts auth object)
│ │ ├── issues.py # Functions for creating/updating/fetching issues - Add 'get_issues' here
│ │ ├── pull_requests.py # Functions for creating/updating PRs
│ │ ├── repositories.py # Functions for repo info, branches, commits, files
│ │ └── models.py # Pydantic models for GitHub data (if needed beyond githubkit)
│ ├── processing/ # Core workflow logic
│ │ ├── __init__.py
│ │ ├── yaml_processor.py # Reads/maps YAML input, writes YAML output
│ │ ├── workflow_runner.py # Orchestrates actions (sync-to-github, export-issues)
│ │ └── models.py # Internal data models (e.g., processed issue data)
│ ├── schemas/ # Pydantic models for input validation
│ │ ├── __init__.py
│ │ └── default_issue.py # Schema for the default expected YAML issue structure
│ ├── utils/
│ │ ├── __init__.py
│ │ ├── constants.py # Shared constants
│ │ ├── helpers.py # Utility functions
│ │ ├── typings.py # Shared type definitions
│ │ ├── config.py # Pydantic Settings model for configuration
│ │ ├── exceptions.py # Custom exception classes
│ │ ├── logging.py # Structlog setup
├── tests/ # Unit and integration tests
│ ├── __init__.py
│ ├── fixtures/ # Test data, mock responses
│ ├── unit/
│ └── integration/
├── .env.example # Example environment variables file
├── .gitignore
├── LICENSE # Choose an appropriate open-source license (e.g., MIT, Apache 2.0)
├── pyproject.toml # Project metadata, dependencies, tool config (ruff, pytest, uv)
├── README.md # This file
└── pre-commit-config.yaml # Configuration for pre-commit hooksThis project uses uv for environment and package management, and pre-commit for code quality checks.
-
Clone the Repository: (Note: Update the URL once the repository is created)
# Example placeholder URL - replace with actual repo URL git clone <your-repository-url> cd github-ops-manager/
-
Prerequisites:
- Python 3.9+ (Check
pyproject.tomlfor the specific minimum version) uvinstalled (pip install uvor follow official instructions)pre-commitinstalled (pip install pre-commit)
- Python 3.9+ (Check
-
Create and Activate Virtual Environment using
uv:# Create a virtual environment named .venv in the project root uv venv # Activate the environment # Linux/macOS: source .venv/bin/activate # Windows (Command Prompt): # .venv\Scripts\activate.bat # Windows (PowerShell): # .venv\Scripts\Activate.ps1
-
Install Dependencies using
uv: Dependencies are defined inpyproject.toml.# Install main dependencies and development dependencies ([dev]) # The -e flag installs the 'github-ops-manager' package itself in editable mode uv pip install -e ".[dev]"
-
Set up Pre-commit Hooks: Installs git hooks defined in
.pre-commit-config.yamlto run linters/formatters automatically.pre-commit install
-
Configure Authentication (Choose ONE method): Set environment variables for authentication. Using a
.envfile (copy.env.exampleto.envand fill it out - ensure.envis in.gitignore!) is recommended for local development. The tool will prioritize GitHub App credentials if found.Method 1: GitHub App (Recommended) Register a GitHub App and install it on your target repository/organization.
# In your .env file or shell environment: export GITHUB_APP_ID="<your_app_id>" # Provide the private key content directly or path to the .pem file # export GITHUB_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n..." export GITHUB_PRIVATE_KEY_PATH="/path/to/your-app.private-key.pem" export GITHUB_INSTALLATION_ID="<installation_id_for_target_repo_or_org>" # Optional: For GitHub Enterprise Server (GHES) # export GITHUB_BASE_URL="[https://your.github.enterprise.url/api/v3](https://your.github.enterprise.url/api/v3)"
Why preferred? Better security (granular permissions, short-lived tokens), higher/scalable rate limits, no need for a bot user account.
Method 2: Personal Access Token (PAT) (Fallback) Create a PAT (classic or fine-grained) with necessary scopes (repo, issue, workflow, etc.).
# In your .env file or shell environment: export GITHUB_TOKEN="ghp_YourPersonalAccessTokenHere" # Optional: For GitHub Enterprise Server (GHES) # export GITHUB_BASE_URL="[https://your.github.enterprise.url/api/v3](https://your.github.enterprise.url/api/v3)"
Use Case: Simpler setup, or when registering/installing a GitHub App on a target (especially GHES) is difficult or blocked by administrative process. Less secure than a GitHub App.
-
Run the Tool (Example Usage - Conceptual): (Commands will be refined as the CLI (
cli.py) is developed)# Example: Process issues from a YAML file (auth detected automatically) github-ops-manager process-issues \ --repo "owner/repository-name" \ --yaml-path ./config_examples/issues_default.yaml # Example: Process issues AND create PRs for associated files github-ops-manager process-issues \ --repo "owner/repository-name" \ --yaml-path ./path/to/your_issues.yaml \ --create-prs # Example: Export existing GitHub issues to YAML (GitHub -> YAML) github-ops-manager export-issues \ --repo "owner/repository-name" \ --output-file ./exported_issues.yaml \ --state "open" \ --label "bug"
-
Run Tests: Execute the test suite using
pytest.pytest tests/
-
Run Linters/Formatters Manually (Optional):
pre-commithandles this automatically on commit.# Example using Ruff (if configured) ruff check . ruff format . # Example using Mypy (if configured) mypy .
This tool can be used with GitHub Enterprise Server instances, but requires specific considerations:
-
Authentication:
- GitHub App (Preferred): The GitHub App must be registered directly on the target GHES instance by a GHES admin or Organization Owner (using a manifest file or setup URL provided by this project). Once registered and installed on your GHES org/repo, configure the tool using the GHES App ID, Private Key, Installation ID, and the
GITHUB_BASE_URL. - Personal Access Token (Fallback): If registering/installing the GitHub App on your GHES instance is not feasible due to administrative hurdles, you can use a PAT generated on the GHES instance. Configure the tool using
GITHUB_TOKENandGITHUB_BASE_URL.
- GitHub App (Preferred): The GitHub App must be registered directly on the target GHES instance by a GHES admin or Organization Owner (using a manifest file or setup URL provided by this project). Once registered and installed on your GHES org/repo, configure the tool using the GHES App ID, Private Key, Installation ID, and the
-
App Registration on GHES (If using App Auth): A GitHub App registered on public GitHub.com cannot be installed on a GHES instance. This project should provide mechanisms (e.g., a
manifest.ymlfile in the repo) for GHES administrators to register the app on their instance. -
Configuration: The
GITHUB_BASE_URLenvironment variable (or equivalent configuration) must be set to the GHES instance's API endpoint (e.g.,https://your.ghe.domain/api/v3) regardless of the authentication method used. -
Rate Limits: Rate limits on GHES instances may be configured differently by the site administrator compared to GitHub.com defaults.