This template repository provides scaffolding for cost center automation. In its initial version, the utility allows for auto-assignment of all Copilot-licensed users in a given enterprise to a cost center. Additional automation use cases will be added.
-
Create a new repository from this template in your GitHub Enterprise organization:
- Click the green
Use this template
button at the top of this repository. - Fill in the repository details and create your own copy.
- Click the green
-
Add your GitHub token as a repository secret:
- Go to your new repository's Settings → Secrets and variables → Actions
- Add secret:
COST_CENTER_AUTOMATION_TOKEN
(your GitHub Personal Access Token withmanage_billing:enterprise
scope)
-
Run the workflow:
- Go to the Actions tab → "Cost center automation"
- Click "Run workflow" → Select "incremental" mode → Run
-
Done! The workflow automatically:
- Detects your enterprise
- Creates cost centers if needed ("00 - No PRU overages", "01 - PRU overages allowed")
- Assigns all Copilot users to appropriate cost centers
- Runs every 6 hours automatically
-
Clone and setup:
git clone <your-repo-url> cd populate_cost_centers pip install -r requirements.txt
-
Configure:
cp config/config.example.yaml config/config.yaml echo "GITHUB_TOKEN=your_github_token_here" > .env # Edit config/config.yaml - set your enterprise name (or leave auto-detection)
-
Run:
# Create cost centers and assign users (with confirmation) python main.py --create-cost-centers --assign-cost-centers --mode apply
That's it! Your Copilot users are now organized in cost centers for better billing tracking.
Automates GitHub Copilot license cost center assignments for enterprises using a simple two-tier model:
- Default: All Copilot users are added to
00 - No PRU overages
cost center - Exceptions: Specified users are added to
01 - PRU overages allowed
cost center
Supports both interactive execution and automated scheduling with incremental processing.
- Automatic cost center creation: Creates cost centers automatically (or use existing cost centers, if preferred)
- Incremental processing: Only process users added since last run (perfect for cron jobs)
- Enhanced result logging: Real-time success/failure tracking with user-level detail
- Plan vs apply execution (
--mode plan|apply
) + interactive safety prompt (bypass with--yes
) - Container friendly (Dockerfile + docker-compose)
- GitHub Actions & cron automation examples
- GitHub Enterprise Cloud admin access
- GitHub Personal Access Token with
manage_billing:enterprise
scope
Additional requirements for local execution:
- Python 3.8 or higher
-
Clone or download your repository created from this template
-
Install required dependencies:
pip install -r requirements.txt
-
Copy the example configuration:
cp config/config.example.yaml config/config.yaml
-
Set up your GitHub token:
echo "GITHUB_TOKEN=your_actual_token_here" > .env
-
Edit
config/config.yaml
with your:- GitHub Enterprise name
- Cost center IDs (if they exist) OR enable auto-creation
- Any users which should get access to additional PRUs
All configuration lives in: config/config.yaml
(example below)
github:
# GitHub Enterprise name (required)
enterprise: "your_enterprise_name"
cost_centers:
# Manual cost center IDs (only needed when auto_create is false)
no_prus_cost_center_id: "REPLACE_WITH_NO_PRUS_COST_CENTER_ID"
prus_allowed_cost_center_id: "REPLACE_WITH_PRUS_ALLOWED_COST_CENTER_ID"
# Users who should get access to PRU overages (always required)
prus_exception_users:
# - "alice"
# - "bob"
# Auto-creation settings (creates cost centers if they don't exist)
auto_create: false # Set to true to enable auto-creation
# Cost center names (only used when auto_create is true)
no_prus_cost_center_name: "00 - No PRU overages" # Name for no-PRU cost center
prus_allowed_cost_center_name: "01 - PRU overages allowed" # Name for PRU-allowed cost center
logging:
level: "INFO"
file: "logs/populate_cost_centers.log"
If either cost center ID still equals REPLACE_WITH_*
(or the sample defaults) a WARNING is logged. In plan mode this is informational; in apply mode you should fix values before proceeding.
- Default: everyone →
no_prus_cost_center_id
- If username in
prus_exception_users
→prus_allowed_cost_center_id
GITHUB_TOKEN
GITHUB_ENTERPRISE
If the Copilot seat API returns the same user more than once, duplicates are skipped and summarized in a warning.
This tool can automatically create cost centers if they don't exist, eliminating manual GitHub UI setup:
# Plan what cost centers would be created
python main.py --create-cost-centers --show-config
# Create cost centers and assign users (with confirmation prompt)
python main.py --create-cost-centers --assign-cost-centers --mode apply
# Non-interactive creation for automation
python main.py --create-cost-centers --assign-cost-centers --mode apply --yes
"00 - No PRU overages"
- For users without PRU access (majority)"01 - PRU overages allowed"
- For exception users with PRU access
Enable via config file:
cost_centers:
auto_create: true # Enable automatic creation
no_prus_cost_center_name: "Custom No PRU Name" # Optional: customize names
prus_allowed_cost_center_name: "Custom PRU Name"
Or use command line flag: --create-cost-centers
- Detection: Checks if cost centers with specified names already exist
- Creation: Creates missing cost centers via GitHub Enterprise API
- Assignment: Uses the created cost center IDs for user assignments
- Idempotent: Safe to run multiple times - won't create duplicates
# Show current configuration and PRUs exception users
python main.py --show-config
# List all Copilot license holders (shows PRUs exceptions)
python main.py --list-users
# Plan cost center assignments (no changes made)
python main.py --assign-cost-centers --mode plan
# Apply cost center assignments (will prompt for confirmation)
python main.py --assign-cost-centers --mode apply
# Apply without interactive confirmation (for automation)
python main.py --assign-cost-centers --mode apply --yes
# Generate summary report (plan mode by default)
python main.py --assign-cost-centers --summary-report
# Process only specific users (plan)
python main.py --users user1,user2,user3 --assign-cost-centers --mode plan
# Auto-create cost centers and assign users (with confirmation)
python main.py --create-cost-centers --assign-cost-centers --mode apply
# Auto-create and assign (non-interactive)
python main.py --create-cost-centers --assign-cost-centers --mode apply --yes
# Incremental processing - only process users added since last run (ideal for cron jobs)
python main.py --assign-cost-centers --incremental --mode apply --yes
# Plan mode with incremental processing (see what new users would be processed)
python main.py --assign-cost-centers --incremental --mode plan
# Full cron job setup: incremental processing with detailed logging and reports
python main.py --assign-cost-centers --incremental --mode apply --yes --summary-report
For efficient cron job automation, the --incremental
flag processes only users added since the last successful run:
- First Run: Processes all users and saves timestamp to
exports/.last_run_timestamp
- Subsequent Runs: Only processes users with
created_at
timestamp after the last run - No New Users: Exits quickly with "No new users found since last run"
- Timestamp Updates: Only saved on successful
--mode apply
executions
The included automation script defaults to incremental mode:
# Incremental mode (default - recommended for cron jobs)
./automation/update_cost_centers.sh
# Full mode (processes all users)
./automation/update_cost_centers.sh full
The tool provides real-time detailed logging showing actual assignment results:
- ✅ Individual User Success:
✅ username → cost_center_id
- ❌ Individual User Failures:
❌ username → cost_center_id (API Error)
- 📊 Batch Progress:
Batch 1 completed: 5 successful, 0 failed
- 📈 Final Results:
📊 ASSIGNMENT RESULTS: 95/100 users successfully assigned
- 🎯 Success Summary:
✅ Assignment success rate: 95/100 users
2025-09-24 10:39:06 [INFO] src.github_api: ✅ Successfully assigned 3 users to cost center abc123
2025-09-24 10:39:06 [INFO] src.github_api: ✅ user1 → abc123
2025-09-24 10:39:06 [INFO] src.github_api: ✅ user2 → abc123
2025-09-24 10:39:06 [INFO] src.github_api: ✅ user3 → abc123
2025-09-24 10:39:06 [INFO] src.github_api: 📊 ASSIGNMENT RESULTS: 3/3 users successfully assigned
2025-09-24 10:39:06 [INFO] src.github_api: 🎉 All users successfully assigned!
Generated files include timestamp for traceability:
logs/populate_cost_centers.log
– Detailed execution log with enhanced result trackingexports/.last_run_timestamp
– Timestamp for incremental processing (JSON format)
- Rotating logs to prevent disk space issues
- Structured format with timestamps and log levels
- Enhanced result tracking with individual user success/failure details
- API response logging for troubleshooting
- Performance metrics and execution summaries
config/config.yaml
- Single configuration file containing all settings (GitHub API, cost centers, logging)config/config.example.yaml
- Example template to copy from.env
- Environment variables (GitHub token, optional overrides)
# Build image
docker build -t copilot-cc .
# Plan mode
docker run --rm -e GITHUB_TOKEN=$GITHUB_TOKEN copilot-cc \
python main.py --assign-cost-centers --mode plan --summary-report
# Apply with auto-creation
docker run --rm -e GITHUB_TOKEN=$GITHUB_TOKEN copilot-cc \
python main.py --create-cost-centers --assign-cost-centers --mode apply --yes --verbose
# Background service
docker compose up -d --build
# Incremental processing (recommended for scheduled workflows)
- name: Apply cost centers (incremental)
run: |
python main.py --assign-cost-centers --incremental --mode apply --yes --summary-report
# Full processing (weekly/monthly)
- name: Apply cost centers (full)
run: |
python main.py --assign-cost-centers --mode apply --yes --summary-report
# Plan mode for validation
- name: Plan cost center assignments
run: |
python main.py --assign-cost-centers --incremental --mode plan --summary-report
See automation/update_cost_centers.sh
- uses incremental processing by default for efficient cron execution:
# Incremental mode (default - processes only new users)
./automation/update_cost_centers.sh
# Full mode (processes all users)
./automation/update_cost_centers.sh full
The script includes detailed logging and --summary-report
for comprehensive automation monitoring.
Monitor execution:
# View live logs
tail -f logs/populate_cost_centers.log
# Cron job examples
0 * * * * cd /path/to/populate_cost_centers && ./automation/update_cost_centers.sh >/dev/null 2>&1 # Hourly incremental
0 2 * * 0 cd /path/to/populate_cost_centers && ./automation/update_cost_centers.sh full >/dev/null 2>&1 # Weekly full
This template includes a built-in template sync workflow that automatically keeps your repository updated with the latest improvements and fixes from the upstream template.
- Automatic Updates: Every Monday at 06:00 UTC, the workflow checks for template updates
- Smart Merging: Only pulls changes that don't conflict with your customizations
- Protected Files: Your configuration and custom files are never overwritten
- Pull Request: Creates a PR with changes for your review before applying
The template sync workflow is automatically configured and ready to use!
Required setup (for most users):
-
Create a GitHub Personal Access Token:
- Go to GitHub Settings → Developer settings → Personal access tokens → Fine-grained tokens
- Create token with these permissions:
- Repository access: Your consumer repository
- Permissions:
Contents: Write
,Pull requests: Write
- Public repositories:
Contents: Read
(to read the template)
-
Add the token as a repository secret:
- Go to your repository's Settings → Secrets and variables → Actions
- Add secret:
TEMPLATE_SYNC_TOKEN
= your PAT
That's it! The workflow will automatically sync from github/cost-center-automation
every Monday.
✅ Always synced:
- Workflow improvements (
/.github/workflows/
) - Bug fixes and new features in source code
- Documentation updates
- Dependency updates
🔒 Never overwritten:
config/config.yaml
(your settings).github/renovate.json
(custom Renovate config)- Any files listed in
.syncignore
Trigger an immediate sync check:
- Go to Actions → "Sync from template" → "Run workflow"
Edit .syncignore
to protect additional files from being overwritten:
# Add patterns for files you want to keep unchanged
echo "my-custom-script.sh" >> .syncignore
If you prefer manual updates only:
- Delete
.github/workflows/template-sync.yml
- Or edit the workflow and remove the
schedule:
trigger
Issue | Explanation | Action |
---|---|---|
Placeholder warning | Cost center ID not replaced | Edit config/config.yaml |
401 / 403 errors | Token missing scope / expired | Regenerate PAT with required scopes |
No users returned | No active Copilot seats | Verify seat assignments in Enterprise settings |
Apply aborted | Confirmation not granted | Re-run with --yes or type apply at prompt |
Cost center creation failed | Missing enterprise permissions | Ensure token has manage_billing:enterprise scope |
Logs: inspect logs/populate_cost_centers.log
for detailed traces (DEBUG if --verbose
).
- Create your own repository from the template & branch (
feat/<name>
) - Add/adjust tests (future enhancement: test harness TBD)
- Keep changeset focused & documented in commit message
- Submit PR with before/after summary
- Tag reviewers & link related issues
This project is licensed under the terms of the MIT open source license. Please refer to the LICENSE file for the full terms.
Maintained state: Tags v0.1.0
(baseline refactor), v0.1.1
(apply confirmation & flags). Latest: Enhanced result logging, incremental processing, automatic cost center creation.