If you have a need to copy code between repos I found it a bit fiddlier than I expected so for my own notes this blog is how you can set this up.
Why might you want to do this
In most cases you probably wont want to do this as you could just create a branch and merge in changes if needed, however there are a couple of scenarios you might want to do this such as:
- You are working on a project where you have a private and public version of your code such as an open source project
- You are getting a code review or doing a proof of concept and you want to give the reviewer a separate disconnected copy of the code for the review without the overhead of your existing processes
- You want to run some tools on a copy of your code on a periodic basis
- You need to give a customer access to a copy of the code as part of a contract
Requirements for the pipeline
- Trigger the pipeline manually or on the 1st friday of the month at 9pm
- Get the code from a repo in project A on the main branch
- Copy it to a repo in project B
- Check in the code that has changed
Prerequisites
- Check Build Service has permission to read the source project
2. Give permissions for the Build Service on the target DevOps Project so it can contribute and add the code to the repo
3. Allow the Pipeline to access other Projects
YAML for Pipeline
Below is the YAML I used in the pipeline.
Points to Note:
- I have split the git commands into separate tasks so its a bit easier to troubleshoot if any of them have an issue.
- I am putting the yaml file in the repo in the destination devops project and pulling the code over to it from the source to the destination keeping everything away from the source project. You could probably do it the other way around just as easily
# Pipeline to copy code from Project A to Project B
# Manual trigger to run on demand
trigger:
- none
pr: none
# Scheduled Trigger to run pipeline first friday of each month
schedules:
- cron: "0 21 1-7 * 5" # Runs on the first Friday of each month at 9:00 PM UTC
displayName: "Monthly Schedule - First Friday of the Month at 9:00 PM UTC"
branches:
include:
- main # Adjust this to the branch you want the schedule to run on
always: true # Ensures the pipeline runs even if there are no code changes
resources:
repositories:
- repository: Source
type: git
name: Mikes.DevOps.Project.A/Mikes.DevOps.Repo.A
ref: main
pool:
vmImage: ubuntu-latest
steps:
# Step 1: Clone repo's
- checkout: self
persistCredentials: true
- checkout: Source
# Listing variables in the pipeline
- task: PowerShell@2
displayName: List Variables
inputs:
targetType: 'inline'
script: |
#Displays all of the environment variables for troubleshooting
gci env:* | sort-object name
# List the files in the directories for diagnostics
- task: PowerShell@2
displayName: List Files in working directory
inputs:
targetType: 'inline'
script: 'Get-ChildItem -Path $(System.DefaultWorkingDirectory) -Recurse'
# Copy files from the source directory to the destination directory so we can copy code over to the destination project folder copy
- task: CopyFiles@2
displayName: Copy files from Source to Destination
inputs:
SourceFolder: '$(System.DefaultWorkingDirectory)/Mikes.DevOps.Repo.A'
Contents: '**'
TargetFolder: '$(System.DefaultWorkingDirectory)/Mikes.DevOps.Repo.B'
- task: PowerShell@2
displayName: Git Configure
inputs:
targetType: 'inline'
script: |
git config --global user.email "[email protected]"
git config --global user.name "DevOps Pipeline"
workingDirectory: '$(System.DefaultWorkingDirectory)/Mikes.DevOps.Repo.B'
- task: PowerShell@2
displayName: Git Add
inputs:
targetType: 'inline'
script: |
git add .
workingDirectory: '$(System.DefaultWorkingDirectory)/Mikes.DevOps.Repo.B'
- task: PowerShell@2
displayName: Git Status
inputs:
targetType: 'inline'
script: |
git status
workingDirectory: '$(System.DefaultWorkingDirectory)/Mikes.DevOps.Repo.B'
- task: PowerShell@2
displayName: Git Commit
inputs:
targetType: 'inline'
script: |
# Check for changes and commit if needed
if ((git diff-index --cached HEAD --quiet) -eq $false) {
Write-Output "Changes detected. Committing..."
git commit -m "$(BUILD.BUILDNUMBER) - Code updated by pipeline"
} else {
Write-Output "No changes to commit."
}
workingDirectory: '$(System.DefaultWorkingDirectory)/Mikes.DevOps.Repo.B'
- task: PowerShell@2
displayName: Git Push
inputs:
targetType: 'inline'
script: |
$lastCommitMessage = git log -1 --pretty=%B
if ($lastCommitMessage -eq "$(BUILD.BUILDNUMBER) - Code updated by pipeline") {
Write-Output "Pushing commit to remote..."
git -c http.extraheader="AUTHORIZATION: bearer $(System.AccessToken)" push origin HEAD:$(Build.SourceBranch)
} else {
Write-Output "No commit to push."
}
workingDirectory: '$(System.DefaultWorkingDirectory)/Mikes.DevOps.Repo.B'
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)