Jump to content

RockMigrations 🚀🚀 The Ultimate Automation and Deployment-Tool for ProcessWire


bernhard

Recommended Posts

12 hours ago, Kiwi Chris said:

I'm not sure whether that's intended behaviour?

Hi @Kiwi Chris thx for the report! Yes and no.

I've just tried and I think it works as expected. I added TestModule.module.php and TestModule.migrate.php to my site.

RockMigrations recognized the new migrate file and - as expected - ran it.

As the migrate file was empty, nothing happened and so also the TestModule kept uninstalled.

So I guess you have something in your migrate file that installs the module, do you?

 

Link to comment
Share on other sites

1 hour ago, bernhard said:

So I guess you have something in your migrate file that installs the module, do you?

I didn't have anything in the migrate file to install the module, but I did have code to create a lot of fields and templates and create some pages which all got created.

I wanted these to be under the control of migrations, but assumed (incorrectly) migrations would only run on installed modules, ie once the module is installed I do want the migrations file watched and run if there are any changes, but if the module isn't yet installed it doesn't make sense to run its migrations. 

An easy way to get it to work the way I want is to do a conditional check at the start of the migrations file to see if the module is installed or not, and only run the actual migration code to create fields and templates if the module is installed. That way I won't get a bunch of fields and templates installed for an inactive module.

  • Like 2
Link to comment
Share on other sites

Yeah @Kiwi Chris I think that's the best solution, because then everybody can decide wether he/she wants migrations to run or not. I could disable watching of Module.migrate.php files if the module is not installed, but then you'd have to manually trigger that migrations if you wanted them to be executed and that's harder to do than adding an early exit to the file.

I'll add a page to the wiki that describes that behaviour, thx!

  • Like 1
Link to comment
Share on other sites

Hey @Kiwi Chris I've created a WIKI page about the watch feature: https://github.com/baumrock/RockMigrations/wiki/The-WATCH-feature

Is that understandable?

Also while writing I've been wondering... Maybe it's really better to just run the MyModule.migrate.php if the module is installed. I think that's what everybody would expect. Also I don't see any downsides as it should trigger the migrations immediately after installation. What do you think?

I don't see any situation where one would want to have the MyModule.migrate.php run migrations on a non-installed module. If you want to install the module via RockMigrations then you'd have a Site.module.php anyhow (at least that's what I'm always recommending) or you simply put $rm->installModule() in /site/migrate.php

Link to comment
Share on other sites

11 minutes ago, bernhard said:

Maybe it's really better to just run the MyModule.migrate.php if the module is installed. I think that's what everybody would expect. Also I don't see any downsides as it should trigger the migrations immediately after installation. What do you think?

I totally agree and would have expected RM to work like that. No use for a module-related migration if the module is not installed.

  • Like 4
Link to comment
Share on other sites

v2.15.1 ignores module migrate files if the corresponding module is not installed 😎 And it will trigger the migratefile right after the module has been installed!

Thx for your input and feedback guys! Keep up bringing good suggestions 🙂 

  • Like 5
  • Thanks 1
Link to comment
Share on other sites

  • 2 weeks later...

v3.0.0 introduces a breaking change as of request from @gebeer

Unfortunately I have chosen a bad order of parameters on the createPage() method that showed warnings for @gebeer (where did that warnings appear?)

That's why I decided to change the order and the recommended way to use the createPage() method is now using named arguments. RockMigrations had PHP8.0 requirement anyhow so we can rely on them!

$rm->createPage(
  template: 'foo',
  parent: 1,
  title: 'My foo page'
);

That's a lot better to read so I think despite the breaking change it is a worthwhile addition.

PS: I tried my best to make that breaking change as obvious as possible including the version bump to 3.0.0 and the note about the breaking change in the release log. If anybody has suggestions on improvements please let me know!

  • Like 1
Link to comment
Share on other sites

Hi @bernhardjust installed a brandnew PW with https://github.com/processwire/site-regular/blob/main/README.md site profile on a local ddev with PHP 8.1. First thing I wanted to install was RockMigrations. After going to Modules->Site->Add New and pasting in the class name and clicking on Get Module Info, I got an exception:

