Blog

Die neue Rechnungsstellung von GitHub - Kostenstellen in großen Mengen zuweisen

Jesse Houwing

Aktualisiert Oktober 14, 2025
5 Minuten

Ich habe kürzlich die internen Kostenstellen eingerichtet, um unsere GitHub Enterprise-Rechnung nach den in GitHub definierten Kostenstellen aufzuteilen. Kostenstellen sind Teil der neuen Abrechnungsfunktion von GitHub, die derzeit für GitHub Enterprise-Kunden eingeführt wird und die auch für GitHub for Teams verfügbar sein wird.

Sie können Ressourcen Kostenstellen zuweisen, die wiederum alle mit dieser Ressource verbundenen Kosten auf diese Kostenstelle umlegen.

Beispiele für Ressourcenkategorien sind:

  • Repositories - Alle Kosten, die mit einem bestimmten Repository verbunden sind. Aktionsprotokolle, Codespaces, LFS-Speicher usw.
  • Benutzer - Alle Kosten, die mit einem bestimmten Benutzer verbunden sind. Enterprise Seat, Copilot, Erweiterte Sicherheit.
  • Organisationen - Alle Kosten, die mit einer bestimmten Organisation verbunden sind. Kosten, die durch nicht zugewiesene Repositories in der Organisation entstehen. GitHub Pakete - Speicherplatz und Netzwerkverkehr.
  • Unternehmen - Alle Kosten, die mit dem gesamten Unternehmen verbunden sind. Kosten, die mit Benutzern verbunden sind, die nicht explizit einer Kostenstelle zugewiesen sind.

Indem Sie Organisationen, Benutzer und Repositories mit einer Kostenstelle verknüpfen, können Sie veranlassen, dass deren spezifische Kosten vom Unternehmen an die spezifische Kostenstelle weitergeleitet werden.

Die Verknüpfung von Organisationen und Repositories kann über die Kostenstellen-Benutzeroberfläche im GitHub Enterprise Admin-Portal vorgenommen werden:

[caption id="" align="aligncenter" width="1294"]Im Portal Enterprise Admin können Sie den Kostenstellen Organisationen und Repositories zuweisen. Mitglieder können nur über die API zugewiesen werden. Im Portal Enterprise Admin können Sie den Kostenstellen Organisationen und Repositories zuweisen. Mitglieder können nur über die API zugewiesen werden. [/caption]

Wenn Sie Glück haben, sind es nur ein paar Organisationen, die zugewiesen werden müssen, aber in unserem Fall waren die Mitglieder eine ganz andere Geschichte. Wir haben bereits mehr als 500 Mitglieder und externe Mitarbeiter in unserem Unternehmen und diese mussten bestimmten Kostenstellen zugewiesen werden. Wie Sie sehen können, kann dies nicht über die Benutzeroberfläche erfolgen, sondern erfordert API-Aufrufe.

Es hat sich herausgestellt, dass die API ein wenig kompliziert ist. Es gibt einige Dinge über die API, die (noch) nicht gut dokumentiert sind:

  • Sie können einer Kostenstelle nur Benutzer in Stapeln von 50 zuweisen (bestätigt durch den GitHub Support)
  • Sie können einen Benutzer nur dann zuweisen, wenn er nicht bereits einer anderen Kostenstelle zugewiesen ist. Das Ändern von Kostenstellen erfordert 2 Vorgänge.
  • Die API ist schließlich konsistent. Es kann ein paar Sekunden dauern, bis Änderungen bei nachfolgenden API-Aufrufen angezeigt werden.
  • Sie können zwar Kostenstellen pro Benutzer zuweisen, aber das ist ein guter Weg, um Ihre API-Ratenlimits schnell zu verbrauchen.

Um diese Probleme zu umgehen, habe ich einen kleinen Wrapper um die API in PowerShell geschrieben, der die bestehenden Ressourcenzuweisungen verwendet, die in den Kostenstellen gespeichert sind, um die Anzahl der erforderlichen Aufrufe der API zu reduzieren:

function Update-CostCenterResources {
    param(
        [Parameter(Mandatory=$true)]
        [string[]]$Handles,

        [Parameter(Mandatory=$true)]
        [ValidateSet('Add','Delete')]
        [string]$Action,

        [Parameter(Mandatory=$true)]
        $CostCenter,

        [Parameter(Mandatory=$true)]
        [string]$Enterprise
    )

    switch ($Action)
    {
        'Add' {
            $method = 'POST'
            $Handles = $Handles | Where-Object { 
                $handle = $_
                return (($costCenter.resources | ?{ $_.type -eq "User" } | ?{$_.name -eq $handle }).Count -eq 0)
            }
        }
        'Delete' {
            $method = 'DELETE'
            $Handles = $Handles | Where-Object { 
                $handle = $_
                return (($costCenter.resources | ?{ $_.type -eq "User" } | ?{$_.name -eq $handle }).Count -gt 0)
            }
        }
    }

    # Call fails when processing too many users at once. Thus batching the calls...
    $count = 0
    do {
        $batch = $Handles | Select-Object -Skip $count -First 50
        $count += $batch.Count

        if ($batch.Count -gt 0) {
            $body = @{
                users = [string[]]$batch
            }

            $_ = ($body | ConvertTo-Json) | gh api --method $method /enterprises/$Enterprise/settings/billing/cost-centers/$($CostCenter.id)/resource --input -
        }
    } while ($batch.Count -gt 0)
}

$enterprise = "xebia"
$costCenters = (invoke-gh -fromJson -- api /enterprises/$enterprise/settings/billing/cost-centers).costCenters

$costCenterNL = $costCenters | ?{ $_.name -eq "Netherlands" }

$handles = @("jessehouwing", "jessehouwing-demo")

# First remove the users from their currently assigned cost centers (if any)
$costCenters | 
  ?{ $_.id -ne $costCenterNL.id } | 
  ?{ $_ | ?{ $.resources | ?{ $_.type -eq "User" -and $_.name -in $handles } } | 
  %{ 
    Update-CostCenterResources -handles $handles -action "Delete" -CostCenter $_ -Enterprise $enterprise
  }

# Then assign the users to their new cost center
Update-CostCenterResources -handles $handles -action "Add" -CostCenter $costCenterNL -Enterprise $enterprise

Sie finden die aktuelle Kostenstelle für einen Benutzer im Feld Ressourcen der Kostenstelle oder über die GitHub Enterprise REST API für zugewiesene Sitze:

$handle = "jessehouwing"
$enterprise = "xebia"

# retrieve from Cost Center API
$costCenters = (gh api /enterprises/$enterprise/settings/billing/cost-centers | ConvertFrom-Json).costCenters
$currentCostCenter = $costCenters | ?{ $_.resources | ?{ $_.type -eq "User" -and $_.name -eq $handle } }

# retrieve from Assigned Seats API:
$enterpriseUsers = gh api https://api.github.com/enterprises/$enterprise/consumed-licenses --jq '.users[]' --paginate | ConvertFrom-Json
$currentCostCenter = ($enterpriseUsers | ?{ $_.github_com_login -eq $handle }).github_com_cost_center

Durch die Kombination der obigen Logik mit etwas mehr proprietärer Magie waren wir in der Lage, alle unsere Mitglieder auf der Grundlage ihrer Azure EntraID-Metadaten schnell Kostenstellen zuzuordnen.

Wie Sie in der Grafik unten sehen können, wurden bei der Zuweisung unserer Kostenstellen am 9. Januar alle zukünftigen Kosten nicht mehr dem Unternehmen (in grün), sondern den jeweiligen Kostenstellen zugeordnet.

[caption id="" align="aligncenter" width="1441"]Kosten, die ab dem 9. Januar zwischen Enterprise und einer Reihe von Kostenstellen aufgeteilt wurden. Kosten, die ab dem 9. Januar zwischen Enterprise und einer Reihe von Kostenstellen aufgeteilt wurden.[/caption]

Hinweis: Es ist derzeit nicht möglich, eine Ressource rückwirkend einer Kostenstelle zuzuordnen. Sonst hätten wir alle Kosten zum 1. des Monats zugewiesen.

 

 


Tags:

Verfasst von

Jesse Houwing

Jesse is a passionate trainer and coach, helping teams improve their productivity and quality all while trying to keep work fun. He is a Professional Scrum Trainer (PST) through Scrum.org, Microsoft Certified Trainer and GitHub Accredited Trainer. Jesse regularly blogs and you'll find him on StackOverflow, he has received the Microsoft Community Contributor Award three years in a row and has been awarded the Microsoft Most Valuable Professional award since 2015. He loves espresso and dark chocolate, travels a lot and takes photos everywhere he goes.

Contact

Let’s discuss how we can support your journey.