Ef core Migration in DevOps pipelines
Ef core migration is a great feature but it has always been a pain to run in pipelines. So far, the recommended approach was to generate a SQL script and then execute it. However, things changed with dotnet 6. With dotnet 6 migration bundle was introduced as command in dotnet ef (And with non-existent documentation).
command: dotnet ef migrations bundle
After few trials I was able to run it in the pipeline. I am using Azure Devops pipeline and deploying to VM but it should work with other pipelines too.
Steps
Configure build pipeline
- Modify your pipeline to include dotnet ef tool. And then add the steps to generate the bundle.
trigger:
- master
pool:
vmImage: 'ubuntu-latest'
variables:
buildConfiguration: 'Release'
steps:
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '6.0.101'
- task: DotNetCoreCLI@2
displayName: Install EF Tool
inputs:
command: custom
custom: 'tool'
arguments: 'install -g dotnet-ef'
- script: dotnet build --configuration $(buildConfiguration)
displayName: 'dotnet build $(buildConfiguration)'
- task: DotNetCoreCLI@2
inputs:
command: 'publish'
publishWebProjects: true
arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)'
displayName: 'dotnet publish $(buildConfiguration)'
- task: Bash@3
displayName: Add migrations directory
inputs:
targetType: 'inline'
script: 'mkdir $(Build.ArtifactStagingDirectory)/bundles'
- task: DotNetCoreCLI@2
displayName: Generate migration bundle - MyApiDbContext
inputs:
command: custom
custom: 'ef'
arguments: 'migrations bundle --startup-project Api --context MyApiDbContext -r "linux-x64" -o $(Build.ArtifactStagingDirectory)/bundles/myApiDbContext'
- task: CopyFiles@2
inputs:
SourceFolder: '$(System.DefaultWorkingDirectory)'
Contents: 'azure-deploy.sh'
TargetFolder: '$(Build.ArtifactStagingDirectory)'
displayName: "copy build script"
# this code takes all the files in $(Build.ArtifactStagingDirectory) and uploads them as an artifact of your build.
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
artifactName: 'MyApi'
displayName: 'dotnet publish artifact'
Here --context
and --startup-project
arguments are only needed if you many of them. -r
command generates the executable for given target architcture.
This step generates the artifact and puts the migrations bundle into bundles
directory.
Configure release pipeline
Generated bundle is an executable, so the next step is run them on the target machine. As I am using a VM, the step is simple.
- Copy the generated files to where other dlls are present. (this part is not documented, but it always failed if being run from anywhere else even with
--connection
argument). - Modify the permissions to run them as executable
- Run it. Here is a sample bash script to do all this.
#stop service if you are running api as service
sudo systemctl stop kestral-myApi.service sudo rm -r -f /var/www/MyApi/
sudo mkdir /var/www/MyMApi/
sudo 7za x Api.zip -o/var/www/MyApi/#copy the migration bundle to Api directory
sudo cp -a bundles/. /var/www/MyApi/
pushd /var/www/MyApi/ || exit 1
sudo chmod a+x myApiDbContext
sudo ./myApiDbContext
popd || exit 1
#restart the service
sudo systemctl start kestral-myApi.service