DEBUG MODE BACKTRACE ($config->debug == true):
#0 /var/www/html/wire/core/Modules.php(688): ProcessWire\ProcessPageEditImageSelect->init()
#1 /var/www/html/wire/core/Modules.php(1455): ProcessWire\Modules->initModule(Object(ProcessWire\ProcessPageEditImageSelect), Array)
#2 /var/www/html/wire/core/Modules.php(1262): ProcessWire\Modules->getModule('ProcessPageEdit...')
#3 /var/www/html/wire/core/Modules.php(1712): ProcessWire\Modules->get('ProcessPageEdit...')
#4 /var/www/html/wire/core/WireArray.php(1789): ProcessWire\Modules->find('alsosetincompos...')
#5 /var/www/html/wire/core/WireArray.php(583): ProcessWire\WireArray->findOne('alsosetincompos...')
#6 /var/www/html/wire/core/Modules.php(1913): ProcessWire\WireArray->get('alsosetincompos...')
#7 /var/www/html/wire/modules/Process/ProcessModule/ProcessModule.module(1166): ProcessWire\Modules->isInstalled('alsosetincompos...')
#8 /var/www/html/wire/core/Wire.php(419): ProcessWire\ProcessModule->___buildDownloadConfirmForm(Array, false)
#9 /var/www/html/wire/core/WireHooks.php(952): ProcessWire\Wire->_callMethod('___buildDownloa...', Array)
#10 /var/www/html/wire/core/Wire.php(484): ProcessWire\WireHooks->runHooks(Object(ProcessWire\ProcessModule), 'buildDownloadCo...', Array)
#11 /var/www/html/wire/modules/Process/ProcessModule/ProcessModule.module(1080): ProcessWire\Wire->__call('buildDownloadCo...', Array)
#12 /var/www/html/wire/modules/Process/ProcessModule/ProcessModule.module(340): ProcessWire\ProcessModule->downloadConfirm('RockMigrations')
#13 /var/www/html/wire/core/Wire.php(413): ProcessWire\ProcessModule->___execute()
#14 /var/www/html/wire/core/WireHooks.php(952): ProcessWire\Wire->_callMethod('___execute', Array)
#15 /var/www/html/wire/core/Wire.php(484): ProcessWire\WireHooks->runHooks(Object(ProcessWire\ProcessModule), 'execute', Array)
#16 /var/www/html/wire/core/ProcessController.php(350): ProcessWire\Wire->__call('execute', Array)
#17 /var/www/html/wire/core/Wire.php(413): ProcessWire\ProcessController->___execute()
#18 /var/www/html/wire/core/WireHooks.php(952): ProcessWire\Wire->_callMethod('___execute', Array)
#19 /var/www/html/wire/core/Wire.php(484): ProcessWire\WireHooks->runHooks(Object(ProcessWire\ProcessController), 'execute', Array)
#20 /var/www/html/wire/core/admin.php(160): ProcessWire\Wire->__call('execute', Array)
#21 /var/www/html/site/templates/admin.php(16): require('/var/www/html/w...')
#22 /var/www/html/wire/core/TemplateFile.php(328): require('/var/www/html/s...')
#23 /var/www/html/wire/core/Wire.php(413): ProcessWire\TemplateFile->___render()
#24 /var/www/html/wire/core/WireHooks.php(952): ProcessWire\Wire->_callMethod('___render', Array)
#25 /var/www/html/wire/core/Wire.php(484): ProcessWire\WireHooks->runHooks(Object(ProcessWire\TemplateFile), 'render', Array)
#26 /var/www/html/wire/modules/PageRender.module(575): ProcessWire\Wire->__call('render', Array)
#27 /var/www/html/wire/core/Wire.php(416): ProcessWire\PageRender->___renderPage(Object(ProcessWire\HookEvent))
#28 /var/www/html/wire/core/WireHooks.php(952): ProcessWire\Wire->_callMethod('___renderPage', Array)
#29 /var/www/html/wire/core/Wire.php(484): ProcessWire\WireHooks->runHooks(Object(ProcessWire\PageRender), 'renderPage', Array)
#30 /var/www/html/wire/core/WireHooks.php(1060): ProcessWire\Wire->__call('renderPage', Array)
#31 /var/www/html/wire/core/Wire.php(484): ProcessWire\WireHooks->runHooks(Object(ProcessWire\Page), 'render', Array)
#32 /var/www/html/wire/modules/Process/ProcessPageView.module(184): ProcessWire\Wire->__call('render', Array)
#33 /var/www/html/wire/modules/Process/ProcessPageView.module(114): ProcessWire\ProcessPageView->renderPage(Object(ProcessWire\Page), Object(ProcessWire\PagesRequest))
#34 /var/www/html/wire/core/Wire.php(416): ProcessWire\ProcessPageView->___execute(true)
#35 /var/www/html/wire/core/WireHooks.php(952): ProcessWire\Wire->_callMethod('___execute', Array)
#36 /var/www/html/wire/core/Wire.php(484): ProcessWire\WireHooks->runHooks(Object(ProcessWire\ProcessPageView), 'execute', Array)
#37 /var/www/html/index.php(55): ProcessWire\Wire->__call('execute', Array)
#38 {main}

Other module installs I tested (ProcessWireUpgrade, ProcessDatabaseBackups), went fine. Don't know if this is related to the site profile or your module. Just wanted to let you know.

Link to comment
Share on other sites

10 hours ago, gebeer said:

Installation went smoothly with 3.1.0. Thank you!

Great. It's an issue with ProcessWire if you put valid php comments in the "requires" portion of getModuleInfo() it breaks 😞 I'll create an issue for that, thx for reporting!

  • Like 1
Link to comment
Share on other sites

  • 3 weeks later...

This module is looking great and I really appreciate all the effort that's gone into describing how to get started, videos etc..

Our team (myself excluded) is experienced with Phinx for database migrations on non-ProcessWire projects. From what I understand, a good thing about Phinx is that a file is created for each migration, that migration will only be run once, the database will record that the migration has been run, and the file will be ignored from then on. It also has a nice CLI that creates the file, dated, with the structure ready to go.

I'm thinking I could write something to make it work this way... a module that manually keeps track of all these files and then creates a list, in date order, with any new files and passes that list to $rm->watch()? Or am I reinventing the wheel with something which goes against the logic of RockMigrations...? I suppose the main aim is to idiot-proof the process so nobody edits old migrations. 

Link to comment
Share on other sites

v3.19.0 comes with a new magic method to easily set the page name whenever a page is saved:

  public function setPageName()
  {
    if (!$this->year()) return uniqid();
    return $this->title . "-" . $this->year();
  }

It will also lock the page name field and show a hint so that everybody understands what's going on:

PXiq7sB.png

  • Like 2
Link to comment
Share on other sites

ChatGPT helped me to improve RockMigrations - it's a little scary but it really saved me time today.

First, I wanted to support single paths (not json) in the workflow file definition:

QIQokCj.png

That worked after I adjusted the variable defaults of input.PATHS to "{}" so that the parsing does not throw an error. No idea why it actually seems to parse the json even if the if-condition is not met, but it works now, so I'm happy with that.

Then, as that worked quite well, I tried to fix a warning that I've been getting for quite some time and that worked even better:

7BEBrO4.png

All updates are on the dev branch.

  • Like 3
Link to comment
Share on other sites

ChatGPT is soon to replace Google, Stackoverflow and Quora for answering questions like these.

I have used it to either confirm or throw speculation on topics and directions of research. I have asked it very technical academic questions in certain fields and it has given balanced views for just about everything, including outsider views and newer untested views on certain problems. Very fun. It has even been able to tell me when a problem that I thought still existed has already been resolutely solved. Such a time saver!

My main comment, though, is that the marriage of page classes and migrations is truly groundbreaking in terms of modular design and in particular the ability to bring over single files that can instantly put in (or remove) scaffolding for demos. This has been AWESOME for live brainstorming and troubleshooting or providing clients with examples of how extensible the system is and how quickly modifications and improvements to functionality can be built out.

This has made me more excited about using RockMigrations - I was a bit on the fence when the automation was centralized in migrate.php because of how unwieldly automation scripts can get in other applications I use - but bringing things that involved scaffolding into their respective page classes allow me to really just use migrate.php for mod installations, configuration, general hooks and other core modification processes.

This is way easier to navigate, share and especially train on. This method is very easy to coach new devs on also.

  • Like 3
Link to comment
Share on other sites

Exactly. I'm happy that you see and understand the potential and that you share that 🙂 

8 minutes ago, gornycreative said:

My main comment, though, is that the marriage of page classes and migrations is truly groundbreaking in terms of modular design

Definitely 🙂 Thx for the comment!

10 minutes ago, gornycreative said:

This has made me more excited about using RockMigrations - I was a bit on the fence when the automation was centralized in migrate.php because of how unwieldly automation scripts can get in other applications I use - but bringing things that involved scaffolding into their respective page classes allow me to really just use migrate.php for mod installations, configuration, general hooks and other core modification processes.

Having everything in one huge migrate.php does not only have the drawback of getting messy quickly. It does also mean that your migrations get slow, because whenever you change anything in that file all migrations will run, no matter if they are necessary or not. If you have everything in separate files on the other hand you get cleaner code, easier to understand chunks and RM will only trigger the migrations that have changes since the last page load, which makes page loads usually be ~1s here even when migrations run.

13 minutes ago, gornycreative said:

This is way easier to navigate, share and especially train on. This method is very easy to coach new devs on also.

Yep! 🙂 If you understand the principle once, then you will instantly understand every project you are working on that follows the same simple principles.

  • Like 2
Link to comment
Share on other sites

15 minutes ago, bernhard said:

Having everything in one huge migrate.php does not only have the drawback of getting messy quickly. It does also mean that your migrations get slow, because whenever you change anything in that file all migrations will run, no matter if they are necessary or not. If you have everything in separate files on the other hand you get cleaner code, easier to understand chunks and RM will only trigger the migrations that have changes since the last page load, which makes page loads usually be ~1s here even when migrations run.

Good to know. I haven't really looked too deeply into the overhead costs for larger migrations, but that makes sense.

Link to comment
Share on other sites

@bernhard At https://github.com/baumrock/RockMigrations#working-with-fieldsets you have e nice description on how to work with fieldsets. This seems to be limited to adding fields to fieldsets at runtime.

Is there a way how we can define a migration that puts fields inside a fieldset in template context? Something like

				'content-page' => [
					'tags' => 'content',
					'fields' => [
						'title' => [
							'label' => 'Page Title',
						],
						'text' => [
							'label' => 'Subtitle',
						],
						'content_blocks' => [],
						'tab' => [], // this adds the fieldsettab open and close
						'fieldname' => [] // how to add this one to the tab fieldset
					],

It works fine with with $rm->addFieldToTemplate('fieldname', 'content-page' , 'tab', 'tab_END'). Just wondering if it is possible to do this inside the fields array in my example above.

  • Like 1
Link to comment
Share on other sites

Hey @gebeer working with fieldsets in migrations has always been a bit of a pain for me. That's why I'm using them only at runtime in all of my projects. I don't see any drawback with this. Using MagicPages it is as simple as doing this:

<?php
...
public function editForm($form) {
  ...
  $rm->wrapFields(
    // current form wrapper
    $form,
    // fields inside the fieldset
    [
      'foo' => ['columnWidth'=>33],
      'bar' => ['columnWidth'=>33],
      'baz' => ['columnWidth'=>33],
    ],
    // fieldset settings
    [
      'label' => 'Your Runtime Fieldset',
      'icon' => 'bolt',
    ]
  );
}

This is a lot quicker than messing around with fields, field order, moving the ending field to the correct place etc.

I only place the fields on the correct template, which is necessary for the fields to be queryable by selectors etc and all the rest is done in code in the pageclass.

That also makes it possible to switch layouts based on the user's role for example. So the approach is very powerful.

1 hour ago, gebeer said:

This seems to be limited to adding fields to fieldsets at runtime.

I don't see that as a limitation. Or are there any things that I'm missing?

  • Like 2
Link to comment
Share on other sites

2 minutes ago, bernhard said:

I don't see that as a limitation. Or are there any things that I'm missing?

I didn't want to say that this is a limitation. Actually it is an enhancement to have this functionality at runtime 🙂 Just wanted to make sure that I'm on the right track with defining fieldsets and their fields in my migrations. Will definitely give the runtime approach a try. Thank you.

Link to comment
Share on other sites

24 minutes ago, gebeer said:

I didn't want to say that this is a limitation. Actually it is an enhancement to have this functionality at runtime 🙂 Just wanted to make sure that I'm on the right track with defining fieldsets and their fields in my migrations. Will definitely give the runtime approach a try. Thank you.

Ok great, I thought I might be missing something, which can easily happen if you don't use the "regular" approach any more 🙂 

For me the runtime approach in general is a huge benefit. Once you start defining things in code all the little details that you would usually avoid because the GUI does not support it suddenly become a no-brainer and very easy to add.

All the little customisations that you'd usually need a hook or a module for. They are simply there in your pageclass and you start to develop the backend (page editor) similar to how you'd develop your frontend.

<?php
public function editForm($form) {
  if ($f = $form->get('title')) {
    $f->appendMarkup("
      <div>Custom field markup without any hooks...</div>
      <style>#wrap_Inputfield_title {border: 5px solid red;z-index:1;}</style>
      <script>console.log('js-demo');</script>
    ");
  }
}

ucdlNRE.png

PS: Note that this code will only be added on the page editor of pages having the pageclass where you defined your editForm() method! So if you added that in HomePage.php you'll only get the red border on the "home" page 🙂 

  • Like 1
Link to comment
Share on other sites

  • 3 weeks later...

@bernhard went to install RockMigrations to a new project today and the install fell over at line 2564 of RockMigrations.module.php on PHP 7.4.

Seems like 7.4 didn't like the Elvis operator for some reason.

Version bump to PHP 8 resolved it - but thought you might want to know for backward compatibility.

 

image-1.png

Link to comment
Share on other sites

Hi @Guy Incognito thx for the input. RockMigrations needs PHP>=8.0 and ProcessWire should warn you about that before installation: https://github.com/baumrock/RockMigrations/blob/1089f625048c4c68e883e46d1d57d7153c155bf2/RockMigrations.info.php#L14

So you did a fresh install and got an error without PW showing the requirement fails?

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...