Package developers.. I see I can use
# package-development
m
Package developers.. I see I can use
Copy code
json
      "Unattended": {
        "PackageMigrationsUnattended": false
to set all packages to have to migrate via the backoffice. Is there a settings on the
migrationBase
perhaps that I can use to just set that my package has to via the backoffice, and not unattended?
s
Just wondering why do you want package migrations not to automatically run?
m
Sure, hitting issues where packageMigration runs unattended, and uSync/Deploy doesn't receive any notifications So then specifically with uSYnc, importAtStartup fires post migration plan and resets all the doctype/datatype changes.. this happens both for a package.xml type approach and also a programmatic update dataype
running via the backoffice, and uSync is getting the change notifications.
Copy code
csharp
    public class MyPackageMigration : PackageMigrationBase
    {
        private IHostingEnvironment _hostingEnvironment;

        public IglooPackageMigration(IPackagingService packagingService,
        IMediaService mediaService,
            MediaFileManager mediaFileManager,
        MediaUrlGeneratorCollection mediaUrlGenerators,
            IShortStringHelper shortStringHelper,
        IContentTypeBaseServiceProvider contentTypeBaseServiceProvider,
            IMigrationContext context,
        IOptions<PackageMigrationSettings> packageMigrationsSettings, IHostingEnvironment hostingEnvironment) 
        : base(
            packagingService,
            mediaService,
            mediaFileManager,
            mediaUrlGenerators,
            shortStringHelper,
            contentTypeBaseServiceProvider,
            context,
            packageMigrationsSettings)
        {
            _hostingEnvironment = hostingEnvironment;
        }

        protected override void Migrate()
        {
            // doctype updatesand new dataypes only
            XDocument xml = XDocument.Load(_hostingEnvironment.MapPathContentRoot("~/igloo/package.xml"));

            if(xml != null) { 
                var importPackageExpression = ImportPackage;

                importPackageExpression.FromEmbeddedResource(GetType());
                importPackageExpression.FromXmlDataManifest(xml).Do();
            }
        }
    }
and programmatic... (as packagemigration via xml can't update dataypes or templates)
Copy code
csharp
var myContentBlockList = _dataTypeService.GetDataType(new Guid("e52e988a-65e8-45b0-87d7-dfa013357177"));

var instagramFeedKey = new Guid("07eb60f2-2b59-4bbf-9625-a5f7cd415873");
var instagramFeedSettingsKey = new Guid("5a8a306a-7e32-458c-ae28-47ed276c5be1");

IContentType instagramFeedContentType = _contentTypeService.Get(instagramFeedKey);
IContentType instagramFeedSettingsContentType = _contentTypeService.Get(instagramFeedSettingsKey);

if (myContentBlockList is null || instagramFeedContentType is null || instagramFeedSettingsContentType is null)
{

    _logger.LogError("DataType update: Required elements not found for Instagram feed widget");
    throw new Exception("DataType update: Required elements not found for Instagram feed widget");
}

var blockConfiguration = myContentBlockList.Configuration as BlockListConfiguration;
var blocks = blockConfiguration.Blocks.ToList();


// check we don't already have the block in the config somehow
if (!blocks.Exists(x => x.ContentElementTypeKey == instagramFeedContentType.Key))
{
    blocks.Add(new BlockListConfiguration.BlockConfiguration
    {
        ContentElementTypeKey = instagramFeedContentType.Key,
        SettingsElementTypeKey = instagramFeedSettingsContentType.Key
    });

    blockConfiguration.Blocks = blocks.ToArray();

    _dataTypeService.Save(igContentBlockList);
    _logger.LogInformation("adding new widget into My-Content-Grid");
}
bit of a dicussion here.. https://github.com/KevinJump/uSync/issues/640 and think I proved to myself at least that can throw and consume a notification from packagemigration, but been a couple of weeks now..
Infact package.xml approach via the backoffice (not unattended) doesn't fire content/datatype change notification for uSync to use either ๐Ÿ˜ฆ
s
Okay, sorry, I will not have chance to read this and comprehend enough, sorry! Think you're going to have to make your own dashboard that can triggerthe code to change doctypes.
m
it's not that like back in earlier versions there is a
save with events
method??
s
inversely, you can tap the button in uSync to export everything after..
dunno
m
yeah.. but it already reimported the unchanged items on startup, then we've lost the package migration...
thanks for having a look..
s
Think you'll just have to make your own trigger ๐Ÿ™‚
m
maybe I can try manually raising a notification?
Copy code
csharp
    public void Save(IDataType dataType, int userId = -1)
    {
      EventMessages messages = this.EventMessagesFactory.Get();
      dataType.CreatorId = userId;
      using (ICoreScope coreScope = this.ScopeProvider.CreateCoreScope())
      {
        SaveEventArgs<IDataType> saveEventArgs = new SaveEventArgs<IDataType>(dataType);
        DataTypeSavingNotification savingNotification = new DataTypeSavingNotification(dataType, messages);
        if (coreScope.Notifications.PublishCancelable((ICancelableNotification) savingNotification))
        {
          coreScope.Complete();
        }
        else
        {
          if (string.IsNullOrWhiteSpace(dataType.Name))
            throw new ArgumentException("Cannot save datatype with empty name.");
          if (dataType.Name != null && dataType.Name.Length > (int) byte.MaxValue)
            throw new InvalidOperationException("Name cannot be more than 255 characters in length.");
          this._dataTypeRepository.Save(dataType);
          coreScope.Notifications.Publish((INotification) new DataTypeSavedNotification(dataType, messages).WithStateFrom<DataTypeSavedNotification, DataTypeSavingNotification>(savingNotification));
          this.Audit(AuditType.Save, userId, dataType.Id);
          coreScope.Complete();
        }
      }
    }
though stepping through the code I can see these are hit.. just no registered notificationhandler gets them ๐Ÿ˜ฆ
r
I'd like to chip in here, highlighting that notifications are suppressed during migrations: https://github.com/umbraco/Umbraco-CMS/blob/41dddee620bc7a7c5c26d15550ee5f11111bf45c/src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs#L308 However, the package migration runner does publish an aggregated notification that contains all results (including the updated entities): https://github.com/umbraco/Umbraco-CMS/blob/41dddee620bc7a7c5c26d15550ee5f11111bf45c/src/Umbraco.Infrastructure/Install/PackageMigrationRunner.cs#L128
And if you look closely at the method that suppresses the notifications: this is only done for scoped migrations (the default). So if you add a migration to your plan that inherits from
UnscopedMigrationBase
and create your own scope (without suppressing notifications), all notifications will get published: https://github.com/umbraco/Umbraco-CMS/blob/41dddee620bc7a7c5c26d15550ee5f11111bf45c/src/Umbraco.Infrastructure/Migrations/UnscopedMigrationBase.cs#L8
m
@Ronald Barendse thanks for the super relevant info.. With regards
// that packages notification handlers may explode because that package isn't fully installed yet.
๐Ÿงจ I am correct that an
unscopedMigrationBase
would have the same potential ๐Ÿ”ฅ Is it safest to use the aggregated notification to then
ImportPackage.FromEmbeddedResource<CustomPackageMigration>().Do();
or
Copy code
csharp
 var file = _hostEnvironment.MapPathContentRoot("~/package/package1.xml");

 if (System.IO.File.Exists(file))
 {
     XDocument xml = XDocument.Load(file);
     if (xml is not null)
     {
         var importPackageExpression = ImportPackage;
         importPackageExpression.FromEmbeddedResource(GetType());
         importPackageExpression.FromXmlDataManifest(xml).Do();
     }
 }
Or am I skating on thin ice here whatever approach I take?
r
You're indeed correct! Package migrations should either use PostMigrations (before v14) or that notification to do things outside of the migration/suppressed scope, like The Starter Kit does to publish the root nodes: https://github.com/umbraco/The-Starter-Kit/blob/v14/dev/src/Umbraco.SampleSite/Migrations/PostMigrationNotificationHandler.cs
The idea behind this is that content/schema added via a package migration is stored in the database as-is, similar to restoring a database backup. And if a package migration e.g. adds tables, but also handles notifications that require those tables to exist, you can run into issues, depending on the order in which the package migrations run. This is also the reason why the package migrations are stored in a weighted collection in v13, as that at least makes the order predictable (before it depended on the order returned by the assembly type scanning)...
But re-reading your initial post/issue now, package migrations don't allow updating existing entities to prevent changing it when you push to another environment that doesn't have the same migration state. Deploy actually suppresses schema/content imports in package migrations on 'remote/hosted' environments (by setting https://docs.umbraco.com/umbraco-cms/reference/configuration/packagemigrationsettings#runschemaandcontentmigrations). This ensures the package migration state is updated on your live environment, but schema/content is handled by Deploy.
Also note that the ImportPackage expression is a little bit buggy/sub-optimal as well. Especially when you want to import ZIP archives, as they need to be embedded resources (so your DLL can get very big). I did start on some improvements/enhancements, but haven't actually completed this: https://github.com/umbraco/Umbraco-CMS/compare/contrib...v9/feature/automaticpackagemigration-enhancements ๐Ÿค“
m
@Ronald Barendse again all good info.. So locally install package, Deploy uses the MigrationPlansExecutedNotification to update UDA's.. we commit to cloud and then on cloud the migrationpackage is suppressed and only updates the UmbracoKeyValue associated with the package. Yep I'm not a fan of package.zips.. seems like a fall back to umbracopackages.. esp when native nuget delivery of file based assets should be the way to do it.. but then depending on what got included in the package.zip could be overwritten.. though for content delivery/template makes like easier.. Maybe revisiting packageMigrations to aligh with uda/usyn configs as a mechanism would be a much nicer packagemigration delivery mechanism?? ๐Ÿ™‚
r
That's indeed how it works and the best/recommended way to work with Deploy yes (the left to right deployment flow)! I'm no fan of the embedded package XML/ZIPs either, but that was already available within the CMS...
l
These posts are a bit older, but @Ronald Barendse thanks for the detailed explanation! I ran into exactly the same problems as @Mike Chambers. I have a package migration that adds a property to an already existing Media type, but uSync reverts the changes. At least I have a good understand what is happenening and why it's happening.
14 Views