From 061d024b984f891d5d4266f55379ed0b27a49058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20W=C3=A5hlin?= Date: Wed, 12 Jul 2023 12:50:36 +0200 Subject: [PATCH] Update ADO Pipeline instructions (#813) * Update ADO Pipeline instructions * Use parameter -Wait instead of while-loop * Update ADOPS module version --- docs/wiki/Azure-Pipelines.md | 158 ++++++++++++++--------------------- 1 file changed, 62 insertions(+), 96 deletions(-) diff --git a/docs/wiki/Azure-Pipelines.md b/docs/wiki/Azure-Pipelines.md index ee97e0e8..b5ca72e4 100644 --- a/docs/wiki/Azure-Pipelines.md +++ b/docs/wiki/Azure-Pipelines.md @@ -66,123 +66,89 @@ $SubscriptionId = '' $ARM_CLIENT_ID = '' $ARM_CLIENT_SECRET = '' -# Create a new project -$Project = az devops project list --query "value[?name=='$ProjectName'].{name:name, id:id}" --organization "https://dev.azure.com/$Organization" | ConvertFrom-Json -if ($null -eq $Project) { - $Project = az devops project create --name $ProjectName --organization "https://dev.azure.com/$Organization" ` - --query "{name:name, id:id}" | ConvertFrom-Json + +$OrgParams = @{ + Organization = $Organization + Project = $ProjectName } -# Set the defaults for the local Azure Cli shell -az devops configure ` - --defaults organization="https://dev.azure.com/$Organization" project="$ProjectName" +# Install the ADOPS PowerShell module +Install-Module -Name ADOPS -Scope CurrentUser -RequiredVersion '2.0.1' -Force -# Create a new repository from the AzOps Accelerator template repository -$Repo = az repos list --query "[?name=='$RepoName'].{name:name, id:id}" | ConvertFrom-Json -if ($null -eq $Repo) { - $Repo = az repos create --name $RepoName --query "{name:name, id:id}" | ConvertFrom-Json +# Connect to Azure DevOps (This will open a browser window for you to login) +Connect-ADOPS -Organization $Organization + +# Create a new project and wait for it to be created +$Project = Get-ADOPSProject @OrgParams +if ($null -eq $Project) { + $Project = New-ADOPSProject -Name $ProjectName -Organization $Organization -Visibility Private -Wait } -az repos import create ` - --git-url "https://github.com/Azure/AzOps-Accelerator.git" --repository "$($Repo.name)" -$null = az repos update --repository $RepoName --default-branch 'main' -# Add a variable group for authenticating pipelines with Azure Resource Manager and record the id output -if ($ARM_CLIENT_SECRET) { - $VariableGroupId = az pipelines variable-group create ` - --name 'credentials' ` - --variables ` - "ARM_TENANT_ID=$TenantId" "ARM_SUBSCRIPTION_ID=$SubscriptionId" "ARM_CLIENT_ID=$ARM_CLIENT_ID" ` - --query 'id' -} else { - $VariableGroupId = az pipelines variable-group create ` - --name 'credentials' ` - --variables ` - "ARM_TENANT_ID=$TenantId" "ARM_SUBSCRIPTION_ID=$SubscriptionId" "ARM_CLIENT_ID=$ARM_CLIENT_ID" "ARM_CLIENT_SECRET=$ARM_CLIENT_SECRET" ` - --query 'id' +# Create a new repository from the AzOps Accelerator template repository +try { + $Repo = Get-ADOPSRepository @OrgParams -Repository $RepoName +} +catch { + $Repo = New-ADOPSRepository @OrgParams -Name $RepoName } -$ConfigVariableGroupId = az pipelines variable-group create ` - --name 'azops' ` - --variables ` - "AZOPS_MODULE_VERSION=" "AZOPS_CUSTOM_SORT_ORDER=false" ` - --query 'id' +# Import the AzOps Accelerator template repository and wait for the import to complete +$null = Import-ADOPSRepository @OrgParams -RepositoryName $RepoName -GitSource 'https://github.com/Azure/AzOps-Accelerator.git' -Wait +$null = Set-ADOPSRepository -RepositoryId $repo.id -DefaultBranch 'main' @OrgParams -# Add a secret to the variable group just created using id from above if using service principal +# Add a variable group for authenticating pipelines with Azure Resource Manager and record the id output +$CredentialVariableGroup = @( + @{Name = 'ARM_TENANT_ID'; Value = $TenantId; IsSecret = $false } + @{Name = 'ARM_SUBSCRIPTION_ID'; Value = $SubscriptionId; IsSecret = $false } + @{Name = 'ARM_CLIENT_ID'; Value = $ARM_CLIENT_ID; IsSecret = $false } +) if ($ARM_CLIENT_SECRET) { - az pipelines variable-group variable create ` - --id $VariableGroupId --name 'ARM_CLIENT_SECRET' --secret true --value $ARM_CLIENT_SECRET + $CredentialVariableGroup += @{Name = 'ARM_CLIENT_SECRET'; Value = $ARM_CLIENT_SECRET; IsSecret = $true } } +$null = New-ADOPSVariableGroup -VariableGroupName 'credentials' -VariableHashtable $CredentialVariableGroup @OrgParams -# Create three new pipelines from existing YAML manifests. -az pipelines create --skip-first-run true ` - --name 'AzOps - Push' --branch main --repository "$RepoName" --repository-type tfsgit --yaml-path .pipelines/push.yml - -az pipelines create --skip-first-run true ` - --name 'AzOps - Pull' --branch main --repository "$RepoName" --repository-type tfsgit --yaml-path .pipelines/pull.yml +$ConfigVariableGroup = @( + @{Name = 'AZOPS_MODULE_VERSION'; Value = ''; IsSecret = $false } + @{Name = 'AZOPS_CUSTOM_SORT_ORDER'; Value = 'false'; IsSecret = $false } +) +$null = New-ADOPSVariableGroup -VariableGroupName 'azops' -VariableHashtable $ConfigVariableGroup @OrgParams -az pipelines create --skip-first-run true ` - --name 'AzOps - Validate' --branch main --repository "$RepoName" --repository-type tfsgit --yaml-path .pipelines/validate.yml +# Create three new pipelines from existing YAML manifests. +$null = New-ADOPSPipeline -Name 'AzOps - Push' -YamlPath '.pipelines/push.yml' -Repository $RepoName @OrgParams +$null = New-ADOPSPipeline -Name 'AzOps - Pull' -YamlPath '.pipelines/pull.yml' -Repository $RepoName @OrgParams +$null = New-ADOPSPipeline -Name 'AzOps - Validate' -YamlPath '.pipelines/validate.yml' -Repository $RepoName @OrgParams # Add build validation policy to validate pull requests -az repos policy build create --blocking true --branch main ` - --build-definition-id (az pipelines show --name 'AzOps - Validate' --query 'id') ` - --display-name 'Validate' --enabled true --queue-on-source-update-only false ` - --repository-id (az repos list --query "[?name=='$RepoName'].id" -o tsv) ` - --manual-queue-only false --valid-duration 0 --path-filter '/root/*' +$RepoId = Get-ADOPSRepository -Repository $RepoName @OrgParams | Select-Object -ExpandProperty Id +$PipelineId = Get-ADOPSPipeline -Name 'AzOps - Validate' @OrgParams | Select-Object -ExpandProperty Id +$BuildPolicyParam = @{ + RepositoryId = $RepoId + Branch = 'main' + PipelineId = $PipelineId + Displayname = 'Validate' + filenamePatterns = '/root/*' +} +$null = New-ADOPSBuildPolicy @BuildPolicyParam @OrgParams # Add branch policy to limit merge types to squash only -az repos policy merge-strategy create --blocking true --branch main ` - --repository-id (az repos list --query "[?name=='$RepoName'].id" -o tsv) --enabled true ` - --allow-no-fast-forward false --allow-rebase false --allow-rebase-merge false ` - --allow-squash true +$null = New-ADOPSMergePolicy -RepositoryId $RepoId -Branch 'main' -allowSquash @OrgParams # Add permissions for the Build Service account to the git repository -$AzureDevOpsGlobalAppId = '499b84ac-1321-427f-aa17-267ca6975798' -$AzureReposSecurityNamespaceId = '2e9eb7ed-3c0a-47d4-87c1-0ffdd275fd87' -$ProjectId = az devops project list --query "value[?name=='$ProjectName'].id" -o tsv -$RepoId = az repos list --query "[?name=='$RepoName'].id" -o tsv -$QueryStrings = "searchFilter=General&queryMembership=None&api-version=6.0&filtervalue=$ProjectName Build Service ($Organization)" -$Uri = "`"https://vssps.dev.azure.com/$Organization/_apis/identities?$QueryStrings`"" -$Subject = az rest --method get --uri $Uri --resource $AzureDevOpsGlobalAppId -o json | ConvertFrom-Json -$Body = @{ - token = "repov2/$ProjectId/$RepoId" - merge = $true - accessControlEntries = @( - @{ - # Contribute: 4 - # Force push: 8 - # CreateBranch: 16 - # Contribute to pull requests: 16384 - # Bypass policies when completing pull requests: 32768 - allow = 4 + 8 + 16 + 16384 + 32768 - deny = 0 - descriptor = $Subject.value.descriptor - } - ) -} | ConvertTo-Json -Compress | ConvertTo-Json # Convert to json twice to properly escape characters for Python interpreter -$Uri = "`"https://dev.azure.com/$Organization/_apis/accesscontrolentries/${AzureReposSecurityNamespaceId}?api-version=6.0`"" -az rest --method post --uri $Uri --body $Body --resource $AzureDevOpsGlobalAppId -o json +$ProjectId = Get-ADOPSProject @OrgParams | Select-Object -ExpandProperty Id +$BuildAccount = Get-ADOPSUser -Organization $Organization | + Where-Object displayName -eq "$ProjectName Build Service ($Organization)" +foreach ($permission in 'GenericContribute', 'ForcePush', 'CreateBranch', 'PullRequestContribute', 'PullRequestBypassPolicy') { + $null = Set-ADOPSGitPermission -ProjectId $ProjectId -RepositoryId $RepoId -Descriptor $BuildAccount.descriptor -Allow $permission +} # Add pipeline permissions for all three pipelines to the credentials Variable Groups -$AzureDevOpsGlobalAppId = '499b84ac-1321-427f-aa17-267ca6975798' -$Pipelines = az pipelines list --query "[? contains(name,'AzOps')].{id:id,name:name}" | ConvertFrom-Json -$Body = @( - @{ - resource = @{} - pipelines = @( - foreach ($pipeline in $Pipelines) { - @{ - id = $pipeline.id - authorized = $true - } - } - ) +$Uri = "https://dev.azure.com/$Organization/$ProjectName/_apis/distributedtask/variablegroups?api-version=7.1-preview.2" +$VariableGroups = (Invoke-ADOPSRestMethod -Uri $Uri -Method 'Get').value | Where-Object name -in 'credentials', 'azops' +foreach ($pipeline in 'AzOps - Push', 'AzOps - Pull', 'AzOps - Validate') { + $PipelineId = Get-ADOPSPipeline -Name $pipeline @OrgParams | Select-Object -ExpandProperty Id + foreach ($groupId in $VariableGroups.id) { + $null = Grant-ADOPSPipelinePermission -PipelineId $PipelineId -ResourceType 'VariableGroup' -ResourceId $groupId @OrgParams } -) | ConvertTo-Json -Depth 5 -Compress | ConvertTo-Json # Convert to json twice to properly escape characters for Python interpreter -foreach($groupName in 'credentials','azops') { - $VariableGroup = az pipelines variable-group list --query "[?name=='$groupName'].{id:id,name:name}" | ConvertFrom-Json - $Uri = "`"https://dev.azure.com/$Organization/$ProjectName/_apis/pipelines/pipelinepermissions/variablegroup/$($VariableGroup.id)?api-version=6.1-preview.1`"" - az rest --method patch --uri $Uri --body $Body --resource $AzureDevOpsGlobalAppId -o json } ```