Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
108 changes: 108 additions & 0 deletions BUDGET_IMPROVEMENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Budget System Improvements for Repository Cost Center Assignment

## Overview
This document outlines the budget system improvements needed for the repository cost center assignment feature to support multiple products and be more resilient.

## Current Implementation Issues
1. **Hardcoded Budget Amount**: `create_cost_center_budget()` uses hardcoded $0 amounts
2. **Missing Actions Support**: No support for Actions product budgets
3. **Limited Product Support**: Only supports Copilot PRU budgets
4. **Manual Budget Type Selection**: No abstraction for different budget types

## Proposed Improvements

### 1. **Configurable Budget Amounts**
```python
def create_cost_center_budget(self, cost_center_id: str, cost_center_name: str, budget_amount: int = 100) -> bool:
# Instead of hardcoded budget_amount: 0
```

### 2. **Product-Agnostic Budget Creation**
```python
def create_product_budget(self, cost_center_id: str, cost_center_name: str, product: str, amount: int) -> bool:
"""
Create a product-level budget for a cost center.

Args:
cost_center_id: UUID of the cost center
cost_center_name: Name of the cost center (for logging)
product: Product name (e.g., 'actions', 'copilot', 'packages')
amount: Budget amount in dollars
"""
# Dynamic budget type selection based on product
budget_type = self._get_budget_type_for_product(product)
product_sku = self._get_product_sku(product)
```

### 3. **Product Registry System**
```python
# Configuration-driven product support
SUPPORTED_PRODUCTS = {
'actions': {
'budget_type': 'ProductPricing',
'sku': 'actions',
'default_amount': 125
},
'copilot': {
'budget_type': 'SkuPricing',
'sku': 'copilot_premium_request',
'default_amount': 100
},
'packages': {
'budget_type': 'ProductPricing',
'sku': 'packages',
'default_amount': 50
},
'codespaces': {
'budget_type': 'ProductPricing',
'sku': 'codespaces',
'default_amount': 200
}
}
```

### 4. **Budget Existence Checking**
```python
def check_cost_center_has_product_budget(self, cost_center_id: str, cost_center_name: str, product: str) -> bool:
"""Check if a cost center already has a budget for a specific product."""
```

### 5. **Configuration-Driven Budget Management**
```yaml
# config.yaml extension
budgets:
enabled: true
products:
- name: copilot
amount: 100
enabled: true
- name: actions
amount: 125
enabled: true
- name: packages
amount: 50
enabled: false
```

## Implementation Priority

### Phase 1 (Critical - Include in current PR)
- ✅ Fix configurable budget amounts
- ✅ Add Actions product budget support
- ✅ Add budget existence checking

### Phase 2 (Future Enhancement)
- 🔄 Product registry system
- 🔄 Configuration-driven budget management
- 🔄 Support for additional products (Packages, Codespaces)

### Phase 3 (Advanced Features)
- 🔄 Budget alerting and monitoring
- 🔄 Cost allocation reporting
- 🔄 Budget approval workflows

## Benefits
1. **Extensibility**: Easy to add new products without code changes
2. **Configurability**: Customers can customize budget amounts per product
3. **Resilience**: Handles API changes better with abstracted product definitions
4. **Maintainability**: Centralized product configuration reduces duplication
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- **Repository-Based Cost Center Assignment**: New mode for assigning repositories to cost centers based on custom properties
- Explicit mapping mode: Map custom property values to specific cost centers
- Works with any repository custom property (team, service, environment, etc.)
- Automatic cost center creation for new mappings
- Full pagination support for organizations with many repositories
- Comprehensive logging showing repository discovery, matching, and assignment
- New module `repository_cost_center_manager.py` for repository-based assignment logic
- New GitHub API methods for custom properties:
- `get_org_custom_properties()`: Fetch organization custom property schema
- `get_org_repositories_with_properties()`: List repositories with their property values (paginated)
- `get_all_org_repositories_with_properties()`: Automatic pagination wrapper
- `get_repository_custom_properties()`: Get properties for a specific repository
- `add_repositories_to_cost_center()`: Batch assign repositories to cost centers
- Configuration support for repository mode in `config_manager.py`
- New `github.cost_centers.mode` setting (supports "users", "teams", or "repository")
- New `github.cost_centers.repository_config` section with validation
- Explicit mappings configuration with property name and value matching
- Documentation for repository mode in README.md with examples
- Detailed design document in `REPOSITORY_COST_CENTER_DESIGN.md`
- **GitHub Enterprise Data Resident Support**: Full support for enterprises running on GitHub Enterprise Data Resident (GHE.com) with custom API endpoints
- **Enhanced Budget System**: Product-agnostic budget creation with multi-product support
- `create_product_budget()`: Generic method for creating budgets for any product (Actions, Copilot, Packages, etc.)
- `check_cost_center_has_product_budget()`: Check for existing budgets before creation
- Configurable budget amounts (no longer hardcoded to $0)
- Support for both ProductPricing (Actions) and SkuPricing (Copilot) budget types
- Product registry system for easy extension to new products
- **Budget Configuration System**: YAML-based budget configuration
- `budgets.enabled`: Global budget creation toggle
- `budgets.products`: Per-product configuration with amounts and enable/disable flags
- Support for Copilot PRU and Actions budgets with different default amounts
- Extensible design for future products (Packages, Codespaces, etc.)
- Repository mode now supports budget creation with `--create-budgets` flag
- New configuration option `github.api_base_url` in config files for custom API endpoints
- New environment variable `GITHUB_API_BASE_URL` for custom API endpoint configuration
- Automatic API URL validation with support for:
Expand All @@ -19,6 +50,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated documentation in README.md, config.example.yaml, and .env.example

