scripts/Invoke-RepoSync.ps1 (183 lines of code) (raw):
# Requires Environment Variables for GitHub Actions
# GH_TOKEN
# ARM_USE_AZUREAD
# ARM_USE_OIDC
# ARM_TENANT_ID
# ARM_SUBSCRIPTION_ID
# ARM_CLIENT_ID
# Must run gh auth login -h "GitHub.com" before running this script
param(
[string]$stateStorageAccountName,
[string]$stateResourceGroupName,
[string]$stateContainerName,
[string]$targetSubscriptionId,
[string]$identityResourceGroupName,
[array]$repoFilter = @(),
[bool]$planOnly = $false,
[bool]$firstRun = $false,
[array]$csvFiles = @(
<# @{
path = "./temp/TerraformResourceModules.csv"
type = "avm"
subtype = "resource"
},
@{
path = "./temp/TerraformPatternModules.csv"
type = "avm"
subtype = "pattern"
},
@{
path = "./temp/TerraformUtilityModules.csv"
type = "avm"
subtype = "utility"
}, #>
@{
path = "./legacy_repos/LegacyRepos.csv"
type = "legacy"
subtype = "legacy"
}
)
)
Write-Host "Running repo sync script"
function Add-IssueToLog {
param(
[string]$orgAndRepoName,
[string]$type,
[string]$message,
[object]$data,
[array]$issueLog,
[string]$issueLogFile="issue.log"
)
$issueLogItem = @{
orgAndRepoName = $orgAndRepoName
type = $type
message = $message
data = $data
}
$issueLog += $issueLogItem
$issueLogItemJson = ConvertTo-Json $issueLogItem -Depth 100
Add-Content -Path $issueLogFile -Value $issueLogItemJson
return $issueLog
}
$env:ARM_USE_AZUREAD = "true"
$repos = @()
Write-Host "Getting repositories from csv files"
foreach ($csvFile in $csvFiles) {
$reposFromFile = Import-Csv $($csvFile.path)
foreach ($repoFromFile in $reposFromFile) {
$repos += @{
id = $repoFromFile.ModuleName
url = $repoFromFile.RepoURL
type = $csvFile.type
subtype = $csvFile.subtype
ownerTeam = $repoFromFile.ModuleOwnersGHTeam
contributorTeam = $repoFromFile.ModuleContributorsGHTeam
}
}
}
Write-Host "Filtering repositories"
if($repoFilter.Length -gt 0) {
$repos = $repos | Where-Object { $repoFilter -contains $_.id }
}
$issueLog = @()
$secretNames = @("ARM_TENANT_ID", "ARM_SUBSCRIPTION_ID", "ARM_CLIENT_ID")
Write-Host "Iterating repositories"
foreach($repo in $repos) {
Write-Host "Checking $($repo.id)"
if(Test-Path "imports.tf") {
Remove-Item "imports.tf" -Force
}
if(Test-Path ".terraform") {
Remove-Item ".terraform" -Recurse -Force
}
$repoUrl = $repo.url
$repoSplit = $repoUrl.Split("/")
$orgName = $repoSplit[3]
$repoName = $repoSplit[4]
$orgAndRepoName = "$orgName/$repoName"
$existingRepo = $(gh api "repos/$orgAndRepoName" 2> $null) | ConvertFrom-Json
if ($existingRepo.status -eq 404) {
Write-Warning "Skipping: $orgAndRepoName has not been created yet."
$issueLog = Add-IssueToLog -orgAndRepoName $orgAndRepoName -type "repo-missing" -message "Repo $orgAndRepoName does not exist." -issueLog $issueLog
} else {
Write-Host "<--->" -ForegroundColor Green
Write-Host "$([Environment]::NewLine)Updating: $orgAndRepoName.$([Environment]::NewLine)" -ForegroundColor Green
Write-Host "<--->" -ForegroundColor Green
$existingEnvironment = $(gh api "repos/$orgAndRepoName/environments/test" 2> $null) | ConvertFrom-Json
if (($existingEnvironment.status -ne 404) -and ($repo.type -eq "avm") -and $firstRun) {
Write-Host "First Run: Taking ownership of test environevent for $orgAndRepoName"
$import = @"
import {
to = github_repository_environment.this[0]
id = "$($repoName):test"
}
"@
Add-Content -Path "imports.tf" -Value $import
foreach($secretName in $secretNames) {
$existingSecret = $(gh api "repos/$orgAndRepoName/environments/test/secrets/$secretName" 2> $null) | ConvertFrom-Json
if($existingSecret.status -ne 404) {
if(!$planOnly) {
Write-Host "Deleting secret: $secretName"
gh api -X DELETE "repos/$orgAndRepoName/environments/test/secrets/$secretName"
} else {
Write-Host "Planning to delete secret: $secretName"
}
}
}
}
$ownerTeamName = ""
if($null -ne $repo.ownerTeam) {
$ownerTeamName = $repo.ownerTeam.Replace("@Azure/", "")
$existingOwnerTeam = $(gh api "orgs/$orgName/teams/$($ownerTeamName)" 2> $null) | ConvertFrom-Json
if($existingOwnerTeam.status -eq 404) {
Write-Warning "Owner team does not exist: $($ownerTeamName)"
$issueLog = Add-IssueToLog -orgAndRepoName $orgAndRepoName -type "owner-team-missing" -message "Team $ownerTeamName does not exist." -data $ownerTeamName -issueLog $issueLog
$ownerTeamName = ""
}
}
$contributorTeamName = ""
if($null -ne $repo.contributorTeam) {
$contributorTeamName = $repo.contributorTeam.Replace("@Azure/", "")
$existingContributorTeam = $(gh api "orgs/$orgName/teams/$($contributorTeamName)" 2> $null) | ConvertFrom-Json
if($existingContributorTeam.status -eq 404) {
Write-Warning "Contributor team does not exist: $($contributorTeamName)"
$issueLog = Add-IssueToLog -orgAndRepoName $orgAndRepoName -type "contributor-team-missing" -message "Team $contributorTeamName does not exist." -data $contributorTeamName -issueLog $issueLog
$contributorTeamName = ""
}
}
terraform init `
-backend-config="resource_group_name=$stateResourceGroupName" `
-backend-config="storage_account_name=$stateStorageAccountName" `
-backend-config="container_name=$stateContainerName" `
-backend-config="key=$($repo.id).tfstate"
terraform plan -out="$($repo.id).tfplan" `
-var="github_repository_owner=$orgName" `
-var="github_repository_name=$repoName" `
-var="github_owner_team_name=$($ownerTeamName)" `
-var="github_contributor_team_name=$($contributorTeamName)" `
-var="manage_github_environment=$(($repo.type -eq "avm").ToString().ToLower())" `
-var="target_subscription_id"=$($targetSubscriptionId) `
-var="identity_resource_group_name=$($identityResourceGroupName)"
$plan = $(terraform show -json "$($repo.id).tfplan") | ConvertFrom-Json
$hasDestroy = $false
foreach($resource in $plan.resource_changes) {
if($resource.change.actions -contains "destroy") {
Write-Warning "Planning to destroy: $($resource.address)"
$hasDestroy = $true
}
}
if($hasDestroy) {
Write-Warning "Skipping: $orgAndRepoName as it has at least one destroy actions."
$issueLog = Add-IssueToLog -orgAndRepoName $orgAndRepoName -type "plan-includes-destroy" -message "Plan includes destroy for $orgAndRepoName." -data $plan -issueLog $issueLog
}
if(!$planOnly -and $plan.errored) {
Write-Warning "Skipping: Plan failed for $orgAndRepoName."
$issueLog = Add-IssueToLog -orgAndRepoName $orgAndRepoName -type "plan-failed" -message "Plan failed for $orgAndRepoName." -data $plan -issueLog $issueLog
}
if(!$hasDestroy -and !$planOnly -and !$plan.errored) {
terraform apply "$($repo.id).tfplan"
}
}
}
$issueLogJson = ConvertTo-Json $issueLog -Depth 100
$issueLogJson | Out-File "issue.log.json"