Foreach repository push files and create a pull request
April 17, 2024 · (updated May 2, 2024) · 3 min · 625 words · Mart de Graaf
For a client, we manage over 60 repositories with frontends and an API behind them. To realize some features, we need to update all repositories with the same change. That seems like a lot of work doesn’t it?
I talked in previous posts about automating these kinds of changes. But for this case, we don’t want to clone all 60 repositories. We could go for a temp folder and clone them one by one and then clean them up. Another solution could be creating a yaml pipeline for it, that clones on the agent machine and loops over all repositories, but I wanted to keep the blame on the person of the initial change.
For this case I used GitHub copilot to help me brainstorm for solutions, another solution I did not follow was using a $gitClient object in Powershell.
In the underlying script, I can create a branch from the main branch and push the contents of the readme file. This is a simple example, but it could be any file. The script can push the file to the repository and create a pull request.
# Prompt the user to login and get the access token# see https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity?toc=%2Fazure%2Fdevops%2Forganizations%2Fsecurity%2Ftoc.json&view=azure-devops#q-can-i-use-a-service-principal-or-managed-identity-with-azure-cli$accessToken=azaccountget-access-token--resource499b84ac-1321-427f-aa17-267ca6975798--query"accessToken"--outputtsvif($null-eq$accessToken){exit1}$orgUrl="https://dev.azure.com/MARTORG"$project="MARTPROJECT"$repositoryId="YOURREPO"$readmeFilePath="README.md"$headers=@{"Authorization"=("Bearer {0}"-f$accessToken)"Accept"="application/json""Content-Type"="application/json"}# Convert the README file to base64$readmeContent=Get-Content-Path$readmeFilePath-Raw$readmeBase64=[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($readmeContent))Write-Host"README file content: $readmeContent"# get current commit object id$commitUrl="$orgUrl/$project/_apis/git/repositories/$repositoryId/refs/heads/main?api-version=6.0"$commitResponse=Invoke-RestMethod-Uri$commitUrl-Headers$headers-MethodGetWrite-Host$commitResponse.Value$commitObjectId=$commitResponse.Value.objectIdWrite-Host"Current commit object id: $commitObjectId"# Create the request body$changes=@(@{changeType="edit"item=@{path="README.md"}newContent=@{content=$readmeBase64contentType="base64encoded"}})$requestBody=@{refUpdates=@(@{name="refs/heads/add-readme"oldObjectId=$commitObjectId})commits=@(@{comment="Adding README file"changes=$changes})}|ConvertTo-Json-Depth6# Set the API endpoint$apiUrl="$orgUrl/$project/_apis/git/repositories/$repositoryId/pushes?api-version=6.0"# Send the API request$response=Invoke-RestMethod-Uri$apiUrl-MethodPost-Headers$headers-Body$requestBody# Check the responseif($response.pushId){Write-Host"README file pushed successfully."}else{Write-Host"Failed to push README file. Error: $($response.message)"}# create a pull request for myfirstbranch$pullRequestUrl="$orgUrl/$project/_apis/git/repositories/$repositoryId/pullrequests?api-version=6.0"$pullRequestBody=@{sourceRefName="refs/heads/add-readme"targetRefName="refs/heads/main"title="Add README file"description="Adding README file"}|ConvertTo-Json-Depth6$pullResponse=Invoke-RestMethod-Uri$pullRequestUrl-MethodPost-Headers$headers-Body$pullRequestBodyif($pullResponse.pullRequestId){Write-Host"Pull request created successfully."}else{Write-Host"Failed to create pull request. Error: $($pullResponse.message)"}
I am going to use this script to update files across all of our repositories. For this client, the code review is important, so the automation would end in a set pull request. In the next blog post, I am going to create a script that will create files to be pushed for every repository.