### Changed
- Updated `main.py` to support three operational modes (PRU-based, Teams-based, Repository-based)
- Renamed "Two Operational Modes" to "Three Operational Modes" in documentation
- `GitHubCopilotManager` now uses configurable API base URL instead of hardcoded value
- URL validation and normalization in `ConfigManager` to ensure proper API endpoint formatting

Expand Down
127 changes: 125 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
**tl;dr:**
- Automate cost center creation and syncing with enterprise teams, org-based teams, or for every Copilot user in your enterprise
- Configure Actions workflow to keep cost centers in sync
- Coming soon: automatically create budgets for each cost center
- Automatically create budgets for cost centers (Copilot PRU, Actions, and future products)

Automate GitHub Copilot license cost center assignments for your enterprise with two powerful modes:

Expand Down Expand Up @@ -88,7 +88,7 @@ Set up GitHub Actions for automatic syncing every 6 hours - see [Automation](#au

## Features

### Two Operational Modes
### Three Operational Modes

**PRU-Based Mode** (Default)
- Simple two-tier model: PRU overages allowed/not allowed
Expand All @@ -103,6 +103,13 @@ Set up GitHub Actions for automatic syncing every 6 hours - see [Automation](#au
- Full sync mode (removes users who left teams)
- Single assignment (existing cost center assignments are preserved by default)

**Repository-Based Mode** (New!)
- Assign repositories to cost centers based on custom properties
- Flexible explicit mapping: map property values to cost centers
- Works with any custom property (team, service, environment, etc.)
- Automatic cost center creation for new mappings
- Perfect for aligning repository ownership with cost tracking

### Additional Features
- 🔄 **Plan/Apply execution**: Preview changes before applying
- 📊 **Enhanced logging**: Real-time success/failure tracking
Expand Down Expand Up @@ -160,6 +167,122 @@ teams:
- Organization scope: `[org team] {org-name}/{team-name}`
- Enterprise scope: `[enterprise team] {team-name}`

### Repository-Based Mode Configuration

Assign repositories to cost centers based on custom properties. This mode is ideal for tracking costs by project, service, or team ownership.

**Prerequisites:**
1. Configure custom properties in your organization settings
2. Assign property values to your repositories
3. Map property values to cost centers in config

**Example Configuration:**

```yaml
github:
cost_centers:
mode: "repository" # Enable repository mode

repository_config:
explicit_mappings:
# Map repositories by team property
- cost_center: "Platform Engineering"
property_name: "team"
property_values:
- "platform"
- "infrastructure"
- "devops"

# Map by environment
- cost_center: "Production Services"
property_name: "environment"
property_values:
- "production"

# Map by service type
- cost_center: "Data & Analytics"
property_name: "team"
property_values:
- "data"
- "analytics"
- "ml"

teams:
organizations:
- "your-org-name" # Required for repository mode
```

**Usage:**

```bash
# Plan mode: See what would be assigned
python main.py --assign-cost-centers --mode plan

# Apply mode: Make the assignments
python main.py --assign-cost-centers --mode apply --yes

# With budget creation
python main.py --assign-cost-centers --mode apply --create-budgets --yes
```

### Budget Configuration (Optional)

Automatically create budgets for cost centers when they're created. Supports multiple GitHub products with configurable amounts.

```yaml
budgets:
enabled: true # Global toggle for budget creation

products:
copilot:
amount: 100 # Budget amount in USD
enabled: true # Create Copilot PRU budgets

actions:
amount: 125 # Budget amount in USD
enabled: true # Create Actions budgets

# Future products
# packages:
# amount: 50
# enabled: false
```

**Usage with Budgets:**

```bash
# Any mode with budget creation
python main.py --create-budgets [other-options]

# Teams mode with budgets
python main.py --teams-mode --create-budgets --mode apply --yes

# Repository mode with budgets
python main.py --assign-cost-centers --mode apply --create-budgets --yes
```

**Supported Products:**
- **Copilot**: GitHub Copilot PRU (Premium Request Units) budgets
- **Actions**: GitHub Actions compute minutes budgets
- **Future**: Packages, Codespaces, and other products (configurable)

**Budget Types:**
- Actions uses `ProductPricing` budget type
- Copilot uses `SkuPricing` budget type
- Automatically handles different API formats per product

**How It Works:**
1. Fetches all repositories in your organization with their custom properties
2. For each mapping, finds repositories with matching property values
3. Creates cost centers if they don't exist (automatically)
4. Assigns matching repositories to their designated cost centers

**Common Use Cases:**
- **By Team**: Map `team` property values to team-specific cost centers
- **By Environment**: Separate production vs. development repository costs
- **By Service**: Group microservices, frontend, backend, data services
- **By Department**: Map organizational units to cost centers

### Environment Variables

Set these instead of config file values:
Expand Down
Loading
Loading