-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to do a missing migration check in CI #26348
Comments
@maxkoshevoi We discussed this in triage; there isn't an easy way to do this now, but we agree that it would be useful. Notes from triage:
|
Hey! I found workaround, mb it'll be useful for somebody. You can use
It gives you structed list of migrations with
|
The issue here is not that migration hasn't been applied, but that it hasn't been created (there're some model changes that are not reflected in |
Oh sorry. I was confused cuz my issue was marked as related. |
@maxkoshevoi You can create a test and use code similar to this: |
if you are ok with using some internal EF Core this does what you're asking for: [Fact]
public void Should_not_have_missing_migrations()
{
var builder = new DesignTimeServicesBuilder(typeof(MyDbContext).Assembly, Assembly.GetExecutingAssembly(), new OperationReporter(null), Array.Empty<string>());
var provider = builder.Build(GetDbContext());
var dependencies = provider.GetRequiredService<MigrationsScaffolderDependencies>();
var modelSnapshot = dependencies.MigrationsAssembly.ModelSnapshot;
var model = dependencies.SnapshotModelProcessor.Process(modelSnapshot?.Model);
var relationalModel = model?.GetRelationalModel();
var hasDifferences = dependencies.MigrationsModelDiffer.HasDifferences(relationalModel, dependencies.Model.GetRelationalModel());
hasDifferences.Should().BeFalse();
} |
@ErikEJ @aboryczko Thank you! This should work as a workaround. |
For anyone using this, if the type 'DesignTimeServicesBuilder' can not be found, make sure "Microsoft.EntityFrameworkCore.Design" is not marked as a private asset in your .csproj file. (It is by default) @aboryczko Thanks btw! Checking if a migration is missing in your PR pipeline seems like a no-brainer to me, hoping ef core will get native support for this. |
a unit test is a cool way to solve the problem! however, am I right in understanding that I need to implement private MyDbContext GetDbContext()
{
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", false, false)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", false, false)
// ^ 🤷???
;
var config = builder.Build();
var connectionString = config.GetConnectionString("Db")!;
var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
optionsBuilder.UseSqlServer(connectionString);
var context = new MyDbContext(optionsBuilder.Options);
return context;
} (maybe I could figure out how to get an |
@BenMakesGames yes, you need to create the context. I use something more complex to get the context via IServiceProvider in a base test class, but what you have written should work fine. For a unit test this would be enough: var builder = new DesignTimeServicesBuilder(typeof(MyDbContext).Assembly, Assembly.GetExecutingAssembly(), new OperationReporter(null), Array.Empty<string>());
var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>().UseSqlServer();
var dbContext = new MyDbContext(optionsBuilder.Options);
var provider = builder.Build(dbContext);
... of course if you use a different Database Provider you should change |
after starting to write a response, I think I'm understanding now; let me confirm: you're saying there's no need to connect to a specific database, because all the information needed to determine "is a new migration needed?" can be determined from code alone? that feels right, and I'll test that now. |
Correct. |
I've started some work on implementing this but would need sign off from the team before making a PR.
Based on @ajcvickers comment it looks like the team was more leaning towards this being it's own command but from a simplicity standpoint it would be easier if it were an optional switch on the dotnet ef migrations add Test --fail-on-empty The weirdness of this usage is that a lot of us want it to fail if a migration with actual operations is created. It's possible to invert that check based on exit code in a CI pipeline but generally it's more annoying. The other way would be to fail on there being actual operations but I personally haven't thought of a name that I like. Things I have thought about: If we were to make it it's own command the design I have thought about is: dotnet ef migrations verify --no-changes It feels a little extra to have it's own command for this to me since the code for it would essentially need emulate getting to this part of the code like |
@justindbaur We discussed this and we don't think it makes sense to have this be part of the |
@ajcvickers I don't disagree, it would feel a little weird in the Did the team have any thoughts about what a |
@bricelam Could you add your thoughts here? |
Dupe of #22105 |
@bricelam can warning fail CI pipeline? |
Most people I've seen write a unit test: [Fact]
public void No_pending_model_changes()
{
using var context = new MyDbContext();
var modelDiffer = context.GetService<IMigrationsModelDiffer>();
var migrationsAssembly = context.GetService<IMigrationsAssembly>();
var modelInitializer = context.GetService<IModelRuntimeInitializer>();
var snapshotModel = migrationsAssembly.ModelSnapshot?.Model;
if (snapshotModel is IMutableModel mutableModel)
snapshotModel = mutableModel.FinalizeModel();
if (snapshotModel is not null)
snapshotModel = modelInitializer.Initialize(snapshotModel);
var designTimeModel = context.GetService<IDesignTimeModel>();
var pendingModelChanges = modelDiffer.HasDifferences(
snapshotModel?.GetRelationalModel(),
designTimeModel.Model.GetRelationalModel())
Assert.Empty(pendingModelChanges);
} #22105 is also about adding a simpler API (something like |
Note from triage. This issue is still tracking having a command-line experience for asking specifically if there are pending migrations A command that returns zero if there are no pending migrations and non-zero if there are would be useful in the C.I. where the return value is used to stop/continue the process. This command would be something like |
just wanted to pop in to give a warning: after updating to the latest minor version of EF 7 (we went from 7.0.2 to 7.0.8), @aboryczko's solution stopped working for me! happily, @bricelam's code works! I only needed some small tweaks to create an options builder (we're using |
I've created a PR adding the |
Looks like we started talking about two separate issues here. React to this comment with 🚀 if you're interested in a command that checks whether there are any migrations that haven't been applied to a database (i.e. if you need to run React with 👀 if you're interested in a command that checks there are any model changes that haven't yet been added to a migration (i.e. if you need to run React with both if you want both. |
FYI, you can test for unapplied migrations today using grep: dotnet ef migrations list | grep "(Pending)" |
My GitHub Action to ensure that no new migrations are needed migration-test:
name: Migration Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0.x'
- name: Install EF Core CLI
run: dotnet tool install --global dotnet-ef
- name: Generate Migrations
run: dotnet ef migrations add ${{ github.sha }} <your-params>
- name: Check Created Migration File Against Regex
run: |
if [[ ! $(find <your-migration-folder> -name "*${{ github.sha }}.cs" | xargs grep -E -zo 'protected\s+override\s+void\s+Up\(.*\)\s*\{\s*\}\s*protected\s+override\s+void\s+Down\(.*\)\s*\{\s*\}') ]]; then
echo "Unapplied Migration Found. Make sure you have run 'dotnet ef migration add ... and committed the generated migration file. See https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli for more information."
exit 1
fi |
Our team doesn't necessarily need something like |
Ask a question
I have an idea to add "missing migration" check to my CI pipeline. This check should validate that DbSnapshot that is present in a branch matches models in that branch (in another words, it should validate that if I will create a migration,
Up
andDown
would be empty).Straightforward way of doing this would be to execute
dotnet ef migrations add Test
and validate that resulting files match "empty migration" ones, but this seems like a hack.Is there an easier way of doing this? Like
dotnet ef migrations --verify-snapshot-up-to-date
or something?Include provider and version information
EF Core version:
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 6.0
Operating system: Linux (for CI pipeline)
IDE: Visual Studio 2022
The text was updated successfully, but these errors were encountered: